Introduction
Detecting a face in digital image is simply a way to find pixels location containing face pattern in it. Examples of this application resides in our smart-phone camera that has an ability to detect face in captured frame, security system that many applied in CCTV (Closed Circuit Television) system, and Marketing field (but this is still rarely found). One thing needed to remember is that the term of ‘face detection’ is different from ‘face recognition’ that the latter means a system can identify ‘whose’ person of any face detected, while the former means a system just ‘point out’ a face in an image – without knowing ‘who’ is he or she’. For this post, C++ programming language will be used to detect a face in an image.

see post equivalent in python programming language:


Prerequisites
In this post, bellow prerequisites are assumed have been installed on your system
  • OpenCV 4.1.1 library or latter
  • C++ compiler and Cmake
  • Your favorite text editor

Codes
Before going into the code, we need to prepare these files first:
lena.jpg (the image that we use to test), and
haarcascade_frontalface_alt.xml (the trained classifier for detection ‘utility’)
The two files mention above has been there in OpenCV directory you installed, just find them on your OpenCV installation directory. In my computer the xml file is in installation/OpenCV-4.1/share/opencv4/haarcascades, and for the image you can save the lena.jpg image from this post (in figure 1).
Figure 1. Our image lena.jpg (source: OpenCV org)


Headers and Namespaces
So the first thing to do in C++ code is to ‘include’ the directory where any function we use refers
#include <opencv4/opencv2/highgui.hpp>
#include <opencv4/opencv2/imgproc.hpp>
#include <opencv4/opencv2/objdetect.hpp>
#include <iostream>
using namespace std;
using namespace cv;

The two namespaces cv and std are deliberately declared global since the size of our code that is short enough to fit on a pc screen. Bellow lines are some functions that we are going to use referring to our header above:
...highgui.hpp:
namedWindow()
imread()
imshow()
...imgproc.hpp:
cvtColor()
equalizedHist():
rectangle()
and other classes and member functions reside in objdetect.hpp file.


Within main() function
The first thing to do is to give our window a name and read an image (lena.jpg)
   namedWindow("face_detect");
   Mat im = imread("../lena.jpg");
   
   vector<Rect> faces;
   Mat frame_gray;
   cvtColor(im,frame_gray,COLOR_BGR2GRAY);
   equalizeHist(frame_gray,frame_gray);

The image that we give to CascadeClassifier instances latter need to be in gray-scale mode. This is achieved by cvtColor() function above -The first and the second argument are for input and output image respectively, while the last argument is color space conversion code flag.
To be well detected, equalizeHist() function is usually used to equalize the histogram for the frame / image given, decreasing ‘dark’ pixels value to balance all other pixels, or simply to brighten a dark image.
The image file ‘../lena.jpg’ - the ‘../’ indicates that our image that is going to be compiled is outside of our buid directory.


Find Face Location
This is where a face location in an image is found. In other words the face detection process happens in these lines of code bellow:
   CascadeClassifier face_cascade;
   if( !face_cascade.load("../haarcascade_frontalface_alt.xml") )
   {
      cout<<"--(!)Error loading face cascade\n"; 
      return -1; 
   }
   face_cascade.detectMultiScale(frame_gray,faces);

The first thing we need to do, is to make an instance of CascadeClassifier class, then continued to load our haarcascade_frontalface_alt.xml file using load() method of the instance. The following code is to check whether the file we load exists or not, the load() method will be false if the file exists or true otherwise.

The next line is where face detection happens by using detectMultiscale() method of the instance. According to OpenCV reference manual, it states that the method detects object of different size in the input image and the detected object are returned as a list of rectangles.
For the first and the second argument of this methods are input and output images respectively. Note that the output is in form of a list of rectangle that we need to declare ‘face’ variable as vector<Rect> above.


Signifying Face Detected
So far, we have detected the face object or the location of the pixel has been found. Therefore it will be meaningless if the frame which will be shown doesn’t give any information about where the pixel (or face location) is in the image. The bellow code will give a red line rectangle that surrounds our lena.jpg face image, and then showing the image with a face detected on computer screen.
   for(size_t i = 0; i < faces.size(); i++ )
      rectangle(im,faces[i],Scalar(0,0,255),2);

   imshow("face_detect",im);
   while(static_cast<unsigned char>(waitKey(0)) != 'q');

the for() loop expression above just counts and processes how many face of the image detected. The face.size() return value is in form of unsigned integer that indicates the number of face detected on the image. Within the for() loop statement, we use rectangle() function to draw a red rectangle of our face-detected image. The first and the second arguments are for input and output image respectively; the face[i] just states which face is going to draw in the container (vector<Rect>) index, because in this case we just have a single face in the image, the for() loop just steps once, i.e., facep[0]. And the last two arguments are for color of the rectangle line and the ‘thickness’ of the line respectively. For the Scalar(0,0,255) will cause our rectangle color red, because the it is in BGR format. You can try to experiment with other values with this function.
And for the last following two lines are to show the image on our computer screen and wait a ‘q’ key to be pressed (to terminate the program) respectively.

When the code is run, the output will be like on the figure 2.
Figure 2. Face detected surrounded by a red line (rectangle)

For the complete code and cmake file, find it here:


Conclusion
Detecting a face in an image is relatively easy to do especially for a beginner who just start to learn. Since almost all necessary functions/methods and “stuffs” has been prepared by OpenCV library, like one we use haarcascade_frontalface_alt.xml file and some methods and classes that support it. There are also so many trained cascade file that you can find out there, like on github, such as banana, dog, cat many other else trained files detector. Just have fun with it.