OpenCV 的人脸detect及PCA匹配


好久没写东西了,一来考试周,二来一直在看deep learning的东西,整理好了一个presentation的ppt,但不是很适合发博客上

人脸识别在OpenCV里面比较简单(我没想到这么简单……)直接调用cvHaarDetectObjects()即可,虽然也不是很好,比如偏头呀,用手遮之后detect的效果就很差强人意了,但我也没法用更好的方法做,一句话,装备跟不上~~~~

做吧做吧,人脸识别还是挺简单的,调用视频,几个简单的函数就搞定了

detect_and_draw		检测脸      
save_face		把脸搞出来单独放一个窗口

// opencv.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include <opencv2\opencv.hpp>
#include <iostream>
#include <string>
#include "opencv\highgui.h"
using namespace cv;
using namespace std;

static CvHaarClassifierCascade* cascade = 0;
const char* cascade_name = 
"haarcascade_frontalface_alt.xml"; 
static CvMemStorage* storage = 0; 
double scale=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


void save_face(IplImage* img, CvRect *face, double scale)
{
	assert(img!=NULL);
	assert(face!=NULL);
	IplImage* pimg=cvCloneImage(img);
	cvSetImageROI(
			pimg,
			cvRect(
				face->x *scale,            /* x = start from leftmost */
				face->y *scale,
				face->width *scale,
				face->height *scale
			)
		);
		//save as 704 * 576 image
		IplImage *dst = 0;   //目标图像指针
		CvSize dst_cvsize;   //目标图像尺寸
		dst_cvsize.width = 240;  
		dst_cvsize.height = 240; 
		dst = cvCreateImage( dst_cvsize, pimg->depth, pimg->nChannels); //构造目标图象
		cvResize(pimg, dst, CV_INTER_LINEAR); //缩放源图像到目标图像
		cvShowImage( "face", dst );
}



void detect_and_draw(IplImage* img ) 
{ 
   
    //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; 
    //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); 
		save_face(img,r,scale);
        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 ); 
    }
}

int main( int argc, char** argv ) { 

    cvNamedWindow( "Face_detect", CV_WINDOW_AUTOSIZE );
	cvNamedWindow( "face", CV_WINDOW_AUTOSIZE );

    CvCapture* capture;
	cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 ); 
	storage = cvCreateMemStorage(0); 

    if (argc==1) {
        capture = cvCreateCameraCapture( 0 );
    } else {
        capture = cvCreateFileCapture( argv[1] );
    }
    assert( capture != NULL );

    IplImage* frame;
    while(1) {
        frame = cvQueryFrame( capture );
        if( !frame ) break;
		IplImage* img_rgb =frame;
		detect_and_draw(img_rgb);
		//IplImage* img_gry = cvCreateImage( cvSize( img_rgb->width,img_rgb->height ), img_rgb->depth, 1);
		//cvCvtColor(img_rgb, img_gry ,CV_BGR2GRAY);
		//IplImage* img_cny = doCanny( img_gry, 35, 100, 3 );
		//IplImage* img_inv = inverse(img_cny);
        cvShowImage( "FaceDetect", img_rgb );
        char c = cvWaitKey(10);
        if( c == 27 ) break;
    }
    cvReleaseCapture( &capture );
    cvDestroyWindow( "FaceDetect" );
	cvDestroyWindow( "face" );

}

完了之后,总觉得太简单也不好,于是想着做下人脸识别,我也没法用其它方法搞出一坨feature,于是只能是用PCA做了一下图片匹配

好在demo效果还不错,界面用MFC做的(那叫一个纠结啊,我的VS开始有个包没装好,结果不给添加事件,一通乱搞)

还有多线程的东西,杂七杂八是搞出来了,但是不好退出(关闭程序后进程残留,所以最好用那个按钮退出程序)

OpenCV 的人脸detect及PCA匹配_第1张图片

“开始检测”点了这个才会开始使用你的摄像头

“采集图像”呢就是你输入下标示信息,如果是分辨是哪个人呢就输入名字,除此之外还有很多玩法嘛,比如输入脸的朝向啦,戴没带眼镜啦,诸如此类

“准备PCA”开始用PCA找eigen,然后保存起来,所以在“解析”之前要准备下PCA(一次准备,多次可用,除非你又采集了新图像)

中间那个checkbox就没什么用,我无聊拿来用脸的朝向控制鼠标移动的。。。。。

“解析” 把采集的图像中和目前detect到的人脸最相似的一张的“标示信息”用MessageBox出来


PCA的部分代码:主要还是三个函数

pca_make_eigen()
prepare()
pca_detect(IplImage *img_test)
void pca_make_eigen()
{	/*
	  to prepare the need for svd recognize
	*/
	int index=get_index();
	Mat SampleSet(index, 100*100, CV_32FC1);  
	CString cs;
	for (int s=0; s<index; ++s)  
    {   cs.Format(_T("C:\\Users\\Darkscope\\Desktop\\face\\%d.jpg"),s);
		IplImage *img = cvLoadImage(cs2ca(cs));  
        IplImage *img_g = cvCreateImage(cvSize(img->width,img->height),IPL_DEPTH_8U, 1);  
        cvCvtColor(img, img_g, CV_BGR2GRAY);//Change it to gray level  
        Mat frame(img_g);  
        for (int row=0; row<img->height; ++row)  
        {  
            for (int col=0; col<img->width; ++col)  
            {  
                float f = (float)(frame.at<uchar>(row, col));  
                SampleSet.at<float>(s, (row*(img->width) + col) ) = f;  
            }  
        }  
        cvReleaseImage(&img);  
        cvReleaseImage(&img_g);  
    }  
	PCA *pca = new PCA(SampleSet, Mat(), CV_PCA_DATA_AS_ROW);
	
	int c_index=0;    
    float sum=0, sum0=0, ratio;    
    for (int d=0; d<pca->eigenvalues.rows; ++d)    
    {    
        sum += pca->eigenvalues.at<float>(d,0);    
    }    
    for (int d=0; d<pca->eigenvalues.rows; ++d)    
    {    
        sum0 += pca->eigenvalues.at<float>(d,0);    
        ratio = sum0/sum;    
        if(ratio > 0.9){  //0.9 is the threshold  
            c_index = d;    
            break;    
        }    
    }    
    Mat eigenvetors_d;    
    eigenvetors_d.create((c_index+1), WIDTH*HEIGHT, CV_32FC1);//eigen values of decreased dimension    
    for (int i=0; i<(c_index+1); ++i)    
    {    
        pca->eigenvectors.row(i).copyTo(eigenvetors_d.row(i));    
    }    
    //cout << "eigenvectors" <<endl << eigenvetors_d << endl;    
    FileStorage fs_w("C:\\Users\\Darkscope\\Desktop\\face\\config.xml", FileStorage::WRITE);//write mean and eigenvalues into xml file    
    fs_w << PCA_MEAN << pca->mean;    
    fs_w << PCA_EIGEN_VECTOR << eigenvetors_d;    
    fs_w.release();    
	delete pca;  
   
}
bool flag=0;
int index;
PCA *pca_encoding;
Mat SampleSet;
CString cs;
Mat encoded;

void prepare()
{
    index=get_index();
	pca_encoding = new PCA();  //Read config  
    SampleSet=Mat(index, 100*100, CV_32FC1);  
	for (int s=0; s<index; ++s)  
    {   cs.Format(_T("C:\\Users\\Darkscope\\Desktop\\face\\%d.jpg"),s);
		IplImage *img = cvLoadImage(cs2ca(cs));  
        IplImage *img_g = cvCreateImage(cvSize(img->width,img->height),IPL_DEPTH_8U, 1);  
        cvCvtColor(img, img_g, CV_BGR2GRAY);//Change it to gray level  
        Mat frame(img_g);  
        for (int row=0; row<img->height; ++row)  
        {  
            for (int col=0; col<img->width; ++col)  
            {  
                float f = (float)(frame.at<uchar>(row, col));  
                SampleSet.at<float>(s, (row*(img->width) + col) ) = f;  
            }  
        }  
        cvReleaseImage(&img);  
        cvReleaseImage(&img_g);  
    }  
    FileStorage fs_r("C:\\Users\\Darkscope\\Desktop\\face\\config.xml", FileStorage::READ);    
    fs_r[PCA_MEAN] >> pca_encoding->mean;    
    fs_r[PCA_EIGEN_VECTOR] >> pca_encoding->eigenvectors;    
    fs_r.release();    
	encoded=Mat(index, pca_encoding->eigenvectors.rows, CV_32FC1);  
    for (int s=0; s<index; ++s)  
    {  
        Mat in = SampleSet.row(s);  
        Mat out = encoded.row(s);  
        //pca->project(in, out);  
        pca_encoding->project(in, out);  
        
    }  
}
int  pca_detect(IplImage *img_test)
{
	
	if (!flag)
	{
		prepare();
		flag=1;
	}

	IplImage *img_test_g = cvCreateImage(cvSize(img_test->width,img_test->height),IPL_DEPTH_8U, 1);  
	cvCvtColor(img_test, img_test_g, CV_BGR2GRAY);
	Mat mat_img(img_test_g);//input  
    Mat mat_test(1, HEIGHT*WIDTH, CV_32FC1);  
	for (int row=0; row<HEIGHT; ++row)  
    {  
        for (int col=0; col<WIDTH; ++col)  
        {  
            float f = (float)(mat_img.at<uchar>(row, col));  
            mat_test.at<float>(0, (row*(WIDTH) + col) ) = f;  
        }  
    }  
    Mat encoded_test(1, pca_encoding->eigenvectors.rows, CV_32FC1);  
    pca_encoding->project(mat_test, encoded_test);  
   // cvReleaseImage(&img_test);  
    cvReleaseImage(&img_test_g);

	float min_sum = CV_MAX_ALLOC_SIZE;  
    int min_index;  
    for (int s=0; s<index; ++s)  
    {  
        float sum=0;  
        for (int e=0; e<pca_encoding->eigenvectors.rows; ++e)  
        {  
            float fs = encoded.at<float>(s,e);  
            float fi = encoded_test.at<float>(0,e);  
            sum += ((fs-fi)*(fs-fi));  
        }  
        if(sum < min_sum){  
            min_sum = sum;  
            min_index = s;  
        }  
       
    }  
	/*
	 reuturn the index of the most similar face for the given img.
	*/
 
	return min_index;
}

其实就是调用下PCA而已,PCA的原理见我的这篇博客 点击打开链接

我把MFC的工程代码放在了 github 有兴趣的可以看下(注意代码里的绝对路径face目录下必须要存在一个access.ini,里面有一个数字0,才能开始采集图像)

发现MFC整个工程居然有200MB+………………我就只上传了代码部分…………



你可能感兴趣的:(OpenCV 的人脸detect及PCA匹配)