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