Face recognition is one of the many wonders that AI research has brought to the world. This is a topic of great curiosity for many techies – they want a basic understanding of how things work. Let’s dive in and see how things work.

Face recognition

When solving problems like this, it’s best not to reinvent the wheel – we can’t! It’s best to follow the model the researchers have given us. There are also many tools available in open source. One such Python library is face_recognition. It works in several steps:

  • Recognize faces in a given image
  • Recognizing facial features
  • Generate 128 values of face coding vector

Based on this code, we can measure the similarity between images of two faces – which can tell us if they belong to the same person.

First, install the face_recognition module

pip install face_recognition
Copy the code

The import module

Next, we import the required modules

import PIL.Image
import PIL.ImageDraw
import requests
from io import BytesIO

from IPython.display import display

import face_recognition
Copy the code

Load the picture

Next, we load the image. I have stored the image in my Github account. So we can read the original image from the URL.

response = requests.get("https://raw.githubusercontent.com/solegaonkar/solegaonkar.github.io/master/img/rahul1.jpeg")
fr_image = face_recognition.load_image_file(BytesIO(response.content))
Copy the code

Recognizing faces

With the face loaded, let’s take a look at the various parts of the face_recognition module. How does it recognize faces?

face_locations = face_recognition.face_locations(fr_image)

number_of_faces = len(face_locations)
print("I found {} face(s) in this photograph.".format(number_of_faces))
Copy the code

This gives us an output:

I found 1 face(s) **in** this photograph.</span>
Copy the code

This means that the algorithm found only one face in the image. Let’s look at the images and faces we’ve identified.

pil_image = PIL.Image.fromarray(fr_image)

for face_location in face_locations:
    # Print the location of each face in this image. Each face is a list of co-ordinates in (top, right, bottom, left) order.
    top, right, bottom, left = face_location
    print("A face is located at pixel location Top: {}, Left: {}, Bottom: {}, Right: {}".format(top, left, bottom, right))
    # Let's draw a box around the face
    draw = PIL.ImageDraw.Draw(pil_image)
    draw.rectangle([left, top, right, bottom], outline="black")
Copy the code

That gives us an output

A face **is** located at pixel location Top: 68, Left: 117, Bottom: 291, Right: 340</span>
Copy the code

The above code also modifies the image to draw a rectangle around the face. Let’s check that it works.

That’s enough

If you’re having trouble learning Python and you’re looking for a python environment, you can join us in PythonThe skirt, pay attention to xiaobian, and private “01” can enter the skirt, receive Python learning materials, will save a lot of time, reduce a lot of problems encountered.

Face encoding

This is our face. However, for our algorithm, it’s just an array of RGB values — matching patterns learned from the data samples we gave it.

For face recognition, the algorithm records certain important measurements of the face, such as the color and size and tilt of the eyes, and the gap between the eyebrows. All of this together defines the facial encoding – the information taken from the image – used to identify a particular face.

To understand what is being read from the face, let’s look at the code being read.

face_encodings = face_recognition.face_encodings(fr_image)
face_encodings[0]
Copy the code

Print out a huge array:

Array ([-0.10213576, 0.05088161, -0.03425048, -0.09622347, -0.12966095, 0.04867411, -0.00511892, -0.03418527, 0.2254715, -0.07892745, 0.21497472, -0.0245543, -0.2127848, -0.08542262, -0.00298059, 0.13224372, -0.21870363, -0.09271716, -0.03727289, -0.1250658, 0.09436664, 0.03037129, -0.02634972, 0.02594662, -0.1627259, -0.29416466, -0.12254384, -0.15237436, 0.14907973, -0.09940194, 0.02000656, 0.04662619, -0.1266906, -0.11484023, 0.04613583, 0.1228286, -0.03202137, -0.0715076, 0.18478717, -0.01387333, -0.11409076, 0.07516225, 0.08549548, 0.31538364, 0.1297821, 0.04055009, 0.0346106, -0.04874525, 0.17533901, -0.22634712, 0.14879328, 0.09331974, 0.17943285, 0.02707857, 0.22914577, -0.20668915, 0.03964197, 0.17524502, -0.20210043, 0.07155308, 0.04467429, 0.02973968, 0.00257265, -0.00049853, 0.18866715, 0.08767469, -0.06483966, -0.13107982, 0.21610288, -0.04506358, -0.02243116, 0.05963502, -0.14988004, -0.11296406, -0.30011353, 0.07316103, 0.38660526, 0.07268623, -0.14636359, 0.08436179, 0.01005938, -0.00661338, 0.09306039, 0.03271955, -0.11528577, -0.0524189, -0.11697718, 0.07356471, 0.10350288, -0.03610475, 0.00390615, 0.17884226, 0.04291092, -0.02914601, 0.06112404, 0.05315027, -0.14561613, -0.01887275, -0.13125736, -0.0362937, 0.16490118, -0.09027836, -0.00981111, 0.1363602, -0.23134531, 0.0788044, -0.00604869, -0.05569676, -0.07010217, -0.0408107, -0.10358225, 0.08519378, 0.16833456, -0.30366772, 0.17561394, 0.14421709, -0.05016343, 0.13464174, 0.0646335, -0.0262765, 0.02722404, -0.06028951, -0.19448066, -0.07304715, 0.0204969, 0.03045784, 0.02818791, 0.06679841])Copy the code

Each of these numbers represents the orthogonal component of the face code.

similar

Now let’s look at the next step – identifying similarities between faces. To do this, we need to load more images.

Let’s start by loading three images. When loading the image, we also find the face first, and then find the face code.

response = requests.get("https://raw.githubusercontent.com/solegaonkar/solegaonkar.github.io/master/img/rahul1.jpeg")
image_of_person_1 = face_recognition.load_image_file(BytesIO(response.content))
face_locations = face_recognition.face_locations(image_of_person_1)
person_1_face_encoding = face_recognition.face_encodings(image_of_person_1, known_face_locations=face_locations)

response = requests.get("https://raw.githubusercontent.com/solegaonkar/solegaonkar.github.io/master/img/rahul2.jpg")
image_of_person_2 = face_recognition.load_image_file(BytesIO(response.content))
face_locations = face_recognition.face_locations(image_of_person_2)
person_2_face_encoding = face_recognition.face_encodings(image_of_person_2, known_face_locations=face_locations)

response = requests.get("https://raw.githubusercontent.com/solegaonkar/solegaonkar.github.io/master/img/trump.jpg")
image_of_person_3 = face_recognition.load_image_file(BytesIO(response.content))
face_locations = face_recognition.face_locations(image_of_person_3)
person_3_face_encoding = face_recognition.face_encodings(image_of_person_3, known_face_locations=face_locations)
Copy the code

Now, it’s not difficult to identify the similarities. The face_recognition module provides a simple API.

face_recognition.compare_faces([person_1_face_encoding,person_3_face_encoding], person_2_face_encoding[0], How = 0.08)Copy the code

This method checks each component of the two faces to be compared and tells us whether the current component is changing within the tolerance range. The command above displays the following output:

[array([ True,  True,  True,  True,  True,  True,  True,  True,  True,
         True,  True,  True,  True,  True,  True,  True,  True,  True,
         True,  True,  True,  True,  True,  True,  True,  True,  True,
         True,  True,  True,  True,  True,  True,  True,  True,  True,
         True,  True,  True,  True, False,  True,  True,  True,  True,
         True,  True,  True,  True,  True,  True,  True,  True, False,
         True,  True,  True,  True,  True,  True,  True,  True,  True,
         True,  True,  True,  True,  True, False,  True,  True,  True,
         True,  True,  True,  True,  True,  True,  True,  True, False,
         True,  True,  True,  True,  True,  True,  True,  True,  True,
         True,  True,  True, False,  True,  True,  True,  True,  True,
         True,  True,  True,  True,  True,  True,  True,  True,  True,
         True,  True,  True,  True,  True,  True,  True,  True,  True,
         True,  True,  True,  True,  True,  True,  True,  True, False,
         True,  True]),
 array([ True,  True,  True,  True,  True,  True, False, False, False,
         True,  True,  True, False,  True,  True,  True, False,  True,
        False,  True,  True,  True,  True, False,  True,  True,  True,
        False,  True,  True,  True, False,  True,  True,  True,  True,
         True,  True,  True,  True, False,  True, False,  True,  True,
         True,  True,  True, False,  True, False,  True,  True,  True,
        False, False,  True,  True,  True,  True,  True, False,  True,
        False, False, False, False,  True, False,  True, False,  True,
        False,  True,  True,  True,  True, False,  True,  True,  True,
         True,  True,  True, False,  True,  True,  True, False,  True,
         True, False,  True,  True,  True,  True,  True,  True,  True,
         True,  True,  True,  True,  True, False, False,  True,  True,
        False, False, False,  True,  True, False,  True,  True,  True,
         True,  True,  True,  True,  True,  True, False, False,  True,
         True,  True])]
Copy the code

These two arrays represent the similarity between the given image (in the second argument) and each known face encoding in the supplied list (in the first argument).

We can see that the first array shows more similarity. The person can be correctly identified.

Digital makeup

If you like fun, we can do a lot more with our facial recognition library. We have an API that helps us identify individual features of the face.

face_landmarks_list = face_recognition.face_landmarks(fr_image)
print(face_landmarks_list)
Copy the code

This gives us a long list of each individual characteristic curve.

[{ 'chin': [(46, 47), 45, 54), (44, 62), a (44, 69), a (44, 77), (46, 84), (49, 91), (54, 95), (61, 97), (68, 97), (76, 95), (84, 91), (90, 87), (94, 81), (97, 75), (99, 68), (101, 60)], 'left_eyebrow': [(51, 42), (54, 39), (58, 39), (63, 40), (67, 42)], 'right_eyebrow': [(75, 44), (80, 44), (86, 44), (90, 47), (93, 51)], 'nose_bridge': [(70, 48), (68, 52), (67, 56), (66, 60)], 'nose_tip': [(60, 64), (62, 65), (65, 67), (68, 66), (71, 66)], 'left_eye': [(55, 47), (57, 45), (61, 46), (63, 48), (60, 48), (57, 48)], 'right_eye': [(77, 51), (80, 50), (84, 51), (86, 54), (83, 54), (79, 53)], 'top_lip': [(54, 75), (58, 72), (61, 72), (64, 73), (66, 73), (70, 75), (73, 80), (71, 79), (66, 75), (63, 75), (61, 74), (56, 75)], 'bottom_lip': [(73, 80), (68, 81), (64, 81), (62, 80), (60, 80), (57, 78), (54, 75), (56, 75), (60, 77), (63, 78), (65, 78), (71, 79)]}]Copy the code

We can apply digital makeup to this image.

for face_landmarks in face_landmarks_list:
    pil_image = PIL.Image.fromarray(fr_image)
    d = PIL.ImageDraw.Draw(pil_image, 'RGBA')

    # Make the eyebrows into a nightmare
    d.line(face_landmarks['left_eyebrow'], fill=(0, 0, 0, 255), width=3)
    d.line(face_landmarks['right_eyebrow'], fill=(0, 0, 0, 255), width=3)
    d.polygon(face_landmarks['left_eyebrow'], fill=(0, 0, 0, 255))
    d.polygon(face_landmarks['right_eyebrow'], fill=(0, 0, 0, 255))

    # Gloss the lips
    d.line(face_landmarks['top_lip'], fill=(0, 0, 0, 255), width=10)
    d.line(face_landmarks['bottom_lip'], fill=(0, 0, 0, 255), width=10)

    d.polygon(face_landmarks['bottom_lip'], fill=(255, 0, 0, 255))
    d.polygon(face_landmarks['top_lip'], fill=(255, 0, 0, 255))
    d.line(face_landmarks['top_lip'], fill=(0, 0, 0, 255), width=2)
    d.line(face_landmarks['bottom_lip'], fill=(0, 0, 0, 255), width=2)

    # Chin
    d.polygon(face_landmarks['chin'], fill=(255, 0, 0, 16))

    # Apply some eyeliner
    d.line(face_landmarks['left_eye'] + [face_landmarks['left_eye'][0]], fill=(10, 0, 0, 255), width=6)
    d.line(face_landmarks['right_eye'] + [face_landmarks['right_eye'][0]], fill=(10, 0, 0, 255), width=6)

    # Sparkle the eyes
    d.polygon(face_landmarks['left_eye'], fill=(255, 0, 0, 200))
    d.polygon(face_landmarks['right_eye'], fill=(255, 0, 0, 200))

    display(pil_image)
Copy the code

Here’s what we got.

That’s it for today. If you’re interested in Python, please join us.Python Learning communicationSkirt 】, receive free learning materials and source code.