OpenCV實現人臉檢測


本文介紹最基本的用OpenCV實現人臉檢測的方法。

 

一.人臉檢測算法原理

Viola-Jones人臉檢測方法

參考文獻:Paul Viola, Michael J. Jones. Robust Real-Time Face Detection[J]. International Journal of Computer Vision,2004,57(2):137-154.

該算法的主要貢獻有三:

1.提出積分圖像(integral image),從而可以快速計算Haar-like特征。

2.利用Adaboost學習算法進行特征選擇和分類器訓練,把弱分類器組合成強分類器。

3.采用分類器級聯提高效率。

二.OpenCV檢測原理

OpenCV中有檢測人臉的函數(該函數還可以檢測一些其他物體), 甚至還包含一些預先訓練好的物體識別文件。

所以利用這些現成的東西就可以很快做出一個人臉檢測的程序。

主要步驟為:

1.加載分類器。

用cvLoad函數讀入xml格式的文件。文件在OpenCV安裝目錄下的“data/haarcascades/”路徑下。

http://blog.csdn.net/yang_xian521/article/details/6973667推薦使用haarcascade_frontalface_atl.xml和haarcascade_frontalface_atl2.xml

2.讀入待檢測圖像。讀入圖片或者視頻。

3.檢測人臉。

主要用的函數:

CvSeq* cvHaarDetectObjects( 
const CvArr* image, 
CvHaarClassifierCascade* cascade, 
CvMemStorage* storage, 
double scale_factor CV_DEFAULT(1.1), 
int min_neighbors CV_DEFAULT(3), 
int flags CV_DEFAULT(0), 
CvSize min_size CV_DEFAULT(cvSize(0,0)), 
CvSize max_size CV_DEFAULT(cvSize(0,0)) 
);

 

函數說明摘自《學習OpenCV》:
CvArr* image是一個灰度圖像,如果設置了ROI,將只處理這個區域。
CvHaarClassifierCascade* cascade是前面讀入的分類器特征級聯。
CvMemStorage* storage 是這個算法的工作緩存。
scale_factor :算法用不同尺寸的窗口進行掃描,scale_factor是每兩個不同大小的窗口之間的尺寸關系。
min_neighbors 控制誤檢測,因為人臉會被不同位置大小的窗口重復檢測到,至少有這么多次檢測,我們才認為真的檢測到了人臉。
flags有四個可用的數值,它們可以用位或操作結合使用。默認值是CV_HAAR_DO_CANNY_PRUNING,告訴分類器跳過平滑區域。
min_size 指示尋找人臉的最小區域。 max_size 顯然應該是尋找人臉的最大區域了。。。

4.檢測結果表示。

可以畫個圈圈或者畫個方框表示。

三.代碼

#include "cv.h" 
#include "highgui.h"

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <assert.h> 
#include <math.h> 
#include <float.h> 
#include <limits.h> 
#include <time.h> 
#include <ctype.h>

#ifdef _EiC 
#define WIN32 
#endif

static CvMemStorage* storage = 0; 
static CvHaarClassifierCascade* cascade = 0;

void detect_and_draw( IplImage* image );

const char* cascade_name = 
"haarcascade_frontalface_alt.xml"; 
/*    "haarcascade_profileface.xml";*/

int main( int argc, char** argv ) 
{ 
    cascade_name = "haarcascade_frontalface_alt2.xml"; 
    cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 ); 
  
    if( !cascade ) 
    { 
        fprintf( stderr, "ERROR: Could not load classifier cascade\n" ); 
        return -1; 
    } 
    storage = cvCreateMemStorage(0); 
    cvNamedWindow( "result", 1 ); 
     
    const char* filename = "Lena.jpg"; 
    IplImage* image = cvLoadImage( filename, 1 );

    if( image ) 
    { 
        detect_and_draw( image ); 
        cvWaitKey(0); 
        cvReleaseImage( &image );   
    }

    cvDestroyWindow("result"); 
  
    return 0; 
}


void detect_and_draw(IplImage* img ) 
{ 
    double scale=1.2; 
    static CvScalar colors[] = { 
        {{0,0,255}},{{0,128,255}},{{0,255,255}},{{0,255,0}}, 
        {{255,128,0}},{{255,255,0}},{{255,0,0}},{{255,0,255}} 
    };//Just some pretty colors to draw with

    //Image Preparation 
    // 
    IplImage* gray = cvCreateImage(cvSize(img->width,img->height),8,1); 
    IplImage* small_img=cvCreateImage(cvSize(cvRound(img->width/scale),cvRound(img->height/scale)),8,1); 
    cvCvtColor(img,gray, CV_BGR2GRAY); 
    cvResize(gray, small_img, CV_INTER_LINEAR);

    cvEqualizeHist(small_img,small_img); //直方圖均衡

    //Detect objects if any 
    // 
    cvClearMemStorage(storage); 
    double t = (double)cvGetTickCount(); 
    CvSeq* objects = cvHaarDetectObjects(small_img, 
                                                                        cascade, 
                                                                        storage, 
                                                                        1.1, 
                                                                        2, 
                                                                        0/*CV_HAAR_DO_CANNY_PRUNING*/, 
                                                                        cvSize(30,30));

    t = (double)cvGetTickCount() - t; 
    printf( "detection time = %gms\n", t/((double)cvGetTickFrequency()*1000.) );

    //Loop through found objects and draw boxes around them 
    for(int i=0;i<(objects? objects->total:0);++i) 
    { 
        CvRect* r=(CvRect*)cvGetSeqElem(objects,i); 
        cvRectangle(img, cvPoint(r->x*scale,r->y*scale), cvPoint((r->x+r->width)*scale,(r->y+r->height)*scale), colors[i%8]); 
    } 
    for( int i = 0; i < (objects? objects->total : 0); i++ ) 
    { 
        CvRect* r = (CvRect*)cvGetSeqElem( objects, i ); 
        CvPoint center; 
        int radius; 
        center.x = cvRound((r->x + r->width*0.5)*scale); 
        center.y = cvRound((r->y + r->height*0.5)*scale); 
        radius = cvRound((r->width + r->height)*0.25*scale); 
        cvCircle( img, center, radius, colors[i%8], 3, 8, 0 ); 
    }

    cvShowImage( "result", img ); 
    cvReleaseImage(&gray); 
    cvReleaseImage(&small_img); 
}

 

四.結果及一些說明

運行結果如下圖:

2012-8-1 21-20-21

需要說明的幾點:

1.圖像和.xml文件要放在該程序的bin目錄下(.sln所在的目錄)。

2.《學習OpenCV》里面就是用矩形表示,但是書里面的代碼不太對,原因是忽略了縮放因子,即void detect_and_draw(IplImage* img )里面的double scale=1.2;

這個縮放因子的作用是:拿到一個圖像,首先將它縮放(scale=1.2即變為一個小圖像),然后在縮放后的小圖像上檢測人臉,這樣會比較快。

最基本的就這么多吧。

 

注:本文所用OpenCV版本為2.3.1


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM