Seniordev22 commited on
Commit
324b7e6
·
verified ·
1 Parent(s): 1a83ff0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +18 -24
app.py CHANGED
@@ -159,7 +159,7 @@ def get_hair_and_exclude_masks(pil_image: Image.Image):
159
 
160
  return hair, exclude, mustache, lip_mask
161
 
162
- # ====================== BEARD MASK ======================
163
  @timed("Beard Mask")
164
  def get_beard_mask_fast(pil_image: Image.Image, exclude_mask: np.ndarray, lip_mask: np.ndarray):
165
  model = load_beard_model()
@@ -180,16 +180,22 @@ def get_beard_mask_fast(pil_image: Image.Image, exclude_mask: np.ndarray, lip_ma
180
  )
181
 
182
  mask = np.zeros((orig_h, orig_w), dtype=np.float32)
 
 
183
  if results[0].masks is not None:
184
  for i, cls in enumerate(results[0].boxes.cls):
185
  if int(cls) == 0:
186
- m = results[0].masks.data[i].cpu().numpy()
187
- m = cv2.resize(m, (orig_w, orig_h), interpolation=cv2.INTER_LINEAR)
188
- mask = np.maximum(mask, (m > 0.25).astype(np.float32))
 
 
 
189
 
190
  mask = np.maximum(mask - exclude_mask * 0.6, 0)
191
 
192
- if mask.sum() > 25:
 
193
  kernel_erode = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))
194
  mask = cv2.erode(mask, kernel_erode, iterations=2)
195
  kernel_close = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (13, 13))
@@ -212,9 +218,9 @@ def get_beard_mask_fast(pil_image: Image.Image, exclude_mask: np.ndarray, lip_ma
212
  mask = cv2.erode(mask, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)), iterations=1)
213
 
214
  mask[lip_mask > 0] = 0
215
- return mask
216
 
217
- # ====================== COLOR TRANSFER - BEARD SAME AS HAIR (FIXED) ======================
218
  @timed("Color Transfer")
219
  def apply_strong_grey_hair(image: Image.Image, hair_mask: np.ndarray, beard_mask: np.ndarray):
220
  # Combine hair and beard masks
@@ -225,11 +231,8 @@ def apply_strong_grey_hair(image: Image.Image, hair_mask: np.ndarray, beard_mask
225
  img = np.array(image).astype(np.float32) / 255.0
226
  hsv = cv2.cvtColor((img * 255).astype(np.uint8), cv2.COLOR_RGB2HSV).astype(np.float32)
227
 
228
- # Apply hair-style transformation using combined mask (hair + beard)
229
  hsv_transformed = hsv.copy()
230
- # Desaturate based on combined mask
231
  hsv_transformed[..., 1] = hsv_transformed[..., 1] * (1 - 0.78 * combined_mask)
232
- # Boost brightness
233
  original_v = hsv[..., 2]
234
  boost_amount = 89 * combined_mask
235
  hsv_transformed[..., 2] = np.clip(
@@ -238,11 +241,9 @@ def apply_strong_grey_hair(image: Image.Image, hair_mask: np.ndarray, beard_mask
238
  )
239
  transformed_rgb = cv2.cvtColor(hsv_transformed.astype(np.uint8), cv2.COLOR_HSV2RGB).astype(np.float32) / 255.0
240
 
241
- # Final blend: only change combined mask area, keep rest original
242
  combined_mask_3ch = np.stack([combined_mask, combined_mask, combined_mask], axis=2)
243
  final = transformed_rgb * combined_mask_3ch + img * (1 - combined_mask_3ch)
244
 
245
- # Light cool tint for natural look
246
  final = final + (np.array([9, 7, 5], dtype=np.float32) / 255.0 * combined_mask[..., None] * 0.18)
247
 
248
  final = np.clip(final * 255, 0, 255).astype(np.uint8)
@@ -251,7 +252,7 @@ def apply_strong_grey_hair(image: Image.Image, hair_mask: np.ndarray, beard_mask
251
 
252
  return result
253
 
254
- # ====================== MAIN PROCESSING ======================
255
  @timed("Total Processing")
256
  def process_face_whitening(input_image: Image.Image):
257
  orig = input_image.convert("RGB")
@@ -264,22 +265,15 @@ def process_face_whitening(input_image: Image.Image):
264
  img_resized = orig.resize((target, target), Image.BILINEAR)
265
 
266
  hair_mask, exclude_mask, mustache_mask, lip_mask = get_hair_and_exclude_masks(img_resized)
267
- beard_mask = get_beard_mask_fast(img_resized, exclude_mask, lip_mask)
268
-
269
- # ========== NEW: Apply mustache only if beard is detected ==========
270
- beard_detected = beard_mask.sum() > 100 # Threshold for beard presence
271
 
272
- if beard_detected:
273
- # Blend mustache into beard mask
274
  beard_mask = np.maximum(beard_mask, mustache_mask * 0.98)
275
-
276
- # Extra boost for thin mustache areas
277
  weak_mustache = (mustache_mask > 0.18) & (beard_mask < 0.48)
278
  beard_mask[weak_mustache] = np.maximum(beard_mask[weak_mustache], 0.75)
279
-
280
- # Ensure lip region stays clear
281
  beard_mask[lip_mask > 0] = 0
282
- # else: no beard → beard_mask remains as is (likely zero, mustache not added)
283
 
284
  final_resized = apply_strong_grey_hair(img_resized, hair_mask, beard_mask)
285
  final_img = final_resized.resize((ow, oh), Image.LANCZOS)
 
159
 
160
  return hair, exclude, mustache, lip_mask
161
 
162
+ # ====================== BEARD MASK (FIXED: returns beard_present flag) ======================
163
  @timed("Beard Mask")
164
  def get_beard_mask_fast(pil_image: Image.Image, exclude_mask: np.ndarray, lip_mask: np.ndarray):
165
  model = load_beard_model()
 
180
  )
181
 
182
  mask = np.zeros((orig_h, orig_w), dtype=np.float32)
183
+ beard_present = False # <-- NEW FLAG
184
+
185
  if results[0].masks is not None:
186
  for i, cls in enumerate(results[0].boxes.cls):
187
  if int(cls) == 0:
188
+ conf = results[0].boxes.conf[i].item()
189
+ if conf > 0.25: # confidence threshold for considering a real beard
190
+ beard_present = True
191
+ m = results[0].masks.data[i].cpu().numpy()
192
+ m = cv2.resize(m, (orig_w, orig_h), interpolation=cv2.INTER_LINEAR)
193
+ mask = np.maximum(mask, (m > 0.25).astype(np.float32))
194
 
195
  mask = np.maximum(mask - exclude_mask * 0.6, 0)
196
 
197
+ # Only apply morphological refinements if beard is actually present
198
+ if beard_present and mask.sum() > 25:
199
  kernel_erode = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))
200
  mask = cv2.erode(mask, kernel_erode, iterations=2)
201
  kernel_close = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (13, 13))
 
218
  mask = cv2.erode(mask, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)), iterations=1)
219
 
220
  mask[lip_mask > 0] = 0
221
+ return mask, beard_present # <-- RETURN BOTH
222
 
223
+ # ====================== COLOR TRANSFER - BEARD SAME AS HAIR ======================
224
  @timed("Color Transfer")
225
  def apply_strong_grey_hair(image: Image.Image, hair_mask: np.ndarray, beard_mask: np.ndarray):
226
  # Combine hair and beard masks
 
231
  img = np.array(image).astype(np.float32) / 255.0
232
  hsv = cv2.cvtColor((img * 255).astype(np.uint8), cv2.COLOR_RGB2HSV).astype(np.float32)
233
 
 
234
  hsv_transformed = hsv.copy()
 
235
  hsv_transformed[..., 1] = hsv_transformed[..., 1] * (1 - 0.78 * combined_mask)
 
236
  original_v = hsv[..., 2]
237
  boost_amount = 89 * combined_mask
238
  hsv_transformed[..., 2] = np.clip(
 
241
  )
242
  transformed_rgb = cv2.cvtColor(hsv_transformed.astype(np.uint8), cv2.COLOR_HSV2RGB).astype(np.float32) / 255.0
243
 
 
244
  combined_mask_3ch = np.stack([combined_mask, combined_mask, combined_mask], axis=2)
245
  final = transformed_rgb * combined_mask_3ch + img * (1 - combined_mask_3ch)
246
 
 
247
  final = final + (np.array([9, 7, 5], dtype=np.float32) / 255.0 * combined_mask[..., None] * 0.18)
248
 
249
  final = np.clip(final * 255, 0, 255).astype(np.uint8)
 
252
 
253
  return result
254
 
255
+ # ====================== MAIN PROCESSING (FIXED: mustache only if beard detected) ======================
256
  @timed("Total Processing")
257
  def process_face_whitening(input_image: Image.Image):
258
  orig = input_image.convert("RGB")
 
265
  img_resized = orig.resize((target, target), Image.BILINEAR)
266
 
267
  hair_mask, exclude_mask, mustache_mask, lip_mask = get_hair_and_exclude_masks(img_resized)
268
+ beard_mask, beard_present = get_beard_mask_fast(img_resized, exclude_mask, lip_mask)
 
 
 
269
 
270
+ # ========== KEY FIX: Apply mustache ONLY if a beard is present ==========
271
+ if beard_present:
272
  beard_mask = np.maximum(beard_mask, mustache_mask * 0.98)
 
 
273
  weak_mustache = (mustache_mask > 0.18) & (beard_mask < 0.48)
274
  beard_mask[weak_mustache] = np.maximum(beard_mask[weak_mustache], 0.75)
 
 
275
  beard_mask[lip_mask > 0] = 0
276
+ # else: no beard → mustache mask is ignored completely
277
 
278
  final_resized = apply_strong_grey_hair(img_resized, hair_mask, beard_mask)
279
  final_img = final_resized.resize((ow, oh), Image.LANCZOS)