ab2207 commited on
Commit
6f206ca
·
verified ·
1 Parent(s): 68f9c28

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +61 -58
app.py CHANGED
@@ -291,48 +291,46 @@ def apply_blur(image, x, y, w, h):
291
 
292
  def draw_label(image, x, y, w, h, text, color):
293
  """
294
- Smart Annotation:
295
- - Draws text OUTSIDE the face box.
296
- - Tries to draw ABOVE. If no space, draws BELOW.
297
- - Background box matches text size.
298
  """
 
 
 
 
 
 
 
 
299
  font = cv2.FONT_HERSHEY_SIMPLEX
300
- scale = 0.6
301
- thickness = 2
302
- (tw, th), _ = cv2.getTextSize(text, font, scale, thickness)
303
 
304
- margin = 10 # Gap between face and text
305
 
306
- # Check if we have space above the face
307
- # We need space for Text Height (th) + Padding (~15px)
308
- space_above = y - th - 15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
309
 
310
- if space_above > 0:
311
- # === DRAW ABOVE ===
312
- text_y = y - margin
313
-
314
- # Coordinates for the background rectangle
315
- box_tl = (x, text_y - th - 5)
316
- box_br = (x + tw + 10, text_y + 5)
317
-
318
- cv2.rectangle(image, box_tl, box_br, color, -1)
319
- cv2.putText(image, text, (x + 5, text_y), font, scale, (255, 255, 255), thickness)
320
- else:
321
- # === DRAW BELOW ===
322
- # y + h is the bottom of the face
323
- text_y = y + h + th + margin
324
-
325
- # Coordinates for the background rectangle
326
- box_tl = (x, text_y - th - 5)
327
- box_br = (x + tw + 10, text_y + 5)
328
-
329
- cv2.rectangle(image, box_tl, box_br, color, -1)
330
- cv2.putText(image, text, (x + 5, text_y), font, scale, (255, 255, 255), thickness)
331
 
332
  def process_frame(image, mode):
333
  """
334
- THE MASTER FUNCTION.
335
- Returns: (processed_image, log_string)
336
  """
337
  if image is None: return None, "No Image"
338
 
@@ -340,59 +338,64 @@ def process_frame(image, mode):
340
  faces = GLOBAL_DETECTOR.detect(image)
341
  processed_img = image.copy()
342
  log_entries = []
 
343
 
 
 
 
344
  for i, face in enumerate(faces):
345
  x, y, w, h = face['box']
346
 
347
- # 2. Analysis
348
- # Default vars
349
- full_log_text = "Unknown" # Goes to text box
350
- img_label_text = "Unknown" # Goes to image overlay
351
- color = (0, 255, 0)
352
 
353
  if mode in ["data", "smart"]:
354
- # Crop and Check DB
355
  face_crop = image[y:y+h, x:x+w]
356
  if face_crop.size > 0:
357
  res = FACE_DB.recognize(face_crop)
358
 
359
  if res['match']:
360
- # 1. LOG GETS FULL DETAILS
361
  full_log_text = f"MATCH - {res['name']} (ID: {res['id']})"
362
  log_entries.append(f"✅ Face #{i+1}: {full_log_text}")
363
-
364
- # 2. IMAGE GETS ID ONLY
365
  img_label_text = f"ID: {res['id']}"
 
366
  else:
 
367
  full_log_text = "UNKNOWN"
368
  log_entries.append(f"⚠️ Face #{i+1}: {full_log_text}")
369
  img_label_text = "Unknown"
370
-
371
- color = res['color']
372
  else:
373
  log_entries.append(f"🔒 Face #{i+1}: Anonymized")
374
 
375
- # 3. Modification
376
- if mode == "privacy":
377
  processed_img = apply_blur(processed_img, x, y, w, h)
378
 
379
- elif mode == "data":
380
- # Draw Box + Label (passing 'h' for smart positioning)
381
- cv2.rectangle(processed_img, (x, y), (x+w, y+h), color, 2)
382
- draw_label(processed_img, x, y, w, h, img_label_text, color)
383
-
384
- elif mode == "smart":
385
- # Blur + Label (passing 'h' for smart positioning)
386
- processed_img = apply_blur(processed_img, x, y, w, h)
387
- draw_label(processed_img, x, y, w, h, img_label_text, color)
388
-
389
- # Create Log String
 
 
 
390
  if not log_entries:
391
  final_log = "No faces detected."
392
  else:
393
  final_log = "--- Detection Report ---\n" + "\n".join(log_entries)
394
 
395
  return processed_img, final_log
 
396
 
397
  # ====================================================
398
  # 5. VIDEO PROCESSING HELPERS
 
291
 
292
  def draw_label(image, x, y, w, h, text, color):
293
  """
294
+ 1. Always draw the border (The primary signal).
295
+ 2. Attempt to draw text inside.
296
+ 3. If text doesn't fit geometrically, hide it automatically.
 
297
  """
298
+ # 1. Dynamic Border Thickness
299
+ # Big face = 2px border, Tiny face = 1px border (so it doesn't look like a blob)
300
+ thickness = 2 if w > 40 else 1
301
+ cv2.rectangle(image, (x, y), (x+w, y+h), color, thickness)
302
+
303
+ # 2. Geometry Check: Can we fit text?
304
+ # We define a 'Minimum Readable Font' (Scale 0.4 is the smallest legible size)
305
+ min_font_scale = 0.4
306
  font = cv2.FONT_HERSHEY_SIMPLEX
307
+ font_thickness = 1
 
 
308
 
309
+ (tw, th), _ = cv2.getTextSize(text, font, min_font_scale, font_thickness)
310
 
311
+ # PADDING: We need at least 2 pixels on sides
312
+ required_width = tw + 4
313
+
314
+ # THE RULE: If the text is wider than the face, DO NOT DRAW IT.
315
+ if required_width > w:
316
+ return
317
+
318
+ # 3. If we passed the check, draw it centered
319
+ center_x = x + (w // 2) - (tw // 2)
320
+ center_y = y + (h // 2) + (th // 2)
321
+
322
+ # Background Strip (for readability against blur)
323
+ bg_tl = (center_x - 2, center_y - th - 2)
324
+ bg_br = (center_x + tw + 2, center_y + 2)
325
+ cv2.rectangle(image, bg_tl, bg_br, color, -1)
326
+
327
+ # Text
328
+ cv2.putText(image, text, (center_x, center_y), font, min_font_scale, (255, 255, 255), font_thickness, cv2.LINE_AA)
329
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
330
 
331
  def process_frame(image, mode):
332
  """
333
+ MASTER FUNCTION (Standardized).
 
334
  """
335
  if image is None: return None, "No Image"
336
 
 
338
  faces = GLOBAL_DETECTOR.detect(image)
339
  processed_img = image.copy()
340
  log_entries = []
341
+ labels_to_draw = []
342
 
343
+ # =================================================
344
+ # PASS 1: BLUR & ANALYZE
345
+ # =================================================
346
  for i, face in enumerate(faces):
347
  x, y, w, h = face['box']
348
 
349
+ # Default: Unknown/Red
350
+ full_log_text = "Unknown"
351
+ img_label_text = "Unknown"
352
+ color = (255, 0, 0)
 
353
 
354
  if mode in ["data", "smart"]:
 
355
  face_crop = image[y:y+h, x:x+w]
356
  if face_crop.size > 0:
357
  res = FACE_DB.recognize(face_crop)
358
 
359
  if res['match']:
360
+ # Match: Green
361
  full_log_text = f"MATCH - {res['name']} (ID: {res['id']})"
362
  log_entries.append(f"✅ Face #{i+1}: {full_log_text}")
 
 
363
  img_label_text = f"ID: {res['id']}"
364
+ color = (0, 255, 0)
365
  else:
366
+ # No Match: Red
367
  full_log_text = "UNKNOWN"
368
  log_entries.append(f"⚠️ Face #{i+1}: {full_log_text}")
369
  img_label_text = "Unknown"
370
+ color = (255, 0, 0)
 
371
  else:
372
  log_entries.append(f"🔒 Face #{i+1}: Anonymized")
373
 
374
+ # Action: Blur
375
+ if mode == "privacy" or mode == "smart":
376
  processed_img = apply_blur(processed_img, x, y, w, h)
377
 
378
+ # Action: Queue Badge
379
+ if mode == "data" or mode == "smart":
380
+ labels_to_draw.append({
381
+ "x": x, "y": y, "w": w, "h": h,
382
+ "text": img_label_text, "color": color
383
+ })
384
+
385
+ # =================================================
386
+ # PASS 2: DRAW BADGES (Top Layer)
387
+ # =================================================
388
+ for item in labels_to_draw:
389
+ draw_label(processed_img, item['x'], item['y'], item['w'], item['h'], item['text'], item['color'])
390
+
391
+ # Create Log
392
  if not log_entries:
393
  final_log = "No faces detected."
394
  else:
395
  final_log = "--- Detection Report ---\n" + "\n".join(log_entries)
396
 
397
  return processed_img, final_log
398
+
399
 
400
  # ====================================================
401
  # 5. VIDEO PROCESSING HELPERS