John Mark Causing

System Administrator | Hosting Support Engineer

Bacolod City, Philippines

+639393497018

John Mark Causing

System Administrator | Hosting Support Engineer

Bacolod City, Philippines

+639393497018

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()