from typing import List import os import gdown import cv2 import pandas as pd import numpy as np from deepface.detectors import OpenCv from deepface.commons import folder_utils from deepface.models.Detector import Detector, FacialAreaRegion from deepface.commons.logger import Logger logger = Logger(module="detectors.SsdWrapper") # pylint: disable=line-too-long, c-extension-no-member class SsdClient(Detector): def __init__(self): self.model = self.build_model() def build_model(self) -> dict: """ Build a ssd detector model Returns: model (dict) """ home = folder_utils.get_deepface_home() # model structure if os.path.isfile(home + "/weights/deploy.prototxt") != True: logger.info("deploy.prototxt will be downloaded...") url = "https://github.com/opencv/opencv/raw/3.4.0/samples/dnn/face_detector/deploy.prototxt" output = home + "/weights/deploy.prototxt" gdown.download(url, output, quiet=False) # pre-trained weights if ( os.path.isfile(home + "/weights/res10_300x300_ssd_iter_140000.caffemodel") != True ): logger.info("res10_300x300_ssd_iter_140000.caffemodel will be downloaded...") url = "https://github.com/opencv/opencv_3rdparty/raw/dnn_samples_face_detector_20170830/res10_300x300_ssd_iter_140000.caffemodel" output = home + "/weights/res10_300x300_ssd_iter_140000.caffemodel" gdown.download(url, output, quiet=False) try: face_detector = cv2.dnn.readNetFromCaffe( home + "/weights/deploy.prototxt", home + "/weights/res10_300x300_ssd_iter_140000.caffemodel", ) except Exception as err: raise ValueError( "Exception while calling opencv.dnn module." + "This is an optional dependency." + "You can install it as pip install opencv-contrib-python." ) from err detector = {} detector["face_detector"] = face_detector detector["opencv_module"] = OpenCv.OpenCvClient() return detector def detect_faces(self, img: np.ndarray) -> List[FacialAreaRegion]: """ Detect and align face with ssd Args: img (np.ndarray): pre-loaded image as numpy array Returns: results (List[FacialAreaRegion]): A list of FacialAreaRegion objects """ opencv_module: OpenCv.OpenCvClient = self.model["opencv_module"] resp = [] detected_face = None ssd_labels = ["img_id", "is_face", "confidence", "left", "top", "right", "bottom"] target_size = (300, 300) original_size = img.shape current_img = cv2.resize(img, target_size) aspect_ratio_x = original_size[1] / target_size[1] aspect_ratio_y = original_size[0] / target_size[0] imageBlob = cv2.dnn.blobFromImage(image=current_img) face_detector = self.model["face_detector"] face_detector.setInput(imageBlob) detections = face_detector.forward() detections_df = pd.DataFrame(detections[0][0], columns=ssd_labels) detections_df = detections_df[detections_df["is_face"] == 1] # 0: background, 1: face detections_df = detections_df[detections_df["confidence"] >= 0.90] detections_df["left"] = (detections_df["left"] * 300).astype(int) detections_df["bottom"] = (detections_df["bottom"] * 300).astype(int) detections_df["right"] = (detections_df["right"] * 300).astype(int) detections_df["top"] = (detections_df["top"] * 300).astype(int) if detections_df.shape[0] > 0: for _, instance in detections_df.iterrows(): left = instance["left"] right = instance["right"] bottom = instance["bottom"] top = instance["top"] confidence = instance["confidence"] x = int(left * aspect_ratio_x) y = int(top * aspect_ratio_y) w = int(right * aspect_ratio_x) - int(left * aspect_ratio_x) h = int(bottom * aspect_ratio_y) - int(top * aspect_ratio_y) detected_face = img[int(y) : int(y + h), int(x) : int(x + w)] left_eye, right_eye = opencv_module.find_eyes(detected_face) # eyes found in the detected face instead image itself # detected face's coordinates should be added if left_eye is not None: left_eye = (int(x + left_eye[0]), int(y + left_eye[1])) if right_eye is not None: right_eye = (int(x + right_eye[0]), int(y + right_eye[1])) facial_area = FacialAreaRegion( x=x, y=y, w=w, h=h, left_eye=left_eye, right_eye=right_eye, confidence=confidence, ) resp.append(facial_area) return resp