def detect_faces(self, image, conf_threshold: float = 0.7) -> List[List[int]]: """Performs facial detection on an image. Uses MTCNN. Args: image (numpy array): conf_threshold (float, optional): Threshold confidence to consider Raises: InvalidImage: When the image is either None or with wrong number of channels. Returns: List[List[int]]: List of bounding box coordinates """ if not is_valid_img(image): raise InvalidImage # Do a forward propagation with the blob created from input img detections = self.face_detector.detect_faces(image) # Bounding box coordinates of faces in image bboxes = [] for _, detection in enumerate(detections): conf = detection["confidence"] if conf >= conf_threshold: x, y, w, h = detection["box"] x1, y1, x2, y2 = x, y, x + w, y + h # Trim forehead area to match dlib style facial ROI if self.crop_forehead: y1 = y1 + int(h * self.shrink_ratio) bboxes.append([x1, y1, x2, y2]) return bboxes
def register_face(self, image=None, name: str = None, bbox: List[int] = None): """Method to register a face via the facial encoding. Siamese neural network is used to generate 128 numbers for a given facial region. These encodings can be used to identify a facial ROI for identification later. Args: image (numpy array, optional): Defaults to None. name (str, optional): Name to associate with the face. Defaults to None. bbox (List[int], optional): Facial ROI bounding box. Defaults to None. Raises: NoNameProvided: NoFaceDetected: Returns: Dict: Facial encodings along with an unique identifier and name """ if not is_valid_img(image) or name is None: raise NoNameProvided if name is None else InvalidImage image = image.copy() face_encoding = None try: if bbox is None: bboxes = self.face_detector.detect_faces(image=image) if len(bboxes) == 0: raise NoFaceDetected bbox = bboxes[0] face_encoding = self.get_facial_fingerprint(image, bbox) # Convert the numpy array to normal python float list # to make json serialization simpler facial_data = { "id": str(uuid.uuid4()), "encoding": tuple(face_encoding.tolist()), "name": name, } # save the encoding with the name self.save_facial_data(facial_data) logger.info("Face registered with name: {}".format(name)) except Exception as exc: raise exc return facial_data
def convert_to_rgb(image): """Converts an image to RGB format. Args: image (numpy array): [description] Raises: InvalidImage: [description] Returns: [type]: [description] """ if not is_valid_img(image): raise InvalidImage return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
def detect_faces(self, image, conf_threshold: float = 0.7) -> List[List[int]]: """Performs facial detection on an image. Uses OpenCV DNN based face detector. Args: image (numpy array): conf_threshold (float, optional): Threshold confidence to consider Raises: InvalidImage: When the image is either None or with wrong number of channels. Returns: List[List[int]]: List of bounding box coordinates """ if not is_valid_img(image): raise InvalidImage # To prevent modification of orig img image = image.copy() height, width = image.shape[:2] # Do a forward propagation with the blob created from input img detections = self.model_inference(image) # Bounding box coordinates of faces in image bboxes = [] for idx in range(detections.shape[2]): conf = detections[0, 0, idx, 2] if conf >= conf_threshold: # Scale the bbox coordinates to suit image x1 = int(detections[0, 0, idx, 3] * width) y1 = int(detections[0, 0, idx, 4] * height) x2 = int(detections[0, 0, idx, 5] * width) y2 = int(detections[0, 0, idx, 6] * height) if self.crop_forehead: y1 = y1 + int(height * self.shrink_ratio) # openCv detector can give a lot of false bboxes # when the image is a zoomed in face / cropped face # This will get rid of atleast few, still there can be other # wrong detections present! if self.is_valid_bbox([x1, y1, x2, y2], height, width): bboxes.append([x1, y1, x2, y2]) return bboxes
def detect_faces(self, image, num_upscaling: int = 1) -> List[List[int]]: """Performs facial detection on an image. Works best with RGB image. Uses a dlib based detector either HOG or MMOD. Args: image (numpy array): num_upscaling (int, optional): Number of times to upscale while detecting faces. Defaults to 1. Raises: InvalidImage: When the image is either None or with wrong number of channels. Returns: List[List[int]]: List of bounding box coordinates """ if not is_valid_img(image): raise InvalidImage return [ self.dlib_rectangle_to_list(bbox) for bbox in self.face_detector(image, num_upscaling) ]