Created
February 7, 2019 01:26
-
-
Save progerjkd/9231a479c512f521925cc36c1014a07d to your computer and use it in GitHub Desktop.
A simple face recognition system using opencv2 and dlib to perform face encodings, and calculate Euclidean distances from a database of previously encoded faces.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import face_recognition | |
import cv2 | |
import numpy as np | |
import glob | |
import os | |
import logging | |
import pickle | |
# adapted from the Deep Learning: Face Recognition course from LinkedIn Learning | |
IMAGES_PATH = './intranet_images' # put your reference images in here | |
#IMAGES_PATH = './images' # put your reference images in here | |
CAMERA_DEVICE_ID = 0 | |
MAX_DISTANCE = 0.6 # increase to make recognition less strict, decrease to make more strict | |
# Define the codec and create VideoWriter object | |
fourcc = cv2.VideoWriter_fourcc(*'XVID') | |
out = cv2.VideoWriter('output/brim.avi', fourcc, 7.0, (640, 480)) | |
def get_face_embeddings_from_image(image, convert_to_rgb=False): | |
""" | |
Take a raw image and run both the face detection and face embedding model on it | |
""" | |
# Convert from BGR to RGB if needed | |
if convert_to_rgb: | |
image = image[:, :, ::-1] | |
# run the face detection model to find face locations | |
face_locations = face_recognition.face_locations(image) | |
# run the embedding model to get face embeddings for the supplied locations | |
face_encodings = face_recognition.face_encodings(image, face_locations) | |
return face_locations, face_encodings | |
def load_database_from_file(): | |
with open('database', 'rb') as fp: | |
database = pickle.load(fp) | |
return database | |
def setup_database(): | |
""" | |
Load reference images and create a database of their face encodings | |
""" | |
database = {} | |
count = 0 | |
for filename in glob.glob(os.path.join(IMAGES_PATH, '*.jpg')): | |
# load image | |
image_rgb = face_recognition.load_image_file(filename) | |
# use the name in the filename as the identity key | |
identity = os.path.splitext(os.path.basename(filename))[0] | |
# get the face encoding and link it to the identity | |
locations, encodings = get_face_embeddings_from_image(image_rgb) | |
if len(encodings) == 0: | |
print(f'Face encodings not found for user {identity}.') | |
else: | |
print(f'Encoding face for user #{count}: {identity}') | |
database[identity] = encodings[0] | |
count = count + 1 | |
with open('database', 'wb') as fp: | |
pickle.dump(database, fp) | |
return database | |
def paint_detected_face_on_image(frame, location, name=None): | |
""" | |
Paint a rectangle around the face and write the name | |
""" | |
# unpack the coordinates from the location tuple | |
top, right, bottom, left = location | |
if name is None: | |
name = 'Unknown' | |
color = (0, 0, 255) # red for unrecognized face | |
else: | |
color = (0, 128, 0) # dark green for recognized face | |
# Draw a box around the face | |
cv2.rectangle(frame, (left, top), (right, bottom), color, 2) | |
# Draw a label with a name below the face | |
cv2.rectangle(frame, (left, bottom - 35), (right, bottom), color, cv2.FILLED) | |
cv2.putText(frame, name, (left + 6, bottom - 6), cv2.FONT_HERSHEY_DUPLEX, 1.0, (255, 255, 255), 1) | |
def run_face_recognition(database): | |
""" | |
Start the face recognition via the webcam | |
""" | |
# Open a handler for the camera | |
video_capture = cv2.VideoCapture(CAMERA_DEVICE_ID) | |
#video_capture.set(3, 900) | |
#video_capture.set(4, 1600) | |
# the face_recognitino library uses keys and values of your database separately | |
known_face_encodings = list(database.values()) | |
known_face_names = list(database.keys()) | |
while video_capture.isOpened(): | |
# Grab a single frame of video (and check if it went ok) | |
ok, frame = video_capture.read() | |
if not ok: | |
logging.error("Could not read frame from camera. Stopping video capture.") | |
break | |
# flip image | |
frame = cv2.flip(frame, 1) | |
# run detection and embedding models | |
face_locations, face_encodings = get_face_embeddings_from_image(frame, convert_to_rgb=True) | |
# Loop through each face in this frame of video and see if there's a match | |
for location, face_encoding in zip(face_locations, face_encodings): | |
# get the distances from this encoding to those of all reference images | |
distances = face_recognition.face_distance(known_face_encodings, face_encoding) | |
# select the closest match (smallest distance) if it's below the threshold value | |
if np.any(distances <= MAX_DISTANCE): | |
best_match_idx = np.argmin(distances) | |
name = known_face_names[best_match_idx] | |
else: | |
name = None | |
# put recognition info on the image | |
paint_detected_face_on_image(frame, location, name) | |
# Display the resulting image | |
cv2.imshow('Video', frame) | |
# write the flipped frame | |
out.write(frame) | |
# Hit 'q' on the keyboard to quit! | |
if cv2.waitKey(1) & 0xFF == ord('q'): | |
break | |
# Release handle to the webcam | |
video_capture.release() | |
out.release() | |
cv2.destroyAllWindows() | |
database = setup_database() | |
# if you want to load the face encoding from a file instead of processing it at each run, use the function load_database_from_file() | |
#database = load_database_from_file() | |
run_face_recognition(database) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment