Just a Computer Graphics Studio & My Life

最先看到有人臉偵測的設備是什麼呢?當然是非「數位相機」莫屬啦~只要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)" (65)

  1. 請問 #include <iostream> 這行什麼意思呢
    我執行這行會編譯錯誤 該如何解決呢 謝謝

    按讚數

  2. HappyMan你好:
    我想請問你,我有問題!?我是電機研究所研究生,我從網路有[人臉偵測]範例!
    我用C++試試看[人臉偵測]範例,但…安裝OpenCV2.6,有debug。
    [fatal error LNK1181: 無法開啟輸入檔 ‘opencv_calib3d246.lib’],我的opencv
    程式庫目錄是[build\x86\vc10/vc9]程式庫目錄都有。[攝影機]不行播放!
    [p.s:我用攝影機是微軟Kinect]

    按讚數

  3. 您好 我想請問一下,所謂min_neighbors以及四個演算法是甚麼意思呀,字面上看不太懂,我們要使用這個演算法來做實驗數據,改參數來測驗,可以使用哪幾個參數來做實驗數據比較好??

    按讚數

    • min_neighbors: 最少鄰近偵測視窗。一個臉可能重複偵測好幾次,但我們只要取一次,如果設0的話,所有偵測的視窗都會畫出來。

      你是說特徵型有四種吧?!文章有列出四種Feature types。

      建議只要有可調整的參數,都可以拿來做實驗,屆時你將會知道怎樣的參數組合,適用於你的目標影像喔~

      按讚數

  4. 不好意思~我想請問一下
    因為影像中的人臉有大有小,有不同角度
    例如獨自的大頭照、團體的合照
    那這樣子以Haar features來訓練的話,是否也要不同大小、角度的Haar features圖塊
    且Haar features的圖塊由小到大在要測試的圖片上一個區塊一個區塊的掃描?
    又如果今天前置條件為人臉區塊設定在window某個區塊範圍內
    如此的話Haar features訓練的樣本是不是就可以減少很多

    按讚數

    • 訓練這部分我尚未深入研究,我就以個人觀點推論⋯⋯

      訓練的話需要考慮所有可能的影像,所以需要各種解析度的圖,而圖的內容也要包含多樣的人臉,男女、角度、年齡、大小、膚色等等。

      以Haar features演算法確實要陸續掃描圖塊。

      訓練樣本跟測試的圖沒有直接關聯,樣本依然要考慮所有可能的影像。你的意思應該是在測試圖上圈一塊區域,然後拿這塊區域來執行掃描,當然會比掃整張圖快很多囉~

      按讚數

  5. 請問cvqueryframe 在3.0好像是不同的用法

    按讚數

發表留言

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s

標籤雲

%d 位部落客按了讚: