Just My Life & My Work

最先看到有人臉偵測的設備是什麼呢?當然是非「數位相機」莫屬啦~只要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)是什麼呢?其實就只是一連串的檢查動作,通過第一關才能進入第二關,通過第二關才能進入地三關……直到通過最後一關,才會將此特徵辨識為人臉。

Cascade Architecture
Cascade Architecture
廣告

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

Feature Types
Feature types used by Viola and Jones
廣告

搜尋了網路的這篇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

Face Detection
我和我弟四人一起到芝山貴族世家吃牛排的兩張相片實驗結果。(因為作業要求一定要有自己的臉在相片中,所以只好出賣自己XD~)

結論: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
相當完美的結果:)~
廣告

參考:簡單的人臉偵測(face detection),使用HaarDetectObjectscvHaarDetectObjectsViola-Jones object detection frameworkFace Detection (人臉偵測)

推薦書籍:

廣告

Comments on: "[OpenCV] 人臉偵測 (Face Detection)" (70)

  1. tony 的大頭貼

    可以請問haar是對「pixel」去找嗎?
    可是要怎麼確定要找的目標會佔幾個pixel呢?

    目標的大小如果改變,訓練出的分類器不就沒有用了嗎?
    還是我哪邊沒有看懂呢?

    謝謝

    Liked by 1 person

  2. 魏華廷 的大頭貼

    請問一下 “錯誤 7 error C2065: ‘TempFrame’ : 未宣告的識別項" 在程式是中
    我都沒有看到對TempFrame的宣告 這要怎麼解決?

  3. 未知 的大頭貼

    […] 一直覺得臉書的功能不斷地在進化,特別讓我驚訝的是關於相片,它除了做到人臉偵測外,還能辨識這個人是誰,方便我們幫友人貼標籤! […]

  4. 葉飛 的大頭貼

    請問如果要做動物的五官變識
    有什麼方法

  5. Hank 的大頭貼

    你好,看上面的範例圖中偵測出人臉的紅色框框好像都是正方形,程式中沒有看到調整這個框框比例的部分。想請教是否能調整成長方形去做偵測呢?

  6. 小吳 的大頭貼

    你好:
    我想請問一下
    CvHaarClassifierCascade* classifier=(CvHaarClassifierCascade*)cvLoad(cascade_name.c_str(), 0, 0, 0);

    在此段中,我一直無法選擇任何的分類器載入
    classifier只要一載入,程式就會中斷,使用版本是OpenCV246,XML檔路徑也確定正確
    請問一下我是少設定了甚麼…..

  7. 小吳 的大頭貼

    你好:
    我想請問一下我這一段:
    CvHaarClassifierCascade* classifier=(CvHaarClassifierCascade*)cvLoad(cascade_name.c_str(), 0, 0, 0);

    classifier無法載入任何XML檔(已經確認路徑是正確的)
    請問是少了甚麼東西沒有設定嗎?

  8. yang 的大頭貼

    不好意思 ,我是個初學者
    想請教一個很基礎的問題
    這個程式碼能用VC C++下去寫嗎
    需如何改寫
    非常感謝 !

  9. 未知 的大頭貼

    […] 回顧之前使用OpenCV所做的人臉偵測 (Face Detection),當時只是覺得這門技術好厲害。如今我感興趣的平台是行動裝置,趁此拿來把玩一下,說不一定可以想出有趣的應用! […]

  10. jason 的大頭貼

    你好: 我想問 如果是用MATLAB 的語言寫的話! 要怎麼改?!

    • HappyMan 的大頭貼

      如果可以找到現成的code來玩玩看是比較好的做法,如果你瞭解人臉偵測的理論,那麼你就可以試著去實做。若你有看到人臉偵測的source code,程式能力好的話就可以對照改成MATLAB的版本~

回覆給小吳 取消回覆

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料

標籤雲