dreamlessx commited on
Commit
27cf3ae
·
verified ·
1 Parent(s): 89d633f

Upload landmarkdiff/clinical.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. landmarkdiff/clinical.py +73 -9
landmarkdiff/clinical.py CHANGED
@@ -1,7 +1,10 @@
1
- """Clinical edge cases: vitiligo, Bell's palsy, keloid, Ehlers-Danlos.
2
 
3
- Each condition modifies the pipeline differently (mask exclusion,
4
- asymmetric deformation, wider radii, etc).
 
 
 
5
  """
6
 
7
  from __future__ import annotations
@@ -16,7 +19,10 @@ from landmarkdiff.landmarks import FaceLandmarks
16
 
17
  @dataclass
18
  class ClinicalFlags:
19
- """Flags that change how the pipeline handles this patient."""
 
 
 
20
 
21
  vitiligo: bool = False
22
  bells_palsy: bool = False
@@ -35,7 +41,20 @@ def detect_vitiligo_patches(
35
  l_threshold: float = 85.0,
36
  min_patch_area: int = 200,
37
  ) -> np.ndarray:
38
- """Detect depigmented (vitiligo) patches on face using LAB luminance."""
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  h, w = image.shape[:2]
40
  lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB).astype(np.float32)
41
 
@@ -83,7 +102,19 @@ def adjust_mask_for_vitiligo(
83
  vitiligo_patches: np.ndarray,
84
  preservation_factor: float = 0.3,
85
  ) -> np.ndarray:
86
- """Reduce mask intensity over vitiligo patches to preserve them."""
 
 
 
 
 
 
 
 
 
 
 
 
87
  patches_f = vitiligo_patches.astype(np.float32) / 255.0
88
  reduction = patches_f * preservation_factor
89
  return np.clip(mask - reduction, 0.0, 1.0)
@@ -92,7 +123,14 @@ def adjust_mask_for_vitiligo(
92
  def get_bells_palsy_side_indices(
93
  side: str,
94
  ) -> dict[str, list[int]]:
95
- """Get landmark indices for the affected side in Bell's palsy."""
 
 
 
 
 
 
 
96
  if side == "left":
97
  return {
98
  "eye": [33, 7, 163, 144, 145, 153, 154, 155, 133, 173, 157, 158, 159, 160, 161, 246],
@@ -116,7 +154,21 @@ def get_keloid_exclusion_mask(
116
  height: int,
117
  margin_px: int = 10,
118
  ) -> np.ndarray:
119
- """Generate mask of keloid-prone regions to exclude from aggressive compositing."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  from landmarkdiff.landmarks import LANDMARK_REGIONS
121
 
122
  mask = np.zeros((height, width), dtype=np.float32)
@@ -145,7 +197,19 @@ def adjust_mask_for_keloid(
145
  keloid_mask: np.ndarray,
146
  reduction_factor: float = 0.5,
147
  ) -> np.ndarray:
148
- """Soften mask transitions in keloid-prone areas."""
 
 
 
 
 
 
 
 
 
 
 
 
149
  # Reduce mask intensity in keloid-prone areas
150
  keloid_reduction = keloid_mask * reduction_factor
151
  modified = mask * (1.0 - keloid_reduction)
 
1
+ """Clinical edge case handling for pathological conditions.
2
 
3
+ Implements special-case logic for:
4
+ - Vitiligo: preserve depigmented patches (don't blend over them)
5
+ - Bell's palsy: disable bilateral symmetry in deformation vectors
6
+ - Keloid: flag keloid-prone areas to reduce aggressive compositing
7
+ - Ehlers-Danlos: wider influence radii for hypermobile tissue
8
  """
9
 
10
  from __future__ import annotations
 
19
 
20
  @dataclass
21
  class ClinicalFlags:
22
+ """Clinical condition flags that modify pipeline behavior.
23
+
24
+ Set flags to True to enable condition-specific handling.
25
+ """
26
 
27
  vitiligo: bool = False
28
  bells_palsy: bool = False
 
41
  l_threshold: float = 85.0,
42
  min_patch_area: int = 200,
43
  ) -> np.ndarray:
44
+ """Detect depigmented (vitiligo) patches on face using LAB luminance.
45
+
46
+ Vitiligo patches appear as high-L, low-saturation regions that deviate
47
+ significantly from surrounding skin tone.
48
+
49
+ Args:
50
+ image: BGR face image.
51
+ face: Extracted landmarks for face ROI.
52
+ l_threshold: Luminance threshold (patches brighter than surrounding skin).
53
+ min_patch_area: Minimum contour area in pixels to count as a patch.
54
+
55
+ Returns:
56
+ Binary mask (uint8, 0/255) of detected vitiligo patches.
57
+ """
58
  h, w = image.shape[:2]
59
  lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB).astype(np.float32)
60
 
 
102
  vitiligo_patches: np.ndarray,
103
  preservation_factor: float = 0.3,
104
  ) -> np.ndarray:
105
+ """Reduce mask intensity over vitiligo patches to preserve them.
106
+
107
+ Instead of full blending over depigmented patches, we reduce the
108
+ mask weight so the original vitiligo pattern shows through.
109
+
110
+ Args:
111
+ mask: Float32 surgical mask [0-1].
112
+ vitiligo_patches: Binary mask of vitiligo regions (0/255 uint8).
113
+ preservation_factor: How much to reduce blending (0=full blend, 1=fully preserve).
114
+
115
+ Returns:
116
+ Modified mask with reduced intensity over vitiligo patches.
117
+ """
118
  patches_f = vitiligo_patches.astype(np.float32) / 255.0
119
  reduction = patches_f * preservation_factor
120
  return np.clip(mask - reduction, 0.0, 1.0)
 
123
  def get_bells_palsy_side_indices(
124
  side: str,
125
  ) -> dict[str, list[int]]:
126
+ """Get landmark indices for the affected side in Bell's palsy.
127
+
128
+ In Bell's palsy, one side of the face is paralyzed. We should NOT
129
+ apply bilateral symmetric deformations — only deform the healthy side.
130
+
131
+ Returns:
132
+ Dict mapping region names to landmark indices on the affected side.
133
+ """
134
  if side == "left":
135
  return {
136
  "eye": [33, 7, 163, 144, 145, 153, 154, 155, 133, 173, 157, 158, 159, 160, 161, 246],
 
154
  height: int,
155
  margin_px: int = 10,
156
  ) -> np.ndarray:
157
+ """Generate mask of keloid-prone regions to exclude from aggressive compositing.
158
+
159
+ Keloid patients should have reduced blending intensity and no sharp
160
+ boundary transitions in prone areas (typically jawline, ears, chest).
161
+
162
+ Args:
163
+ face: Extracted landmarks.
164
+ regions: List of region names prone to keloids.
165
+ width: Image width.
166
+ height: Image height.
167
+ margin_px: Extra margin around keloid regions.
168
+
169
+ Returns:
170
+ Float32 mask [0-1] where 1 = keloid-prone area.
171
+ """
172
  from landmarkdiff.landmarks import LANDMARK_REGIONS
173
 
174
  mask = np.zeros((height, width), dtype=np.float32)
 
197
  keloid_mask: np.ndarray,
198
  reduction_factor: float = 0.5,
199
  ) -> np.ndarray:
200
+ """Soften mask transitions in keloid-prone areas.
201
+
202
+ Reduces the mask gradient steepness to prevent hard boundaries
203
+ that could trigger keloid formation in real surgical planning.
204
+
205
+ Args:
206
+ mask: Float32 surgical mask [0-1].
207
+ keloid_mask: Float32 keloid region mask [0-1].
208
+ reduction_factor: How much to reduce mask intensity in keloid areas.
209
+
210
+ Returns:
211
+ Modified mask with gentler transitions in keloid regions.
212
+ """
213
  # Reduce mask intensity in keloid-prone areas
214
  keloid_reduction = keloid_mask * reduction_factor
215
  modified = mask * (1.0 - keloid_reduction)