Marwan
Restructure + add reverse face search (PimEyes-style)
f5eeb1c
Raw
History Blame Contribute Delete
1.85 kB
"""
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