// 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" #include "eigenface.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 IplImage ** eigenPics = 0; // eigenvectors char eig_name[20]; //// Function prototypes void learn(); void recognize(); void doPCA(); void storeTrainingData(); int loadTrainingData(CvMat ** pTrainPersonNumMat); int findNearestNeighbor(float * projectedTestFace); int loadFaceImgArray(char * filename); void convertToUImage(IplImage *fImg, IplImage *uImg); ////////////////////////////////// // learn() // void learn(char * filename) { int i, offset; // load training data nTrainFaces = loadFaceImgArray(filename); 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); //~ calcDecomp( //~ faceImgArr[i], //~ nEigens, //~ eigenVectArr, //~ pAvgTrainImg, //~ //projectedTrainFaceMat->data.fl + i*nEigens); //~ projectedTrainFaceMat->data.fl + i*offset); } // store the recognition data as an xml file storeTrainingData(); } ////////////////////////////////// // recognize() // void recognize(IplImage *faceImg) { 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) ); // project the test image onto the PCA subspace cvEigenDecomposite( faceImg, nEigens, eigenVectArr, 0, 0, pAvgTrainImg, projectedTestFace); //~ calcDecomp( //~ faceImg, //~ nEigens, //~ eigenVectArr, //~ pAvgTrainImg, //~ projectedTestFace); iNearest = findNearestNeighbor(projectedTestFace); nearest = trainPersonNumMat->data.i[iNearest]; printf("nearest = %d\n", nearest); } ////////////////////////////////// // loadTrainingData() // 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); eigenPics = (IplImage**)cvAlloc(sizeof(IplImage*) * nEigens); for(i=0; idata.fl); calcEigenFaces( nTrainFaces, faceImgArr, eigenVectArr, nEigens, pAvgTrainImg, eigenValMat->data.fl); cvNormalize(eigenValMat, eigenValMat, 1, 0, CV_L1, 0); for(i=0; idata.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; } void convertToUImage(IplImage *fImg, IplImage *uImg) { int i; float *bf; uchar *bu; CvSize size; cvGetImageRawData(fImg, (uchar**)&bf, NULL, &size); cvGetImageRawData(uImg, (uchar**)&bu, NULL, NULL); // Find the Maximum and Minimum of the pixel values float max, min; max = min = 0.0; for(i=0; i< size.width * size.height; i++) { if(max < bf[i]) max = bf[i]; if(min > bf[i]) min = bf[i]; } // Normalize the eigenface values between 0 and 255 for(i = 0; i< size.width * size.height; i++) { bu[i] = (uchar)(( 255 * (( bf[i] - min)/ (max- min)) )); } } ////////////////////////////////// // printUsage() // void printUsage() { printf("Usage: eigenface \n", " Valid commands are\n" " train\n" " test\n"); }