// eigenface.c, by Robin Hewitt, 2007 // // Example program showing how to implement eigenface with OpenCV // Usage: // // First, you need some face images. I used the ORL face database. // You can download it for free at // www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html // // List the training and test face images you want to use in the // input files train.txt and test.txt. (Example input files are provided // in the download.) To use these input files exactly as provided, unzip // the ORL face database, and place train.txt, test.txt, and eigenface.exe // at the root of the unzipped database. // // To run the learning phase of eigenface, enter // eigenface train // at the command prompt. To run the recognition phase, enter // eigenface test #include #include #include "cv.h" #include "cvaux.h" #include "highgui.h" //// Global variables IplImage ** faceImgArr = 0; // array of face images CvMat * personNumTruthMat = 0; // array of person numbers int nTrainFaces = 0; // the number of training images int nEigens = 0; // the number of eigenvalues IplImage * pAvgTrainImg = 0; // the average image IplImage ** eigenVectArr = 0; // eigenvectors CvMat * eigenValMat = 0; // eigenvalues CvMat * projectedTrainFaceMat = 0; // projected training faces //// Function prototypes void learn(); void recognize(); void doPCA(); void storeTrainingData(); int loadTrainingData(CvMat ** pTrainPersonNumMat); int findNearestNeighbor(float * projectedTestFace); int loadFaceImgArray(char * filename); void printUsage(); ////////////////////////////////// // main() // //void main( int argc, char** argv ) //{ // // validate that an input was specified // if( argc != 2 ) // { // printUsage(); // return; // } // // if( !strcmp(argv[1], "train") ) learn(); // else if( !strcmp(argv[1], "test") ) recognize(); // else // { // printf("Unknown command: %s\n", argv[1]); // printUsage(); // } //} ////////////////////////////////// // learn() // void learn() { int i, offset; // load training data nTrainFaces = loadFaceImgArray("train.txt"); if( nTrainFaces < 2 ) { fprintf(stderr, "Need 2 or more training faces\n" "Input file contains only %d\n", nTrainFaces); return; } // do PCA on the training faces doPCA(); // project the training images onto the PCA subspace projectedTrainFaceMat = cvCreateMat( nTrainFaces, nEigens, CV_32FC1 ); offset = projectedTrainFaceMat->step / sizeof(float); for(i=0; idata.fl + i*nEigens); projectedTrainFaceMat->data.fl + i*offset); } // store the recognition data as an xml file storeTrainingData(); } ////////////////////////////////// // recognize() // void recognize(IplImage *faceImg, CvMat * trainPersonNumMat) { int i, nTestFaces = 0; // the number of test images //CvMat * trainPersonNumMat = 0; // the person numbers during training float * projectedTestFace = 0; int iNearest, nearest, truth; // load test images and ground truth for person number //nTestFaces = loadFaceImgArray("test.txt"); //printf("%d test faces loaded\n", nTestFaces); // load the saved training data //if( !loadTrainingData( &trainPersonNumMat ) ) return; // project the test images onto the PCA subspace projectedTestFace = (float *)cvAlloc( nEigens*sizeof(float) ); // for(i=0; idata.i[i]; nearest = trainPersonNumMat->data.i[iNearest]; printf("nearest = %d\n", nearest); // } } ////////////////////////////////// // loadTrainingData() // //int loadTrainingData(CvMat ** pTrainPersonNumMat) int loadTrainingData(CvMat ** pTrainPersonNumMat) { CvFileStorage * fileStorage; int i; // create a file-storage interface fileStorage = cvOpenFileStorage( "facedata.xml", 0, CV_STORAGE_READ ); if( !fileStorage ) { fprintf(stderr, "Can't open facedata.xml\n"); return 0; } nEigens = cvReadIntByName(fileStorage, 0, "nEigens", 0); nTrainFaces = cvReadIntByName(fileStorage, 0, "nTrainFaces", 0); *pTrainPersonNumMat = (CvMat *)cvReadByName(fileStorage, 0, "trainPersonNumMat", 0); eigenValMat = (CvMat *)cvReadByName(fileStorage, 0, "eigenValMat", 0); projectedTrainFaceMat = (CvMat *)cvReadByName(fileStorage, 0, "projectedTrainFaceMat", 0); pAvgTrainImg = (IplImage *)cvReadByName(fileStorage, 0, "avgTrainImg", 0); eigenVectArr = (IplImage **)cvAlloc(nTrainFaces*sizeof(IplImage *)); for(i=0; idata.fl[iTrain*nEigens + i]; distSq += d_i*d_i / eigenValMat->data.fl[i]; // Mahalanobis //distSq += d_i*d_i; // Euclidean } if(distSq < leastDistSq) { leastDistSq = distSq; iNearest = iTrain; } } return iNearest; } ////////////////////////////////// // doPCA() // void doPCA() { int i; CvTermCriteria calcLimit; CvSize faceImgSize; // set the number of eigenvalues to use nEigens = nTrainFaces-1; // allocate the eigenvector images faceImgSize.width = faceImgArr[0]->width; faceImgSize.height = faceImgArr[0]->height; eigenVectArr = (IplImage**)cvAlloc(sizeof(IplImage*) * nEigens); for(i=0; idata.fl); cvNormalize(eigenValMat, eigenValMat, 1, 0, CV_L1, 0); } ////////////////////////////////// // loadFaceImgArray() // int loadFaceImgArray(char * filename) { FILE * imgListFile = 0; char imgFilename[512]; int iFace, nFaces=0; // open the input file if( !(imgListFile = fopen(filename, "r")) ) { fprintf(stderr, "Can\'t open file %s\n", filename); return 0; } // count the number of faces while( fgets(imgFilename, 512, imgListFile) ) ++nFaces; rewind(imgListFile); // allocate the face-image array and person number matrix faceImgArr = (IplImage **)cvAlloc( nFaces*sizeof(IplImage *) ); personNumTruthMat = cvCreateMat( 1, nFaces, CV_32SC1 ); // store the face images in an array for(iFace=0; iFacedata.i+iFace, imgFilename); // load the face image faceImgArr[iFace] = cvLoadImage(imgFilename, CV_LOAD_IMAGE_GRAYSCALE); if( !faceImgArr[iFace] ) { fprintf(stderr, "Can\'t load image from %s\n", imgFilename); return 0; } } fclose(imgListFile); return nFaces; } ////////////////////////////////// // printUsage() // void printUsage() { printf("Usage: eigenface \n", " Valid commands are\n" " train\n" " test\n"); }