[OpenCV] 臉部偵測 (Face Detection)

我的實作環境

  • 作業系統: Ubuntu 17.04
  • OpenCV 函式庫版本: Version 3.3
  • 程式語言: C++

在作業系統方面請不用擔心,因為 OpenCV 是一個跨平台的電腦視覺函式庫


臉部偵測 - Face Detection

來寫一個簡單的臉部偵測(Face Detection) 程式,使其將一張照片的人臉以及人眼圈出。

先建立檔案

先依序建立以下幾個檔案:

1
2
3
4
$ mkdir FaceID
$ cd FaceID
$ mkdir Picture Source
$ touch FaceDetection.cpp

此時 FaceID 資料夾內應該要有以下檔案

picture01


下載人臉以及人眼分類器

取得 Eyes Classifier

1
$ wget https://raw.githubusercontent.com/a1996850622/FaceDetection/master/Source/haarcascade_eye_tree_eyeglasses.xml

取得 Face Classifier

1
$ wget https://raw.githubusercontent.com/a1996850622/FaceDetection/master/Source/haarcascade_frontalface_default.xml

接著將取得的兩個 XML 檔放進 Source 資料夾

XML 是可自行定義各標籤名稱的標記式語言,透過透過標記式語言,電腦之間便可以傳輸各種資訊。所以當我們 Load 上面兩個 XML 進程式之後,便可以使用他們的演算法來找出人臉及眼睛。


開始撰寫臉部偵測

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/** FaceDetection.cpp **/
#include <opencv2/opencv.hpp>
#include <iostream>
#include <stdio.h>

using namespace std;
using namespace cv;

/** Print error message **/
void PANIC(char *msg);
#define PANIC(msg){perror(msg); exit(-1);}

/** Function for face detection **/
void DetectAndDraw(Mat frame);

/** Global variables **/
String face_cascade_name = "Source/haarcascade_frontalface_default.xml";
String eyes_cascade_name = "Source/haarcascade_eye_tree_eyeglasses.xml";
CascadeClassifier face_cascade; // Declare the face classifier
CascadeClassifier eyes_cascade; // Declare the eyes classifier
String window_name = "Face detection";

int main(int argc, char *argv[]){
/* Open the web camera */
VideoCapture capture = VideoCapture(0);
Mat frame, image;

/** Load cascade classifiers **/
if(!face_cascade.load(face_cascade_name))
PANIC("Error loading face cascade");
if(!eyes_cascade.load(eyes_cascade_name))
PANIC("Error loading eyes cascade");

/** After the camera is opened **/
if(capture.isOpened()){
cout<<"Face Detection Started..."<<endl;

for(;;){
/* Get image from camera */
capture>>frame;
if(frame.empty())
PANIC("Error capture frame");

/* Start the face detection function */
DetectAndDraw(frame);

/** If you press ESC, q, or Q , the process will end **/
char ch = (char)waitKey(10);
if(ch==27 || ch=='q' || ch=='Q')
break;
}
}
else
PANIC("Error open camera");

return 0;
}

void DetectAndDraw(Mat frame){
/* Declare vector for faces and eyes */
std::vector<Rect> faces, eyes;
Mat frame_gray, frame_resize;
int radius;

/* Convert to gray scale */
cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
//imshow("grayscale", frame_gray);

/* Resize the grayscale Image */
//resize(frame_gray, frame_resize, Size(), 1, 1, INTER_LINEAR);
//imshow("resize", frame_resize);

/* Histogram equalization */
equalizeHist(frame_gray, frame_gray);
//imshow("equalize", frame_gray);

/* Detect faces of different sizes using cascade classifier */
face_cascade.detectMultiScale(frame_gray, faces, 1.1, 5, CV_HAAR_SCALE_IMAGE, Size(30, 30));

/** Draw circles around the faces **/
for (size_t i = 0; i < faces.size(); i++)
{
Point center;

/* Draw rectangular on face */
rectangle(frame, faces[i], Scalar(255, 0, 0), 3, 8, 0);

Mat faceROI = frame_gray(faces[i]);

/* Detection of eyes int the input image */
eyes_cascade.detectMultiScale(faceROI, eyes, 1.1, 1, CV_HAAR_SCALE_IMAGE, Size(3, 3));

/** Draw circles around eyes **/
for (size_t j = 0; j < eyes.size(); j++)
{
center.x = cvRound((faces[i].x + eyes[j].x + eyes[j].width*0.5));
center.y = cvRound((faces[i].y + eyes[j].y + eyes[j].height*0.5));
radius = cvRound((eyes[j].width + eyes[j].height)*0.25);
circle(frame, center, radius, Scalar(0, 255, 0), 3, 8, 0);
}
}

// Show Processed Image with detected faces
imshow( "Face Detection", frame);
}


解釋臉部偵測程式

其實過程很簡單,大致是以下幾個步驟:

  • 將人臉及人眼分類器演算法的 XML 檔 Load 進來 (程式第28~32行)
  • 使用 cvtColor() 將影像轉成灰階(GaryScale),目的是減少運算量 (程式第66行)
  • 使用 resize() 更改影像大小比率,視情況而定,在這裡我們先不使用 (程式第70行)
  • 使用 equalizeHist() 將影像做直方圖等化,以增強對比度 (程式第74行)
  • 運用 XML 內的分類演算法來偵測出人臉和人眼 (程式第78行和91行)
  • 分別圈出人臉以及人眼 (程式第80~101行)
  • 完成臉部偵測


執行結果

picture02


Reference