from src.config_loader import FaceSettings from src.face_geometry import create_face_roi from src.models import BoundingBox, TrackedPerson def settings(**overrides: object) -> FaceSettings: values = dict(enabled=True, backend="mediapipe", process_every_n_frames=1, max_persons_per_frame=3, require_confirmed_track=True, process_only_inside_region=False, roi_height_ratio=.5, roi_expand_ratio=.1, min_roi_width=10, min_roi_height=10, static_image_mode=False, max_num_faces=1, refine_landmarks=True, min_detection_confidence=.5, min_tracking_confidence=.5) values.update(overrides) return FaceSettings(**values) # type: ignore[arg-type] def person(bbox: BoundingBox, confirmed: bool = True, inside: bool = True) -> TrackedPerson: return TrackedPerson(1, bbox, .9, 0, "person", bbox.center_x, bbox.center_y, bbox.foot_x, bbox.foot_y, inside, confirmed, 3, 0) def test_roi_ratio_expansion_and_clipping() -> None: roi = create_face_roi(person(BoundingBox(10, 10, 110, 210)), 200, 300, settings()) assert roi is not None assert (roi.x1, roi.x2) == (0, 120) assert roi.y1 == 0 assert roi.y2 == 120 clipped = create_face_roi(person(BoundingBox(0, 0, 50, 100)), 60, 80, settings(roi_height_ratio=1.0)) assert clipped and clipped.x1 == 0 and clipped.y1 == 0 and clipped.y2 == 80 def test_small_unconfirmed_and_outside_are_excluded() -> None: assert create_face_roi(person(BoundingBox(0, 0, 20, 20)), 100, 100, settings(min_roi_width=40, min_roi_height=40)) is None assert create_face_roi(person(BoundingBox(0, 0, 80, 100), confirmed=False), 100, 100, settings()) is None assert create_face_roi(person(BoundingBox(0, 0, 80, 100), inside=False), 100, 100, settings(process_only_inside_region=True)) is None