implement multi-faces detections

This commit is contained in:
Pei-Yun Sun 2020-10-16 22:58:49 +11:00
parent f36af9ffe7
commit 47733dc7a6
8 changed files with 1261 additions and 789 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@ -103,8 +103,8 @@ def verify(img1_path, img2_path = '', model_name ='VGG-Face', distance_metric =
input_shape = input_shape[1:3] input_shape = input_shape[1:3]
img1 = functions.preprocess_face(img = img1_path, target_size = input_shape, enforce_detection = enforce_detection, detector_backend = detector_backend) img1 = functions.preprocess_face(img = img1_path, target_size = input_shape, enforce_detection = enforce_detection, detector_backend = detector_backend)['processed']
img2 = functions.preprocess_face(img = img2_path, target_size = input_shape, enforce_detection = enforce_detection, detector_backend = detector_backend) img2 = functions.preprocess_face(img = img2_path, target_size = input_shape, enforce_detection = enforce_detection, detector_backend = detector_backend)['processed']
img1_representation = custom_model.predict(img1)[0,:] img1_representation = custom_model.predict(img1)[0,:]
img2_representation = custom_model.predict(img2)[0,:] img2_representation = custom_model.predict(img2)[0,:]
@ -271,8 +271,8 @@ def verify(img1_path, img2_path = '', model_name ='VGG-Face', distance_metric =
#---------------------- #----------------------
#crop and align faces #crop and align faces
img1 = functions.preprocess_face(img=img1_path, target_size=(input_shape_y, input_shape_x), enforce_detection = enforce_detection, detector_backend = detector_backend) img1 = functions.preprocess_face(img=img1_path, target_size=(input_shape_y, input_shape_x), enforce_detection = enforce_detection, detector_backend = detector_backend)['processed']
img2 = functions.preprocess_face(img=img2_path, target_size=(input_shape_y, input_shape_x), enforce_detection = enforce_detection, detector_backend = detector_backend) img2 = functions.preprocess_face(img=img2_path, target_size=(input_shape_y, input_shape_x), enforce_detection = enforce_detection, detector_backend = detector_backend)['processed']
#---------------------- #----------------------
#find embeddings #find embeddings
@ -358,7 +358,8 @@ def analyze(img_path, actions = [], models = {}, enforce_detection = True, detec
#if a specific target is not passed, then find them all #if a specific target is not passed, then find them all
if len(actions) == 0: if len(actions) == 0:
actions= ['emotion', 'age', 'gender', 'race'] # actions= ['emotion', 'age', 'gender', 'race']
actions = ['emotion', 'age', 'gender']
#print("Actions to do: ", actions) #print("Actions to do: ", actions)
@ -403,14 +404,21 @@ def analyze(img_path, actions = [], models = {}, enforce_detection = True, detec
for j in global_pbar: for j in global_pbar:
img_path = img_paths[j] img_path = img_paths[j]
resp_obj = "{"
disable_option = False if len(actions) > 1 else True disable_option = False if len(actions) > 1 else True
pbar = tqdm(range(0,len(actions)), desc='Finding actions', disable = disable_option) pbar = tqdm(range(0,len(actions)), desc='Finding actions', disable = disable_option)
# preprocess images
emotion_imgs = functions.preprocess_face(img=img_path, target_size=(48, 48), grayscale=True, enforce_detection=enforce_detection, detector_backend=detector_backend)['processed']
imgs_224 = functions.preprocess_face(img_path, target_size=(224, 224), grayscale=False, enforce_detection=enforce_detection) # just emotion model expects grayscale images
orig_faces = imgs_224['original']
imgs_224 = imgs_224['processed']
for i in range(len(imgs_224)):
resp_obj = "{"
action_idx = 0 action_idx = 0
img_224 = None # Set to prevent re-detection
#for action in actions: #for action in actions:
for index in pbar: for index in pbar:
action = actions[index] action = actions[index]
@ -421,9 +429,8 @@ def analyze(img_path, actions = [], models = {}, enforce_detection = True, detec
if action == 'emotion': if action == 'emotion':
emotion_labels = ['angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral'] emotion_labels = ['angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral']
img = functions.preprocess_face(img = img_path, target_size = (48, 48), grayscale = True, enforce_detection = enforce_detection, detector_backend = detector_backend)
emotion_predictions = emotion_model.predict(img)[0,:] emotion_predictions = emotion_model.predict(emotion_imgs[i])[0,:]
sum_of_predictions = emotion_predictions.sum() sum_of_predictions = emotion_predictions.sum()
@ -443,20 +450,16 @@ def analyze(img_path, actions = [], models = {}, enforce_detection = True, detec
resp_obj += emotion_obj resp_obj += emotion_obj
elif action == 'age': elif action == 'age':
if img_224 is None:
img_224 = functions.preprocess_face(img_path, target_size = (224, 224), grayscale = False, enforce_detection = enforce_detection) #just emotion model expects grayscale images
#print("age prediction") #print("age prediction")
age_predictions = age_model.predict(img_224)[0,:] age_predictions = age_model.predict(imgs_224[i])[0,:]
apparent_age = Age.findApparentAge(age_predictions) apparent_age = Age.findApparentAge(age_predictions)
resp_obj += "\"age\": %s" % (apparent_age) resp_obj += "\"age\": %s" % (apparent_age)
elif action == 'gender': elif action == 'gender':
if img_224 is None:
img_224 = functions.preprocess_face(img = img_path, target_size = (224, 224), grayscale = False, enforce_detection = enforce_detection, detector_backend = detector_backend) #just emotion model expects grayscale images
#print("gender prediction") #print("gender prediction")
gender_prediction = gender_model.predict(img_224)[0,:] gender_prediction = gender_model.predict(imgs_224[i])[0,:]
if np.argmax(gender_prediction) == 0: if np.argmax(gender_prediction) == 0:
gender = "Woman" gender = "Woman"
@ -466,9 +469,7 @@ def analyze(img_path, actions = [], models = {}, enforce_detection = True, detec
resp_obj += "\"gender\": \"%s\"" % (gender) resp_obj += "\"gender\": \"%s\"" % (gender)
elif action == 'race': elif action == 'race':
if img_224 is None: race_predictions = race_model.predict(imgs_224[i])[0,:]
img_224 = functions.preprocess_face(img = img_path, target_size = (224, 224), grayscale = False, enforce_detection = enforce_detection, detector_backend = detector_backend) #just emotion model expects grayscale images
race_predictions = race_model.predict(img_224)[0,:]
race_labels = ['asian', 'indian', 'black', 'white', 'middle eastern', 'latino hispanic'] race_labels = ['asian', 'indian', 'black', 'white', 'middle eastern', 'latino hispanic']
sum_of_predictions = race_predictions.sum() sum_of_predictions = race_predictions.sum()
@ -493,30 +494,27 @@ def analyze(img_path, actions = [], models = {}, enforce_detection = True, detec
resp_obj = json.loads(resp_obj) resp_obj = json.loads(resp_obj)
if bulkProcess == True:
resp_objects.append(resp_obj) resp_objects.append(resp_obj)
else:
return resp_obj
if bulkProcess == True: # resp_obj = "{"
resp_obj = "{" #
# for i in range(0, len(resp_objects)):
# resp_item = json.dumps(resp_objects[i])
#
# if i > 0:
# resp_obj += ", "
#
# resp_obj += "\"instance_"+str(i+1)+"\": "+resp_item
# resp_obj += "}"
# resp_obj = json.loads(resp_obj)
# return resp_obj
return resp_objects, orig_faces
for i in range(0, len(resp_objects)): def detectFace(img_path, detector_backend='opencv'):
resp_item = json.dumps(resp_objects[i]) imgs = functions.preprocess_face(img=img_path, detector_backend=detector_backend)['processed'] #preprocess_face returns (1, 224, 224, 3)
for i in range(len(imgs)):
if i > 0: imgs[i] = imgs[i][0][:, :, ::-1] #bgr to rgb
resp_obj += ", " return imgs
resp_obj += "\"instance_"+str(i+1)+"\": "+resp_item
resp_obj += "}"
resp_obj = json.loads(resp_obj)
return resp_obj
#return resp_objects
def detectFace(img_path, detector_backend = 'opencv'):
img = functions.preprocess_face(img = img_path, detector_backend = detector_backend)[0] #preprocess_face returns (1, 224, 224, 3)
return img[:, :, ::-1] #bgr to rgb
def find(img_path, db_path, model_name ='VGG-Face', distance_metric = 'cosine', model = None, enforce_detection = True, detector_backend = 'opencv'): def find(img_path, db_path, model_name ='VGG-Face', distance_metric = 'cosine', model = None, enforce_detection = True, detector_backend = 'opencv'):
@ -538,22 +536,22 @@ def find(img_path, db_path, model_name ='VGG-Face', distance_metric = 'cosine',
if model == None: if model == None:
if model_name == 'VGG-Face': if model_name == 'VGG-Face':
print("Using VGG-Face model backend and", distance_metric,"distance.") print("Using VGG-Face model backend and", distance_metric, "distance.")
model = VGGFace.loadModel() model = VGGFace.loadModel()
elif model_name == 'OpenFace': elif model_name == 'OpenFace':
print("Using OpenFace model backend", distance_metric,"distance.") print("Using OpenFace model backend", distance_metric, "distance.")
model = OpenFace.loadModel() model = OpenFace.loadModel()
elif model_name == 'Facenet': elif model_name == 'Facenet':
print("Using Facenet model backend", distance_metric,"distance.") print("Using Facenet model backend", distance_metric, "distance.")
model = Facenet.loadModel() model = Facenet.loadModel()
elif model_name == 'DeepFace': elif model_name == 'DeepFace':
print("Using FB DeepFace model backend", distance_metric,"distance.") print("Using FB DeepFace model backend", distance_metric, "distance.")
model = FbDeepFace.loadModel() model = FbDeepFace.loadModel()
elif model_name == 'DeepID': elif model_name == 'DeepID':
print("Using DeepID model backend", distance_metric,"distance.") print("Using DeepID model backend", distance_metric, "distance.")
model = DeepID.loadModel() model = DeepID.loadModel()
elif model_name == 'Dlib': elif model_name == 'Dlib':
print("Using Dlib ResNet model backend", distance_metric,"distance.") print("Using Dlib ResNet model backend", distance_metric, "distance.")
from deepface.basemodels.DlibResNet import DlibResNet #this is not a must because it is very huge from deepface.basemodels.DlibResNet import DlibResNet #this is not a must because it is very huge
model = DlibResNet() model = DlibResNet()
elif model_name == 'Ensemble': elif model_name == 'Ensemble':
@ -659,7 +657,7 @@ def find(img_path, db_path, model_name ='VGG-Face', distance_metric = 'cosine',
input_shape_x = input_shape[0]; input_shape_y = input_shape[1] input_shape_x = input_shape[0]; input_shape_y = input_shape[1]
img = functions.preprocess_face(img = employee, target_size = (input_shape_y, input_shape_x), enforce_detection = enforce_detection, detector_backend = detector_backend) img = functions.preprocess_face(img = employee, target_size = (input_shape_y, input_shape_x), enforce_detection = enforce_detection, detector_backend = detector_backend)['processed']
representation = model.predict(img)[0,:] representation = model.predict(img)[0,:]
instance = [] instance = []
@ -685,7 +683,7 @@ def find(img_path, db_path, model_name ='VGG-Face', distance_metric = 'cosine',
input_shape_x = input_shape[0]; input_shape_y = input_shape[1] input_shape_x = input_shape[0]; input_shape_y = input_shape[1]
img = functions.preprocess_face(img = employee, target_size = (input_shape_y, input_shape_x), enforce_detection = enforce_detection, detector_backend = detector_backend) img = functions.preprocess_face(img = employee, target_size = (input_shape_y, input_shape_x), enforce_detection = enforce_detection, detector_backend = detector_backend)['processed']
representation = ensemble_model.predict(img)[0,:] representation = ensemble_model.predict(img)[0,:]
instance.append(representation) instance.append(representation)
@ -730,7 +728,7 @@ def find(img_path, db_path, model_name ='VGG-Face', distance_metric = 'cosine',
else: else:
input_shape = input_shape[1:3] input_shape = input_shape[1:3]
img = functions.preprocess_face(img = img_path, target_size = input_shape, enforce_detection = enforce_detection, detector_backend = detector_backend) img = functions.preprocess_face(img = img_path, target_size = input_shape, enforce_detection = enforce_detection, detector_backend = detector_backend)['processed']
target_representation = ensemble_model.predict(img)[0,:] target_representation = ensemble_model.predict(img)[0,:]
for k in metric_names: for k in metric_names:
@ -822,7 +820,7 @@ def find(img_path, db_path, model_name ='VGG-Face', distance_metric = 'cosine',
input_shape_x = input_shape[0]; input_shape_y = input_shape[1] input_shape_x = input_shape[0]; input_shape_y = input_shape[1]
img = functions.preprocess_face(img = img_path, target_size = (input_shape_y, input_shape_x), enforce_detection = enforce_detection, detector_backend = detector_backend) img = functions.preprocess_face(img = img_path, target_size = (input_shape_y, input_shape_x), enforce_detection = enforce_detection, detector_backend = detector_backend)['processed']
target_representation = model.predict(img)[0,:] target_representation = model.predict(img)[0,:]
distances = [] distances = []

View File

@ -18,7 +18,8 @@ import tensorflow as tf
import keras import keras
import bz2 import bz2
from deepface.commons import distance from deepface.commons import distance
from mtcnn import MTCNN #0.1.0 from mtcnn import MTCNN # 0.1.0
def loadBase64Img(uri): def loadBase64Img(uri):
encoded_data = uri.split(',')[1] encoded_data = uri.split(',')[1]
@ -26,20 +27,20 @@ def loadBase64Img(uri):
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR) img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
return img return img
def initializeFolder():
def initializeFolder():
home = str(Path.home()) home = str(Path.home())
if not os.path.exists(home+"/.deepface"): if not os.path.exists(home + "/.deepface"):
os.mkdir(home+"/.deepface") os.mkdir(home + "/.deepface")
print("Directory ",home,"/.deepface created") print("Directory ", home, "/.deepface created")
if not os.path.exists(home + "/.deepface/weights"):
os.mkdir(home + "/.deepface/weights")
print("Directory ", home, "/.deepface/weights created")
if not os.path.exists(home+"/.deepface/weights"):
os.mkdir(home+"/.deepface/weights")
print("Directory ",home,"/.deepface/weights created")
def findThreshold(model_name, distance_metric): def findThreshold(model_name, distance_metric):
threshold = 0.40 threshold = 0.40
if model_name == 'VGG-Face': if model_name == 'VGG-Face':
@ -92,6 +93,7 @@ def findThreshold(model_name, distance_metric):
return threshold return threshold
def get_opencv_path(): def get_opencv_path():
opencv_home = cv2.__file__ opencv_home = cv2.__file__
folders = opencv_home.split(os.path.sep)[0:-1] folders = opencv_home.split(os.path.sep)[0:-1]
@ -100,10 +102,10 @@ def get_opencv_path():
for folder in folders[1:]: for folder in folders[1:]:
path = path + "/" + folder path = path + "/" + folder
return path+"/data/" return path + "/data/"
def load_image(img): def load_image(img):
exact_image = False exact_image = False
if type(img).__module__ == np.__name__: if type(img).__module__ == np.__name__:
exact_image = True exact_image = True
@ -112,35 +114,36 @@ def load_image(img):
if len(img) > 11 and img[0:11] == "data:image/": if len(img) > 11 and img[0:11] == "data:image/":
base64_img = True base64_img = True
#--------------------------- # ---------------------------
if base64_img == True: if base64_img == True:
img = loadBase64Img(img) img = loadBase64Img(img)
elif exact_image != True: #image path passed as input elif exact_image != True: # image path passed as input
if os.path.isfile(img) != True: if os.path.isfile(img) != True:
raise ValueError("Confirm that ",img," exists") raise ValueError("Confirm that ", img, " exists")
img = cv2.imread(img) img = cv2.imread(img)
return img return img
def detect_face(img, detector_backend = 'opencv', grayscale = False, enforce_detection = True):
def detect_face(img, detector_backend='opencv', grayscale=False, enforce_detection=True):
home = str(Path.home()) home = str(Path.home())
if detector_backend == 'opencv': if detector_backend == 'opencv':
#get opencv configuration up first # get opencv configuration up first
opencv_path = get_opencv_path() opencv_path = get_opencv_path()
face_detector_path = opencv_path+"haarcascade_frontalface_default.xml" face_detector_path = opencv_path + "haarcascade_frontalface_default.xml"
if os.path.isfile(face_detector_path) != True: if os.path.isfile(face_detector_path) != True:
raise ValueError("Confirm that opencv is installed on your environment! Expected path ",face_detector_path," violated.") raise ValueError("Confirm that opencv is installed on your environment! Expected path ", face_detector_path,
" violated.")
face_detector = cv2.CascadeClassifier(face_detector_path) face_detector = cv2.CascadeClassifier(face_detector_path)
#-------------------------- # --------------------------
faces = [] faces = []
@ -150,58 +153,60 @@ def detect_face(img, detector_backend = 'opencv', grayscale = False, enforce_det
pass pass
if len(faces) > 0: if len(faces) > 0:
x,y,w,h = faces[0] #focus on the 1st face found in the image detected_faces = []
detected_face = img[int(y):int(y+h), int(x):int(x+w)] for face in faces:
return detected_face print(face)
x, y, w, h = face
detected_face = img[int(y):int(y + h), int(x):int(x + w)]
detected_faces.append(detected_face)
return detected_faces
else: #if no face detected else: # if no face detected
if enforce_detection != True: if enforce_detection != True:
return img return img
else: 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.") 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.")
elif detector_backend == 'ssd': elif detector_backend == 'ssd':
#--------------------------- # ---------------------------
#check required ssd model exists in the home/.deepface/weights folder # check required ssd model exists in the home/.deepface/weights folder
#model structure
if os.path.isfile(home+'/.deepface/weights/deploy.prototxt') != True:
# model structure
if os.path.isfile(home + '/.deepface/weights/deploy.prototxt') != True:
print("deploy.prototxt will be downloaded...") print("deploy.prototxt will be downloaded...")
url = "https://github.com/opencv/opencv/raw/3.4.0/samples/dnn/face_detector/deploy.prototxt" url = "https://github.com/opencv/opencv/raw/3.4.0/samples/dnn/face_detector/deploy.prototxt"
output = home+'/.deepface/weights/deploy.prototxt' output = home + '/.deepface/weights/deploy.prototxt'
gdown.download(url, output, quiet=False) gdown.download(url, output, quiet=False)
# pre-trained weights
#pre-trained weights if os.path.isfile(home + '/.deepface/weights/res10_300x300_ssd_iter_140000.caffemodel') != True:
if os.path.isfile(home+'/.deepface/weights/res10_300x300_ssd_iter_140000.caffemodel') != True:
print("res10_300x300_ssd_iter_140000.caffemodel will be downloaded...") print("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" url = "https://github.com/opencv/opencv_3rdparty/raw/dnn_samples_face_detector_20170830/res10_300x300_ssd_iter_140000.caffemodel"
output = home+'/.deepface/weights/res10_300x300_ssd_iter_140000.caffemodel' output = home + '/.deepface/weights/res10_300x300_ssd_iter_140000.caffemodel'
gdown.download(url, output, quiet=False) gdown.download(url, output, quiet=False)
#--------------------------- # ---------------------------
ssd_detector = cv2.dnn.readNetFromCaffe( ssd_detector = cv2.dnn.readNetFromCaffe(
home+"/.deepface/weights/deploy.prototxt", home + "/.deepface/weights/deploy.prototxt",
home+"/.deepface/weights/res10_300x300_ssd_iter_140000.caffemodel" home + "/.deepface/weights/res10_300x300_ssd_iter_140000.caffemodel"
) )
ssd_labels = ["img_id", "is_face", "confidence", "left", "top", "right", "bottom"] ssd_labels = ["img_id", "is_face", "confidence", "left", "top", "right", "bottom"]
target_size = (300, 300) target_size = (300, 300)
base_img = img.copy() #we will restore base_img to img later base_img = img.copy() # we will restore base_img to img later
original_size = img.shape original_size = img.shape
@ -210,14 +215,14 @@ def detect_face(img, detector_backend = 'opencv', grayscale = False, enforce_det
aspect_ratio_x = (original_size[1] / target_size[1]) aspect_ratio_x = (original_size[1] / target_size[1])
aspect_ratio_y = (original_size[0] / target_size[0]) aspect_ratio_y = (original_size[0] / target_size[0])
imageBlob = cv2.dnn.blobFromImage(image = img) imageBlob = cv2.dnn.blobFromImage(image=img)
ssd_detector.setInput(imageBlob) ssd_detector.setInput(imageBlob)
detections = ssd_detector.forward() detections = ssd_detector.forward()
detections_df = pd.DataFrame(detections[0][0], columns = ssd_labels) 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['is_face'] == 1] # 0: background, 1: face
detections_df = detections_df[detections_df['confidence'] >= 0.90] detections_df = detections_df[detections_df['confidence'] >= 0.90]
detections_df['left'] = (detections_df['left'] * 300).astype(int) detections_df['left'] = (detections_df['left'] * 300).astype(int)
@ -227,9 +232,9 @@ def detect_face(img, detector_backend = 'opencv', grayscale = False, enforce_det
if detections_df.shape[0] > 0: if detections_df.shape[0] > 0:
#TODO: sort detections_df # TODO: sort detections_df
#get the first face in the image # get the first face in the image
instance = detections_df.iloc[0] instance = detections_df.iloc[0]
left = instance["left"] left = instance["left"]
@ -237,21 +242,24 @@ def detect_face(img, detector_backend = 'opencv', grayscale = False, enforce_det
bottom = instance["bottom"] bottom = instance["bottom"]
top = instance["top"] top = instance["top"]
detected_face = base_img[int(top*aspect_ratio_y):int(bottom*aspect_ratio_y), int(left*aspect_ratio_x):int(right*aspect_ratio_x)] detected_face = base_img[int(top * aspect_ratio_y):int(bottom * aspect_ratio_y),
int(left * aspect_ratio_x):int(right * aspect_ratio_x)]
return detected_face return detected_face
else: #if no face detected else: # if no face detected
if enforce_detection != True: if enforce_detection != True:
img = base_img.copy() img = base_img.copy()
return img return img
else: 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.") 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.")
elif detector_backend == 'dlib': elif detector_backend == 'dlib':
import dlib #this is not a must library within deepface. that's why, I didn't put this import to a global level. version: 19.20.0 import \
dlib # this is not a must library within deepface. that's why, I didn't put this import to a global level. version: 19.20.0
detector = dlib.get_frontal_face_detector() detector = dlib.get_frontal_face_detector()
@ -260,20 +268,23 @@ def detect_face(img, detector_backend = 'opencv', grayscale = False, enforce_det
if len(detections) > 0: if len(detections) > 0:
for idx, d in enumerate(detections): for idx, d in enumerate(detections):
left = d.left(); right = d.right() left = d.left();
top = d.top(); bottom = d.bottom() right = d.right()
top = d.top();
bottom = d.bottom()
detected_face = img[top:bottom, left:right] detected_face = img[top:bottom, left:right]
return detected_face return detected_face
else: #if no face detected else: # if no face detected
if enforce_detection != True: if enforce_detection != True:
return img return img
else: 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.") 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.")
elif detector_backend == 'mtcnn': elif detector_backend == 'mtcnn':
@ -282,60 +293,63 @@ def detect_face(img, detector_backend = 'opencv', grayscale = False, enforce_det
detections = mtcnn_detector.detect_faces(img) detections = mtcnn_detector.detect_faces(img)
if len(detections) > 0: if len(detections) > 0:
detection = detections[0] detected_faces = []
for detection in detections:
x, y, w, h = detection["box"] x, y, w, h = detection["box"]
detected_face = img[int(y):int(y+h), int(x):int(x+w)] detected_face = img[int(y):int(y + h), int(x):int(x + w)]
return detected_face detected_faces.append(detected_face)
return detected_faces
else: #if no face detected else: # if no face detected
if enforce_detection != True: if enforce_detection != True:
return img return img
else: 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.") 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.")
else: else:
detectors = ['opencv', 'ssd', 'dlib', 'mtcnn'] detectors = ['opencv', 'ssd', 'dlib', 'mtcnn']
raise ValueError("Valid backends are ", detectors," but you passed ", detector_backend) raise ValueError("Valid backends are ", detectors, " but you passed ", detector_backend)
return 0 return 0
def alignment_procedure(img, left_eye, right_eye):
#this function aligns given face in img based on left and right eye coordinates def alignment_procedure(img, left_eye, right_eye):
# this function aligns given face in img based on left and right eye coordinates
left_eye_x, left_eye_y = left_eye left_eye_x, left_eye_y = left_eye
right_eye_x, right_eye_y = right_eye right_eye_x, right_eye_y = right_eye
#----------------------- # -----------------------
#find rotation direction # find rotation direction
if left_eye_y > right_eye_y: if left_eye_y > right_eye_y:
point_3rd = (right_eye_x, left_eye_y) point_3rd = (right_eye_x, left_eye_y)
direction = -1 #rotate same direction to clock direction = -1 # rotate same direction to clock
else: else:
point_3rd = (left_eye_x, right_eye_y) point_3rd = (left_eye_x, right_eye_y)
direction = 1 #rotate inverse direction of clock direction = 1 # rotate inverse direction of clock
#----------------------- # -----------------------
#find length of triangle edges # find length of triangle edges
a = distance.findEuclideanDistance(np.array(left_eye), np.array(point_3rd)) a = distance.findEuclideanDistance(np.array(left_eye), np.array(point_3rd))
b = distance.findEuclideanDistance(np.array(right_eye), np.array(point_3rd)) b = distance.findEuclideanDistance(np.array(right_eye), np.array(point_3rd))
c = distance.findEuclideanDistance(np.array(right_eye), np.array(left_eye)) c = distance.findEuclideanDistance(np.array(right_eye), np.array(left_eye))
#----------------------- # -----------------------
#apply cosine rule # apply cosine rule
if b != 0 and c != 0: #this multiplication causes division by zero in cos_a calculation if b != 0 and c != 0: # this multiplication causes division by zero in cos_a calculation
cos_a = (b*b + c*c - a*a)/(2*b*c) cos_a = (b * b + c * c - a * a) / (2 * b * c)
angle = np.arccos(cos_a) #angle in radian angle = np.arccos(cos_a) # angle in radian
angle = (angle * 180) / math.pi #radian to degree angle = (angle * 180) / math.pi # radian to degree
#----------------------- # -----------------------
#rotate base image # rotate base image
if direction == -1: if direction == -1:
angle = 90 - angle angle = 90 - angle
@ -343,27 +357,27 @@ def alignment_procedure(img, left_eye, right_eye):
img = Image.fromarray(img) img = Image.fromarray(img)
img = np.array(img.rotate(direction * angle)) img = np.array(img.rotate(direction * angle))
#----------------------- # -----------------------
return img #return img anyway return img # return img anyway
def align_face(img, detector_backend = 'opencv'):
def align_face(img, detector_backend='opencv'):
home = str(Path.home()) home = str(Path.home())
if (detector_backend == 'opencv') or (detector_backend == 'ssd'): if (detector_backend == 'opencv') or (detector_backend == 'ssd'):
opencv_path = get_opencv_path() opencv_path = get_opencv_path()
eye_detector_path = opencv_path+"haarcascade_eye.xml" eye_detector_path = opencv_path + "haarcascade_eye.xml"
eye_detector = cv2.CascadeClassifier(eye_detector_path) eye_detector = cv2.CascadeClassifier(eye_detector_path)
detected_face_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #eye detector expects gray scale image detected_face_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # eye detector expects gray scale image
eyes = eye_detector.detectMultiScale(detected_face_gray) eyes = eye_detector.detectMultiScale(detected_face_gray)
if len(eyes) >= 2: if len(eyes) >= 2:
#find the largest 2 eye # find the largest 2 eye
base_eyes = eyes[:, 2] base_eyes = eyes[:, 2]
@ -372,63 +386,65 @@ def align_face(img, detector_backend = 'opencv'):
item = (base_eyes[i], i) item = (base_eyes[i], i)
items.append(item) items.append(item)
df = pd.DataFrame(items, columns = ["length", "idx"]).sort_values(by=['length'], ascending=False) df = pd.DataFrame(items, columns=["length", "idx"]).sort_values(by=['length'], ascending=False)
eyes = eyes[df.idx.values[0:2]] #eyes variable stores the largest 2 eye eyes = eyes[df.idx.values[0:2]] # eyes variable stores the largest 2 eye
#----------------------- # -----------------------
#decide left and right eye # decide left and right eye
eye_1 = eyes[0]; eye_2 = eyes[1] eye_1 = eyes[0];
eye_2 = eyes[1]
if eye_1[0] < eye_2[0]: if eye_1[0] < eye_2[0]:
left_eye = eye_1; right_eye = eye_2 left_eye = eye_1;
right_eye = eye_2
else: else:
left_eye = eye_2; right_eye = eye_1 left_eye = eye_2;
right_eye = eye_1
#----------------------- # -----------------------
#find center of eyes # find center of eyes
left_eye = (int(left_eye[0] + (left_eye[2] / 2)), int(left_eye[1] + (left_eye[3] / 2))) left_eye = (int(left_eye[0] + (left_eye[2] / 2)), int(left_eye[1] + (left_eye[3] / 2)))
right_eye = (int(right_eye[0] + (right_eye[2]/2)), int(right_eye[1] + (right_eye[3]/2))) right_eye = (int(right_eye[0] + (right_eye[2] / 2)), int(right_eye[1] + (right_eye[3] / 2)))
img = alignment_procedure(img, left_eye, right_eye) img = alignment_procedure(img, left_eye, right_eye)
return img #return img anyway return img # return img anyway
elif detector_backend == 'dlib': elif detector_backend == 'dlib':
#check required file exists in the home/.deepface/weights folder # check required file exists in the home/.deepface/weights folder
if os.path.isfile(home+'/.deepface/weights/shape_predictor_5_face_landmarks.dat') != True:
if os.path.isfile(home + '/.deepface/weights/shape_predictor_5_face_landmarks.dat') != True:
print("shape_predictor_5_face_landmarks.dat.bz2 is going to be downloaded") print("shape_predictor_5_face_landmarks.dat.bz2 is going to be downloaded")
url = "http://dlib.net/files/shape_predictor_5_face_landmarks.dat.bz2" url = "http://dlib.net/files/shape_predictor_5_face_landmarks.dat.bz2"
output = home+'/.deepface/weights/'+url.split("/")[-1] output = home + '/.deepface/weights/' + url.split("/")[-1]
gdown.download(url, output, quiet=False) gdown.download(url, output, quiet=False)
zipfile = bz2.BZ2File(output) zipfile = bz2.BZ2File(output)
data = zipfile.read() data = zipfile.read()
newfilepath = output[:-4] #discard .bz2 extension newfilepath = output[:-4] # discard .bz2 extension
open(newfilepath, 'wb').write(data) open(newfilepath, 'wb').write(data)
#------------------------------ # ------------------------------
import dlib #this is not a must dependency in deepface import dlib # this is not a must dependency in deepface
detector = dlib.get_frontal_face_detector() detector = dlib.get_frontal_face_detector()
sp = dlib.shape_predictor(home+"/.deepface/weights/shape_predictor_5_face_landmarks.dat") sp = dlib.shape_predictor(home + "/.deepface/weights/shape_predictor_5_face_landmarks.dat")
detections = detector(img, 1) detections = detector(img, 1)
if len(detections) > 0: if len(detections) > 0:
detected_face = detections[0] detected_face = detections[0]
img_shape = sp(img, detected_face) img_shape = sp(img, detected_face)
img = dlib.get_face_chip(img, img_shape, size = img.shape[0]) img = dlib.get_face_chip(img, img_shape, size=img.shape[0])
return img #return img anyway return img # return img anyway
elif detector_backend == 'mtcnn': elif detector_backend == 'mtcnn':
@ -444,46 +460,63 @@ def align_face(img, detector_backend = 'opencv'):
img = alignment_procedure(img, left_eye, right_eye) img = alignment_procedure(img, left_eye, right_eye)
return img #return img anyway return img # return img anyway
def preprocess_face(img, target_size=(224, 224), grayscale = False, enforce_detection = True, detector_backend = 'opencv'):
#img might be path, base64 or numpy array. Convert it to numpy whatever it is. def preprocess_face(img, target_size=(224, 224), grayscale=False, enforce_detection=True, detector_backend='opencv'):
# img might be path, base64 or numpy array. Convert it to numpy whatever it is.
img = load_image(img) img = load_image(img)
base_img = img.copy() base_img = img.copy()
img = detect_face(img = img, detector_backend = detector_backend, grayscale = grayscale, enforce_detection = enforce_detection) imgs = detect_face(img=img, detector_backend=detector_backend, grayscale=grayscale,
enforce_detection=enforce_detection)
#-------------------------- # --------------------------
for i in range(len(imgs)):
img = imgs[i]
if img.shape[0] > 0 and img.shape[1] > 0: if img.shape[0] > 0 and img.shape[1] > 0:
img = align_face(img = img, detector_backend = detector_backend) imgs[i] = align_face(img=img, detector_backend=detector_backend)
else: else:
if enforce_detection == True: if enforce_detection == True:
raise ValueError("Detected face shape is ", img.shape,". Consider to set enforce_detection argument to False.") raise ValueError("Detected face shape is ", img.shape,
else: #restore base image ". Consider to set enforce_detection argument to False.")
img = base_img.copy() else: # restore base image
imgs[i] = base_img.copy()
#-------------------------- # --------------------------
# post-processing
pixels = []
for img in imgs:
#post-processing
if grayscale == True: if grayscale == True:
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img = cv2.resize(img, target_size) img = cv2.resize(img, target_size)
img_pixels = image.img_to_array(img) img_pixels = image.img_to_array(img)
img_pixels = np.expand_dims(img_pixels, axis = 0) img_pixels = np.expand_dims(img_pixels, axis=0)
img_pixels /= 255 #normalize input in [0, 1] img_pixels /= 255 # normalize input in [0, 1]
pixels.append(img_pixels)
return {'processed': pixels, 'original': imgs}
return img_pixels
def allocateMemory(): def allocateMemory():
# find allocated memories
#find allocated memories
gpu_indexes = [] gpu_indexes = []
memory_usage_percentages = []; available_memories = []; total_memories = []; utilizations = [] memory_usage_percentages = [];
power_usages = []; power_capacities = [] available_memories = [];
total_memories = [];
utilizations = []
power_usages = [];
power_capacities = []
try: try:
result = subprocess.check_output(['nvidia-smi']) result = subprocess.check_output(['nvidia-smi'])
@ -502,9 +535,9 @@ def allocateMemory():
power_usages.append(power_usage) power_usages.append(power_usage)
power_capacities.append(power_capacity) power_capacities.append(power_capacity)
#---------------------------- # ----------------------------
memory_info = line.split("|")[2].replace("MiB","").split("/") memory_info = line.split("|")[2].replace("MiB", "").split("/")
utilization_info = int(line.split("|")[3].split("%")[0]) utilization_info = int(line.split("|")[3].split("%")[0])
allocated = int(memory_info[0]) allocated = int(memory_info[0])
@ -513,7 +546,7 @@ def allocateMemory():
total_memories.append(total_memory) total_memories.append(total_memory)
available_memories.append(available_memory) available_memories.append(available_memory)
memory_usage_percentages.append(round(100*int(allocated)/int(total_memory), 4)) memory_usage_percentages.append(round(100 * int(allocated) / int(total_memory), 4))
utilizations.append(utilization_info) utilizations.append(utilization_info)
gpu_indexes.append(gpu_idx) gpu_indexes.append(gpu_idx)
@ -523,11 +556,11 @@ def allocateMemory():
except Exception as err: except Exception as err:
gpu_count = 0 gpu_count = 0
#print(str(err)) # print(str(err))
#------------------------------ # ------------------------------
df = pd.DataFrame(gpu_indexes, columns = ["gpu_index"]) df = pd.DataFrame(gpu_indexes, columns=["gpu_index"])
df["total_memories_in_mb"] = total_memories df["total_memories_in_mb"] = total_memories
df["available_memories_in_mb"] = available_memories df["available_memories_in_mb"] = available_memories
df["memory_usage_percentage"] = memory_usage_percentages df["memory_usage_percentage"] = memory_usage_percentages
@ -535,30 +568,30 @@ def allocateMemory():
df["power_usages_in_watts"] = power_usages df["power_usages_in_watts"] = power_usages
df["power_capacities_in_watts"] = power_capacities df["power_capacities_in_watts"] = power_capacities
df = df.sort_values(by = ["available_memories_in_mb"], ascending = False).reset_index(drop = True) df = df.sort_values(by=["available_memories_in_mb"], ascending=False).reset_index(drop=True)
#------------------------------ # ------------------------------
required_memory = 10000 #All deepface models require 9016 MiB required_memory = 10000 # All deepface models require 9016 MiB
if df.shape[0] > 0: #has gpu if df.shape[0] > 0: # has gpu
if df.iloc[0].available_memories_in_mb > required_memory: if df.iloc[0].available_memories_in_mb > required_memory:
my_gpu = str(int(df.iloc[0].gpu_index)) my_gpu = str(int(df.iloc[0].gpu_index))
os.environ["CUDA_VISIBLE_DEVICES"] = my_gpu os.environ["CUDA_VISIBLE_DEVICES"] = my_gpu
#------------------------------ # ------------------------------
#tf allocates all memory by default # tf allocates all memory by default
#this block avoids greedy approach # this block avoids greedy approach
config = tf.ConfigProto() config = tf.ConfigProto()
config.gpu_options.allow_growth = True config.gpu_options.allow_growth = True
session = tf.Session(config=config) session = tf.Session(config=config)
keras.backend.set_session(session) keras.backend.set_session(session)
print("DeepFace will run on GPU (gpu_", my_gpu,")") print("DeepFace will run on GPU (gpu_", my_gpu, ")")
else: else:
#this case has gpu but no enough memory to allocate # this case has gpu but no enough memory to allocate
os.environ["CUDA_VISIBLE_DEVICES"] = "" #run it on cpu os.environ["CUDA_VISIBLE_DEVICES"] = "" # run it on cpu
print("Even though the system has GPUs, there is no enough space in memory to allocate.") print("Even though the system has GPUs, there is no enough space in memory to allocate.")
print("DeepFace will run on CPU") print("DeepFace will run on CPU")
else: else:

441
my_deepface.ipynb Normal file

File diff suppressed because one or more lines are too long

BIN
test_imgs/.DS_Store vendored Normal file

Binary file not shown.

BIN
test_imgs/test1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 KiB

BIN
test_imgs/test2.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
test_imgs/test3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB