Evan Li commited on
Commit
dfb09f4
Β·
1 Parent(s): 8aee038

fixed unknown fields, SegFromer processor assigned, MediaPipe for lips

Browse files
analyzers/color_analyzer.py CHANGED
@@ -41,6 +41,18 @@ EYE_COLOR_RANGES = {
41
  HAIR_TEXTURE_CURLY_THRESHOLD = 25.0
42
  HAIR_TEXTURE_WAVY_THRESHOLD = 15.0
43
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
  class ColorAnalyzer:
46
  def __init__(self):
@@ -66,6 +78,14 @@ class ColorAnalyzer:
66
  if lip_mask is not None:
67
  lip_mask = lip_mask.astype(bool)
68
 
 
 
 
 
 
 
 
 
69
  # ── Skin Tone ────────────────────────────────────────────────
70
  if skin_mask is not None and skin_mask.sum() > 100:
71
  skin_lab = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2LAB)
@@ -258,6 +278,33 @@ class ColorAnalyzer:
258
  return "wavy"
259
  return "straight"
260
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
  # ------------------------------------------------------------------
262
  # Eye color helpers
263
  # ------------------------------------------------------------------
 
41
  HAIR_TEXTURE_CURLY_THRESHOLD = 25.0
42
  HAIR_TEXTURE_WAVY_THRESHOLD = 15.0
43
 
44
+ # MediaPipe FaceMesh lip contours. Outer ring traces the lip border;
45
+ # inner ring traces the mouth opening β€” subtract one from the other
46
+ # to get just the lip flesh and avoid sampling teeth or tongue.
47
+ MEDIAPIPE_LIP_OUTER = [
48
+ 61, 146, 91, 181, 84, 17, 314, 405, 321, 375,
49
+ 291, 409, 270, 269, 267, 0, 37, 39, 40, 185,
50
+ ]
51
+ MEDIAPIPE_LIP_INNER = [
52
+ 78, 95, 88, 178, 87, 14, 317, 402, 318, 324,
53
+ 308, 415, 310, 311, 312, 13, 82, 81, 80, 191,
54
+ ]
55
+
56
 
57
  class ColorAnalyzer:
58
  def __init__(self):
 
78
  if lip_mask is not None:
79
  lip_mask = lip_mask.astype(bool)
80
 
81
+ # SegFormer human-parsing has no dedicated lip class, so the
82
+ # parser hands us an empty mask. Fall back to MediaPipe lip
83
+ # landmarks whenever the parser-derived mask is missing or tiny.
84
+ if (lip_mask is None or lip_mask.sum() < 50) and landmarks:
85
+ derived = self._lip_mask_from_landmarks(landmarks, h, w)
86
+ if derived is not None:
87
+ lip_mask = derived
88
+
89
  # ── Skin Tone ────────────────────────────────────────────────
90
  if skin_mask is not None and skin_mask.sum() > 100:
91
  skin_lab = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2LAB)
 
278
  return "wavy"
279
  return "straight"
280
 
281
+ # ------------------------------------------------------------------
282
+ # Lip mask helper
283
+ # ------------------------------------------------------------------
284
+
285
+ @staticmethod
286
+ def _lip_mask_from_landmarks(
287
+ landmarks: list[dict], h: int, w: int
288
+ ) -> np.ndarray | None:
289
+ """Build a lip-flesh mask by filling outer lip contour minus inner."""
290
+ max_idx = max(MEDIAPIPE_LIP_OUTER + MEDIAPIPE_LIP_INNER)
291
+ if len(landmarks) <= max_idx:
292
+ return None
293
+
294
+ def _poly(indices: list[int]) -> np.ndarray:
295
+ return np.array(
296
+ [
297
+ [int(landmarks[i]["x"] * w), int(landmarks[i]["y"] * h)]
298
+ for i in indices
299
+ ],
300
+ dtype=np.int32,
301
+ )
302
+
303
+ mask = np.zeros((h, w), dtype=np.uint8)
304
+ cv2.fillPoly(mask, [_poly(MEDIAPIPE_LIP_OUTER)], 255)
305
+ cv2.fillPoly(mask, [_poly(MEDIAPIPE_LIP_INNER)], 0)
306
+ return mask.astype(bool)
307
+
308
  # ------------------------------------------------------------------
309
  # Eye color helpers
310
  # ------------------------------------------------------------------
analyzers/parsing_analyzer.py CHANGED
@@ -63,6 +63,7 @@ class ParsingAnalyzer:
63
  self.processor = None
64
  self.model = None
65
  try:
 
66
  self.model = SegformerForSemanticSegmentation.from_pretrained(MODEL_ID)
67
  self.model.to(self.device).eval()
68
  except Exception as exc:
 
63
  self.processor = None
64
  self.model = None
65
  try:
66
+ self.processor = SegformerImageProcessor.from_pretrained(MODEL_ID)
67
  self.model = SegformerForSemanticSegmentation.from_pretrained(MODEL_ID)
68
  self.model.to(self.device).eval()
69
  except Exception as exc: