Open In App

Face Alignment with OpenCV and Python

Improve
Improve
Like Article
Like
Save
Share
Report

Face Alignment is the technique in which the image of the person is rotated according to the angle of the eyes.  This technique is actually used as a part of the pipeline process in which facial detection is done using the image. This implementation of face alignment can be easily done with the help of python module cv2(computer vision). It has so many features included in it.

Suppose if the person’s eyes in the image are at an x angle (x!=180 degrees) with reference to the frame of the image then this technique will rotate the image according to the angle where the x angle will be equal to 180 degrees with reference to the image frame.

Original image and Referenced frame

Now the angle x can be easily calculated from the triangle formed by the eyes and the referenced frame using trigonometry. By applying the Euclidean distance we can get the value of the angle x.

                                                    cos(x) = (b2+ c2– a2 ) / (2bc)

Trigonometry for calculating the angle x

Steps required for Face Alignment

Step 1: First we need to detect the face in the image.

Python3




# Face detection function to
# detect the face and return images
def face_detection(img):
    faces = face_detector.detectMultiScale(img, 1.1, 4)
    if (len(faces) <= 0):
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        return img, img_gray
    else:
        X, Y, W, H = faces[0]
        img = img[int(Y):int(Y+H), int(X):int(X+W)]
        return img, cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)


Step 2: Then we need to find the largest pair of eyes in the referenced image.

Python3




# finding the largest pair of
# eyes in the image
if len(eyes) >= 2:
    eye = eyes[:, 2]
    container1 = []
    for i in range(0, len(eye)):
        container = (eye[i], i)
        container1.append(container)
    df = pd.DataFrame(container1, columns=[
                      "length", "idx"]).sort_values(by=['length'])
    eyes = eyes[df.idx.values[0:2]]


Step 3: Capturing the eyes.

Python3




# center of right eye
right_eye_center = (
    int(right_eye[0] + (right_eye[2]/2)),
  int(right_eye[1] + (right_eye[3]/2)))
right_eye_x = right_eye_center[0]
right_eye_y = right_eye_center[1]
cv2.circle(img, right_eye_center, 2, (255, 0, 0), 3)
 
# center of left eye
left_eye_center = (
    int(left_eye[0] + (left_eye[2] / 2)),
  int(left_eye[1] + (left_eye[3] / 2)))
left_eye_x = left_eye_center[0]
left_eye_y = left_eye_center[1]
cv2.circle(img, left_eye_center, 2, (255, 0, 0), 3)
 
# finding rotation direction
if left_eye_y > right_eye_y:
    print("Rotate image to clock direction")
    point_3rd = (right_eye_x, left_eye_y)
    direction = -1  # rotate image direction to clock
else:
    print("Rotate to inverse clock direction")
    point_3rd = (left_eye_x, right_eye_y)
    direction = 1  # rotate inverse direction of clock


Step 4: Using trigonometry to calculate the length of all the edges of the triangle formed.

Python3




# Calculate the length of all the edges
def trignometry_for_distance(a, b):
    return math.sqrt(((b[0] - a[0]) * (b[0] - a[0])) \
                     + ((b[1] - a[1]) * (b[1] - a[1])))


Step 5: Now we will calculate the angle x as discussed in the above example.

Python3




# calculating the angle between a, b, c
cv2.circle(img, point_3rd, 2, (255, 0, 0), 2)
a = trignometry_for_distance(left_eye_center, point_3rd)
b = trignometry_for_distance(right_eye_center, point_3rd)
c = trignometry_for_distance(right_eye_center, left_eye_center)
cos_a = (b*b + c*c - a*a)/(2*b*c)
angle = (np.arccos(cos_a) * 180) / math.pi


Step 6: Rotate the image according to the referenced frame of the image.

Python3




# rotate images
new_img = Image.fromarray(img_raw)
new_img = np.array(new_img.rotate(direction * angle))


Step 7: At last scale the image to see the face image.

Python3




# scale the image
test_set = ["pic.png"]
for i in test_set:
    alignedFace = Face_Alignment(i)
    pl.imshow(alignedFace[:, :, ::-1])
    pl.show()
    img, gray_img = face_detection(alignedFace)
    pl.imshow(img[:, :, ::-1])
    pl.show()


Below is the complete Implementation

Python3




# install and import above modules first
import os
import cv2
import math
import matplotlib.pyplot as pl
import pandas as pd
from PIL import Image
import numpy as np
 
# Detect face
def face_detection(img):
    faces = face_detector.detectMultiScale(img, 1.1, 4)
    if (len(faces) <= 0):
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        return img, img_gray
    else:
        X, Y, W, H = faces[0]
        img = img[int(Y):int(Y+H), int(X):int(X+W)]
        return img, cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
 
 
def trignometry_for_distance(a, b):
    return math.sqrt(((b[0] - a[0]) * (b[0] - a[0])) +\
                     ((b[1] - a[1]) * (b[1] - a[1])))
 
# Find eyes
def Face_Alignment(img_path):
    pl.imshow(cv2.imread(img_path)[:, :, ::-1])
    pl.show()
    img_raw = cv2.imread(img_path).copy()
    img, gray_img = face_detection(cv2.imread(img_path))
    eyes = eye_detector.detectMultiScale(gray_img)
 
    # for multiple people in an image find the largest
    # pair of eyes
    if len(eyes) >= 2:
        eye = eyes[:, 2]
        container1 = []
        for i in range(0, len(eye)):
            container = (eye[i], i)
            container1.append(container)
        df = pd.DataFrame(container1, columns=[
                          "length", "idx"]).sort_values(by=['length'])
        eyes = eyes[df.idx.values[0:2]]
 
        # deciding to choose left and right eye
        eye_1 = eyes[0]
        eye_2 = eyes[1]
        if eye_1[0] > eye_2[0]:
            left_eye = eye_2
            right_eye = eye_1
        else:
            left_eye = eye_1
            right_eye = eye_2
 
        # center of eyes
        # center of right eye
        right_eye_center = (
            int(right_eye[0] + (right_eye[2]/2)),
          int(right_eye[1] + (right_eye[3]/2)))
        right_eye_x = right_eye_center[0]
        right_eye_y = right_eye_center[1]
        cv2.circle(img, right_eye_center, 2, (255, 0, 0), 3)
 
        # center of left eye
        left_eye_center = (
            int(left_eye[0] + (left_eye[2] / 2)),
          int(left_eye[1] + (left_eye[3] / 2)))
        left_eye_x = left_eye_center[0]
        left_eye_y = left_eye_center[1]
        cv2.circle(img, left_eye_center, 2, (255, 0, 0), 3)
 
        # finding rotation direction
        if left_eye_y > right_eye_y:
            print("Rotate image to clock direction")
            point_3rd = (right_eye_x, left_eye_y)
            direction = -1  # rotate image direction to clock
        else:
            print("Rotate to inverse clock direction")
            point_3rd = (left_eye_x, right_eye_y)
            direction = 1  # rotate inverse direction of clock
 
        cv2.circle(img, point_3rd, 2, (255, 0, 0), 2)
        a = trignometry_for_distance(left_eye_center,
                                     point_3rd)
        b = trignometry_for_distance(right_eye_center,
                                     point_3rd)
        c = trignometry_for_distance(right_eye_center,
                                     left_eye_center)
        cos_a = (b*b + c*c - a*a)/(2*b*c)
        angle = (np.arccos(cos_a) * 180) / math.pi
 
        if direction == -1:
            angle = 90 - angle
        else:
            angle = -(90-angle)
 
        # rotate image
        new_img = Image.fromarray(img_raw)
        new_img = np.array(new_img.rotate(direction * angle))
 
    return new_img
 
 
opencv_home = cv2.__file__
folders = opencv_home.split(os.path.sep)[0:-1]
path = folders[0]
for folder in folders[1:]:
    path = path + "/" + folder
path_for_face = path+"/data/haarcascade_frontalface_default.xml"
path_for_eyes = path+"/data/haarcascade_eye.xml"
path_for_nose = path+"/data/haarcascade_mcs_nose.xml"
 
if os.path.isfile(path_for_face) != True:
    raise ValueError(
        "opencv is not installed pls install using pip install opencv ",
      detector_path, " violated.")
 
face_detector = cv2.CascadeClassifier(path_for_face)
eye_detector = cv2.CascadeClassifier(path_for_eyes)
nose_detector = cv2.CascadeClassifier(path_for_nose)
 
# Name of the image for face alignment if on
# the other folder kindly paste the name of
# the image with path included
test_set = ["pic.png"]
for i in test_set:
    alignedFace = Face_Alignment(i)
    pl.imshow(alignedFace[:, :, ::-1])
    pl.show()
    img, gray_img = face_detection(alignedFace)
    pl.imshow(img[:, :, ::-1])
    pl.show()


Output:

 



Last Updated : 22 Mar, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads