CoolFace
Apppublic

KnowingFly/depression-detection-api

sourceHugging Facemitupdated 10mo agoView on Hugging Face
0likes
face_detector.py180 linesDownload Raw Back to root
1import cv22import numpy as np3from typing import Optional, Tuple, List4 5 6class FaceDetector:7    """Face detection utility with multiple detection strategies."""8    9    def __init__(self):10        """Initialize the face detector with multiple Haar Cascade classifiers."""11        # Primary detector - frontal face12        self.face_cascade = cv2.CascadeClassifier(13            cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'14        )15        # Alternative detector - frontal face alt16        self.face_cascade_alt = cv2.CascadeClassifier(17            cv2.data.haarcascades + 'haarcascade_frontalface_alt.xml'18        )19        # Another alternative - frontal face alt220        self.face_cascade_alt2 = cv2.CascadeClassifier(21            cv2.data.haarcascades + 'haarcascade_frontalface_alt2.xml'22        )23    24    def _detect_with_cascade(25        self, 26        gray: np.ndarray, 27        cascade: cv2.CascadeClassifier,28        scale_factor: float = 1.1,29        min_neighbors: int = 3,30        min_size: Tuple[int, int] = (20, 20)31    ) -> List:32        """Detect faces using a specific cascade classifier."""33        try:34            faces = cascade.detectMultiScale(35                gray,36                scaleFactor=scale_factor,37                minNeighbors=min_neighbors,38                minSize=min_size,39                flags=cv2.CASCADE_SCALE_IMAGE40            )41            return list(faces) if len(faces) > 0 else []42        except Exception:43            return []44    45    def detect_and_crop_face(46        self, 47        image: np.ndarray, 48        target_size: Tuple[int, int] = (224, 224),49        padding: float = 0.250    ) -> Optional[np.ndarray]:51        """52        Detect face in image and crop it with padding.53        Uses multiple detection strategies for robustness.54        55        Args:56            image: Input image as numpy array (BGR format from OpenCV)57            target_size: Target size for the cropped face (width, height)58            padding: Padding ratio to add around the detected face59            60        Returns:61            Cropped and resized face image, or None if no face detected62        """63        if image is None or image.size == 0:64            print("Warning: Empty or invalid image received")65            return None66        67        # Convert to grayscale68        try:69            if len(image.shape) == 2:70                gray = image71            else:72                gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)73        except Exception as e:74            print(f"Warning: Failed to convert to grayscale: {e}")75            return None76        77        # Enhance contrast for better detection78        gray = cv2.equalizeHist(gray)79        80        faces = []81        82        # Strategy 1: Primary cascade with standard parameters83        faces = self._detect_with_cascade(gray, self.face_cascade, 1.1, 5, (30, 30))84        85        # Strategy 2: Primary cascade with more lenient parameters86        if len(faces) == 0:87            faces = self._detect_with_cascade(gray, self.face_cascade, 1.05, 3, (20, 20))88        89        # Strategy 3: Alt cascade90        if len(faces) == 0:91            faces = self._detect_with_cascade(gray, self.face_cascade_alt, 1.1, 3, (20, 20))92        93        # Strategy 4: Alt2 cascade94        if len(faces) == 0:95            faces = self._detect_with_cascade(gray, self.face_cascade_alt2, 1.1, 3, (20, 20))96        97        # Strategy 5: Very lenient detection98        if len(faces) == 0:99            faces = self._detect_with_cascade(gray, self.face_cascade, 1.02, 2, (15, 15))100        101        # Strategy 6: Try with different image sizes102        if len(faces) == 0:103            # Try with scaled up image104            scale = 1.5105            scaled = cv2.resize(gray, None, fx=scale, fy=scale, interpolation=cv2.INTER_LINEAR)106            faces = self._detect_with_cascade(scaled, self.face_cascade, 1.1, 3, (30, 30))107            if len(faces) > 0:108                # Scale coordinates back109                faces = [(int(x/scale), int(y/scale), int(w/scale), int(h/scale)) 110                         for (x, y, w, h) in faces]111        112        # Strategy 7: If still no face, use the entire image as the face region113        # This is a fallback for cases where face detection fails but user insists image has a face114        if len(faces) == 0:115            print("Warning: No face detected with any strategy. Using center crop as fallback.")116            h, w = image.shape[:2]117            # Use center 70% of the image118            margin_w = int(w * 0.15)119            margin_h = int(h * 0.15)120            face_crop = image[margin_h:h-margin_h, margin_w:w-margin_w]121            122            if face_crop.size > 0:123                face_resized = cv2.resize(face_crop, target_size, interpolation=cv2.INTER_AREA)124                if len(face_resized.shape) == 3:125                    face_rgb = cv2.cvtColor(face_resized, cv2.COLOR_BGR2RGB)126                else:127                    face_rgb = cv2.cvtColor(face_resized, cv2.COLOR_GRAY2RGB)128                return face_rgb129            return None130        131        # Get the largest face132        x, y, w, h = max(faces, key=lambda f: f[2] * f[3])133        134        # Add padding135        pad_w = int(w * padding)136        pad_h = int(h * padding)137        138        img_h, img_w = image.shape[:2]139        x1 = max(0, x - pad_w)140        y1 = max(0, y - pad_h)141        x2 = min(img_w, x + w + pad_w)142        y2 = min(img_h, y + h + pad_h)143        144        face_crop = image[y1:y2, x1:x2]145        146        if face_crop.size == 0:147            return None148        149        face_resized = cv2.resize(face_crop, target_size, interpolation=cv2.INTER_AREA)150        151        # Convert to RGB152        if len(face_resized.shape) == 3:153            face_rgb = cv2.cvtColor(face_resized, cv2.COLOR_BGR2RGB)154        else:155            face_rgb = cv2.cvtColor(face_resized, cv2.COLOR_GRAY2RGB)156        157        return face_rgb158    159    def detect_faces_count(self, image: np.ndarray) -> int:160        """161        Count number of faces detected in image.162        163        Args:164            image: Input image as numpy array165            166        Returns:167            Number of faces detected168        """169        try:170            gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)171            gray = cv2.equalizeHist(gray)172            173            faces = self._detect_with_cascade(gray, self.face_cascade, 1.1, 3, (20, 20))174            return len(faces)175        except Exception:176            return 0177 178 179face_detector = FaceDetector()180