最先看到有人臉偵測的設備是什麼呢?當然是非「數位相機」莫屬啦~只要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)
[…] 另外人臉佔整張相片太小,也不容易被偵測出來,看來跟它的演算法參數設定有關係。這部分可參考我2011年寫的文章:[OpenCV] 人臉偵測 (Face Detection)。 […]
讚讚
現在寫App,也要來整合人臉偵測功能囉!🤡
讚讚
容我叫您一聲大神!~
小弟我正好在仔細閱讀這篇論文,加上您的解說讓我閱讀的速度提升不少!在此感謝您!
對了,2018/06/02 引用次數已經來到:16025 次
讚Liked by 2 people
很高興有幫助到你^_^
有什麼好的進展也可以分享給我喔~
引用數一直在增加呢
讚Liked by 2 people
您好!
我有問題想問您一下
我偵測道人臉之後,想要在偵測眼睛
for( size_t i = 0; i < faces.size(); i++ )
{
Point center( faces[i].x + faces[i].width/2, faces[i].y + faces[i].height/2 );
ellipse( frame, center, Size( faces[i].width/2, faces[i].height/2), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
請問有什麼辦法可以解決嘛?
讚讚
請問 #include &lt;iostream&gt; 這行什麼意思呢
我執行這行會編譯錯誤 該如何解決呢 謝謝
讚讚
HappyMan你好:
我想請問你,我有問題!?我是電機研究所研究生,我從網路有[人臉偵測]範例!
我用C++試試看[人臉偵測]範例,但…安裝OpenCV2.6,有debug。
[fatal error LNK1181: 無法開啟輸入檔 ‘opencv_calib3d246.lib’],我的opencv
程式庫目錄是[build\x86\vc10/vc9]程式庫目錄都有。[攝影機]不行播放!
[p.s:我用攝影機是微軟Kinect]
讚Liked by 1 person
嗨~你好:
看起來是版本弄錯,你安裝OpenCV2.6,應該要設定opencv_calib3d260.lib,而不是opencv_calib3d246.lib喔~
試試看吧!
讚Liked by 1 person
HappyMan:
好!我再試試看!謝謝你。^^
讚Liked by 1 person
HappyMan:
我用你的範例試試看!可是…一樣有bug!
[LINK : fatal error LNK1181: 無法開啟輸入檔 ‘opencv_contrib246.lib’]
對了!我有update,opencv2.4.13程式庫,是否可以用嗎?謝謝!
讚Liked by 1 person
使用opencv_contrib246.lib是因為有安裝OpenCV2.4.6,然而你是安裝OpenCV2.4.13,所以應該是要opencv_contrib2413.lib(不確定,要找一下正確檔名)。
可以參考我這篇文章,裡頭有路徑,可以讓你找到該檔名,然後設定到專案中。
https://cg2010studio.com/2012/11/26/opencv-visual-studio-2012-%E5%AE%89%E8%A3%9D-opencv-2-4-3/
讚讚
HappyMan你好:
我的程式已經沒有bug!但….我的kinect攝影機不行
打開!?是否我寫opencv+C++它不支援kinect攝影機
呢?!
讚讚
您好 我想請問一下,所謂min_neighbors以及四個演算法是甚麼意思呀,字面上看不太懂,我們要使用這個演算法來做實驗數據,改參數來測驗,可以使用哪幾個參數來做實驗數據比較好??
讚讚
min_neighbors: 最少鄰近偵測視窗。一個臉可能重複偵測好幾次,但我們只要取一次,如果設0的話,所有偵測的視窗都會畫出來。
你是說特徵型有四種吧?!文章有列出四種Feature types。
建議只要有可調整的參數,都可以拿來做實驗,屆時你將會知道怎樣的參數組合,適用於你的目標影像喔~
讚讚
不好意思~我想請問一下
因為影像中的人臉有大有小,有不同角度
例如獨自的大頭照、團體的合照
那這樣子以Haar features來訓練的話,是否也要不同大小、角度的Haar features圖塊
且Haar features的圖塊由小到大在要測試的圖片上一個區塊一個區塊的掃描?
又如果今天前置條件為人臉區塊設定在window某個區塊範圍內
如此的話Haar features訓練的樣本是不是就可以減少很多
讚讚
訓練這部分我尚未深入研究,我就以個人觀點推論⋯⋯
訓練的話需要考慮所有可能的影像,所以需要各種解析度的圖,而圖的內容也要包含多樣的人臉,男女、角度、年齡、大小、膚色等等。
以Haar features演算法確實要陸續掃描圖塊。
訓練樣本跟測試的圖沒有直接關聯,樣本依然要考慮所有可能的影像。你的意思應該是在測試圖上圈一塊區域,然後拿這塊區域來執行掃描,當然會比掃整張圖快很多囉~
讚讚
[…] 人臉偵測 OpenCV […]
讚讚
請問cvqueryframe 在3.0好像是不同的用法
讚Liked by 2 people
開發時要注意版本,我還沒試過3.0,但用法應相去不遠~
讚Liked by 1 person