// eigenface.c, by Robin Hewitt, 2007
// edited by Xin QIao, AUG 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 <stdio.h>
#include <string.h>
#include <math.h>
#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);
double * findNearestNeighbor(float * projectedTestFace);
int loadFaceImgArray(char * filename);
void printUsage();
//////////////////////////////////
// main()
//
int main( int argc, char** argv )
{
// validate that an input was specified
if( argc != 2 )
{
printUsage();
return -1;
}
if( !strcmp(argv[1], "train") )
learn();
else if( !strcmp(argv[1], "test") ) recognize();
else
{
printf("Unknown command: %s\n", argv[1]);
printUsage();
}
return 0;
}
//////////////////////////////////
// learn()
//
void learn()
{
int i, j, k, offset;
// load training data
nTrainFaces = loadFaceImgArray("E:\\test\\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; i<nTrainFaces; i++)
{
//int offset = i * nEigens;
cvEigenDecomposite(
(IplImage *)faceImgArr,
nEigens,
eigenVectArr,
0, 0,
pAvgTrainImg,
//projectedTrainFaceMat->data.fl + i*nEigens);
projectedTrainFaceMat->data.fl + i*offset);
}
// store the projectedTrainFaceMat as TrainFace.txt
FILE * TrainfaceFile = 0;
if( TrainfaceFile = fopen("TrainFace.txt", "w") )
{
for(j = 0 ; j < nTrainFaces ; j++){
fprintf(TrainfaceFile,"%d ", j);
for(k = 0; k < nEigens ; k++){
fprintf(TrainfaceFile, " %d : %f ", k, (projectedTrainFaceMat->data.fl + j*offset)[k] );
}
fprintf(TrainfaceFile," -1 : ? \n");
}
}
// store the recognition data as an xml file
storeTrainingData();
}
//////////////////////////////////
// recognize()
//
void recognize()
{
int i, j=0, nTestFaces = 0; // the number of test images
CvMat * trainPersonNumMat = 0; // the person numbers during training
float * projectedTestFace = 0;
// 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) );
double * sim = (double *)cvAlloc( nEigens*sizeof(double) );;
for(i=0; i<nTestFaces; i++)
{
int iNearest=0, k;
//int star[nTrainFaces];
// project the test image onto the PCA subspace
cvEigenDecomposite(
(IplImage *)faceImgArr,
nEigens,
eigenVectArr,
0, 0,
pAvgTrainImg,
projectedTestFace);
// store the projectedTestFace as TestFace.txt
FILE * TestfaceFile = 0;
if( TestfaceFile = fopen("TestFace.txt", "w") )
{
fprintf(TestfaceFile,"%d ", 0);
for(k = 0; k < nEigens ; k++){
fprintf(TestfaceFile, " %d : %f ", k, projectedTestFace[k] );
}
fprintf(TestfaceFile," -1 : ? \n");
}
sim = findNearestNeighbor(projectedTestFace);
//truth = personNumTruthMat->data.i;
//nearest = trainPersonNumMat->data.i[iNearest];
/*
//sort
int order[nTrainFaces];
order[0] = iNearest;
double temp[nTrainFaces];
for ( j = 0; j < nTrainFaces; j++){
temp[j] = sim[j];
}
for ( k = 0; k < nTrainFaces; k++){
//记录temp中最小元素的index
int result=0;
double leastSim = DBL_MAX;
//找到temp中最小元素的index,记录入result
for ( j = 0; j < nTrainFaces; j++){
if( temp[j] < leastSim ){
leastSim = temp[j];
result = j;
}
}
order = result;
//将temp中找到的最小元素置为无穷大
temp[result] = DBL_MAX;
//}
*/
printf("%d test image : \n",i+1);
for ( k = 0; k < nTrainFaces; k++)
printf("star : %d, simility : %f\n", k, sim[ k ]);
//printf("nearest = %d, Truth = %d\n\n", nearest, truth);
}
}
//////////////////////////////////
// loadTrainingData()
//
int loadTrainingData(CvMat ** pTrainPersonNumMat)
{
CvFileStorage * fileStorage;
int i;
// create a file-storage interface
fileStorage = cvOpenFileStorage( "./data/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; i<nEigens; i++)
{
char varname[200];
sprintf( varname, "eigenVect_%d", i );
eigenVectArr = (IplImage **)cvReadByName(fileStorage, 0, varname, 0);
}
// release the file-storage interface
cvReleaseFileStorage( &fileStorage );
return 1;
}
//////////////////////////////////
// storeTrainingData()
//
void storeTrainingData()
{
CvFileStorage * fileStorage;
int i;