Face Recognition with OpenCV

OpenCV is one of the most popular computer vision libraries that are often used for image analysis and machine learning. It is a very easy to use library that provides not only basic image transformation, but also image filtering, face recognition, object recognition, object tracking, and other functions that are often used in practice. It is a library that I always use when I work with image recognition in practice.

In this article, we will try to detect faces, which is a standard feature of OpenCV.

github

  • The file in jupyter notebook format is here

google colaboratory

  • To run it in google colaboratory here face_nb.ipynb)

environment

The author’s OS is macOS, and the options are different from Linux and Unix commands.

My environment

! sw_vers
ProductName: Mac OS X
ProductVersion: 10.14.6
BuildVersion: 18G95
Python -V
Python 3.8.5
import cv2

print('opencv version :', cv2.__version__)
opencv version : 4.4.0

We will also import matplotlib for image display. We will save the images as svg for better web appearance.

%matplotlib inline
%config InlineBackend.figure_format = 'svg'

import matplotlib.pyplot as plt
Matplotlib is building the font cache; this may take a moment.

Let’s say you have a file called lena.jpg in the upper level.

%%bash

ls -a ... / | grep jpg
binary_out.jpg
bitwise_out.jpg
gray_out.jpg
lena.jpg
lena_out.jpg
rotation.jpg
rotation_scale_1_angle_-30.jpg
rotation_scale_1_angle_-30.jpg
rotation_scale_2_angle_-30.jpg
rotation_scale_2_angle_-30.jpg
filename = '. /lena.jpg'.

Loading an image

Let’s load an image and display it, using matplotlib to display it in jupyter notebook.

img = cv2.imread(filename=filename)

# In OpenCV, the image is loaded in GBR preparation, but in JupyterNotebook, it is displayed in RGB.
rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

plt.imshow(rgb_img)
plt.show()
# Create a grayscale image for later use
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

Get Image Information

Check the height, width and number of colors (usually 3 for RGB) of the image if it is color.

def get_image_info(img):
  if len(img.shape) == 3:
    img_height, img_width, img_channels = img.shape[:3].
    print('img_channels :', img_channels)
  else:
    img_height, img_width = img.shape[:2].

  print('img_height :', img_height)
  print('img_width :', img_width)

get_image_info(img=img)
img_channels : 3
img_height : 225
img_width : 225

Face recognition

To detect a human face in OpenCV, load the face recognition model file “haircascade_frontalface_alt.xml”, OpenCV has models for nose and mouth recognition as well.

cascade_file = "haircascade_frontalface_alt.xml"
cascade = cv2.CascadeClassifier(cascade_file)

gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
face_list = cascade.detectMultiScale(gray_img, minSize=(50, 50))

# Mark the detected faces.
for (x, y, w, h) in face_list:
  color = (0, 0, 225)
  pen_w = 3
  cv2.rectangle(img, (x, y), (x + w, y + h), color, thickness = pen_w)

plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.show()

Facial Feature Extraction (dlib)

You can also use dlib, a library for facial feature extraction, to capture facial features. dlib’s shape_predictor will load a 68-point model of the face. There is no OpenCV for this.

The following code is adapted from Chapter 9, “10 Knocks on Image Processing to Understand Potential Customers,” in “100 Knocks on Python Data Analysis” (https://www.amazon.co.jp/dp/B07ZSGSN9S/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1) . The following code is based on Chapter 9, “10 Knocks on Image Processing to Understand Potential Customers” in 100 Knocks on Python Data Analysis . This book is very useful because it covers a wide range of skills required for data analysis.

import dlib
import math

predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
detector = dlib.get_frontal_face_detector()
dets = detector(img, 1)

for k, d in enumerate(dets):
  shape = predictor(img, d)

  # Display the face area
  color_f = (0, 0, 225)
  color_l_out = (255, 0, 0)
  color_l_in = (0, 255, 0)
  line_w = 3
  circle_r = 3
  fontType = cv2.FONT_HERSHEY_SIMPLEX
  fontSize = 1
  cv2.rectangle(img, (d.left(), d.top()), (d.right(), d.bottom()), color_f, line_w)
  cv2.putText(img, str(k), (d.left(), d.top()), fontType, fontSize, color_f, line_w)

  num_of_points_out = 17
  num_of_points_in = shape.num_parts - num_of_points_out
  gx_out = 0
  gy_out = 0
  gx_in = 0
  gy_in = 0

  for shape_point_count in range(shape.num_parts):
    shape_point = shape.part(shape_point_count)

    #draw each organ
    if shape_point_count<num_of_points_out:
      cv2.circle(img,(shape_point.x, shape_point.y),circle_r,color_l_out, line_w)
      gx_out = gx_out + shape_point.x/num_of_points_out
      gy_out = gy_out + shape_point.y/num_of_points_out
    else:
      cv2.circle(img,(shape_point.x, shape_point.y),circle_r,color_l_in, line_w)
      gx_in = gx_in + shape_point.x/num_of_points_in
      gy_in = gy_in + shape_point.y/num_of_points_in

  # Draw the center of gravity position
  cv2.circle(img,(int(gx_out), int(gy_out)),circle_r,(0,0,255), line_w)
  cv2.circle(img,(int(gx_in), int(gy_in)),circle_r,(0,0,0), line_w)

  # Calculate the orientation of the face
  theta = math.asin(2*(gx_in-gx_out)/(d.right()-d.left()))
  radian = theta*180/math.pi
  print("Face orientation:{} (angle:{} degrees)".format(theta,radian))

  # print the face orientation
  if radian<0:
    textPrefix = " left "
  else:
    textPrefix = " right "
  textShow = textPrefix + str(round(abs(radian),1)) + " deg."
  cv2.putText(img, textShow, (d.left(), d.top()), fontType, fontSize, color_f, line_w)
Face orientation: 0.30603061652114893 (Angle: 17.534262728448397 degrees)

We now know that lena is facing the right direction. The angle is also computed.

plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.show()

Conclusion

OpenCV is a very easy to use image analysis library. Recently, deep learning recognition has become popular, but considering the contrast with the cost, OpenCV is often sufficient. When I am asked if I can improve the accuracy of image analysis by using deep learning, I make a proposal while thinking whether it is really necessary to use deep learning or not, and whether there is a less expensive way to satisfy the customer.

If we can get enough accuracy using the various modules of OpenCV, we often find that we do not need the relatively high cost of deep learning.