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. Cat 的大頭貼

    請問為什麼我compiler後什麼都沒有,「影像」和「訓練集」也直接放在程式碼檔哦同一資料夾,可是按下去甚麼也沒有…

  2. rain 的大頭貼

    請問想對框取來的人臉做運算很直覺想到Rect=cvRect(point1.x,point1.y,…)
    但那個好像是一點點畫出來 想得知起始點 跟 最終點 該如何寫

  3. 賴明毅 的大頭貼

    您好,不好意思打擾您
    這幾天有去看看這篇論文
    不太懂的地方是
    最後他輸入這一大張照片(大家聚在一起的合照)
    他是如何框選(偵測/找到)大家的人臉
    是將這大合照做切割成很多塊小照片後去判斷有沒有特徵嗎
    但想想這樣不會通過瀑布偵測的條件…
    謝謝您熱心解答

    • HappyMan 的大頭貼

      設定偵測框的大小、x和y位移的大小。
      首先從第一行由左到右掃描完,
      接著第二行同樣由左到右掃描……
      直到最後一行結束。
      我說的「行」表示每次增加y位移的大小,
      而由左到右表示每次增加x位移的大小。

  4. q504658 的大頭貼

    請問如果要偵測的東西不是影片的話那是要從哪個地方改

    • HappyMan 的大頭貼

      不是影片?那就是影像囉!?這篇文章就是教你怎麼偵測「影像」裡的人臉。

      • q504658 的大頭貼

        噢我說錯了 我說的是 不是人臉
        而且opencv的資料庫也找不到的話
        那該怎麼改?

      • HappyMan 的大頭貼

        你找的不是人的臉?那麼這篇文章的code你可能就用不到了,除非haarcascade_frontalface_default.xml這個檔改成針對你要偵測的特徵,如貓、狗的臉喔!

      • q504658 的大頭貼

        所以如果我想用這篇文章的方法去判斷出這張圖片裡有沒有車子的話會行的通嗎
        如果可以的話該從何下手才好呢?
        或者是有其他更好的解法??
        抱歉因為我剛接觸opencv很多地方不懂 ~"~

        • HappyMan 的大頭貼

          人臉有人臉的特徵,而車子也有車子的特徵,本篇文章的方法行不通喔!你必須抓出車子的特徵來讓程式判斷,就有機會找到圖片中的車子,但這並不容易呢!因為不同車子有不同的特徵,你就必須收集一系列車子的特徵,接著你就必須訓練這些車子的特徵,就如同使用本篇文章程式一樣使用已經訓練好的人臉特徵集來進行判斷。當然還有其它可行辦法。

  5. pig 的大頭貼

    你好
    就是當我偵測人臉之後
    只顯示人臉(被框)的圖片就好
    不是整張圖片
    謝謝

  6. pig 的大頭貼

    你好~
    (因為我是要跟android結合)
    我opencv那裡偵測處理好
    要怎麼只顯示偵測到的紅框的那部分圖片就好
    而不是顯示整張圖片
    謝謝您

  7. nick 的大頭貼

    請問為什麼我compiler後什麼都沒有,在文章中說特別注意的地方是路徑以及後面分類和訓練等,有點不太懂,能否詳細教我,另外webcam裡+上文章中的人臉偵測,有偵測到在持續拍成jpg檔,不知可以嗎

    • HappyMan 的大頭貼

      嗨~你說的什麼都沒有,是指編譯過可執行?
      要注意我使用的影像名稱為:XD2.jpg
      而人臉訓練集名稱為:haarcascade_frontalface_default.xml
      若路徑皆設定正確,應該會出現結果才是。
      還有我使用的ΙDE是:Dev C++ 4.9.9.2
      而函式庫是:OpenCV 2.0

      • nick 的大頭貼

        你好,我有注意到XD2.jpg,但要放在哪?
        我也不知道人臉訓練集名稱為:haarcascade_frontalface_default.xml 這東西需要去改嗎?
        另外路徑我不會設,能麻煩跟我說嗎
        工具我都用跟你一樣的
        抱歉,我是新手所以有一堆問題,感謝

      • HappyMan 的大頭貼

        如果不知道路徑怎麼設的話,「影像」和「訓練集」直接放在程式碼檔同一資料夾即可,原本"../image/XD2.jpg"就改為"XD2.jpg",而"../haarcascades/haarcascade_frontalface_default.xml"則改為"haarcascade_frontalface_default.xml"。
        haarcascade_frontalface_default.xml這個檔案可以去google一下,馬上就可以在OpenCV官方網站中下載到。

  8. fly 的大頭貼

    若是要偵測的是影片
    那要怎麼載入?

    謝謝:)

  9. 未知 的大頭貼

    […] 去年已經寫過人臉偵測 (Face Detection),那是Sedir同學 (目前單身,想認識可留言或寄信給我)推薦我使用的程式碼,這次我自己試用OpenCV 2.4 beta裡的tutorial code,發現它多了人眼偵測 (Eye Detection),那就直接來玩這版的人臉偵測 (Face Detection)。 […]

  10. 未知 的大頭貼

    […] 人臉偵測使用Haar features來區分window影像是否為人臉特徵,然而以暴力法來做速度實在很慢,因為要掃描整張影像,而且影像裡人臉的特徵除了位置因素,還有大小和型態等因素需要考量,勢必得利用特殊計算方法,才能達到現在數位相機的real-time人臉偵測,於是積分影像 (Integral Image)這個計算方法因應而生! […]

隨意留個言吧:)~

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

標籤雲