diff --git a/deepface/modules/verification.py b/deepface/modules/verification.py index c6ee5bc..a5cc934 100644 --- a/deepface/modules/verification.py +++ b/deepface/modules/verification.py @@ -105,19 +105,54 @@ def verify( ) dims = model.output_shape - def extract_faces_from_img(img_path, index=1): - # extract faces from img + no_facial_area = { + "x": None, + "y": None, + "w": None, + "h": None, + "left_eye": None, + "right_eye": None, + } + + def extract_embeddings_and_facial_areas( + img_path: Union[str, np.ndarray, List[float]], + index: int + ) -> Tuple[List[List[float]], List[dict]]: + """ + Extracts facial embeddings and corresponding facial areas from an + image or returns pre-calculated embeddings. + + Depending on the type of img_path, the function either extracts + facial embeddings from the provided image + (via a path or NumPy array) or verifies that the input is a list of + pre-calculated embeddings and validates them. + + Args: + img_path (Union[str, np.ndarray, List[float]]): + - A string representing the file path to an image, + - A NumPy array containing the image data, + - Or a list of pre-calculated embedding values (of type `float`). + index (int): An index value used in error messages and logging + to identify the number of the image. + + Returns: + Tuple[List[List[float]], List[dict]]: + - A list containing lists of facial embeddings for each detected face. + - A list of dictionaries where each dictionary contains facial area information. + """ if isinstance(img_path, list): # given image is already pre-calculated embedding if not all(isinstance(dim, float) for dim in img_path): raise ValueError( - f"When passing img{index}_path as a list, ensure that all its items are of type float." + f"When passing img{index}_path as a list," + " ensure that all its items are of type float." ) if silent is False: logger.warn( "You passed 1st image as pre-calculated embeddings." - f"Please ensure that embeddings have been calculated for the {model_name} model." + "Please ensure that embeddings have been calculated" + f" for the {model_name} model." ) if len(img_path) != dims: @@ -127,7 +162,7 @@ def verify( ) img_embeddings = [img_path] - img_facial_areas = [None] + img_facial_areas = [no_facial_area] else: try: img_embeddings, img_facial_areas = __extract_faces_and_embeddings( @@ -144,17 +179,8 @@ def verify( raise ValueError(f"Exception while processing img{index}_path") from err return img_embeddings, img_facial_areas - img1_embeddings, img1_facial_areas = extract_faces_from_img(img1_path, 1) - img2_embeddings, img2_facial_areas = extract_faces_from_img(img2_path, 2) - - no_facial_area = { - "x": None, - "y": None, - "w": None, - "h": None, - "left_eye": None, - "right_eye": None, - } + img1_embeddings, img1_facial_areas = extract_embeddings_and_facial_areas(img1_path, 1) + img2_embeddings, img2_facial_areas = extract_embeddings_and_facial_areas(img2_path, 2) min_distance, min_idx, min_idy = float("inf"), None, None for idx, img1_embedding in enumerate(img1_embeddings): @@ -166,8 +192,10 @@ def verify( # find the face pair with minimum distance threshold = threshold or find_threshold(model_name, distance_metric) distance = float(min_distance) - facial_areas = (no_facial_area, no_facial_area) if None in (min_idx, min_idy) else \ - (img1_facial_areas[min_idx], img2_facial_areas[min_idy]) + facial_areas = ( + no_facial_area if min_idx is None else img1_facial_areas[min_idx], + no_facial_area if min_idy is None else img2_facial_areas[min_idy], + ) toc = time.time() diff --git a/tests/test_verify.py b/tests/test_verify.py index 2efa7d0..0277507 100644 --- a/tests/test_verify.py +++ b/tests/test_verify.py @@ -121,6 +121,25 @@ def test_verify_for_precalculated_embeddings(): assert result["verified"] is True assert result["distance"] < result["threshold"] assert result["model"] == model_name + assert result["facial_areas"]["img1"] is not None + assert result["facial_areas"]["img2"] is not None + + assert isinstance(result["facial_areas"]["img1"], dict) + assert isinstance(result["facial_areas"]["img2"], dict) + + assert "x" in result["facial_areas"]["img1"].keys() + assert "y" in result["facial_areas"]["img1"].keys() + assert "w" in result["facial_areas"]["img1"].keys() + assert "h" in result["facial_areas"]["img1"].keys() + assert "left_eye" in result["facial_areas"]["img1"].keys() + assert "right_eye" in result["facial_areas"]["img1"].keys() + + assert "x" in result["facial_areas"]["img2"].keys() + assert "y" in result["facial_areas"]["img2"].keys() + assert "w" in result["facial_areas"]["img2"].keys() + assert "h" in result["facial_areas"]["img2"].keys() + assert "left_eye" in result["facial_areas"]["img2"].keys() + assert "right_eye" in result["facial_areas"]["img2"].keys() logger.info("✅ test verify for pre-calculated embeddings done")