File size: 1,851 Bytes
bbc3fdf 892fa81 bbc3fdf aac350d 892fa81 aac350d 892fa81 bbc3fdf aac350d bbc3fdf aac350d 892fa81 bbc3fdf aac350d bbc3fdf 892fa81 bbc3fdf aac350d bbc3fdf | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | """
OpenCV Haar Cascade face detector.
Uses cores.vision for all image operations — no duplicated logic.
"""
from __future__ import annotations
import cv2
import numpy as np
from config.settings import Settings, settings as _default_settings
from cores.vision import to_gray, BBox
from pipeline.feature_extraction import PipelineOutput
from providers.base import BaseProvider, ProviderCapability
class HaarDetector(BaseProvider):
name = "haar"
capability = ProviderCapability.DETECTION
def __init__(self, settings: Settings | None = None) -> None:
super().__init__(settings=settings or _default_settings)
cascade_path = cv2.data.haarcascades + "haarcascade_frontalface_default.xml"
self._cascade = cv2.CascadeClassifier(cascade_path)
if self._cascade.empty():
raise RuntimeError("Failed to load Haar cascade classifier.")
def is_available(self) -> bool:
return not self._cascade.empty()
def _run(self, pipeline_output: PipelineOutput) -> tuple[dict, dict]:
img: np.ndarray = pipeline_output.image
s = self._settings
gray = cv2.equalizeHist(to_gray(img))
rects = self._cascade.detectMultiScale(
gray,
scaleFactor=s.haar_scale_factor,
minNeighbors=s.haar_min_neighbors,
minSize=(30, 30),
flags=cv2.CASCADE_SCALE_IMAGE,
)
boxes = [BBox(int(x), int(y), int(w), int(h)).to_dict() for (x, y, w, h) in rects]
raw = {
"rectangles": [[int(x), int(y), int(w), int(h)] for (x, y, w, h) in rects],
"num_faces": len(rects),
}
normalized = {
"boxes": boxes,
"num_faces": len(boxes),
"landmarks": None,
"confidences": [1.0] * len(boxes),
}
return raw, normalized
|