OpenCV人脸识别的原理 完整版代码

http://blog.csdn.net/yanming901012/article/details/8606183

[cpp]  view plain  copy
  1. 本程序首先利用从摄像头检测到的人脸图片,先进行直方图均衡化  
  2. 并缩放到92*112的图片大小,然后根据train.txt的采集到的人脸模版  
  3. 进行匹配识别(最好是在统一光照下,采集不同角度的人脸图片各一张)  
  4. 注意:影响的极大因素在于光照,模版若与采集的图像光照不一样,识别率很低。  
  5. 经测试,模板若与检测的图像在同一光照下的话,侧脸,仰脸,正脸均可识别,且识别率较高  
[cpp]  view plain  copy
  1. //  
  2. #include <stdio.h>  
  3. #include <string.h>  
  4. #include "cv.h"  
  5. #include "cvaux.h"  
  6. #include "highgui.h"  
  7. #include <stdlib.h>  
  8. #include <assert.h>    
  9. #include <math.h>    
  10. #include <float.h>    
  11. #include <limits.h>    
  12. #include <time.h>    
  13. #include <ctype.h>    
  14.   
  15. 定义几个重要的全局变量  
  16. IplImage ** faceImgArr        = 0; // 指向训练人脸和测试人脸的指针(在学习和识别阶段指向不同)  
  17. CvMat    *  personNumTruthMat = 0; // 人脸图像的ID号  
  18. int nTrainFaces               = 0; // 训练图像的数目  
  19. int nEigens                   = 0; // 自己取的主要特征值数目  
  20. IplImage * pAvgTrainImg       = 0; // 训练人脸数据的平均值  
  21. IplImage ** eigenVectArr      = 0; // 投影矩阵,也即主特征向量  
  22. CvMat * eigenValMat           = 0; // 特征值  
  23. CvMat * projectedTrainFaceMat = 0; // 训练图像的投影  
  24. char *filename[5]={"face1.jpg","face2.jpg","face3.jpg","face4.jpg","face5.jpg"};  
  25.   
  26. static CvMemStorage* storage = 0;    
  27. static CvHaarClassifierCascade* cascade = 0;    
  28. int j=0;//统计记录的人脸数  
  29. char a[512]={0};  
  30. int a1,a2,a3,a4;  
  31. time_t timeBegin, timeEnd;      
  32.   int timeuse;    
  33.  函数原型  
  34. void learn();  
  35. void doPCA();  
  36. void storeTrainingData();  
  37. int  loadTrainingData(CvMat ** pTrainPersonNumMat);  
  38. int  findNearestNeighbor(float * projectedTestFace);  
  39. int  loadFaceImgArray(char * filename);  
  40. void printUsage();  
  41. int detect_and_draw( IplImage* image );    
  42. int recognize(IplImage *faceimg);  
  43.   
  44. //主函数,主要包括学习和识别两个阶段,需要运行两次,通过命令行传入的参数区分  
  45. int main( int argc, char** argv )  
  46. {  
  47.     CvCapture* capture = 0;    
  48.     IplImage *frame, *frame_copy = 0;    
  49.     int optlen = strlen("--cascade=");    
  50.     char *cascade_name = "H://opencv-2.4.3//opencv//data//haarcascades//haarcascade_frontalface_alt2.xml";    
  51.         //opencv装好后haarcascade_frontalface_alt2.xml的路径,    
  52.        //也可以把这个文件拷到你的工程文件夹下然后不用写路径名cascade_name= "haarcascade_frontalface_alt2.xml";      
  53.        //或者cascade_name ="C:\\Program Files\\OpenCV\\data\\haarcascades\\haarcascade_frontalface_alt2.xml"    
  54.     cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );    
  55.      
  56.     if( !cascade )    
  57.     {    
  58.         fprintf( stderr, "ERROR: Could not load classifier cascade\n" );    
  59.         fprintf( stderr,    
  60.         "Usage: facedetect --cascade=\"<cascade_path>\" [filename|camera_index]\n" );    
  61.         return -1;    
  62.     }    
  63.     storage = cvCreateMemStorage(0);    
  64.      capture = cvCreateCameraCapture(-1);    
  65.     cvNamedWindow( "result", 1 );    
  66.      
  67.     if( capture )    
  68.     {     timeBegin = time(NULL);      
  69.           learn();  
  70.         for(;;)    
  71.         {   timeEnd = time(NULL);      
  72.     timeuse=timeEnd - timeBegin;//计算经过的时间,统计人数  
  73.             if( !cvGrabFrame( capture ))    
  74.                 break;    
  75.             frame = cvRetrieveFrame( capture );    
  76.             if( !frame )    
  77.                 break;    
  78.             if( !frame_copy )    
  79.                 frame_copy = cvCreateImage( cvSize(frame->width,frame->height),    
  80.                                             IPL_DEPTH_8U, frame->nChannels );    
  81.             if( frame->origin == IPL_ORIGIN_TL )//如果图像的起点在左上角    
  82.                 cvCopy( frame, frame_copy, 0 );    
  83.             else    
  84.                 cvFlip( frame, frame_copy, 0 );//如果图像的起点不在左上角,而在左下角时,进行X轴对称    
  85.      
  86.             detect_and_draw( frame_copy );  //检测并且识别  
  87.             
  88.             if( cvWaitKey( 10 ) >= 0 )    
  89.                 break;    
  90.         }    
  91.      
  92.         cvReleaseImage( &frame_copy );    
  93.         cvReleaseCapture( &capture );    
  94.     }    
  95.     else    
  96.     {    
  97.         printf("Cannot read from CAM");    
  98.         return -1;    
  99.     }    
  100.      
  101.     cvDestroyWindow("result");    
  102.      
  103.     return 0;    
  104. }    
  105.   
  106. //学习阶段代码  
  107. void learn()  
  108. {  
  109.     int i, offset;  
  110.   
  111.     //加载训练图像集  
  112.     nTrainFaces = loadFaceImgArray("train.txt");  
  113.     if( nTrainFaces < 2 )  
  114.     {  
  115.         fprintf(stderr,  
  116.             "Need 2 or more training faces\n"  
  117.             "Input file contains only %d\n", nTrainFaces);  
  118.           
  119.         return;  
  120.     }  
  121.   
  122.     // 进行主成分分析  
  123.     doPCA();  
  124.   
  125.     //将训练图集投影到子空间中  
  126.     projectedTrainFaceMat = cvCreateMat( nTrainFaces, nEigens, CV_32FC1 );  
  127.     offset = projectedTrainFaceMat->step / sizeof(float);  
  128.     for(i=0; i<nTrainFaces; i++)  
  129.     {  
  130.         //int offset = i * nEigens;  
  131.         cvEigenDecomposite(  
  132.             faceImgArr[i],  
  133.             nEigens,  
  134.             eigenVectArr,  
  135.             0, 0,  
  136.             pAvgTrainImg,  
  137.             //projectedTrainFaceMat->data.fl + i*nEigens);  
  138.             projectedTrainFaceMat->data.fl + i*offset);  
  139.     }  
  140.   
  141.     //将训练阶段得到的特征值,投影矩阵等数据存为.xml文件,以备测试时使用  
  142.     storeTrainingData();  
  143. }  
  144.   
  145.   
  146. //加载保存过的训练结果  
  147. int loadTrainingData(CvMat ** pTrainPersonNumMat)  
  148. {  
  149.     CvFileStorage * fileStorage;  
  150.     int i;  
  151.   
  152.       
  153.     fileStorage = cvOpenFileStorage( "facedata.xml", 0, CV_STORAGE_READ );  
  154.     if( !fileStorage )  
  155.     {  
  156.         fprintf(stderr, "Can't open facedata.xml\n");  
  157.         return 0;  
  158.     }  
  159.   
  160.     nEigens = cvReadIntByName(fileStorage, 0, "nEigens", 0);  
  161.     nTrainFaces = cvReadIntByName(fileStorage, 0, "nTrainFaces", 0);  
  162.     *pTrainPersonNumMat = (CvMat *)cvReadByName(fileStorage, 0, "trainPersonNumMat", 0);  
  163.     eigenValMat  = (CvMat *)cvReadByName(fileStorage, 0, "eigenValMat", 0);  
  164.     projectedTrainFaceMat = (CvMat *)cvReadByName(fileStorage, 0, "projectedTrainFaceMat", 0);  
  165.     pAvgTrainImg = (IplImage *)cvReadByName(fileStorage, 0, "avgTrainImg", 0);  
  166.     eigenVectArr = (IplImage **)cvAlloc(nTrainFaces*sizeof(IplImage *));  
  167.     for(i=0; i<nEigens; i++)  
  168.     {  
  169.         char varname[200];  
  170.         sprintf( varname, "eigenVect_%d", i );  
  171.         eigenVectArr[i] = (IplImage *)cvReadByName(fileStorage, 0, varname, 0);  
  172.     }  
  173.   
  174.       
  175.     cvReleaseFileStorage( &fileStorage );  
  176.   
  177.     return 1;  
  178. }  
  179.   
  180. //存储训练结果  
  181. void storeTrainingData()  
  182. {  
  183.     CvFileStorage * fileStorage;  
  184.     int i;  
  185.     fileStorage = cvOpenFileStorage( "facedata.xml", 0, CV_STORAGE_WRITE );  
  186.   
  187.     //存储特征值,投影矩阵,平均矩阵等训练结果  
  188.     cvWriteInt( fileStorage, "nEigens", nEigens );  
  189.     cvWriteInt( fileStorage, "nTrainFaces", nTrainFaces );  
  190.     cvWrite(fileStorage, "trainPersonNumMat", personNumTruthMat, cvAttrList(0,0));  
  191.     cvWrite(fileStorage, "eigenValMat", eigenValMat, cvAttrList(0,0));  
  192.     cvWrite(fileStorage, "projectedTrainFaceMat", projectedTrainFaceMat, cvAttrList(0,0));  
  193.     cvWrite(fileStorage, "avgTrainImg", pAvgTrainImg, cvAttrList(0,0));  
  194.     for(i=0; i<nEigens; i++)  
  195.     {  
  196.         char varname[200];  
  197.         sprintf( varname, "eigenVect_%d", i );  
  198.         cvWrite(fileStorage, varname, eigenVectArr[i], cvAttrList(0,0));  
  199.     }  
  200.     cvReleaseFileStorage( &fileStorage );  
  201. }  
  202.   
  203. //寻找最接近的图像  
  204. int findNearestNeighbor(float * projectedTestFace)  
  205. {  
  206.   
  207.     double leastDistSq = DBL_MAX;       //定义最小距离,并初始化为无穷大  
  208.     int i, iTrain, iNearest = 0;  
  209.   
  210.     for(iTrain=0; iTrain<nTrainFaces; iTrain++)  
  211.     {  
  212.         double distSq=0;  
  213.   
  214.         for(i=0; i<nEigens; i++)  
  215.         {  
  216.             float d_i =  
  217.                 projectedTestFace[i] -  
  218.                 projectedTrainFaceMat->data.fl[iTrain*nEigens + i];  
  219.         distSq += d_i*d_i / eigenValMat->data.fl[i];  // Mahalanobis算法计算的距离,差的距离的平方除以平均脸的特征值  
  220.         //  distSq += d_i*d_i; // Euclidean算法计算的距离  
  221.         }  
  222.   
  223.         if(distSq < leastDistSq)  
  224.         {  
  225.             leastDistSq = distSq;  
  226.             iNearest = iTrain;  
  227.         }  
  228.     }  
  229.     //printf("leastdistsq==%f",leastDistSq);  
  230.     return iNearest;  
  231. }  
  232.   
  233.   
  234.   
  235. //主成分分析  
  236. void doPCA()  
  237. {  
  238.     int i;  
  239.     CvTermCriteria calcLimit;  
  240.     CvSize faceImgSize;  
  241.   
  242.     // 自己设置主特征值个数  
  243.     nEigens = nTrainFaces-1;  
  244.   
  245.     //分配特征向量存储空间  
  246.     faceImgSize.width  = faceImgArr[0]->width;  
  247.     faceImgSize.height = faceImgArr[0]->height;  
  248.     eigenVectArr = (IplImage**)cvAlloc(sizeof(IplImage*) * nEigens);    //分配个数为住特征值个数  
  249.     for(i=0; i<nEigens; i++)  
  250.         eigenVectArr[i] = cvCreateImage(faceImgSize, IPL_DEPTH_32F, 1);  
  251.   
  252.     //分配主特征值存储空间  
  253.     eigenValMat = cvCreateMat( 1, nEigens, CV_32FC1 );  
  254.   
  255.     // 分配平均图像存储空间  
  256.     pAvgTrainImg = cvCreateImage(faceImgSize, IPL_DEPTH_32F, 1);  
  257.   
  258.     // 设定PCA分析结束条件  
  259.     calcLimit = cvTermCriteria( CV_TERMCRIT_ITER, nEigens, 1);//最大迭代次数为nEigens  
  260.   
  261.     // 计算平均图像,特征值,特征向量  
  262.     cvCalcEigenObjects(  
  263.         nTrainFaces,  
  264.         (void*)faceImgArr,  
  265.         (void*)eigenVectArr,  
  266.         CV_EIGOBJ_NO_CALLBACK,  
  267.         0,  
  268.         0,  
  269.         &calcLimit,  
  270.         pAvgTrainImg,  
  271.         eigenValMat->data.fl//存储求得的eigenvalue  
  272.         );  
  273.   
  274.     cvNormalize(eigenValMat, eigenValMat, 1, 0, CV_L1, 0);  
  275. }  
  276.   
  277.   
  278.   
  279. //加载txt文件的列举的图像  
  280. int loadFaceImgArray(char * filename)  
  281. {  
  282.     FILE * imgListFile = 0;  
  283.     char imgFilename[512];  
  284.     int iFace, nFaces=0;  
  285.   
  286.   
  287.     if( !(imgListFile = fopen(filename, "r")) )  
  288.     {  
  289.         fprintf(stderr, "Can\'t open file %s\n", filename);  
  290.         return 0;  
  291.     }  
  292.   
  293.     // 统计人脸数  
  294.     while( fgets(imgFilename, 512, imgListFile) ) ++nFaces;//char *fgets(char *buf, int bufsize, FILE *stream);从文件结构体指针stream中读取数据,每次读取一行。读取的数据保存在buf指向的字符数组中,每次最多读取bufsize-1个字符(第bufsize个字符赋'\0'),如果文件中的该行,不足bufsize个字符,则读完该行就结束。如果函数读取成功,则返回指针buf,失败则返回NULL。  
  295.     rewind(imgListFile);//将文件内部的位置指针重新指向一个流(数据流/文件)的开头  
  296.   
  297.     // 分配人脸图像存储空间和人脸ID号存储空间  
  298.     faceImgArr        = (IplImage **)cvAlloc( nFaces*sizeof(IplImage *) );  
  299.     personNumTruthMat = cvCreateMat( 1, nFaces, CV_32SC1 );//CvMat* cvCreateMat( int rows, int cols, int type );  
  300.   
  301.     for(iFace=0; iFace<nFaces; iFace++)  
  302.     {  
  303.         // 从文件中读取序号和人脸名称  
  304.         fscanf(imgListFile,  
  305.             "%d %s", personNumTruthMat->data.i+iFace, imgFilename);// fscanf(FILE *stream, char *format,[argument...])功 能: 从一个流中执行格式化输入,fscanf遇到空格和换行时结束  
  306.   
  307.         // 加载人脸图像  
  308.         faceImgArr[iFace] = cvLoadImage(imgFilename, CV_LOAD_IMAGE_GRAYSCALE);  
  309.   
  310.         if( !faceImgArr[iFace] )  
  311.         {  
  312.             fprintf(stderr, "Can\'t load image from %s\n", imgFilename);  
  313.             return 0;  
  314.         }  
  315.     }  
  316.   
  317.     fclose(imgListFile);  
  318.   
  319.     return nFaces;  
  320. }  
  321.   
  322.   
  323.   
  324. //  
  325. void printUsage()  
  326. {  
  327.     printf("Usage: eigenface <command>\n",  
  328.         "  Valid commands are\n"  
  329.         "    train\n"  
  330.         "    test\n");  
  331. }  
  332.   
  333. int detect_and_draw( IplImage* img )    
  334. {    
  335.  CvFont font;  
  336.  cvInitFont( &font, CV_FONT_VECTOR0,1, 1, 0, 1, 8);  
  337.     static CvScalar colors[] =     
  338.     {    
  339.         {{0,0,255}},    
  340.         {{0,128,255}},    
  341.         {{0,255,255}},    
  342.         {{0,255,0}},    
  343.         {{255,128,0}},    
  344.         {{255,255,0}},    
  345.         {{255,0,0}},    
  346.         {{255,0,255}}    
  347.     };    
  348.      
  349.     double scale = 1.3;    
  350.     IplImage* gray = cvCreateImage( cvSize(img->width,img->height), 8, 1 );    
  351.     IplImage* small_img = cvCreateImage( cvSize( cvRound (img->width/scale),    
  352.                          cvRound (img->height/scale)),    
  353.                      8, 1 );    
  354.     int i,personnum=0;    
  355.      
  356.     cvCvtColor( img, gray, CV_BGR2GRAY );    
  357.     cvResize( gray, small_img, CV_INTER_LINEAR );    
  358.     cvEqualizeHist( small_img, small_img );    
  359.     cvClearMemStorage( storage );    
  360.      
  361.     if( cascade )    
  362.     {    
  363.         double t = (double)cvGetTickCount();    
  364.         CvSeq* faces = cvHaarDetectObjects( small_img, cascade, storage,    
  365.                                             1.1, 2, 0/*CV_HAAR_DO_CANNY_PRUNING*/,    
  366.                                             cvSize(30, 30) );    
  367.         t = (double)cvGetTickCount() - t;    
  368.       //  printf( "detection time = %gms\n", t/((double)cvGetTickFrequency()*1000.) );    
  369.          IplImage* temp_img=cvCreateImage(cvSize(92,112),8,1);    
  370.         for( i = 0; i < (faces ? faces->total : 0); i++ )    
  371.         {    
  372.             CvRect* r = (CvRect*)cvGetSeqElem( faces, i );    
  373.             
  374.             IplImage *dst=cvCreateImage(cvSize(r->width,r->height),8,1);//cvsize只能选取r->width,r->height不能再后面*scale或+100    
  375.           CvPoint p1;    
  376.           p1.x=cvRound((r->x)*scale);    
  377.           p1.y=cvRound((r->y)*scale);    
  378.           CvPoint p2;    
  379.           p2.x=cvRound((r->x+r->width)*scale);    
  380.           p2.y=cvRound((r->y+r->height)*scale);    
  381.             cvRectangle(img,p1,p2,colors[i%8],3,8,0);    
  382.             cvSetImageROI(small_img,*r);    
  383.             cvCopy(small_img,dst);    
  384.             cvResize(dst,temp_img);    
  385.         cvEqualizeHist( temp_img, temp_img );    
  386.              cvResetImageROI(small_img);       
  387.             cvSaveImage(filename[i],temp_img);    
  388.               cvReleaseImage(&dst);    
  389.               //开始识别temp_img  
  390.             
  391.               personnum=recognize(temp_img);  
  392.               if(personnum==1)  
  393.                cvPutText(img, "Yanming" , cvPoint(20, 20), &font, CV_RGB(255,255,255));//将正确识别的人的姓名显示在屏幕上  
  394.                  
  395.         }    
  396.     }    
  397.      
  398.     cvShowImage( "result", img );    
  399.     cvReleaseImage( &gray );    
  400.     cvReleaseImage( &small_img );    
  401.  return -1;  
  402. }    
  403.   
  404. int recognize(IplImage *faceimg)  
  405. {  
  406.     int i, nTestFaces  = 0;         // 测试人脸数  
  407.     CvMat * trainPersonNumMat = 0;  // 训练阶段的人脸数  
  408.     float * projectedTestFace = 0;  
  409.     // 加载保存在.xml文件中的训练结果  
  410.     if( !loadTrainingData( &trainPersonNumMat ) ) return -3;  
  411.   
  412.     projectedTestFace = (float *)cvAlloc( nEigens*sizeof(float) );  
  413.       
  414.     int iNearest, nearest;  
  415.   
  416.         //将测试图像投影到子空间中  
  417.         cvEigenDecomposite(  
  418.             faceimg,  
  419.             nEigens,  
  420.             eigenVectArr,  
  421.             0, 0,  
  422.             pAvgTrainImg,  
  423.             projectedTestFace);  
  424.         //cvNormalize(projectedTestFace, projectedTestFace, 1, 0, CV_L1, 0);  
  425.         iNearest = findNearestNeighbor(projectedTestFace);  
  426.         nearest  = trainPersonNumMat->data.i[iNearest];  
  427.         printf("nearest = %d", nearest);  
  428.         if(timeuse<=10)  
  429.         {  
  430.               
  431.         if((nearest==1)|(nearest==11)|(nearest==111))//可以更改train.txt中训练图片的编号,这里将侧脸,仰脸,正脸都归为一起  
  432.             a1++;  
  433.         if(nearest==2)  
  434.             a2++;  
  435.         if(nearest==3)  
  436.             a3++;  
  437.         if(nearest==4)  
  438.             a4++;  
  439.           
  440.                   
  441.         if(a1>7)//如果10s中识别的次数为6则认定为a1  
  442.         {  
  443.         printf("yanming\n");  
  444.         return 1;  
  445.         }  
  446.         if(a2>6)  
  447.         {printf("others\n");}  
  448.         if(a3>6)  
  449.         {printf("ma\n");}  
  450.         if(a4>6)  
  451.         {printf("ba\n");}  
  452.         }  
  453.         else  
  454.             {  
  455.                 timeBegin=time(NULL);  
  456.                 a1=0;  
  457.                 a2=0;  
  458.                 a3=0;  
  459.                 a4=0;  
  460.                 return 0;  
  461.             }  
  462.     return -1;  
  463. }  



  • 14
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值