好久没写东西了,一来考试周,二来一直在看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开始有个包没装好,结果不给添加事件,一通乱搞)
还有多线程的东西,杂七杂八是搞出来了,但是不好退出(关闭程序后进程残留,所以最好用那个按钮退出程序)
“开始检测”点了这个才会开始使用你的摄像头
“采集图像”呢就是你输入下标示信息,如果是分辨是哪个人呢就输入名字,除此之外还有很多玩法嘛,比如输入脸的朝向啦,戴没带眼镜啦,诸如此类
“准备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; }
我把MFC的工程代码放在了 github 有兴趣的可以看下(注意代码里的绝对路径face目录下必须要存在一个access.ini,里面有一个数字0,才能开始采集图像)
发现MFC整个工程居然有200MB+………………我就只上传了代码部分…………