Basic python recognition using face_recognition library. Below you can find a few simple examples of face_recognition library.
Requirements:
- dlib
- cmake
Follow this guide to install those (for Windows 10) https://medium.com/analytics-vidhya/how-to-install-dlib-library-for-python-in-windows-10-57348ba1117f
Then just install the other requirements from requirements.txt: pip3 install -r requirements.txt
Video demo: https://youtu.be/C-bPW5KqPKs
Blog post: https://johnmark.me/python-face-recognition/
Github repo: https://github.com/jmcausing/face_detect
Face identifier.
The codes below will loop each file on a specific folder to check if there are faces or not and count how many total faces.
Face detector using face_recognition
requirements.txt
cmake
dlib
face_recognition
opencv-python
opencv
face.py
import face_recognition
from PIL import Image
import os
# Extract faces in "face" directory
target_folder = "/mnt/c/Users/JMC/python/wsl_cf_gsc_kac/face"
# Get all files in "face" folder as list
unknown_faces = os.listdir(target_folder)
for image in unknown_faces:
image_of_people = face_recognition.load_image_file(f"face/{image}")
unknown_face_locations = face_recognition.face_locations(image_of_people)
print(f"# Scanning face in: {image}..")
if unknown_face_locations:
print(f"# Face found in {image}. Total faces: {len(unknown_face_locations)}")
else:
print(f"# Error! No face detected in {image}!")
for face_location in unknown_face_locations:
top, right, bottom, left = face_location
face_image = image_of_people[top:bottom, left:right]
pil_image = Image.fromarray(face_image)
# Save the detected faces
#pil_image.save(f"face/{image}_{top}.jpg")
Face recognition
Below is a code sample where you can place a target image file to check if that face is found on all other image files.
Note: It is not 100% perfect. The screenshot below shows joy.png detects the same face of miggy.jpg (Mother and Son 😄)
import face_recognition
import os
# Extract faces in "face" directory
target_folder = "/mnt/c/Users/JMC/python/wsl_cf_gsc_kac/face"
# Get all files in "face" folder as list
unknown_faces = os.listdir(target_folder)
# Setup target image file
target_file = 'miggy.jpg'
target_image_to_search = face_recognition.load_image_file(f"{target_folder}/{target_file}")
face_locations = face_recognition.face_locations(target_image_to_search, number_of_times_to_upsample=2)
target_image_encoding = face_recognition.face_encodings(target_image_to_search,known_face_locations=face_locations, num_jitters=100)[0]
files_found_resuilts = []
for image in unknown_faces:
# Skipping target file to check face recognition
if image == target_file:
continue
print(f"# Scanning face in: {image}..")
# Load images from files
image_of_people = face_recognition.load_image_file(f"{target_folder}/{image}")
# Check if there's a face on this specific image file {image}
if face_recognition.face_encodings(image_of_people):
total_face_in_image = len(face_recognition.face_encodings(image_of_people))
unknown_encoding = face_recognition.face_encodings(image_of_people)[0]
# Compare target image to this specific loop image {image}
results = face_recognition.compare_faces([target_image_encoding], unknown_encoding, tolerance=0.45)
# If target face found (True)
if results[0]:
files_found_resuilts.append(image)
print(f"# We found the face of {target_file} in {image}")
# List the files that the target image was found
if files_found_resuilts:
print(f"# List of files matched {target_file}: {files_found_resuilts}")
Face recognition with rectangle drawings
import face_recognition
import os
from PIL import Image, ImageDraw
import numpy as np
# Extract faces in "face" directory
target_folder = "/mnt/c/Users/JMC/python/face/images"
# Get all files in "face" folder as list
unknown_faces = os.listdir(target_folder)
# Setup target image file
target_file = 'jm.png'
target_image_to_search = face_recognition.load_image_file(f"{target_folder}/{target_file}")
target_image_encoding = face_recognition.face_encodings(target_image_to_search)
files_found_resuilts = []
for image in unknown_faces:
# Skipping target file to check face recognition
if image == target_file:
continue
# Load images from files
image_of_people = face_recognition.load_image_file(f"{target_folder}/{image}")
pil_image = Image.fromarray(image_of_people)
# Create a Pillow ImageDraw Draw instance to draw with
draw = ImageDraw.Draw(pil_image)
# face_location - check how many faces in an image.
face_locations = face_recognition.face_locations(image_of_people)
total_face = len(face_locations)
print(f"# Scanning face in: {image}..", end =" ")
print(f"Total face found {total_face}")
# Check if there's a face on this specific image file {image}
if face_recognition.face_encodings(image_of_people):
total_face_in_image = len(face_recognition.face_encodings(image_of_people))
face_locations1 = face_recognition.face_locations(image_of_people)
unknown_encoding = face_recognition.face_encodings(image_of_people)
# # 1 more more results in a list array.
# # We need to loop each encoding to each and compare each face encoding
itop = []
iright = []
ileft = []
ibottom = []
#for face_encoding in unknown_encoding:
for (top, right, bottom, left), face_encoding in zip(face_locations1, unknown_encoding):
# Get compare match results (True or False) for each face encoding
results = face_recognition.compare_faces(face_encoding, target_image_encoding, tolerance=0.52)
if results[0]:
files_found_resuilts.append(image)
print(f"# We found the face of {target_file} in {image}")
# Append face coordinates for drawing rectagles
itop.append(top)
iright.append(right)
ileft.append(left)
ibottom.append(bottom)
# Check if there's a face coordinate 'top'
if bool(len(itop)):
# Loop all face coordinates to draw a square. Ex. 1 image 10 faces, will check how many face that can match the image target
x = 0
while x < len(itop):
#Draw a box around the face using the Pillow module
draw.rectangle(((ileft[x], itop[x]), (iright[x], ibottom[x])), outline=(0, 0, 255))
# Draw a label with a name below the face
text_height = 11 # 11px text height for label
draw.rectangle(((ileft[x], ibottom[x] - text_height - 10), (iright[x], ibottom[x])), fill=(0, 0, 255), outline=(0, 0, 255))
draw.text((ileft[x] + 6, ibottom[x] - text_height - 0), target_file, fill=(255, 255, 255, 255))
x += 1
# Display the resulting image
pil_image.show()
# Remove the drawing library from memory as per the Pillow docs
del draw
# List the files that the target image was found
if files_found_resuilts:
print(f"# List of files matched {target_file}: {files_found_resuilts}")
Calculate accuracy and display only if it can match 89%
import face_recognition
import os
from PIL import Image, ImageDraw
import numpy as np
import math
# Extract faces in "face" directory
target_folder = "/mnt/c/Users/JMC/python/face/images"
# Get all files in "face" folder as list
unknown_faces = os.listdir(target_folder)
# Setup target image file
target_file = 'miggy.jpg'
target_image_to_search = face_recognition.load_image_file(f"{target_folder}/{target_file}")
target_image_encoding = face_recognition.face_encodings(target_image_to_search)
files_found_resuilts = []
def face_distance_to_conf(face_distance, face_match_threshold=0.5):
if face_distance > face_match_threshold:
range = (1.0 - face_match_threshold)
linear_val = (1.0 - face_distance) / (range * 2.0)
return linear_val
else:
range = face_match_threshold
linear_val = 1.0 - (face_distance / (range * 2.0))
return linear_val + ((1.0 - linear_val) * math.pow((linear_val - 0.5) * 2, 0.2))
for image in unknown_faces:
# Skipping target file to check face recognition
if image == target_file:
continue
# Load images from files
image_of_people = face_recognition.load_image_file(f"{target_folder}/{image}")
# Create a Pillow ImageDraw Draw instance to draw with
pil_image = Image.fromarray(image_of_people)
draw = ImageDraw.Draw(pil_image)
# face_location - check how many faces in an image.
face_locations = face_recognition.face_locations(image_of_people)
total_face = len(face_locations)
print(f"# Scanning face in: {image}..", end =" ")
print(f"Total face found {total_face}")
# Check if there's a face on this specific image file {image}
if face_recognition.face_encodings(image_of_people):
total_face_in_image = len(face_recognition.face_encodings(image_of_people))
face_locations1 = face_recognition.face_locations(image_of_people)
unknown_encoding = face_recognition.face_encodings(image_of_people)
# Setup list to append results (we use this for show image and rectagle box drawing)
itop = []
iright = []
ileft = []
ibottom = []
iaccuracy = []
#for face_encoding in unknown_encoding:
for (top, right, bottom, left), face_encoding in zip(face_locations1, unknown_encoding):
# Get compare match results (True or False) for each face encoding
results = face_recognition.compare_faces(face_encoding, target_image_encoding, tolerance=0.5)
if results[0]:
# Face distance to convert accuracy
face_distance = face_recognition.face_distance(face_encoding,target_image_encoding)
accuracy = face_distance_to_conf(face_distance)
# Only append and show image if accuracy is % and above
if float(accuracy) >= 0.88:
print(f"# We found the face of {target_file} in {image}")
percentage = "{:.0%}".format(float(accuracy)) # Convert to percentage
# Append things and face coordinates for drawing rectagles
files_found_resuilts.append(image)
itop.append(top)
iright.append(right)
ileft.append(left)
ibottom.append(bottom)
iaccuracy.append(percentage)
# Check if there's a face coordinate 'top'
if bool(len(itop)):
print(iaccuracy)
# Loop all face coordinates to draw a square. Ex. 1 image 10 faces, will check how many face that can match the image target
x = 0
while x < len(itop):
#Draw a box around the face using the Pillow module
draw.rectangle(((ileft[x], itop[x]), (iright[x], ibottom[x])), outline=(0, 0, 255))
# Draw a label with a name below the face
text_height = 11 # 11px text height for label
draw.rectangle(((ileft[x], ibottom[x] - text_height - 10), (iright[x], ibottom[x])), fill=(0, 0, 255), outline=(0, 0, 255))
#draw.text((ileft[x] + 6, ibottom[x] - text_height - 5), target_file, fill=(255, 255, 255, 255))
draw.text((ileft[x] + 6, ibottom[x] - text_height - 5), str(iaccuracy[x]), fill=(255, 255, 255, 255))
x += 1
# Display the resulting image
pil_image.show()
# Remove the drawing library from memory as per the Pillow docs
del draw
# List the files that the target image was found
if files_found_resuilts:
print(f"# List of files matched {target_file}: {files_found_resuilts}")
Converted to OOP
import face_recognition
import os
from PIL import Image, ImageDraw
import numpy as np
import math
class Face_detect:
"""
Face detection with target image file and directories to scan
"""
def __init__(self, target_file, target_file_dir, target_dir,tolerance_compare, tolerance_accuracy):
# Setup initial values
self.target_file = target_file
self.target_file_dir = target_file_dir
self.target_dir = target_dir
self.tolerance_compare = tolerance_compare
self.tolerance_accuracy = tolerance_accuracy
self.files_found_resuilts = []
def encode_target_file(self):
load_image = face_recognition.load_image_file(f"{self.target_file_dir}/{self.target_file}")
return face_recognition.face_encodings(load_image)
# This function gather all files from the target_dir and start the loop
def start_face_detect(self):
# Debug
print(f"# Searching {self.target_file} \n# in {self.target_dir} \n# using tolerance compare {self.tolerance_compare} and tolerance accuracy {self.tolerance_accuracy}...")
print("#")
# Get all files in targetr DIR
list_files = os.listdir(self.target_dir)
for file in list_files:
# Skipping target file to check face recognition
if file == self.target_file:
continue
# Calling function encoding_list_of_files that accepts: file, target_dir
self.encoding_list_of_files(file,self.target_dir)
print("#")
print('# Done!')
print(f"# List of files matched the face of {self.target_file}: {self.files_found_resuilts}")
# Encode all files from the target dir
def encoding_list_of_files(self,file,target_dir):
# Debug
print(f"# Start scanning faces in {file}...",end=" ")
# Start loading files..
loaded_files = face_recognition.load_image_file(f"{target_dir}/{file}")
# Check if face exist on this given file
face_locations = face_recognition.face_locations(loaded_files)
total_face = len(face_locations)
# Debug
print(f"Total face found {total_face}")
# Only encode files that has faces
if total_face:
self.encode_faces(file,loaded_files,face_locations)
# Start comparing faces of target_file to list of given files
def encode_faces(self,file,loaded_files,face_locations):
# Debug
# print(f"## Total face of {file}: {len(face_locations)} to encode. Starting face_recognition.face_encodings: {file}..")
# Encoded faces we can loop. Each face has its own encodings
encoded_faces = face_recognition.face_encodings(loaded_files)
for face_number, (top, right, bottom, left), face_encoding in zip(range(len(face_locations)),face_locations, encoded_faces):
self.compare_encoded(face_number,file,top,right,bottom,left,face_encoding,loaded_files)
# Function to compare encoded files from target_file encoded and faces from the file list
def compare_encoded(self,face_number,file,top,right,bottom,left,face_encoding,loaded_files):
# Setup list to append results (we use this for show image and rectagle box drawing)
self.itop = []
self.iright = []
self.ileft = []
self.ibottom = []
self.iaccuracy = []
# Start comparing faces
compare_result = face_recognition.compare_faces(face_encoding, self.encode_target_file(), tolerance=self.tolerance_compare)
# Here we only show with True results (face matched)
if compare_result[0]:
# Check accuracy for the face matched.
face_distance = face_recognition.face_distance(face_encoding,self.encode_target_file())
accuracy = self.face_distance_to_conf(face_distance, self.tolerance_accuracy)
percentage = "{:.0%}".format(float(accuracy)) # Convert to percentage
# Debug
print(f"# !!! Face matched in face # {face_number}: with {percentage} accuracy!")
# Now we found the matched faces, we'll start the rectangle drawings to mark those matched faces.
# Append things and face coordinates for drawing rectagles
self.files_found_resuilts.append(file)
self.itop.append(top)
self.iright.append(right)
self.ileft.append(left)
self.ibottom.append(bottom)
self.iaccuracy.append(percentage)
# Call the rectangle drawing function where face is matched
self.start_drawing(loaded_files)
def start_drawing(self,loaded_files):
# Create a Pillow ImageDraw Draw instance to draw with
pil_image = Image.fromarray(loaded_files)
draw = ImageDraw.Draw(pil_image)
if bool(len(self.itop)):
# Loop all face coordinates to draw a square. Ex. 1 image 10 faces, will check how many face that can match the image target
x = 0
while x < len(self.itop):
#Draw a box around the face using the Pillow module
draw.rectangle(((self.ileft[x], self.itop[x]), (self.iright[x], self.ibottom[x])), outline=(0, 0, 255))
# Draw a label with a name below the face
text_height = 11 # 11px text height for label
draw.rectangle(((self.ileft[x], self.ibottom[x] - text_height - 10), (self.iright[x], self.ibottom[x])), fill=(0, 0, 255), outline=(0, 0, 255))
#draw.text((ileft[x] + 6, ibottom[x] - text_height - 5), target_file, fill=(255, 255, 255, 255))
draw.text((self.ileft[x] + 6, self.ibottom[x] - text_height - 5), str(self.iaccuracy[x]), fill=(255, 255, 255, 255))
x += 1
# Display the resulting image
pil_image.show()
# Calculate accuracy from facedistance results (face distance of target face and other faces)
def face_distance_to_conf(self,face_distance,face_match_threshold):
if face_distance > face_match_threshold:
range = (1.0 - face_match_threshold)
linear_val = (1.0 - face_distance) / (range * 2.0)
return linear_val
else:
range = face_match_threshold
linear_val = 1.0 - (face_distance / (range * 2.0))
return linear_val + ((1.0 - linear_val) * math.pow((linear_val - 0.5) * 2, 0.2))
# Enter your target file (the face you want to scan to the target directory)
# Enter your target folder (the dir where it scans all files based on your target file)
# Tolerance for compare
# Tolerance for accuracy
target_file = 'elon.jpg'
target_file_dir = '/mnt/c/Users/JMC/python/face/images'
target_dir = '/mnt/c/Users/JMC/python/face/images'
tolerance_compare = 0.5
tolerance_accuracy = 0.5
source_and_target_dir = Face_detect(target_file,target_file_dir,target_dir,tolerance_compare,tolerance_accuracy)
source_and_target_dir.start_face_detect()