Spaces:
Sleeping
Sleeping
pipeline
#1
by
Ryonaly
- opened
- pipeline/rules.py +37 -0
pipeline/rules.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from dataclasses import dataclass
|
| 2 |
+
from typing import List, Optional
|
| 3 |
+
import statistics, math
|
| 4 |
+
|
| 5 |
+
@dataclass
|
| 6 |
+
class FrameFeatures:
|
| 7 |
+
b_count: int
|
| 8 |
+
b_area_frac: float = 0.0
|
| 9 |
+
has_consolidation: bool = False
|
| 10 |
+
quality: float = 1.0
|
| 11 |
+
|
| 12 |
+
@dataclass
|
| 13 |
+
class ZoneFeatures:
|
| 14 |
+
b_count: int
|
| 15 |
+
b_area_frac: float
|
| 16 |
+
has_consolidation: bool
|
| 17 |
+
|
| 18 |
+
def aggregate_zone(frames: List[FrameFeatures],
|
| 19 |
+
min_quality: float = 0.5, min_frames: int = 3,
|
| 20 |
+
coalescent_percentile: float = 0.90, consolidation_majority: float = 0.25) -> Optional[ZoneFeatures]:
|
| 21 |
+
kept=[f for f in frames if f.quality>=min_quality]
|
| 22 |
+
if len(kept)<min_frames: return None
|
| 23 |
+
b_counts=[f.b_count for f in kept]
|
| 24 |
+
area_vals=sorted(f.b_area_frac for f in kept)
|
| 25 |
+
p_idx=max(0,min(len(area_vals)-1,math.floor(coalescent_percentile*(len(area_vals)-1))))
|
| 26 |
+
b_area_agg=area_vals[p_idx]
|
| 27 |
+
has_consol=(sum(1 for f in kept if f.has_consolidation)/len(kept))>=consolidation_majority
|
| 28 |
+
return ZoneFeatures(int(round(statistics.median(b_counts))), float(b_area_agg), bool(has_consol))
|
| 29 |
+
|
| 30 |
+
def zone_lus_score(z: ZoneFeatures, b_count_threshold: int = 3, coalescent_area_threshold: float = 0.40) -> int:
|
| 31 |
+
if z.has_consolidation: return 3
|
| 32 |
+
if z.b_area_frac >= coalescent_area_threshold: return 2
|
| 33 |
+
if z.b_count >= b_count_threshold: return 1
|
| 34 |
+
return 0
|
| 35 |
+
|
| 36 |
+
def patient_lus_score(zones: List[Optional[ZoneFeatures]]) -> int:
|
| 37 |
+
return sum(zone_lus_score(z) for z in zones if z is not None)
|