OpenCV中人脸识别代码实现

本文介绍了一种基于PCA(主成分分析)的人脸识别方法,包括样本训练与人脸识别两个过程。通过OpenCV实现特征脸方法,对训练样本进行PCA降维处理并保存,识别时计算待识别图像与样本间的距离,找出最相似人脸。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

声明:本文代码来源于http://www.cognotics.com/opencv/servo_2007_series/,实现平台为Linux+OpenCV,共分为两部分:人脸检测与人脸识别。本文为后半部分的代码,关于第一部分请参见http://blog.youkuaiyun.com/liudekuan/article/details/8560251。不多言,以下给出代码及相关注解

  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include "cv.h"  
  4. #include "cvaux.h"  
  5. #include "highgui.h"  
  6.   
  7. using namespace cv;  
  8.   
  9. //globle variables  
  10. int nTrainFaces         = 0;    // number of trainning images  
  11. int nEigens             = 0;    // number of eigenvalues  
  12. IplImage** faceImgArr       = 0;    // array of face images  
  13. CvMat* personNumTruthMat    = 0;    // array of person numbers  
  14. IplImage* pAvgTrainImg      = 0;    // the average image  
  15. IplImage** eigenVectArr     = 0;    // eigenvectors  
  16. CvMat* eigenValMat      = 0;    // eigenvalues  
  17. CvMat* projectedTrainFaceMat    = 0;    // projected training faces  
  18.   
  19. //// Function prototypes  
  20. void learn();  
  21. void recognize();  
  22. void doPCA();  
  23. void storeTrainingData();  
  24. int loadTrainingData(CvMat** pTrainPersonNumMat);  
  25. int findNearestNeighbor(float* projectedTestFace);  
  26. int loadFaceImgArray(char* filename);  
  27. void printUsage();  
  28.   
  29. int main( int argc, char** argv )  
  30. {  
  31.     if((argc != 2) && (argc != 3)){  
  32.     printUsage();  
  33.     return -1;  
  34.     }  
  35.   
  36.     if( !strcmp(argv[1], "train" )){  
  37.     learn();  
  38.     } else if( !strcmp(argv[1], "test") ){  
  39.     recognize();  
  40.     } else {  
  41.     printf("Unknown command: %s\n", argv[1]);  
  42.     }  
  43.     return 0;  
  44. }  
  45.   
  46. void printUsage(){  
  47.     printf("Usage: eigenface <command>\n",  
  48.     "  Valid commands are\n"  
  49.     "    train\n"  
  50.     "    test\n"  
  51.     );  
  52. }  
  53.   
  54. void learn(){  
  55.     int i;  
  56.   
  57.     // load training data  
  58.     nTrainFaces = loadFaceImgArray("train.txt");  
  59.     if( nTrainFaces < 2){  
  60.     fprintf(  
  61.         stderr,  
  62.         "Need 2 or more training faces\n"  
  63.         "Input file contains only %d\n",  
  64.         nTrainFaces     
  65.     );  
  66.     return;  
  67.     }  
  68.   
  69.     // do PCA on the training faces  
  70.     doPCA();  
  71.   
  72.     // project the training images onto the PCA subspace  
  73.     projectedTrainFaceMat = cvCreateMat(nTrainFaces, nEigens, CV_32FC1);  
  74.     for(i = 0; i < nTrainFaces; i ++){  
  75.     cvEigenDecomposite(  
  76.         faceImgArr[i],  
  77.         nEigens,  
  78.         eigenVectArr,  
  79.         0, 0,  
  80.         pAvgTrainImg,  
  81.         projectedTrainFaceMat->data.fl + i*nEigens  
  82.     );  
  83.     }  
  84.   
  85.     // store the recognition data as an xml file  
  86.     storeTrainingData();  
  87. }  
  88.   
  89. int loadFaceImgArray(char* filename){  
  90.     FILE* imgListFile = 0;  
  91.     char imgFilename[512];  
  92.     int iFace, nFaces = 0;  
  93.   
  94.     // open the input file  
  95.     imgListFile = fopen(filename, "r");  
  96.       
  97.     // count the number of faces  
  98.     while( fgets(imgFilename, 512, imgListFile) ) ++ nFaces;  
  99.     rewind(imgListFile);  
  100.   
  101.     // allocate the face-image array and person number matrix  
  102.     faceImgArr = (IplImage **)cvAlloc( nFaces*sizeof(IplImage *) );  
  103.     personNumTruthMat = cvCreateMat( 1, nFaces, CV_32SC1 );  
  104.   
  105.     // store the face images in an array  
  106.     for(iFace=0; iFace<nFaces; iFace++){  
  107.     //read person number and name of image file  
  108.     fscanf(imgListFile, "%d %s", personNumTruthMat->data.i+iFace, imgFilename);  
  109.   
  110.     // load the face image  
  111.     faceImgArr[iFace] = cvLoadImage(imgFilename, CV_LOAD_IMAGE_GRAYSCALE);  
  112.     }  
  113.   
  114.     fclose(imgListFile);  
  115.   
  116.     return nFaces;  
  117. }  
  118.   
  119. void doPCA(){  
  120.     int i;  
  121.     CvTermCriteria calcLimit;  
  122.     CvSize faceImgSize;  
  123.   
  124.     // set the number of eigenvalues to use  
  125.     nEigens = nTrainFaces - 1;  
  126.   
  127.     // allocate the eigenvector images  
  128.     faceImgSize.width = faceImgArr[0]->width;  
  129.     faceImgSize.height = faceImgArr[0]->height;  
  130.     eigenVectArr = (IplImage**)cvAlloc(sizeof(IplImage*) * nEigens);  
  131.     for(i=0; i<nEigens; i++){  
  132.     eigenVectArr[i] = cvCreateImage(faceImgSize, IPL_DEPTH_32F, 1);  
  133.     }  
  134.   
  135.     // allocate the eigenvalue array  
  136.     eigenValMat = cvCreateMat( 1, nEigens, CV_32FC1 );  
  137.   
  138.     // allocate the averaged image  
  139.     pAvgTrainImg = cvCreateImage(faceImgSize, IPL_DEPTH_32F, 1);  
  140.   
  141.     // set the PCA termination criterion  
  142.     calcLimit = cvTermCriteria( CV_TERMCRIT_ITER, nEigens, 1);  
  143.   
  144.     // compute average image, eigenvalues, and eigenvectors  
  145.     cvCalcEigenObjects(  
  146.     nTrainFaces,  
  147.     (void*)faceImgArr,  
  148.     (void*)eigenVectArr,  
  149.     CV_EIGOBJ_NO_CALLBACK,  
  150.     0,  
  151.     0,  
  152.     &calcLimit,  
  153.     pAvgTrainImg,  
  154.     eigenValMat->data.fl  
  155.     );  
  156. }  
  157.   
  158. void storeTrainingData(){  
  159.     CvFileStorage* fileStorage;  
  160.     int i;  
  161.      
  162.     // create a file-storage interface  
  163.     fileStorage = cvOpenFileStorage( "facedata.xml", 0, CV_STORAGE_WRITE);  
  164.   
  165.     // store all the data  
  166.     cvWriteInt( fileStorage, "nEigens", nEigens);  
  167.     cvWriteInt( fileStorage, "nTrainFaces", nTrainFaces );  
  168.     cvWrite(fileStorage, "trainPersonNumMat", personNumTruthMat, cvAttrList(0, 0));  
  169.     cvWrite(fileStorage, "eigenValMat", eigenValMat, cvAttrList(0,0));  
  170.     cvWrite(fileStorage, "projectedTrainFaceMat", projectedTrainFaceMat, cvAttrList(0,0));  
  171.     cvWrite(fileStorage, "avgTrainImg", pAvgTrainImg, cvAttrList(0,0));  
  172.   
  173.     for(i=0; i<nEigens; i++){  
  174.     char varname[200];  
  175.     sprintf( varname, "eigenVect_%d", i);  
  176.     cvWrite(fileStorage, varname, eigenVectArr[i], cvAttrList(0,0));  
  177.     }  
  178.   
  179.     //release the file-storage interface  
  180.     cvReleaseFileStorage( &fileStorage );  
  181. }  
  182.   
  183. void recognize(){  
  184.     int i, nTestFaces = 0;      // the number of test images  
  185.     CvMat* trainPersonNumMat = 0;   // the person numbers during training      
  186.     float* projectedTestFace = 0;     
  187.   
  188.     // load test images and ground truth for person number  
  189.     nTestFaces = loadFaceImgArray("test.txt");      
  190.     printf("%d test faces loaded\n", nTestFaces);  
  191.       
  192.     // load the saved training data  
  193.     if( !loadTrainingData( &trainPersonNumMat ) ) return;  
  194.   
  195.     // project the test images onto the PCA subspace  
  196.     projectedTestFace = (float*)cvAlloc( nEigens*sizeof(float) );  
  197.     for(i=0; i<nTestFaces; i++){  
  198.     int iNearest, nearest, truth;  
  199.   
  200.     // project the test image onto PCA subspace  
  201.     cvEigenDecomposite(  
  202.         faceImgArr[i],  
  203.         nEigens,  
  204.         eigenVectArr,  
  205.             0, 0,  
  206.         pAvgTrainImg,  
  207.         projectedTestFace  
  208.     );  
  209.   
  210.     iNearest = findNearestNeighbor(projectedTestFace);  
  211.     truth = personNumTruthMat->data.i[i];  
  212.     nearest = trainPersonNumMat->data.i[iNearest];  
  213.   
  214.     printf("nearest = %d, Truth = %d\n", nearest, truth);  
  215.     }  
  216. }  
  217.   
  218. int loadTrainingData(CvMat** pTrainPersonNumMat){  
  219.     CvFileStorage* fileStorage;  
  220.     int i;  
  221.    
  222.     // create a file-storage interface  
  223.     fileStorage = cvOpenFileStorage( "facedata.xml", 0, CV_STORAGE_READ );  
  224.     if( !fileStorage ){  
  225.     fprintf(stderr, "Can't open facedata.xml\n");  
  226.     return 0;  
  227.     }  
  228.   
  229.     nEigens = cvReadIntByName(fileStorage, 0, "nEigens", 0);  
  230.     nTrainFaces = cvReadIntByName(fileStorage, 0, "nTrainFaces", 0);  
  231.     *pTrainPersonNumMat = (CvMat*)cvReadByName(fileStorage, 0, "trainPersonNumMat", 0);  
  232.     eigenValMat = (CvMat*)cvReadByName(fileStorage, 0, "eigenValMat", 0);  
  233.     projectedTrainFaceMat = (CvMat*)cvReadByName(fileStorage, 0, "projectedTrainFaceMat", 0);  
  234.     pAvgTrainImg = (IplImage*)cvReadByName(fileStorage, 0, "avgTrainImg", 0);  
  235.     eigenVectArr = (IplImage**)cvAlloc(nTrainFaces*sizeof(IplImage*));  
  236.     for(i=0; i<nEigens; i++){  
  237.     char varname[200];  
  238.     sprintf( varname, "eigenVect_%d", i );  
  239.     eigenVectArr[i] = (IplImage*)cvReadByName(fileStorage, 0, varname, 0);  
  240.     }  
  241.   
  242.     // release the file-storage interface  
  243.     cvReleaseFileStorage( &fileStorage );  
  244.   
  245.     return 1;  
  246. }  
  247.   
  248. int findNearestNeighbor(float* projectedTestFace){  
  249.     double leastDistSq = DBL_MAX;  
  250.     int i, iTrain, iNearest = 0;  
  251.   
  252.     for(iTrain=0; iTrain<nTrainFaces; iTrain++){  
  253.     double distSq = 0;  
  254.   
  255.     for(i=0; i<nEigens; i++){  
  256.         float d_i = projectedTestFace[i] -  
  257.         projectedTrainFaceMat->data.fl[iTrain*nEigens + i];  
  258.         distSq += d_i*d_i;  
  259.     }  
  260.   
  261.     if(distSq < leastDistSq){  
  262.         leastDistSq = distSq;  
  263.         iNearest = iTrain;  
  264.     }  
  265.     }  
  266.   
  267.     return iNearest;  
  268. }  

代码解析:

        OpenCV实现了基于PCA的特征脸人脸识别方法,相关理论可参考Paul Viola和Michael Jones于2001年发表的《Rapid Object Detection using a Boosted Cascade of SimpleFeatures》。整个算法又分为样本训练和人脸识别两个过程,在上述代码中,分别通过函数learn()与recognize()来实现。在样本训练阶段,将样本库中的人脸图像转换为特征向量表示,并投影到PCA子空间,最终将这些向量数据保存到中间文件facedata.xml中。而在识别阶段,同样将待识别的人脸图像使用PCA子空间的向量表示,通过计算待识别图像的向量与样本中的向量之间的距离,寻找其中最相近的人脸图像,作为识别结果。

        需要说明的是,在代码中训练样本图像及待识别的图像分别通过文本文件train.txt和test.txt记录,所用图像均为pgm格式,train.txt及test.txt中的内容如下所示:

其中,在这两个文件中,每一行记录一幅人脸图像。每条记录开始的数字表示人的序号,紧跟其后的则是此照片的存储路径。显然,此例在训练样本时只使用了序号为1,2,4三个人的第一幅照片,而识别时则对这三个人的多幅人脸图像进行了识别。其最终的识别结果如下所示:

nearest表示最相似的样本图像的序号,而Truth则表示待识别图像的序号。当二者相同时,表示正确识别,否则识别错误。


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值