Umut Kocasari Claude Opus 4.8 commited on
Commit
6b32ef4
·
1 Parent(s): da04fcf

Face crop: square again (better for the model), but tight to face+hair

Browse files

The model performs better on square inputs, so square the crop again — but base
it on the tight face+hair mask (not the expanded detection box), center
horizontally, anchor at the chin (face always kept), and cap the side at
1.5x head width so a tall head doesn't blow up the side margins (only a little
hair-top is dropped then; hair is mostly in). Minimizes the inherent left/right
background of a square head crop. Verified on the example: 517x517 square,
face+most hair in, much less side background than the old full-width square.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Files changed (1) hide show
  1. app.py +20 -9
app.py CHANGED
@@ -430,12 +430,18 @@ def _cstm_crop_box(mean_b, max_b, img_h, img_w, scale=1.42):
430
 
431
 
432
  def _combine_face_hair_box(face_box, hair_bbox, img_h, img_w,
433
- pad_top=0.04, pad_side=0.04, pad_bot=0.03):
434
- """Tight crop around the face + hair segmentation bbox, with small margins. The
435
- box is NOT squared: the model resizes the longest side to ``process_res`` while
436
- preserving aspect ratio (``upper_bound_resize``), so a square crop is
437
- unnecessary and only adds large background margins on the sides / top. Falls
438
- back to the pixel3dmm face box when no hair bbox is available.
 
 
 
 
 
 
439
 
440
  face_box: (ymin, ymax, xmin, xmax). hair_bbox: (x0, y0, x1, y1) or None."""
441
  if hair_bbox is None:
@@ -444,9 +450,14 @@ def _combine_face_hair_box(face_box, hair_bbox, img_h, img_w,
444
  bw = max(hx1 - hx0, 1.0); bh = max(hy1 - hy0, 1.0)
445
  x0 = hx0 - pad_side * bw; x1 = hx1 + pad_side * bw
446
  y0 = hy0 - pad_top * bh; y1 = hy1 + pad_bot * bh
447
- xmin = max(int(round(x0)), 0); ymin = max(int(round(y0)), 0)
448
- xmax = min(int(round(x1)), img_w - 1); ymax = min(int(round(y1)), img_h - 1)
449
- return ymin, ymax, xmin, xmax
 
 
 
 
 
450
 
451
 
452
  def _face_crop_frames(frame_paths, device, out_dir, log, process_res):
 
430
 
431
 
432
  def _combine_face_hair_box(face_box, hair_bbox, img_h, img_w,
433
+ pad_top=0.06, pad_side=0.03, pad_bot=0.03,
434
+ max_aspect=1.5):
435
+ """Square crop around the face + hair segmentation bbox. The model performs
436
+ better on square inputs, so we square the box — but base it on the *tight*
437
+ face+hair mask (not the expanded detection box) to keep the inherent
438
+ left/right background (a head is taller than wide) to a minimum.
439
+
440
+ side = larger padded box dim, but capped at ``max_aspect`` * head width so a
441
+ very tall head doesn't produce huge side margins; the box is centered
442
+ horizontally and anchored at the bottom, so the chin/face is always kept and
443
+ only a little hair-top is dropped when the cap bites ("hair is mostly in").
444
+ Falls back to the face box when no hair bbox is available.
445
 
446
  face_box: (ymin, ymax, xmin, xmax). hair_bbox: (x0, y0, x1, y1) or None."""
447
  if hair_bbox is None:
 
450
  bw = max(hx1 - hx0, 1.0); bh = max(hy1 - hy0, 1.0)
451
  x0 = hx0 - pad_side * bw; x1 = hx1 + pad_side * bw
452
  y0 = hy0 - pad_top * bh; y1 = hy1 + pad_bot * bh
453
+ bw_p, bh_p = x1 - x0, y1 - y0
454
+ side = min(max(bw_p, bh_p), max_aspect * bw_p, float(img_w), float(img_h))
455
+ nx0 = (x0 + x1) / 2.0 - side / 2.0 # centered horizontally on the head
456
+ ny0 = y1 - side # anchored at the bottom (keep the chin)
457
+ nx0 = min(max(nx0, 0.0), img_w - side)
458
+ ny0 = min(max(ny0, 0.0), img_h - side)
459
+ xmin = int(round(nx0)); ymin = int(round(ny0)); side = int(round(side))
460
+ return ymin, min(ymin + side, img_h - 1), xmin, min(xmin + side, img_w - 1)
461
 
462
 
463
  def _face_crop_frames(frame_paths, device, out_dir, log, process_res):