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:
+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