From e4484ac3095dfe21a8ba73a4f865c2831cd9d616 Mon Sep 17 00:00:00 2001 From: Sefik Ilkin Serengil Date: Sat, 31 Jul 2021 22:14:52 +0300 Subject: [PATCH] issue 131 normalization --- deepface/DeepFace.py | 31 +++++++++++++++----- deepface/commons/functions.py | 53 ++++++++++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 8 deletions(-) diff --git a/deepface/DeepFace.py b/deepface/DeepFace.py index 327661b..a7f89e8 100644 --- a/deepface/DeepFace.py +++ b/deepface/DeepFace.py @@ -66,7 +66,7 @@ def build_model(model_name): return model_obj[model_name] -def verify(img1_path, img2_path = '', model_name = 'VGG-Face', distance_metric = 'cosine', model = None, enforce_detection = True, detector_backend = 'opencv', align = True, prog_bar = True): +def verify(img1_path, img2_path = '', model_name = 'VGG-Face', distance_metric = 'cosine', model = None, enforce_detection = True, detector_backend = 'opencv', align = True, prog_bar = True, normalization = 'base'): """ This function verifies an image pair is same person or different persons. @@ -161,12 +161,16 @@ def verify(img1_path, img2_path = '', model_name = 'VGG-Face', distance_metric = img1_representation = represent(img_path = img1_path , model_name = model_name, model = custom_model , enforce_detection = enforce_detection, detector_backend = detector_backend - , align = align) + , align = align + , normalization = normalization + ) img2_representation = represent(img_path = img2_path , model_name = model_name, model = custom_model , enforce_detection = enforce_detection, detector_backend = detector_backend - , align = align) + , align = align + , normalization = normalization + ) #---------------------- #find distances between embeddings @@ -458,7 +462,7 @@ def analyze(img_path, actions = ['emotion', 'age', 'gender', 'race'] , models = return resp_obj -def find(img_path, db_path, model_name ='VGG-Face', distance_metric = 'cosine', model = None, enforce_detection = True, detector_backend = 'opencv', align = True, prog_bar = True): +def find(img_path, db_path, model_name ='VGG-Face', distance_metric = 'cosine', model = None, enforce_detection = True, detector_backend = 'opencv', align = True, prog_bar = True, normalization = 'base'): """ This function applies verification several times and find an identity in a database @@ -571,7 +575,9 @@ def find(img_path, db_path, model_name ='VGG-Face', distance_metric = 'cosine', representation = represent(img_path = employee , model_name = model_name, model = custom_model , enforce_detection = enforce_detection, detector_backend = detector_backend - , align = align) + , align = align + , normalization = normalization + ) instance.append(representation) @@ -613,7 +619,9 @@ def find(img_path, db_path, model_name ='VGG-Face', distance_metric = 'cosine', target_representation = represent(img_path = img_path , model_name = model_name, model = custom_model , enforce_detection = enforce_detection, detector_backend = detector_backend - , align = align) + , align = align + , normalization = normalization + ) for k in metric_names: distances = [] @@ -704,7 +712,7 @@ def find(img_path, db_path, model_name ='VGG-Face', distance_metric = 'cosine', return None -def represent(img_path, model_name = 'VGG-Face', model = None, enforce_detection = True, detector_backend = 'opencv', align = True): +def represent(img_path, model_name = 'VGG-Face', model = None, enforce_detection = True, detector_backend = 'opencv', align = True, normalization = 'base'): """ This function represents facial images as vectors. @@ -722,6 +730,8 @@ def represent(img_path, model_name = 'VGG-Face', model = None, enforce_detection detector_backend (string): set face detector backend as retinaface, mtcnn, opencv, ssd or dlib + normalization (string): normalize the input image before feeding to model + Returns: Represent function returns a multidimensional vector. The number of dimensions is changing based on the reference model. E.g. FaceNet returns 128 dimensional vector; VGG-Face returns 2622 dimensional vector. """ @@ -741,6 +751,13 @@ def represent(img_path, model_name = 'VGG-Face', model = None, enforce_detection , detector_backend = detector_backend , align = align) + #--------------------------------- + #custom normalization + + img = functions.normalize_input(img = img, normalization = normalization) + + #--------------------------------- + #represent embedding = model.predict(img)[0].tolist() diff --git a/deepface/commons/functions.py b/deepface/commons/functions.py index f1ed9dc..a35f8bc 100644 --- a/deepface/commons/functions.py +++ b/deepface/commons/functions.py @@ -104,6 +104,57 @@ def detect_face(img, detector_backend = 'opencv', grayscale = False, enforce_det else: raise ValueError("Face could not be detected. Please confirm that the picture is a face photo or consider to set enforce_detection param to False.") +def normalize_input(img, normalization = 'base'): + + #issue 131 declares that some normalization techniques improves the accuracy + + if normalization == 'base': + return img + else: #@trevorgribble recommend the following idea + + img *= 255 #restore input in scale of [0, 255] because it was normalized in scale of [0, 1] in preprocess_face + + if normalization == 'Facenet': + mean, std = img.mean(), img.std() + img = (img - mean) / std + + elif normalization == 'v1': + #BGR mean subtraction / 255 normalization + img[..., 0]-= 131.0912 + img[..., 1] -= 103.8827 + img[..., 2] -= 91.4953 + img = img[..., ::-1] + img /= 255 + + elif(normalization =="v2"): + #RGB mean subtraction / 255 normalization + img[..., 0]-= 131.0912 + img[..., 1] -= 103.8827 + img[..., 2] -= 91.4953 + img /= 255 + + elif(normalization =="v3"): + #BGR mean subtraction normalization + img[..., 0]-= 131.0912 + img[..., 1] -= 103.8827 + img[..., 2] -= 91.4953 + img = img[..., ::-1] + + elif(normalization =="v4"): + #RGB mean subtraction normalization + img[..., 0]-= 131.0912 + img[..., 1] -= 103.8827 + img[..., 2] -= 91.4953 + + elif(normalization=="v6"): + # simply / 127.5 - 1 (similar to facenet 2018 model preprocessing step as @iamrishab posted) + img /= 127.5 + img -= 1 + + #----------------------------- + + return img + def preprocess_face(img, target_size=(224, 224), grayscale = False, enforce_detection = True, detector_backend = 'opencv', return_region = False, align = True): #img might be path, base64 or numpy array. Convert it to numpy whatever it is. @@ -155,7 +206,7 @@ def preprocess_face(img, target_size=(224, 224), grayscale = False, enforce_dete #normalizing the image pixels - img_pixels = image.img_to_array(img) + img_pixels = image.img_to_array(img) #what this line doing? must? img_pixels = np.expand_dims(img_pixels, axis = 0) img_pixels /= 255 #normalize input in [0, 1]