A Simple Guide on Face and Eye detection using Python OpenCV

Introduction:

I have not yet worked with images and I had to give it a try. But where to begin? I started looking for Data. Of course, I checked Kaggle and downloaded some image data files. Then, I stared blankly at those images for some time with zero ideas about what to do. Finally, I decided to start with something simple and fun! So, this post is all about face and eye detection using Python OpenCV.

Applications:

I use a few mobile apps which work with images and do some amazing things.

Well, there is a couple of Plants Identifying apps that help to identify a plant and then recommend the care for those plants. I do love plants. But, I have a very bad reputation with them. I even killed a cactus. Now, don’t judge me, please!

I saw an app called “Planta: Keep your plants alive“. Yes, that tagline caught my attention. I am still fighting with the plants’ care, but that’s a story for another day. This app has a Plant identification feature which is very useful.

Another app that I use and that work with images is YouCam Makeup-Magic Selfie Cam. Yes, You guessed it right! It’s an app that will take a picture of lazy me and put some makeup to make it ready to upload in social media. During this lockdown, with my girl talking non-stop and asking me some weird questions continuously, who has time to dress up? This app is really fun! It will also do some live makeup which is using some cool machine learning tricks on images.

So, yes, this YouCam makeup app inspired me to do something similar today. In this post, I will start with a simple exercise. I will take an image of mine and detect the face and the eyes. Sound simple, right? Let’s make it simpler. I will divide this small project into smaller steps and analyzing each step.

Let’s get started with the exercise!

1. Install Libraries:

I will use the opencv-python package in this project. So first, let’s install that one. I specifically supplied the version since I was reading somewhere that the 4.x versions lack some functionalities. I need to check this!

pip install opencv-python

2. Select an Image

Now, we need a couple of images for this exercise. I didn’t want to spend some time on finding royalty-free images. That’s why, at first, I am using my own image in portrait mode to track my eyes. Cool?

Let’s do some coding!

3. Import Libraries

First, we will import all the required libraries.

import cv2
import numpy
from matplotlib import pyplot as plt

4. Read Image

Now, we will copy the image in the working directory and will read and display the image.

img = cv2.imread("IMG_2315.jpg")
plt.imshow(img)
plt.title('Thats Me!')
plt.show()
That’s Me!

5. Convert to GrayScale

There is a method called cvtColor() in OpenCV that converts an image from one color space to another. So, let’s gray it out!

gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imwrite('outputs/gray_img_2315.jpg', gray_img)
plt.imshow(gray_img)
plt.title('Thats Gray Me!')
plt.show()
That’s GRAY Me!

Detect the Face

Now, to detect face or eyes, we need classifiers. For example, the Face Classifier will classify a Face and Not-A-Face. For classifying face and eyes, we can use the Face Detection Classifier(Haar Cascades) that comes with OpenCV.

face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
faces = face_cascade.detectMultiScale(gray_img, scaleFactor=1.3, minNeighbors=5, minSize=(30, 30),
flags=cv2.CASCADE_SCALE_IMAGE)
faces
Error:

I got an error like below after writing the above piece of code.

Actually, we need to put the file “haarcascade_frontalface_default.xml” in the working directory or you can pass the file path before the name. I searched for the file on my computer and copied and put it in the same folder. Or, you can simply download the file directly from the Github Repository. Once the file is copied to my working directory, the above issue is resolved.

detectMultiScale” detects objects of different sizes in the input image. The detected objects are returned as a list of rectangles. Now, in this example, I am using only one face image and thus one rectangle should be returned.

Parameters for the method detectMultiScale:
imageMatrix of the type CV_8U containing an image where objects are detected.
objectsVector of rectangles where each rectangle contains the detected object, the rectangles may be partially outside the original image.
scaleFactorParameter specifying how much the image size is reduced at each image scale.
minNeighborsParameter specifying how many neighbors each candidate rectangle should have to retain it.
flagsParameter with the same meaning for an old cascade as in the function cvHaarDetectObjects. It is not used for a new cascade.
minSizeMinimum possible object size. Objects smaller than that are ignored.
maxSizeMaximum possible object size. Objects larger than that are ignored. If maxSize == minSize model is evaluated on single scale.

If faces are found, it returns the positions of detected faces as Rect(x,y,w,h) , an array object like below:

array([[ 98, 603, 881, 881]], dtype=int32)

Here, I have a confession to make. In all the examples that I was checking on cascades, it was passing the gray image to the argument “image”. But, I tried both! I passed the gray image object and the original colored image object and I got the same result. I am still confused about why everyone is insisting on passing the gray image.

Draw a Rectangle along the face

In this step, we will draw a rectangle along the face.

for (x,y,w,h) in faces:
    rect_img = cv2.rectangle(img,(x,y),(x+w,y+h),(0, 255, 0),2)
    roi_color = img[y:y+h, x:x+w]

Here, we are drawing a rectangle along the face and then basically zoomed it to that measurement. That sounded a bit confusing, right? Now, let’s save the two images(rect_img and roi_color) and take a look.

cv2.imwrite('outputs/Mod_IMG_2315_1.jpg', rect_img)
cv2.imwrite('outputs/Mod_IMG_2315_2.jpg', roi_color)
Mod_IMG_2315_1.jpg
Mod_IMG_2315_2.jpg

Now, does the above line makes any sense?

Detect the Eyes

In this example, we have a single face and it’s quite simple. We will use the Zoomed image to detect eyes. And this time, I copied the “haarcascade_eye.xml” file beforehand in my working directory. And in the end, I am writing the modified image on my computer.

eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml')
eyes = eye_cascade.detectMultiScale(roi_color)

#Loop
for (ex,ey,ew,eh) in eyes:
    mod_img = cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)

#Write the image
cv2.imwrite('outputs/Mod_IMG_2315_3.jpg', mod_img)

Finally, let’s take a look!

Mod_IMG_2315_3.jpg

Hmm, it has detected a third eye! I always tell my daughter that I have a third eye. But I had never imagined that my dreams would come true like this!!! Jokes apart, there must be some fix for this problem!

Finally, I decided to write a function combining all the above code and thus pass different image file as an input and check what other issues do we get. So, here goes the function:

def detect_face_eyes(img, mod_name):
    import numpy as np
    import cv2

    face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') 
    eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml') 

    img = cv2.imread(img) 
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 

    faces = face_cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=5, minSize=(30, 30), flags=cv2.CASCADE_SCALE_IMAGE) 

    for (x,y,w,h) in faces: 
        new_img=cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2) 
        roi_gray = gray[y:y+h, x:x+w] 
        roi_color = new_img[y:y+h, x:x+w] 
        
        eyes = eye_cascade.detectMultiScale(roi_color) 
        for (ex,ey,ew,eh) in eyes: 
            final_img=cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2) 

    cv2.imwrite('outputs/'+mod_name, final_img)

Now since the function is ready, I would like to check the below scenarios:

  1. An image with One Face and with Glasses on
  2. Another image having multiple Faces
  3. And an image with no faces at all.

Oh No! it seems like the above function needs a lot of tuning. Faces and Eyes are detected everywhere!

So, let’s keep that part for my next post.

A Jupyter Notebook with all the code is available at my Github. Please take a look if any of the above piece of code is not working.

Also, I want to try the Face and Eye Detection on a Live Video. What about a smile detection? Well, so many things to explore!

Keep coding and continue having Fun!

Stay tuned for my next post. Thank You!

0

Leave a Reply

Your email address will not be published. Required fields are marked *