最先看到有人臉偵測的設備是什麼呢?當然是非「數位相機」莫屬啦~只要real-time找到人臉,接著加以追蹤,直到按下快門前,焦點都會在這個人臉上頭,如此一來就不太會發生失焦的狀況。
多媒體設計課程老師介紹一篇paper「Robust Real-Time Face Detection」,這是一篇2004年在IJCV上發表的論文,裡頭談到Haar-Features、Detection Framework、Integral Image、Feature Selection、Learning the Classifier、AdaBoost、Detection Procedure、Cascade Method。
Face Detection基本作法就是先做Feature Extraction,接著做Cascade Detection。特徵擷取(Feature Extraction)沒有問題,那麼瀑布偵測(Cascade Detection)是什麼呢?其實就只是一連串的檢查動作,通過第一關才能進入第二關,通過第二關才能進入地三關……直到通過最後一關,才會將此特徵辨識為人臉。

paper所使用的特徵型有四種,在偵測階段時,因為大部分的window沒有包含人臉,於是提早拒絕負面的window,來加快偵測速度。因為我們人臉不一定都是「正」的,有時候會坐著、躺著、手會支撐著臉、情人依偎等等,臉可能會有高達45度角的狀況,此時檢測視窗(如下圖的A、B、C、D特徵型態)就會改變角度來掃描搜索視窗(如下圖的正方形)。

搜尋了網路的這篇paper,竟然有2146次被引用的紀錄!我想偵測人臉是個非常實用的技術,在照相、攝影、監視器等各種追蹤人的設備上都相當需要,能想到這idea的作者真是厲害呢!
註:2012/11/20查詢google,該篇引用次數已達6260次!
首先來看一下程式碼:
/**
Theme: Face Detection
Compiler: Dev C++ 4.9.9.2
Date: 100/04/26
Author: ShengWen
Blog: https://cg2010studio.wordpress.com/
*/
#include "cv.h"
#include "cxcore.h"
#include "highgui.h"
#include <iostream>
using namespace std;
// the minimum object size
int min_face_height = 50;
int min_face_width = 50;
int main( int argc , char ** argv ){
string image_name="../image/XD2.jpg";
// Load image
IplImage* image_detect=cvLoadImage(image_name.c_str(), 1);
string cascade_name="../haarcascades/haarcascade_frontalface_default.xml";
// Load cascade
CvHaarClassifierCascade* classifier=(CvHaarClassifierCascade*)cvLoad(cascade_name.c_str(), 0, 0, 0);
if(!classifier){
cerr<<"ERROR: Could not load classifier cascade."<<endl;
return -1;
}
CvMemStorage* facesMemStorage=cvCreateMemStorage(0);
IplImage* tempFrame=cvCreateImage(cvSize(image_detect->width, image_detect->height), IPL_DEPTH_8U, image_detect->nChannels);
if(image_detect->origin==IPL_ORIGIN_TL){
cvCopy(image_detect, tempFrame, 0); }
else{
cvFlip(image_detect, tempFrame, 0); }
cvClearMemStorage(facesMemStorage);
CvSeq* faces=cvHaarDetectObjects(tempFrame, classifier, facesMemStorage, 1.1, 3
, CV_HAAR_DO_CANNY_PRUNING, cvSize(min_face_width, min_face_height));
if(faces){
for(int i=0; i<faces->total; ++i){
// Setup two points that define the extremes of the rectangle,
// then draw it to the image
CvPoint point1, point2;
CvRect* rectangle = (CvRect*)cvGetSeqElem(faces, i);
point1.x = rectangle->x;
point2.x = rectangle->x + rectangle->width;
point1.y = rectangle->y;
point2.y = rectangle->y + rectangle->height;
cvRectangle(tempFrame, point1, point2, CV_RGB(255,0,0), 3, 8, 0);
}
}
// Save the image to a file
cvSaveImage("../result/result.jpg", tempFrame);
// Show the result in the window
cvNamedWindow("Face Detection Result", 1);
cvShowImage("Face Detection Result", tempFrame);
cvWaitKey(0);
cvDestroyWindow("Face Detection Result");
// Clean up allocated OpenCV objects
cvReleaseMemStorage(&facesMemStorage);
cvReleaseImage(&tempFrame);
cvReleaseHaarClassifierCascade(&classifier);
cvReleaseImage(&image_detect);
return EXIT_SUCCESS;
}
cvHaarDetectObjects(const CvArr* image, CvHaarClassifierCascade* cascade,
CvMemStorage* storage, double scale_factor=1.1,
int min_neighbors=3, int flags=0,
CvSize min_size=cvSize(0,0) );
說明:
- image: 要偵測的圖片。
- cascade: 要使用的分類器。
- storage: 偵測到的物件所儲存的記憶體區塊。
- scale_factor: 搜索視窗成長比率。
- min_neighbors: 最少鄰近偵測視窗。一個臉可能重複偵測好幾次,但我們只要取一次,如果設0的話,所有偵測的視窗都會畫出來。
- flag: 演算法模式。
- min_size: 檢測視窗的最小尺寸。因為AdaBoost的演算法,分成搜索視窗和檢測視窗兩個部分,搜索視窗在整個影像中移動,檢測視窗在搜索視窗中移動並計算特徵值。當檢測視窗越小,則計算特徵值的單位就越小,需要的運算量就越高,但是結果不一定會更為精確。
在此需要特別注意的地方是路徑,接著就是classifier的選擇,我所使用的是OpenCV 2.0,訓練好的分類器放在C:\OpenCV2.0\data\haarcascades,這次人臉偵測實驗使用haarcascade_frontalface_default.xml,效果比較好的則是haarcascade_frontalface_alt.xml。其它的還有可以偵測眼睛、嘴巴、鼻子、上半身、下半身等等,但並不是所有分類器都能運作的相當好。這次實做相當好玩,有興趣的人趕快來玩玩看吧~
註:對於初學者來說,可以試著先安裝環境來跑程式,接著瞭解程式碼的意義喔!環境建置可以參考我這篇:Dev-C++4.9.9.2 安裝 OpenCV 2.0。
結論:Haar Features的效果非常好,然而在影像長寬不一樣(如上)時,會有不一樣的偵測結果,我想這跟我設定的偵測框架大小有關係,像素多的影像可以擷取較細節的特徵,而像素少的則相反,看來還是得根據需要來調整影像大小或偵測框架大小。因為影像有縮小,但依然可以看到,左邊也就是像素大的影像紅框比較細,而右邊則比較粗。
我將參數調整恰到好處:
- int min_face_height = 50;
- int min_face_width = 50;
- CvSeq* faces=cvHaarDetectObjects(tempFrame, classifier, facesMemStorage, 1.1, 3, CV_HAAR_DO_CANNY_PRUNING, cvSize(min_face_width, min_face_height));
參考:簡單的人臉偵測(face detection),使用HaarDetectObjects、cvHaarDetectObjects、Viola-Jones object detection framework、Face Detection (人臉偵測)。
推薦書籍:
- 博客來 – OpenCV with Microsoft Visual Studio影像辨識處理
- 博客來 – OpenCV圖像處理編程實例
- 博客來 – OpenCV3編程入門
- 博客來 – OpenCV程式設計參考手冊


Comments on: "[OpenCV] 人臉偵測 (Face Detection)" (70)
請問為什麼我compiler後什麼都沒有,「影像」和「訓練集」也直接放在程式碼檔哦同一資料夾,可是按下去甚麼也沒有…
讚讚
編譯成功之後會出現一個執行檔,
你可以用命令提示字元去執行它,
看它出現什麼錯誤訊息。
若照我所給的程式跑的話,是沒問題的才對~
讚讚
她好像顯示說遺失了libcv200.dll,我去載了之後換出現遺失libcxcore200,這個我就找不到了==
讚讚
我也有同樣問題耶請問怎麼解決?
讚讚
到SDK資料夾去找囉~然後放到執行檔同目錄底下,可以暫時解決!
讚讚
那個她遺失的我都載了最後變成跑不動(開啟後當掉)…
讚讚
影像名稱和訓練集名稱對嗎?
讚讚
剛重寫了另一個
編譯後跑吃一個訊息視窗 :
this application has requested the Runtime to terminate it in an unusual way.
Please contact the application’s support team for more information.
請問該怎麼辦
抱歉一直問,我對Dev跟Open-CV是初學…非常感恩
讚讚
恩 我是直接放在專案的資料夾裡
string image_name="123.jpg";
string cascade_name="haarcascade_frontalface_default.xml";
讚讚
請問想對框取來的人臉做運算很直覺想到Rect=cvRect(point1.x,point1.y,…)
但那個好像是一點點畫出來 想得知起始點 跟 最終點 該如何寫
讚讚
你說的框確實是一點一點畫出來的!你是說要把偵測到的人臉框起來的起點和終點嗎?只要知道左上點和右下點即可框出人臉喔!
讚讚
您好,不好意思打擾您
這幾天有去看看這篇論文
不太懂的地方是
最後他輸入這一大張照片(大家聚在一起的合照)
他是如何框選(偵測/找到)大家的人臉
是將這大合照做切割成很多塊小照片後去判斷有沒有特徵嗎
但想想這樣不會通過瀑布偵測的條件…
謝謝您熱心解答
讚讚
設定偵測框的大小、x和y位移的大小。
首先從第一行由左到右掃描完,
接著第二行同樣由左到右掃描……
直到最後一行結束。
我說的「行」表示每次增加y位移的大小,
而由左到右表示每次增加x位移的大小。
讚讚
請問如果要偵測的東西不是影片的話那是要從哪個地方改
讚讚
不是影片?那就是影像囉!?這篇文章就是教你怎麼偵測「影像」裡的人臉。
讚讚
噢我說錯了 我說的是 不是人臉
而且opencv的資料庫也找不到的話
那該怎麼改?
讚讚
你找的不是人的臉?那麼這篇文章的code你可能就用不到了,除非haarcascade_frontalface_default.xml這個檔改成針對你要偵測的特徵,如貓、狗的臉喔!
讚讚
所以如果我想用這篇文章的方法去判斷出這張圖片裡有沒有車子的話會行的通嗎
如果可以的話該從何下手才好呢?
或者是有其他更好的解法??
抱歉因為我剛接觸opencv很多地方不懂 ~"~
讚讚
人臉有人臉的特徵,而車子也有車子的特徵,本篇文章的方法行不通喔!你必須抓出車子的特徵來讓程式判斷,就有機會找到圖片中的車子,但這並不容易呢!因為不同車子有不同的特徵,你就必須收集一系列車子的特徵,接著你就必須訓練這些車子的特徵,就如同使用本篇文章程式一樣使用已經訓練好的人臉特徵集來進行判斷。當然還有其它可行辦法。
讚讚
你好
就是當我偵測人臉之後
只顯示人臉(被框)的圖片就好
不是整張圖片
謝謝
讚讚
你好~
(因為我是要跟android結合)
我opencv那裡偵測處理好
要怎麼只顯示偵測到的紅框的那部分圖片就好
而不是顯示整張圖片
謝謝您
讚讚
嗨~你可以參考:感興趣區域(點選可連結)
把這些程式碼鑲進去就是你要的功能囉~
讚讚
請問為什麼我compiler後什麼都沒有,在文章中說特別注意的地方是路徑以及後面分類和訓練等,有點不太懂,能否詳細教我,另外webcam裡+上文章中的人臉偵測,有偵測到在持續拍成jpg檔,不知可以嗎
讚讚
嗨~你說的什麼都沒有,是指編譯過可執行?
要注意我使用的影像名稱為:XD2.jpg
而人臉訓練集名稱為:haarcascade_frontalface_default.xml
若路徑皆設定正確,應該會出現結果才是。
還有我使用的ΙDE是:Dev C++ 4.9.9.2
而函式庫是:OpenCV 2.0
讚讚
你好,我有注意到XD2.jpg,但要放在哪?
我也不知道人臉訓練集名稱為:haarcascade_frontalface_default.xml 這東西需要去改嗎?
另外路徑我不會設,能麻煩跟我說嗎
工具我都用跟你一樣的
抱歉,我是新手所以有一堆問題,感謝
讚讚
如果不知道路徑怎麼設的話,「影像」和「訓練集」直接放在程式碼檔同一資料夾即可,原本"../image/XD2.jpg"就改為"XD2.jpg",而"../haarcascades/haarcascade_frontalface_default.xml"則改為"haarcascade_frontalface_default.xml"。
haarcascade_frontalface_default.xml這個檔案可以去google一下,馬上就可以在OpenCV官方網站中下載到。
讚讚
若是要偵測的是影片
那要怎麼載入?
謝謝:)
讚讚
你可以參考:人臉偵測2 (Face Detection)(點選可連結),裡頭有可以啟動webcam來偵測人臉的程式碼,若無法開啟webcam,則會開啟影像來偵測人臉,不過我還沒有試過載入影片……
讚讚
你好,我還是不行ㄟ,不知道是不是我哪裡出錯了,我將圖片寄給大大的信箱,不知能否幫忙看一下嗎?感謝
讚讚
嗨~nick,剛看到你兩天前寄的信,剛已經回覆給你了:)
讚讚
[…] 去年已經寫過人臉偵測 (Face Detection),那是Sedir同學 (目前單身,想認識可留言或寄信給我)推薦我使用的程式碼,這次我自己試用OpenCV 2.4 beta裡的tutorial code,發現它多了人眼偵測 (Eye Detection),那就直接來玩這版的人臉偵測 (Face Detection)。 […]
讚讚
[…] 人臉偵測使用Haar features來區分window影像是否為人臉特徵,然而以暴力法來做速度實在很慢,因為要掃描整張影像,而且影像裡人臉的特徵除了位置因素,還有大小和型態等因素需要考量,勢必得利用特殊計算方法,才能達到現在數位相機的real-time人臉偵測,於是積分影像 (Integral Image)這個計算方法因應而生! […]
讚讚