好久没写东西了,一来考试周,二来一直在看deep learning的东西,整理好了一个presentation的ppt,但不是很适合发博客上
人脸识别在OpenCV里面比较简单(我没想到这么简单……)直接调用cvHaarDetectObjects()即可,虽然也不是很好,比如偏头呀,用手遮之后detect的效果就很差强人意了,但我也没法用更好的方法做,一句话,装备跟不上~~~~
做吧做吧,人脸识别还是挺简单的,调用视频,几个简单的函数就搞定了
detect_and_draw 检测脸
save_face 把脸搞出来单独放一个窗口
// opencv.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#include
#include
#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; swidth,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; rowheight; ++row)
{
for (int col=0; colwidth; ++col)
{
float f = (float)(frame.at(row, col));
SampleSet.at(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; deigenvalues.rows; ++d)
{
sum += pca->eigenvalues.at(d,0);
}
for (int d=0; deigenvalues.rows; ++d)
{
sum0 += pca->eigenvalues.at(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" <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; swidth,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; rowheight; ++row)
{
for (int col=0; colwidth; ++col)
{
float f = (float)(frame.at(row, col));
SampleSet.at(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; sproject(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(row, col));
mat_test.at(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; seigenvectors.rows; ++e)
{
float fs = encoded.at(s,e);
float fi = encoded_test.at(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+………………我就只上传了代码部分…………