Add geometric upper-bound gates: max face-area fraction, aspect window
Tested against real failure samples from the v2 run: full-frame feather storm (area .64) and wide effect blob (area .70) now rejected; normal and close-up faces pass. Note: stylized OP/ED emblems are geometrically face-shaped and NOT catchable this way — documented, CCIP gate is the answer for those.
This commit is contained in:
@@ -59,6 +59,8 @@ context leaks onto the wrong card:
|
||||
| `--conf` | 0.3 | detector confidence (model's own recommendation; it is high-precision) |
|
||||
| `--min-width` / `--min-height` | 100 | minimum face box size in px |
|
||||
| `--min-face-fraction` | 0.005 | face box area as fraction of frame — kills distant background extras; `0` disables |
|
||||
| `--max-face-fraction` | 0.30 | face box area upper cap — kills detector meltdowns on full-frame ED/OP effects (feather storms etc.); `0` disables |
|
||||
| `--min-aspect` / `--max-aspect` | 0.45 / 1.6 | face box W/H ratio window — effect blobs rarely keep face proportions |
|
||||
| `--edge-margin` | 0 | require faces this far inside frame edges; `0` accepts edge-touching faces (original hard-rejected them) |
|
||||
| `--scene-threshold` | 30.0 | PySceneDetect ContentDetector threshold (same as original) |
|
||||
| `--imgsz` | 1280 | inference size; model was trained at 1280, `640` is faster at some recall cost |
|
||||
|
||||
+37
-4
@@ -77,6 +77,27 @@ def parse_arguments():
|
||||
help="Minimum face box area as a fraction of frame area (kills "
|
||||
"background-extra faces in wide shots; 0 disables).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--max-face-fraction",
|
||||
type=float,
|
||||
default=0.30,
|
||||
help="Maximum face box area as a fraction of frame area (kills "
|
||||
"detector meltdowns on full-frame effects like ED feather "
|
||||
"storms; 0 disables).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--min-aspect",
|
||||
type=float,
|
||||
default=0.45,
|
||||
help="Minimum face box width/height ratio.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--max-aspect",
|
||||
type=float,
|
||||
default=1.6,
|
||||
help="Maximum face box width/height ratio (a face wider than 1.6x "
|
||||
"itself is almost always an effect blob).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--conf",
|
||||
type=float,
|
||||
@@ -168,10 +189,13 @@ def download_model(path):
|
||||
|
||||
|
||||
def face_qualifies(box, frame_shape, min_width, min_height,
|
||||
min_face_fraction, edge_margin):
|
||||
min_face_fraction, max_face_fraction,
|
||||
min_aspect, max_aspect, edge_margin):
|
||||
"""Original is_full_face(), corrected: the box must actually be a face
|
||||
(enforced by the detector class), size gates stay, hard
|
||||
'must-not-touch-edge' rule becomes an optional margin."""
|
||||
'must-not-touch-edge' rule becomes an optional margin.
|
||||
Upper-bound gates (max area, aspect) kill detector meltdowns on
|
||||
full-frame stylized effects (ED feather storms etc.)."""
|
||||
x1, y1, x2, y2 = box
|
||||
frame_h, frame_w = frame_shape[:2]
|
||||
|
||||
@@ -179,8 +203,15 @@ def face_qualifies(box, frame_shape, min_width, min_height,
|
||||
if w < min_width or h < min_height:
|
||||
return False
|
||||
|
||||
if min_face_fraction > 0:
|
||||
if (w * h) < (frame_w * frame_h * min_face_fraction):
|
||||
area_frac = (w * h) / float(frame_w * frame_h)
|
||||
if min_face_fraction > 0 and area_frac < min_face_fraction:
|
||||
return False
|
||||
if max_face_fraction > 0 and area_frac > max_face_fraction:
|
||||
return False
|
||||
|
||||
if h > 0:
|
||||
aspect = w / float(h)
|
||||
if aspect < min_aspect or aspect > max_aspect:
|
||||
return False
|
||||
|
||||
if edge_margin > 0:
|
||||
@@ -255,6 +286,8 @@ def process_video(video_path, output_dir, args, model, device, draw,
|
||||
if face_qualifies(box, frame.shape, args.min_width,
|
||||
args.min_height,
|
||||
args.min_face_fraction,
|
||||
args.max_face_fraction,
|
||||
args.min_aspect, args.max_aspect,
|
||||
args.edge_margin):
|
||||
out = os.path.join(
|
||||
output_dir,
|
||||
|
||||
Reference in New Issue
Block a user