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 withvoid 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开始有个包没装好,结果不给添加事件,一通乱搞)

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


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

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

“准备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+………………我就只上传了代码部分…………



           
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值