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. Parameters: img_path: exact image path, numpy array (BGR) or based64 encoded images could be passed. model_name (string): VGG-Face, Facenet, OpenFace, DeepFace, DeepID, Dlib, ArcFace. model: Built deepface model. A face recognition model is built every call of verify function. You can pass pre-built face recognition model optionally if you will call verify function several times. Consider to pass model if you are going to call represent function in a for loop. model = DeepFace.build_model('VGG-Face') enforce_detection (boolean): If any face could not be detected in an image, then verify function will return exception. Set this to False not to have this exception. This might be convenient for low resolution images. 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. """ if model is None: model = build_model(model_name) #--------------------------------- #decide input shape input_shape_x, input_shape_y = functions.find_input_shape(model) #detect and align img = functions.preprocess_face(img=img_path, target_size=(input_shape_y, input_shape_x), enforce_detection=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() return embedding
def get_features_vec(pic) -> np.ndarray: """ :argument pic: input PIL.Image.open object :return features_vec: features vec np array """ pic = np.array(pic) model = Facenet.loadModel() input_shape = functions.find_input_shape(model) input_shape_x = input_shape[0] input_shape_y = input_shape[1] img = functions.preprocess_face(pic, target_size=(input_shape_y, input_shape_x), enforce_detection=True, detector_backend='mtcnn') features_vec = model.predict(img)[0, :] return features_vec
def analysis(db_path, model_name, distance_metric, enable_face_analysis=True, source=0, time_threshold=5, frame_threshold=5): input_shape = (224, 224) input_shape_x = input_shape[0] input_shape_y = input_shape[1] text_color = (255, 255, 255) employees = [] #check passed db folder exists if os.path.isdir(db_path) == True: for r, d, f in os.walk(db_path): # r=root, d=directories, f = files for file in f: if ('.jpg' in file): #exact_path = os.path.join(r, file) exact_path = r + "/" + file #print(exact_path) employees.append(exact_path) if len(employees) == 0: print("WARNING: There is no image in this path ( ", db_path, ") . Face recognition will not be performed.") #------------------------ if len(employees) > 0: model = DeepFace.build_model(model_name) print(model_name, " is built") #------------------------ input_shape = functions.find_input_shape(model) input_shape_x = input_shape[0] input_shape_y = input_shape[1] #tuned thresholds for model and metric pair threshold = dst.findThreshold(model_name, distance_metric) #------------------------ #facial attribute analysis models if enable_face_analysis == True: tic = time.time() emotion_model = DeepFace.build_model('Emotion') print("Emotion model loaded") age_model = DeepFace.build_model('Age') print("Age model loaded") gender_model = DeepFace.build_model('Gender') print("Gender model loaded") toc = time.time() print("Facial attibute analysis models loaded in ", toc - tic, " seconds") #------------------------ #find embeddings for employee list tic = time.time() pbar = tqdm(range(0, len(employees)), desc='Finding embeddings') embeddings = [] #for employee in employees: for index in pbar: employee = employees[index] pbar.set_description("Finding embedding for %s" % (employee.split("/")[-1])) embedding = [] img = functions.preprocess_face(img=employee, target_size=(input_shape_y, input_shape_x), enforce_detection=False) img_representation = model.predict(img)[0, :] embedding.append(employee) embedding.append(img_representation) embeddings.append(embedding) df = pd.DataFrame(embeddings, columns=['employee', 'embedding']) df['distance_metric'] = distance_metric toc = time.time() print("Embeddings found for given data set in ", toc - tic, " seconds") #----------------------- pivot_img_size = 112 #face recognition result image #----------------------- opencv_path = functions.get_opencv_path() face_detector_path = opencv_path + "haarcascade_frontalface_default.xml" face_cascade = cv2.CascadeClassifier(face_detector_path) #----------------------- freeze = False face_detected = False face_included_frames = 0 #freeze screen if face detected sequantially 5 frames freezed_frame = 0 tic = time.time() cap = cv2.VideoCapture(source) #webcam while (True): ret, img = cap.read() #cv2.namedWindow('img', cv2.WINDOW_FREERATIO) #cv2.setWindowProperty('img', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN) raw_img = img.copy() resolution = img.shape resolution_x = img.shape[1] resolution_y = img.shape[0] if freeze == False: faces = face_cascade.detectMultiScale(img, 1.3, 5) if len(faces) == 0: face_included_frames = 0 else: faces = [] detected_faces = [] face_index = 0 for (x, y, w, h) in faces: if w > 130: #discard small detected faces face_detected = True if face_index == 0: face_included_frames = face_included_frames + 1 #increase frame for a single face cv2.rectangle(img, (x, y), (x + w, y + h), (67, 67, 67), 1) #draw rectangle to main image cv2.putText(img, str(frame_threshold - face_included_frames), (int(x + w / 4), int(y + h / 1.5)), cv2.FONT_HERSHEY_SIMPLEX, 4, (255, 255, 255), 2) detected_face = img[int(y):int(y + h), int(x):int(x + w)] #crop detected face #------------------------------------- detected_faces.append((x, y, w, h)) face_index = face_index + 1 #------------------------------------- if face_detected == True and face_included_frames == frame_threshold and freeze == False: freeze = True #base_img = img.copy() base_img = raw_img.copy() detected_faces_final = detected_faces.copy() tic = time.time() if freeze == True: toc = time.time() if (toc - tic) < time_threshold: if freezed_frame == 0: freeze_img = base_img.copy() #freeze_img = np.zeros(resolution, np.uint8) #here, np.uint8 handles showing white area issue for detected_face in detected_faces_final: x = detected_face[0] y = detected_face[1] w = detected_face[2] h = detected_face[3] cv2.rectangle(freeze_img, (x, y), (x + w, y + h), (67, 67, 67), 1) #draw rectangle to main image #------------------------------- #apply deep learning for custom_face custom_face = base_img[y:y + h, x:x + w] #------------------------------- #facial attribute analysis if enable_face_analysis == True: gray_img = functions.preprocess_face( img=custom_face, target_size=(48, 48), grayscale=True, enforce_detection=False) emotion_labels = [ 'Angry', 'Disgust', 'Fear', 'Happy', 'Sad', 'Surprise', 'Neutral' ] emotion_predictions = emotion_model.predict( gray_img)[0, :] sum_of_predictions = emotion_predictions.sum() mood_items = [] for i in range(0, len(emotion_labels)): mood_item = [] emotion_label = emotion_labels[i] emotion_prediction = 100 * emotion_predictions[ i] / sum_of_predictions mood_item.append(emotion_label) mood_item.append(emotion_prediction) mood_items.append(mood_item) emotion_df = pd.DataFrame( mood_items, columns=["emotion", "score"]) emotion_df = emotion_df.sort_values( by=["score"], ascending=False).reset_index(drop=True) #background of mood box #transparency overlay = freeze_img.copy() opacity = 0.4 if x + w + pivot_img_size < resolution_x: #right cv2.rectangle( freeze_img #, (x+w,y+20) , (x + w, y), (x + w + pivot_img_size, y + h), (64, 64, 64), cv2.FILLED) cv2.addWeighted(overlay, opacity, freeze_img, 1 - opacity, 0, freeze_img) elif x - pivot_img_size > 0: #left cv2.rectangle( freeze_img #, (x-pivot_img_size,y+20) , (x - pivot_img_size, y), (x, y + h), (64, 64, 64), cv2.FILLED) cv2.addWeighted(overlay, opacity, freeze_img, 1 - opacity, 0, freeze_img) for index, instance in emotion_df.iterrows(): emotion_label = "%s " % (instance['emotion']) emotion_score = instance['score'] / 100 bar_x = 35 #this is the size if an emotion is 100% bar_x = int(bar_x * emotion_score) if x + w + pivot_img_size < resolution_x: text_location_y = y + 20 + (index + 1) * 20 text_location_x = x + w if text_location_y < y + h: cv2.putText( freeze_img, emotion_label, (text_location_x, text_location_y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1) cv2.rectangle( freeze_img, (x + w + 70, y + 13 + (index + 1) * 20), (x + w + 70 + bar_x, y + 13 + (index + 1) * 20 + 5), (255, 255, 255), cv2.FILLED) elif x - pivot_img_size > 0: text_location_y = y + 20 + (index + 1) * 20 text_location_x = x - pivot_img_size if text_location_y <= y + h: cv2.putText( freeze_img, emotion_label, (text_location_x, text_location_y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1) cv2.rectangle( freeze_img, (x - pivot_img_size + 70, y + 13 + (index + 1) * 20), (x - pivot_img_size + 70 + bar_x, y + 13 + (index + 1) * 20 + 5), (255, 255, 255), cv2.FILLED) #------------------------------- face_224 = functions.preprocess_face( img=custom_face, target_size=(224, 224), grayscale=False, enforce_detection=False) age_predictions = age_model.predict(face_224)[0, :] apparent_age = Age.findApparentAge(age_predictions) #------------------------------- gender_prediction = gender_model.predict(face_224)[ 0, :] if np.argmax(gender_prediction) == 0: gender = "W" elif np.argmax(gender_prediction) == 1: gender = "M" #print(str(int(apparent_age))," years old ", dominant_emotion, " ", gender) analysis_report = str( int(apparent_age)) + " " + gender #------------------------------- info_box_color = (46, 200, 255) #top if y - pivot_img_size + int( pivot_img_size / 5) > 0: triangle_coordinates = np.array([ (x + int(w / 2), y), (x + int(w / 2) - int(w / 10), y - int(pivot_img_size / 3)), (x + int(w / 2) + int(w / 10), y - int(pivot_img_size / 3)) ]) cv2.drawContours(freeze_img, [triangle_coordinates], 0, info_box_color, -1) cv2.rectangle( freeze_img, (x + int(w / 5), y - pivot_img_size + int(pivot_img_size / 5)), (x + w - int(w / 5), y - int(pivot_img_size / 3)), info_box_color, cv2.FILLED) cv2.putText(freeze_img, analysis_report, (x + int(w / 3.5), y - int(pivot_img_size / 2.1)), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 111, 255), 2) #bottom elif y + h + pivot_img_size - int( pivot_img_size / 5) < resolution_y: triangle_coordinates = np.array([ (x + int(w / 2), y + h), (x + int(w / 2) - int(w / 10), y + h + int(pivot_img_size / 3)), (x + int(w / 2) + int(w / 10), y + h + int(pivot_img_size / 3)) ]) cv2.drawContours(freeze_img, [triangle_coordinates], 0, info_box_color, -1) cv2.rectangle( freeze_img, (x + int(w / 5), y + h + int(pivot_img_size / 3)), (x + w - int(w / 5), y + h + pivot_img_size - int(pivot_img_size / 5)), info_box_color, cv2.FILLED) cv2.putText(freeze_img, analysis_report, (x + int(w / 3.5), y + h + int(pivot_img_size / 1.5)), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 111, 255), 2) #------------------------------- #face recognition custom_face = functions.preprocess_face( img=custom_face, target_size=(input_shape_y, input_shape_x), enforce_detection=False) #check preprocess_face function handled if custom_face.shape[1:3] == input_shape: if df.shape[ 0] > 0: #if there are images to verify, apply face recognition img1_representation = model.predict( custom_face)[0, :] #print(freezed_frame," - ",img1_representation[0:5]) def findDistance(row): distance_metric = row['distance_metric'] img2_representation = row['embedding'] distance = 1000 #initialize very large value if distance_metric == 'cosine': distance = dst.findCosineDistance( img1_representation, img2_representation) elif distance_metric == 'euclidean': distance = dst.findEuclideanDistance( img1_representation, img2_representation) elif distance_metric == 'euclidean_l2': distance = dst.findEuclideanDistance( dst.l2_normalize( img1_representation), dst.l2_normalize( img2_representation)) return distance df['distance'] = df.apply(findDistance, axis=1) df = df.sort_values(by=["distance"]) candidate = df.iloc[0] employee_name = candidate['employee'] best_distance = candidate['distance'] #print(candidate[['employee', 'distance']].values) #if True: if best_distance <= threshold: #print(employee_name) display_img = cv2.imread(employee_name) display_img = cv2.resize( display_img, (pivot_img_size, pivot_img_size)) label = employee_name.split( "/")[-1].replace(".jpg", "") label = re.sub('[0-9]', '', label) try: if y - pivot_img_size > 0 and x + w + pivot_img_size < resolution_x: #top right freeze_img[ y - pivot_img_size:y, x + w:x + w + pivot_img_size] = display_img overlay = freeze_img.copy() opacity = 0.4 cv2.rectangle( freeze_img, (x + w, y), (x + w + pivot_img_size, y + 20), (46, 200, 255), cv2.FILLED) cv2.addWeighted( overlay, opacity, freeze_img, 1 - opacity, 0, freeze_img) cv2.putText( freeze_img, label, (x + w, y + 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, text_color, 1) #connect face and text cv2.line(freeze_img, (x + int(w / 2), y), (x + 3 * int(w / 4), y - int(pivot_img_size / 2)), (67, 67, 67), 1) cv2.line(freeze_img, (x + 3 * int(w / 4), y - int(pivot_img_size / 2)), (x + w, y - int(pivot_img_size / 2)), (67, 67, 67), 1) elif y + h + pivot_img_size < resolution_y and x - pivot_img_size > 0: #bottom left freeze_img[ y + h:y + h + pivot_img_size, x - pivot_img_size:x] = display_img overlay = freeze_img.copy() opacity = 0.4 cv2.rectangle( freeze_img, (x - pivot_img_size, y + h - 20), (x, y + h), (46, 200, 255), cv2.FILLED) cv2.addWeighted( overlay, opacity, freeze_img, 1 - opacity, 0, freeze_img) cv2.putText( freeze_img, label, (x - pivot_img_size, y + h - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, text_color, 1) #connect face and text cv2.line(freeze_img, (x + int(w / 2), y + h), (x + int(w / 2) - int(w / 4), y + h + int(pivot_img_size / 2)), (67, 67, 67), 1) cv2.line(freeze_img, (x + int(w / 2) - int(w / 4), y + h + int(pivot_img_size / 2)), (x, y + h + int(pivot_img_size / 2)), (67, 67, 67), 1) elif y - pivot_img_size > 0 and x - pivot_img_size > 0: #top left freeze_img[ y - pivot_img_size:y, x - pivot_img_size:x] = display_img overlay = freeze_img.copy() opacity = 0.4 cv2.rectangle( freeze_img, (x - pivot_img_size, y), (x, y + 20), (46, 200, 255), cv2.FILLED) cv2.addWeighted( overlay, opacity, freeze_img, 1 - opacity, 0, freeze_img) cv2.putText( freeze_img, label, (x - pivot_img_size, y + 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, text_color, 1) #connect face and text cv2.line( freeze_img, (x + int(w / 2), y), (x + int(w / 2) - int(w / 4), y - int(pivot_img_size / 2)), (67, 67, 67), 1) cv2.line( freeze_img, (x + int(w / 2) - int(w / 4), y - int(pivot_img_size / 2)), (x, y - int(pivot_img_size / 2)), (67, 67, 67), 1) elif x + w + pivot_img_size < resolution_x and y + h + pivot_img_size < resolution_y: #bottom righ freeze_img[ y + h:y + h + pivot_img_size, x + w:x + w + pivot_img_size] = display_img overlay = freeze_img.copy() opacity = 0.4 cv2.rectangle( freeze_img, (x + w, y + h - 20), (x + w + pivot_img_size, y + h), (46, 200, 255), cv2.FILLED) cv2.addWeighted( overlay, opacity, freeze_img, 1 - opacity, 0, freeze_img) cv2.putText( freeze_img, label, (x + w, y + h - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, text_color, 1) #connect face and text cv2.line(freeze_img, (x + int(w / 2), y + h), (x + int(w / 2) + int(w / 4), y + h + int(pivot_img_size / 2)), (67, 67, 67), 1) cv2.line(freeze_img, (x + int(w / 2) + int(w / 4), y + h + int(pivot_img_size / 2)), (x + w, y + h + int(pivot_img_size / 2)), (67, 67, 67), 1) except Exception as err: print(str(err)) tic = time.time( ) #in this way, freezed image can show 5 seconds #------------------------------- time_left = int(time_threshold - (toc - tic) + 1) cv2.rectangle(freeze_img, (10, 10), (90, 50), (67, 67, 67), -10) cv2.putText(freeze_img, str(time_left), (40, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 1) cv2.imshow('img', freeze_img) freezed_frame = freezed_frame + 1 else: face_detected = False face_included_frames = 0 freeze = False freezed_frame = 0 else: cv2.imshow('img', img) if cv2.waitKey(1) & 0xFF == ord('q'): #press q to quit break #kill open cv things cap.release() cv2.destroyAllWindows()
def find(img_path, db_path, model_name='VGG-Face', distance_metric='cosine', model=None, enforce_detection=True, detector_backend='mtcnn'): """ This function applies verification several times and find an identity in a database Parameters: img_path: exact image path, numpy array or based64 encoded image. If you are going to find several identities, then you should pass img_path as array instead of calling find function in a for loop. e.g. img_path = ["img1.jpg", "img2.jpg"] db_path (string): You should store some .jpg files in a folder and pass the exact folder path to this. model_name (string): VGG-Face, Facenet, OpenFace, DeepFace, DeepID, Dlib or Ensemble distance_metric (string): cosine, euclidean, euclidean_l2 model: built deepface model. A face recognition models are built in every call of find function. You can pass pre-built models to speed the function up. model = DeepFace.build_model('VGG-Face') enforce_detection (boolean): The function throws exception if a face could not be detected. Set this to True if you don't want to get exception. This might be convenient for low resolution images. detector_backend (string): set face detector backend as mtcnn, opencv, ssd or dlib Returns: This function returns pandas data frame. If a list of images is passed to img_path, then it will return list of pandas data frame. """ tic = time.time() img_paths, bulkProcess = functions.initialize_input(img_path) functions.initialize_detector(detector_backend=detector_backend) #------------------------------- if os.path.isdir(db_path) == True: if model == None: if model_name == 'Ensemble': print("Ensemble learning enabled") models = Boosting.loadModel() else: #model is not ensemble model = build_model(model_name) models = {} models[model_name] = model else: #model != None print("Already built model is passed") if model_name == 'Ensemble': Boosting.validate_model(model) models = model.copy() else: models = {} models[model_name] = model #--------------------------------------- if model_name == 'Ensemble': model_names = ['VGG-Face', 'Facenet', 'OpenFace', 'DeepFace'] metric_names = ['cosine', 'euclidean', 'euclidean_l2'] elif model_name != 'Ensemble': model_names = [] metric_names = [] model_names.append(model_name) metric_names.append(distance_metric) #--------------------------------------- file_name = "representations_%s.pkl" % (model_name) file_name = file_name.replace("-", "_").lower() if path.exists(db_path + "/" + file_name): # print("WARNING: Representations for images in ",db_path," folder were previously stored in ", file_name, ". If you added new instances after this file creation, then please delete this file and call find function again. It will create it again.") f = open(db_path + '/' + file_name, 'rb') representations = pickle.load(f) print("There are ", len(representations), " representations found in ", file_name) else: #create representation.pkl from scratch employees = [] for r, d, f in os.walk( db_path): # r=root, d=directories, f = files for file in f: if ('.jpg' in file.lower()) or ('.png' in file.lower()): exact_path = r + "/" + file employees.append(exact_path) if len(employees) == 0: raise ValueError( "There is no image in ", db_path, " folder! Validate .jpg or .png files exist in this path.") #------------------------ #find representations for db images representations = [] pbar = tqdm(range(0, len(employees)), desc='Finding representations') #for employee in employees: for index in pbar: employee = employees[index] instance = [] instance.append(employee) for j in model_names: custom_model = models[j] #---------------------------------- #decide input shape input_shape = functions.find_input_shape(custom_model) 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) representation = custom_model.predict(img)[0, :] instance.append(representation) #------------------------------- representations.append(instance) f = open(db_path + '/' + file_name, "wb") pickle.dump(representations, f) f.close() print( "Representations stored in ", db_path, "/", file_name, " file. Please delete this file when you add new identities in your database." ) #---------------------------- #now, we got representations for facial database if model_name != 'Ensemble': df = pd.DataFrame( representations, columns=["identity", "%s_representation" % (model_name)]) else: #ensemble learning columns = ['identity'] [columns.append('%s_representation' % i) for i in model_names] df = pd.DataFrame(representations, columns=columns) df_base = df.copy( ) #df will be filtered in each img. we will restore it for the next item. resp_obj = [] global_pbar = tqdm(range(0, len(img_paths)), desc='Analyzing') for j in global_pbar: img_path = img_paths[j] #find representation for passed image for j in model_names: custom_model = models[j] #-------------------------------- #decide input shape input_shape = functions.find_input_shape(custom_model) 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) target_representation = custom_model.predict(img)[0, :] for k in metric_names: distances = [] for index, instance in df.iterrows(): source_representation = instance["%s_representation" % (j)] if k == 'cosine': distance = dst.findCosineDistance( source_representation, target_representation) elif k == 'euclidean': distance = dst.findEuclideanDistance( source_representation, target_representation) elif k == 'euclidean_l2': distance = dst.findEuclideanDistance( dst.l2_normalize(source_representation), dst.l2_normalize(target_representation)) distances.append(distance) #--------------------------- if model_name == 'Ensemble' and j == 'OpenFace' and k == 'euclidean': continue else: df["%s_%s" % (j, k)] = distances if model_name != 'Ensemble': threshold = dst.findThreshold(j, k) df = df.drop(columns=["%s_representation" % (j)]) df = df[df["%s_%s" % (j, k)] <= threshold] df = df.sort_values( by=["%s_%s" % (j, k)], ascending=True).reset_index(drop=True) resp_obj.append(df) df = df_base.copy( ) #restore df for the next iteration #---------------------------------- if model_name == 'Ensemble': feature_names = [] for j in model_names: for k in metric_names: if model_name == 'Ensemble' and j == 'OpenFace' and k == 'euclidean': continue else: feature = '%s_%s' % (j, k) feature_names.append(feature) #print(df.head()) x = df[feature_names].values #-------------------------------------- boosted_tree = Boosting.build_gbm() y = boosted_tree.predict(x) verified_labels = [] scores = [] for i in y: verified = np.argmax(i) == 1 score = i[np.argmax(i)] verified_labels.append(verified) scores.append(score) df['verified'] = verified_labels df['score'] = scores df = df[df.verified == True] #df = df[df.score > 0.99] #confidence score df = df.sort_values(by=["score"], ascending=False).reset_index(drop=True) df = df[['identity', 'verified', 'score']] resp_obj.append(df) df = df_base.copy() #restore df for the next iteration #---------------------------------- toc = time.time() print("find function lasts ", toc - tic, " seconds") if len(resp_obj) == 1: return resp_obj[0] return resp_obj else: raise ValueError("Passed db_path does not exist!") return None
def verify(img1_path, img2_path='', model_name='VGG-Face', distance_metric='cosine', model=None, enforce_detection=True, detector_backend='mtcnn'): """ This function verifies an image pair is same person or different persons. Parameters: img1_path, img2_path: exact image path, numpy array or based64 encoded images could be passed. If you are going to call verify function for a list of image pairs, then you should pass an array instead of calling the function in for loops. e.g. img1_path = [ ['img1.jpg', 'img2.jpg'], ['img2.jpg', 'img3.jpg'] ] model_name (string): VGG-Face, Facenet, OpenFace, DeepFace, DeepID, Dlib, ArcFace or Ensemble distance_metric (string): cosine, euclidean, euclidean_l2 model: Built deepface model. A face recognition model is built every call of verify function. You can pass pre-built face recognition model optionally if you will call verify function several times. model = DeepFace.build_model('VGG-Face') enforce_detection (boolean): If any face could not be detected in an image, then verify function will return exception. Set this to False not to have this exception. This might be convenient for low resolution images. detector_backend (string): set face detector backend as mtcnn, opencv, ssd or dlib Returns: Verify function returns a dictionary. If img1_path is a list of image pairs, then the function will return list of dictionary. { "verified": True , "distance": 0.2563 , "max_threshold_to_verify": 0.40 , "model": "VGG-Face" , "similarity_metric": "cosine" } """ tic = time.time() img_list, bulkProcess = functions.initialize_input(img1_path, img2_path) functions.initialize_detector(detector_backend=detector_backend) resp_objects = [] #-------------------------------- if model_name == 'Ensemble': model_names = ["VGG-Face", "Facenet", "OpenFace", "DeepFace"] metrics = ["cosine", "euclidean", "euclidean_l2"] else: model_names = [] metrics = [] model_names.append(model_name) metrics.append(distance_metric) #-------------------------------- if model == None: if model_name == 'Ensemble': models = Boosting.loadModel() else: model = build_model(model_name) models = {} models[model_name] = model else: if model_name == 'Ensemble': Boosting.validate_model(model) models = model.copy() else: models = {} models[model_name] = model #------------------------------ #calling deepface in a for loop causes lots of progress bars. this prevents it. disable_option = False if len(img_list) > 1 else True pbar = tqdm(range(0, len(img_list)), desc='Verification', disable=disable_option) for index in pbar: instance = img_list[index] if type(instance) == list and len(instance) >= 2: img1_path = instance[0] img2_path = instance[1] ensemble_features = [] for i in model_names: custom_model = models[i] #decide input shape input_shape = functions.find_input_shape(custom_model) input_shape_x = input_shape[0] input_shape_y = input_shape[1] #---------------------- #detect 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) img2 = functions.preprocess_face( img=img2_path, target_size=(input_shape_y, input_shape_x), enforce_detection=enforce_detection, detector_backend=detector_backend) #---------------------- #find embeddings img1_representation = custom_model.predict(img1)[0, :] img2_representation = custom_model.predict(img2)[0, :] #---------------------- #find distances between embeddings for j in metrics: if j == 'cosine': distance = dst.findCosineDistance( img1_representation, img2_representation) elif j == 'euclidean': distance = dst.findEuclideanDistance( img1_representation, img2_representation) elif j == 'euclidean_l2': distance = dst.findEuclideanDistance( dst.l2_normalize(img1_representation), dst.l2_normalize(img2_representation)) else: raise ValueError("Invalid distance_metric passed - ", distance_metric) distance = np.float64( distance ) #causes trobule for euclideans in api calls if this is not set (issue #175) #---------------------- #decision if model_name != 'Ensemble': threshold = dst.findThreshold(i, j) if distance <= threshold: identified = True else: identified = False resp_obj = { "verified": identified, "distance": distance, "max_threshold_to_verify": threshold, "model": model_name, "similarity_metric": distance_metric } if bulkProcess == True: resp_objects.append(resp_obj) else: return resp_obj else: #Ensemble #this returns same with OpenFace - euclidean_l2 if i == 'OpenFace' and j == 'euclidean': continue else: ensemble_features.append(distance) #---------------------- if model_name == 'Ensemble': boosted_tree = Boosting.build_gbm() prediction = boosted_tree.predict( np.expand_dims(np.array(ensemble_features), axis=0))[0] verified = np.argmax(prediction) == 1 score = prediction[np.argmax(prediction)] resp_obj = { "verified": verified, "score": score, "distance": ensemble_features, "model": ["VGG-Face", "Facenet", "OpenFace", "DeepFace"], "similarity_metric": ["cosine", "euclidean", "euclidean_l2"] } if bulkProcess == True: resp_objects.append(resp_obj) else: return resp_obj #---------------------- else: raise ValueError("Invalid arguments passed to verify function: ", instance) #------------------------- toc = time.time() if bulkProcess == True: resp_obj = {} for i in range(0, len(resp_objects)): resp_item = resp_objects[i] resp_obj["pair_%d" % (i + 1)] = resp_item return resp_obj
def verify(img1_path, img2_path='', model_name='VGG-Face', distance_metric='cosine', model=None, enforce_detection=True, detector_backend='mtcnn'): tic = time.time() img_list, bulkProcess = initialize_input(img1_path, img2_path) functions.initialize_detector(detector_backend=detector_backend) resp_objects = [] #-------------------------------- if model_name == 'Ensemble': model_names = ["VGG-Face", "Facenet", "OpenFace", "DeepFace"] metrics = ["cosine", "euclidean", "euclidean_l2"] else: model_names = [] metrics = [] model_names.append(model_name) metrics.append(distance_metric) #-------------------------------- if model == None: if model_name == 'Ensemble': models = Boosting.loadModel() else: model = build_model(model_name) models = {} models[model_name] = model else: if model_name == 'Ensemble': Boosting.validate_model(model) else: models = {} models[model_name] = model #------------------------------ #calling deepface in a for loop causes lots of progress bars. this prevents it. disable_option = False if len(img_list) > 1 else True pbar = tqdm(range(0, len(img_list)), desc='Verification', disable=disable_option) for index in pbar: instance = img_list[index] if type(instance) == list and len(instance) >= 2: img1_path = instance[0] img2_path = instance[1] ensemble_features = [] for i in model_names: custom_model = models[i] #decide input shape input_shape = functions.find_input_shape(custom_model) input_shape_x = input_shape[0] input_shape_y = input_shape[1] #---------------------- #detect 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) img2 = functions.preprocess_face( img=img2_path, target_size=(input_shape_y, input_shape_x), enforce_detection=enforce_detection, detector_backend=detector_backend) #---------------------- #find embeddings img1_representation = custom_model.predict(img1)[0, :] img2_representation = custom_model.predict(img2)[0, :] #---------------------- #find distances between embeddings for j in metrics: if j == 'cosine': distance = dst.findCosineDistance( img1_representation, img2_representation) elif j == 'euclidean': distance = dst.findEuclideanDistance( img1_representation, img2_representation) elif j == 'euclidean_l2': distance = dst.findEuclideanDistance( dst.l2_normalize(img1_representation), dst.l2_normalize(img2_representation)) else: raise ValueError("Invalid distance_metric passed - ", distance_metric) #---------------------- #decision if model_name != 'Ensemble': threshold = dst.findThreshold(i, j) if distance <= threshold: identified = True else: identified = False resp_obj = { "verified": identified, "distance": distance, "max_threshold_to_verify": threshold, "model": model_name, "similarity_metric": distance_metric } if bulkProcess == True: resp_objects.append(resp_obj) else: return resp_obj else: #Ensemble #this returns same with OpenFace - euclidean_l2 if i == 'OpenFace' and j == 'euclidean': continue else: ensemble_features.append(distance) #---------------------- if model_name == 'Ensemble': boosted_tree = Boosting.build_gbm() prediction = boosted_tree.predict( np.expand_dims(np.array(ensemble_features), axis=0))[0] verified = np.argmax(prediction) == 1 score = prediction[np.argmax(prediction)] resp_obj = { "verified": verified, "score": score, "distance": ensemble_features, "model": ["VGG-Face", "Facenet", "OpenFace", "DeepFace"], "similarity_metric": ["cosine", "euclidean", "euclidean_l2"] } if bulkProcess == True: resp_objects.append(resp_obj) else: return resp_obj #---------------------- else: raise ValueError("Invalid arguments passed to verify function: ", instance) #------------------------- toc = time.time() if bulkProcess == True: resp_obj = {} for i in range(0, len(resp_objects)): resp_item = resp_objects[i] resp_obj["pair_%d" % (i + 1)] = resp_item return resp_obj
def analysis(db_path, model_name, distance_metric, enable_face_analysis=False, source=0, time_threshold=5, frame_threshold=5): #Intitalize the input shape #input_shape = (224, 224); input_shape_x = input_shape[0]; input_shape_y = input_shape[1] employees = [] #check passed db folder exists if os.path.isdir(db_path) == True: for r, d, f in os.walk(db_path): # r=root, d=directories, f = files for file in f: if ('.jpg' in file): #exact_path = os.path.join(r, file) exact_path = r + "/" + file #print(exact_path) employees.append(exact_path) #------------------------ if len(employees) > 0: model = DeepFace.build_model(model_name) print(model_name, " is built") #------------------------ input_shape = functions.find_input_shape(model) input_shape_x = input_shape[0] input_shape_y = input_shape[1] #------------------------ #facial attribute analysis models if enable_face_analysis == True: tic = time.time() emotion_model = DeepFace.build_model('Emotion') #sg.popup_quick_message('Emotion Model Loaded') print("Emotion model loaded") toc = time.time() print("Facial attibute analysis models loaded in ", toc - tic, " seconds") #------------------------ #find embeddings for employee list tic = time.time() pbar = tqdm(range(0, len(employees)), desc='Finding embeddings') embeddings = [] #for employee in employees: for index in pbar: employee = employees[index] pbar.set_description("Finding embedding for %s" % (employee.split("/")[-1])) embedding = [] captured_frame = functions.preprocess_face(img=employee, target_size=(input_shape_y, input_shape_x), enforce_detection=False) img_representation = model.predict(captured_frame)[0, :] embedding.append(employee) embedding.append(img_representation) embeddings.append(embedding) df = pd.DataFrame(embeddings, columns=['employee', 'embedding']) df['distance_metric'] = distance_metric toc = time.time() print("Embeddings found for given data set in ", toc - tic, " seconds") #----------------------- pivot_img_size = 112 #face recognition result image #----------------------- opencv_path = functions.get_opencv_path() face_detector_path = opencv_path + "haarcascade_frontalface_default.xml" face_cascade = cv2.CascadeClassifier(face_detector_path) #-----------------------Declare Variables freeze = False face_detected = False face_included_frames = 0 #freeze screen if face detected sequantially 5 frames freezed_frame = 0 tic = time.time() # START CAMERA win_started = False captured_video = cv2.VideoCapture(source) #Start webcam while (True): ret, captured_frame = captured_video.read() #cv2.namedWindow('captured_frame', cv2.WINDOW_FREERATIO) #cv2.setWindowProperty('captured_frame', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN) raw_img = captured_frame.copy() resolution = captured_frame.shape resolution_x = captured_frame.shape[1] resolution_y = captured_frame.shape[0] if freeze == False: faces = face_cascade.detectMultiScale(captured_frame, 1.3, 5) if len(faces) == 0: face_included_frames = 0 else: faces = [] detected_faces = [] face_index = 0 for (x, y, w, h) in faces: if w > 130: #discard small detected faces face_detected = True if face_index == 0: face_included_frames = face_included_frames + 1 #increase frame for a single face cv2.rectangle(captured_frame, (x, y), (x + w, y + h), (67, 67, 67), 1) #draw rectangle to main image cv2.putText(captured_frame, str(frame_threshold - face_included_frames), (int(x + w / 4), int(y + h / 1.5)), cv2.FONT_HERSHEY_SIMPLEX, 4, (255, 255, 255), 2) detected_face = captured_frame[int(y):int(y + h), int(x):int( x + w)] #crop detected face #------------------------------------- detected_faces.append((x, y, w, h)) face_index = face_index + 1 #------------------------------------- if face_detected == True and face_included_frames == frame_threshold and freeze == False: freeze = True #base_img = captured_frame.copy() base_img = raw_img.copy() detected_faces_final = detected_faces.copy() tic = time.time() if freeze == True: toc = time.time() if (toc - tic) < time_threshold: if freezed_frame == 0: freeze_img = base_img.copy() #freeze_img = np.zeros(resolution, np.uint8) #here, np.uint8 handles showing white area issue for detected_face in detected_faces_final: x = detected_face[0] y = detected_face[1] w = detected_face[2] h = detected_face[3] cv2.rectangle(freeze_img, (x, y), (x + w, y + h), (67, 67, 67), 1) #draw rectangle to main image #------------------------------- #apply deep learning for custom_face custom_face = base_img[y:y + h, x:x + w] #------------------------------- #facial attribute analysis if enable_face_analysis == True: gray_img = functions.preprocess_face( img=custom_face, target_size=(48, 48), grayscale=True, enforce_detection=False) emotion_labels = [ 'Angry', 'Disgust', 'Fear', 'Happy', 'Sad', 'Surprise', 'Neutral' ] emotion_predictions = emotion_model.predict( gray_img)[0, :] sum_of_predictions = emotion_predictions.sum() mood_items = [] for i in range(0, len(emotion_labels)): mood_item = [] emotion_label = emotion_labels[i] emotion_prediction = 100 * emotion_predictions[ i] / sum_of_predictions mood_item.append(emotion_label) mood_item.append(emotion_prediction) mood_items.append(mood_item) emotion_df = pd.DataFrame( mood_items, columns=["emotion", "score"]) emotion_df = emotion_df.sort_values( by=["score"], ascending=False).reset_index(drop=True) #background of mood box #transparency overlay = freeze_img.copy() opacity = 0.1 if x + w + pivot_img_size < resolution_x: #right cv2.rectangle( freeze_img #, (x+w,y+20) , (x + w, y), (x + w + pivot_img_size, y + h), (208, 189, 0), cv2.FILLED) #TEAL cv2.addWeighted( overlay, opacity, freeze_img, 1 - opacity, 0, freeze_img, ) elif x - pivot_img_size > 0: #left cv2.rectangle( freeze_img #, (x-pivot_img_size,y+20) , (x - pivot_img_size, y), (x, y + h), (208, 189, 0), cv2.FILLED) #TEAL cv2.addWeighted(overlay, opacity, freeze_img, 1 - opacity, 0, freeze_img) for index, instance in emotion_df.iterrows(): emotion_label = "%s " % (instance['emotion']) emotion_score = instance['score'] / 100 bar_x = 35 #this is the size if an emotion is 100% bar_x = int(bar_x * emotion_score) if x + w + pivot_img_size < resolution_x: text_location_y = y + 20 + (index + 1) * 20 text_location_x = x + w if text_location_y < y + h: cv2.putText( freeze_img, emotion_label, (text_location_x, text_location_y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1) cv2.rectangle( freeze_img, (x + w + 70, y + 13 + (index + 1) * 20), (x + w + 70 + bar_x, y + 13 + (index + 1) * 20 + 5), (255, 255, 255), cv2.FILLED) elif x - pivot_img_size > 0: text_location_y = y + 20 + (index + 1) * 20 text_location_x = x - pivot_img_size if text_location_y <= y + h: cv2.putText( freeze_img, emotion_label, (text_location_x, text_location_y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1) cv2.rectangle( freeze_img, (x - pivot_img_size + 70, y + 13 + (index + 1) * 20), (x - pivot_img_size + 70 + bar_x, y + 13 + (index + 1) * 20 + 5), (255, 255, 255), cv2.FILLED) #------------------------------- # time_left = int(time_threshold - (toc - tic) + 1) # countdown box # cv2.rectangle(freeze_img, (10, 10), (90, 50), (208,189,0), -10) # cv2.putText(freeze_img, str(time_left), (40, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 1) cv2.imshow('Analysis Report', freeze_img) freezed_frame = freezed_frame + 1 else: face_detected = False face_included_frames = 0 freeze = False freezed_frame = 0 imgbytes = cv2.imencode('.png', captured_frame)[1].tobytes( ) # Have to add this and also chnage parrameter # ---------------------------- THE GUI ---------------------------- sg.theme('Reddit') if not win_started: win_started = True layout = [ [sg.Text('Facial Analysis in Progress', size=(30, 1))], [sg.Image(data=imgbytes, key='_IMAGE_')], # THIS IS THE ACTUAL CV FEED WINDOW [sg.Button('Stop')] ] window = sg.Window('Emotion Detection', layout, default_element_size=(14, 1), text_justification='left', auto_size_text=False, font='helvetica', icon=icon_logo64, finalize=True) image_elem = window['_IMAGE_'] else: image_elem.update(data=imgbytes) event, values = window.read(timeout=0) if event is None or event == 'Stop': break window.close() #kill open cv things captured_video.release() cv2.destroyAllWindows()