From 4800aa3e8c2c5b3220e0edfb5542e7dd4dda7835 Mon Sep 17 00:00:00 2001 From: Sefik Ilkin Serengil Date: Wed, 31 Jan 2024 19:37:43 +0000 Subject: [PATCH] input shape is now retrieved from models --- deepface/basemodels/ArcFace.py | 2 ++ deepface/basemodels/DeepID.py | 2 ++ deepface/basemodels/Dlib.py | 2 ++ deepface/basemodels/Facenet.py | 4 ++++ deepface/basemodels/FbDeepFace.py | 2 ++ deepface/basemodels/OpenFace.py | 2 ++ deepface/basemodels/SFace.py | 2 ++ deepface/basemodels/VGGFace.py | 2 ++ deepface/commons/functions.py | 30 ----------------------- deepface/models/FacialRecognition.py | 5 +++- deepface/modules/realtime.py | 11 +++++---- deepface/modules/recognition.py | 8 ++++--- deepface/modules/representation.py | 3 +-- deepface/modules/verification.py | 8 ++++--- tests/face-recognition-how.py | 36 +++++++++++++++++++--------- 15 files changed, 64 insertions(+), 55 deletions(-) diff --git a/deepface/basemodels/ArcFace.py b/deepface/basemodels/ArcFace.py index bb639f3..cacacd4 100644 --- a/deepface/basemodels/ArcFace.py +++ b/deepface/basemodels/ArcFace.py @@ -53,6 +53,8 @@ class ArcFaceClient(FacialRecognition): def __init__(self): self.model = load_model() self.model_name = "ArcFace" + self.input_shape = (112, 112) + self.output_shape = 512 def find_embeddings(self, img: np.ndarray) -> List[float]: """ diff --git a/deepface/basemodels/DeepID.py b/deepface/basemodels/DeepID.py index 8b4a7d5..0933c27 100644 --- a/deepface/basemodels/DeepID.py +++ b/deepface/basemodels/DeepID.py @@ -49,6 +49,8 @@ class DeepIdClient(FacialRecognition): def __init__(self): self.model = load_model() self.model_name = "DeepId" + self.input_shape = (47, 55) + self.output_shape = 160 def find_embeddings(self, img: np.ndarray) -> List[float]: """ diff --git a/deepface/basemodels/Dlib.py b/deepface/basemodels/Dlib.py index 6d06ef4..8336ca6 100644 --- a/deepface/basemodels/Dlib.py +++ b/deepface/basemodels/Dlib.py @@ -20,6 +20,8 @@ class DlibClient(FacialRecognition): def __init__(self): self.model = DlibResNet() self.model_name = "Dlib" + self.input_shape = (150, 150) + self.output_shape = 128 def find_embeddings(self, img: np.ndarray) -> List[float]: """ diff --git a/deepface/basemodels/Facenet.py b/deepface/basemodels/Facenet.py index d95da02..31811a3 100644 --- a/deepface/basemodels/Facenet.py +++ b/deepface/basemodels/Facenet.py @@ -53,6 +53,8 @@ class FaceNet128dClient(FacialRecognition): def __init__(self): self.model = load_facenet128d_model() self.model_name = "FaceNet-128d" + self.input_shape = (160, 160) + self.output_shape = 128 def find_embeddings(self, img: np.ndarray) -> List[float]: """ @@ -75,6 +77,8 @@ class FaceNet512dClient(FacialRecognition): def __init__(self): self.model = load_facenet512d_model() self.model_name = "FaceNet-512d" + self.input_shape = (160, 160) + self.output_shape = 512 def find_embeddings(self, img: np.ndarray) -> List[float]: """ diff --git a/deepface/basemodels/FbDeepFace.py b/deepface/basemodels/FbDeepFace.py index 075626b..1a47685 100644 --- a/deepface/basemodels/FbDeepFace.py +++ b/deepface/basemodels/FbDeepFace.py @@ -46,6 +46,8 @@ class DeepFaceClient(FacialRecognition): def __init__(self): self.model = load_model() self.model_name = "DeepFace" + self.input_shape = (152, 152) + self.output_shape = 4096 def find_embeddings(self, img: np.ndarray) -> List[float]: """ diff --git a/deepface/basemodels/OpenFace.py b/deepface/basemodels/OpenFace.py index 3867291..8ee2d95 100644 --- a/deepface/basemodels/OpenFace.py +++ b/deepface/basemodels/OpenFace.py @@ -36,6 +36,8 @@ class OpenFaceClient(FacialRecognition): def __init__(self): self.model = load_model() self.model_name = "OpenFace" + self.input_shape = (96, 96) + self.output_shape = 128 def find_embeddings(self, img: np.ndarray) -> List[float]: """ diff --git a/deepface/basemodels/SFace.py b/deepface/basemodels/SFace.py index ba8b55e..f8ec192 100644 --- a/deepface/basemodels/SFace.py +++ b/deepface/basemodels/SFace.py @@ -22,6 +22,8 @@ class SFaceClient(FacialRecognition): def __init__(self): self.model = load_model() self.model_name = "SFace" + self.input_shape = (112, 112) + self.output_shape = 128 def find_embeddings(self, img: np.ndarray) -> List[float]: """ diff --git a/deepface/basemodels/VGGFace.py b/deepface/basemodels/VGGFace.py index 7f204f4..c4516a8 100644 --- a/deepface/basemodels/VGGFace.py +++ b/deepface/basemodels/VGGFace.py @@ -43,6 +43,8 @@ class VggFaceClient(FacialRecognition): def __init__(self): self.model = load_model() self.model_name = "VGG-Face" + self.input_shape = (224, 224) + self.output_shape = 4096 def find_embeddings(self, img: np.ndarray) -> List[float]: """ diff --git a/deepface/commons/functions.py b/deepface/commons/functions.py index cc39756..c7b317a 100644 --- a/deepface/commons/functions.py +++ b/deepface/commons/functions.py @@ -40,33 +40,3 @@ def get_deepface_home() -> str: str: the home directory. """ return str(os.getenv("DEEPFACE_HOME", default=str(Path.home()))) - - -def find_target_size(model_name: str) -> tuple: - """Find the target size of the model. - - Args: - model_name (str): the model name. - - Returns: - tuple: the target size. - """ - - target_sizes = { - "VGG-Face": (224, 224), - "Facenet": (160, 160), - "Facenet512": (160, 160), - "OpenFace": (96, 96), - "DeepFace": (152, 152), - "DeepID": (47, 55), - "Dlib": (150, 150), - "ArcFace": (112, 112), - "SFace": (112, 112), - } - - target_size = target_sizes.get(model_name) - - if target_size == None: - raise ValueError(f"unimplemented model name - {model_name}") - - return target_size diff --git a/deepface/models/FacialRecognition.py b/deepface/models/FacialRecognition.py index b49292c..c7aff6b 100644 --- a/deepface/models/FacialRecognition.py +++ b/deepface/models/FacialRecognition.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from typing import Any, Union, List +from typing import Any, Union, List, Tuple import numpy as np from deepface.commons import functions @@ -15,6 +15,9 @@ else: class FacialRecognition(ABC): model: Union[Model, Any] model_name: str + input_shape: Tuple[int, int] + output_shape: int + @abstractmethod def find_embeddings(self, img: np.ndarray) -> List[float]: diff --git a/deepface/modules/realtime.py b/deepface/modules/realtime.py index 3edd5d8..b87377f 100644 --- a/deepface/modules/realtime.py +++ b/deepface/modules/realtime.py @@ -4,7 +4,7 @@ import numpy as np import pandas as pd import cv2 from deepface import DeepFace -from deepface.commons import functions +from deepface.models.FacialRecognition import FacialRecognition from deepface.commons.logger import Logger logger = Logger(module="commons.realtime") @@ -32,12 +32,13 @@ def analysis( enable_emotion = True enable_age_gender = True # ------------------------ - # find custom values for this input set - target_size = functions.find_target_size(model_name=model_name) - # ------------------------ # build models once to store them in the memory # otherwise, they will be built after cam started and this will cause delays - DeepFace.build_model(model_name=model_name) + model: FacialRecognition = DeepFace.build_model(model_name=model_name) + + # find custom values for this input set + target_size = model.input_shape + logger.info(f"facial recognition model {model_name} is just built") if enable_face_analysis: diff --git a/deepface/modules/recognition.py b/deepface/modules/recognition.py index 393b8ff..f678a2b 100644 --- a/deepface/modules/recognition.py +++ b/deepface/modules/recognition.py @@ -10,9 +10,10 @@ import pandas as pd from tqdm import tqdm # project dependencies -from deepface.commons import functions, distance as dst +from deepface.commons import distance as dst from deepface.commons.logger import Logger -from deepface.modules import representation, detection +from deepface.modules import representation, detection, modeling +from deepface.models.FacialRecognition import FacialRecognition logger = Logger(module="deepface/modules/recognition.py") @@ -89,7 +90,8 @@ def find( if os.path.isdir(db_path) is not True: raise ValueError("Passed db_path does not exist!") - target_size = functions.find_target_size(model_name=model_name) + model: FacialRecognition = modeling.build_model(model_name) + target_size = model.input_shape # --------------------------------------- diff --git a/deepface/modules/representation.py b/deepface/modules/representation.py index 3a389eb..2b76835 100644 --- a/deepface/modules/representation.py +++ b/deepface/modules/representation.py @@ -7,7 +7,6 @@ import cv2 # project dependencies from deepface.modules import modeling, detection, preprocessing -from deepface.commons import functions from deepface.models.FacialRecognition import FacialRecognition @@ -61,7 +60,7 @@ def represent( # --------------------------------- # we have run pre-process in verification. so, this can be skipped if it is coming from verify. - target_size = functions.find_target_size(model_name=model_name) + target_size = model.input_shape if detector_backend != "skip": img_objs = detection.extract_faces( img_path=img_path, diff --git a/deepface/modules/verification.py b/deepface/modules/verification.py index 26281fb..9310e82 100644 --- a/deepface/modules/verification.py +++ b/deepface/modules/verification.py @@ -6,8 +6,9 @@ from typing import Any, Dict, Union import numpy as np # project dependencies -from deepface.commons import functions, distance as dst -from deepface.modules import representation, detection +from deepface.commons import distance as dst +from deepface.modules import representation, detection, modeling +from deepface.models.FacialRecognition import FacialRecognition def verify( @@ -79,7 +80,8 @@ def verify( tic = time.time() # -------------------------------- - target_size = functions.find_target_size(model_name=model_name) + model: FacialRecognition = modeling.build_model(model_name) + target_size = model.input_shape # img pairs might have many faces img1_objs = detection.extract_faces( diff --git a/tests/face-recognition-how.py b/tests/face-recognition-how.py index 2903237..36ec45b 100644 --- a/tests/face-recognition-how.py +++ b/tests/face-recognition-how.py @@ -1,7 +1,8 @@ import matplotlib.pyplot as plt import numpy as np from deepface import DeepFace -from deepface.commons import functions +from deepface.commons import distance +from deepface.models.FacialRecognition import FacialRecognition from deepface.commons.logger import Logger logger = Logger() @@ -11,9 +12,9 @@ logger = Logger() model_name = "VGG-Face" -model = DeepFace.build_model(model_name=model_name) +model: FacialRecognition = DeepFace.build_model(model_name=model_name) -target_size = functions.find_target_size(model_name) +target_size = model.input_shape logger.info(f"target_size: {target_size}") @@ -22,21 +23,34 @@ logger.info(f"target_size: {target_size}") img1 = DeepFace.extract_faces(img_path="dataset/img1.jpg", target_size=target_size)[0]["face"] img1 = np.expand_dims(img1, axis=0) # to (1, 224, 224, 3) -img1_representation = model.predict(img1)[0, :] +img1_representation = model.find_embeddings(img1) img2 = DeepFace.extract_faces(img_path="dataset/img3.jpg", target_size=target_size)[0]["face"] img2 = np.expand_dims(img2, axis=0) -img2_representation = model.predict(img2)[0, :] +img2_representation = model.find_embeddings(img2) + +img1_representation = np.array(img1_representation) +img2_representation = np.array(img2_representation) # ---------------------------------------------- -# distance between two images - +# distance between two images - euclidean distance formula distance_vector = np.square(img1_representation - img2_representation) -logger.debug(distance_vector) +current_distance = np.sqrt(distance_vector.sum()) +logger.info(f"Euclidean distance: {current_distance}") -distance = np.sqrt(distance_vector.sum()) -logger.info(f"Euclidean distance: {distance}") +threshold = distance.findThreshold(model_name=model_name, distance_metric="euclidean") +logger.info(f"Threshold for {model_name}-euclidean pair is {threshold}") +if current_distance < threshold: + logger.info( + f"This pair is same person because its distance {current_distance}" + f" is less than threshold {threshold}" + ) +else: + logger.info( + f"This pair is different persons because its distance {current_distance}" + f" is greater than threshold {threshold}" + ) # ---------------------------------------------- # expand vectors to be shown better in graph @@ -75,7 +89,7 @@ im = plt.imshow(img2_graph, interpolation="nearest", cmap=plt.cm.ocean) plt.colorbar() ax5 = fig.add_subplot(3, 2, 5) -plt.text(0.35, 0, f"Distance: {distance}") +plt.text(0.35, 0, f"Distance: {current_distance}") plt.axis("off") ax6 = fig.add_subplot(3, 2, 6)