好久没写东西了,一来考试周,二来一直在看deep learning的东西,整理好了一个presentation的ppt,但不是很适合发博客上
人脸识别在OpenCV里面比较简单(我没想到这么简单……)直接调用cvHaarDetectObjects()即可,虽然也不是很好,比如偏头呀,用手遮之后detect的效果就很差强人意了,但我也没法用更好的方法做,一句话,装备跟不上~~~~
做吧做吧,人脸识别还是挺简单的,调用视频,几个简单的函数就搞定了
detect_and_draw 检测脸
save_face 把脸搞出来单独放一个窗口
-
-
-
- #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}}
- };
-
-
- 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,
- face->y *scale,
- face->width *scale,
- face->height *scale
- )
- );
-
- 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 )
- {
-
-
-
- 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);
-
-
-
- cvClearMemStorage(storage);
- double t = (double)cvGetTickCount();
- CvSeq* objects = cvHaarDetectObjects(small_img,
- cascade,
- storage,
- 1.1,
- 2,
- 0,
- cvSize(30,30));
-
- t = (double)cvGetTickCount() - t;
-
- 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);
-
-
-
-
- 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()
- {
-
-
- 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);
- 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){
- c_index = d;
- break;
- }
- }
- Mat eigenvetors_d;
- eigenvetors_d.create((c_index+1), WIDTH*HEIGHT, CV_32FC1);
- for (int i=0; i<(c_index+1); ++i)
- {
- pca->eigenvectors.row(i).copyTo(eigenvetors_d.row(i));
- }
-
- FileStorage fs_w("C:\\Users\\Darkscope\\Desktop\\face\\config.xml", FileStorage::WRITE);
- 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();
- 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);
- 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_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);
- 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_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;
- }
-
- }
-
-
-
-
- return min_index;
- }
其实就是调用下PCA而已,PCA的原理见我的这篇博客 点击打开链接
我把MFC的工程代码放在了 github 有兴趣的可以看下(注意代码里的绝对路径face目录下必须要存在一个access.ini,里面有一个数字0,才能开始采集图像)
发现MFC整个工程居然有200MB+………………我就只上传了代码部分…………