Spaces:
Running
Running
File size: 1,918 Bytes
887f5f0 | 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 | import cv2
import numpy as np
class FaceDetector:
"""
Detects faces in images/frames using OpenCV's Haar Cascade classifier.
"""
def __init__(self):
# Path to Haar cascade file included in opencv-python
cascade_path = cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
self.face_cascade = cv2.CascadeClassifier(cascade_path)
if self.face_cascade.empty():
raise RuntimeError("Failed to load Haar cascade for face detection.")
def detect_faces(self, frame_rgb: np.ndarray) -> list[dict]:
"""
Detects faces in an RGB image.
Returns a list of dicts: {'box': [x, y, w, h], 'face_crop': np.ndarray}
"""
# OpenCV Haar cascade expects grayscale and BGR layout for speed
# But we pass RGB, so convert to grayscale directly
gray = cv2.cvtColor(frame_rgb, cv2.COLOR_RGB2GRAY)
# Detect faces
faces = self.face_cascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=8,
minSize=(60, 60),
flags=cv2.CASCADE_SCALE_IMAGE
)
detected = []
for (x, y, w, h) in faces:
# Add small padding to crop to capture full facial features
pad_h = int(h * 0.1)
pad_w = int(w * 0.1)
y_start = max(0, y - pad_h)
y_end = min(frame_rgb.shape[0], y + h + pad_h)
x_start = max(0, x - pad_w)
x_end = min(frame_rgb.shape[1], x + w + pad_w)
face_crop = frame_rgb[y_start:y_end, x_start:x_end]
detected.append({
"box": [int(x), int(y), int(w), int(h)],
"padded_box": [int(x_start), int(y_start), int(x_end - x_start), int(y_end - y_start)],
"face_crop": face_crop
})
return detected
|