source: proiecte/PPPP/eigenface/eigenface.c @ 28

Last change on this file since 28 was 28, checked in by (none), 14 years ago

first try at eigenface

File size: 9.1 KB
Line 
1// eigenface.c, by Robin Hewitt, 2007
2//
3// Example program showing how to implement eigenface with OpenCV
4
5// Usage:
6//
7// First, you need some face images. I used the ORL face database.
8// You can download it for free at
9//    www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html
10//
11// List the training and test face images you want to use in the
12// input files train.txt and test.txt. (Example input files are provided
13// in the download.) To use these input files exactly as provided, unzip
14// the ORL face database, and place train.txt, test.txt, and eigenface.exe
15// at the root of the unzipped database.
16//
17// To run the learning phase of eigenface, enter
18//    eigenface train
19// at the command prompt. To run the recognition phase, enter
20//    eigenface test
21
22
23#include <stdio.h>
24#include <string.h>
25#include "cv.h"
26#include "cvaux.h"
27#include "highgui.h"
28
29
30//// Global variables
31IplImage ** faceImgArr        = 0; // array of face images
32CvMat    *  personNumTruthMat = 0; // array of person numbers
33int nTrainFaces               = 0; // the number of training images
34int nEigens                   = 0; // the number of eigenvalues
35IplImage * pAvgTrainImg       = 0; // the average image
36IplImage ** eigenVectArr      = 0; // eigenvectors
37CvMat * eigenValMat           = 0; // eigenvalues
38CvMat * projectedTrainFaceMat = 0; // projected training faces
39
40
41//// Function prototypes
42void learn();
43void recognize();
44void doPCA();
45void storeTrainingData();
46int  loadTrainingData(CvMat ** pTrainPersonNumMat);
47int  findNearestNeighbor(float * projectedTestFace);
48int  loadFaceImgArray(char * filename);
49void printUsage();
50
51
52//////////////////////////////////
53// main()
54//
55//void main( int argc, char** argv )
56//{
57//      // validate that an input was specified
58//      if( argc != 2 )
59//      {
60//              printUsage();
61//              return;
62//      }
63//
64//      if( !strcmp(argv[1], "train") ) learn();
65//      else if( !strcmp(argv[1], "test") ) recognize();
66//      else
67//      {
68//              printf("Unknown command: %s\n", argv[1]);
69//              printUsage();
70//      }
71//}
72
73
74//////////////////////////////////
75// learn()
76//
77void learn()
78{
79        int i, offset;
80
81        // load training data
82        nTrainFaces = loadFaceImgArray("train.txt");
83        if( nTrainFaces < 2 )
84        {
85                fprintf(stderr,
86                        "Need 2 or more training faces\n"
87                        "Input file contains only %d\n", nTrainFaces);
88                return;
89        }
90
91        // do PCA on the training faces
92        doPCA();
93
94        // project the training images onto the PCA subspace
95        projectedTrainFaceMat = cvCreateMat( nTrainFaces, nEigens, CV_32FC1 );
96        offset = projectedTrainFaceMat->step / sizeof(float);
97        for(i=0; i<nTrainFaces; i++)
98        {
99                //int offset = i * nEigens;
100                cvEigenDecomposite(
101                        faceImgArr[i],
102                        nEigens,
103                        eigenVectArr,
104                        0, 0,
105                        pAvgTrainImg,
106                        //projectedTrainFaceMat->data.fl + i*nEigens);
107                        projectedTrainFaceMat->data.fl + i*offset);
108        }
109
110        // store the recognition data as an xml file
111        storeTrainingData();
112}
113
114
115//////////////////////////////////
116// recognize()
117//
118void recognize(IplImage *faceImg, CvMat * trainPersonNumMat)
119{
120        int i, nTestFaces  = 0;         // the number of test images
121        //CvMat * trainPersonNumMat = 0;  // the person numbers during training
122        float * projectedTestFace = 0;
123        int iNearest, nearest, truth;
124
125        // load test images and ground truth for person number
126        //nTestFaces = loadFaceImgArray("test.txt");
127        //printf("%d test faces loaded\n", nTestFaces);
128
129        // load the saved training data
130        //if( !loadTrainingData( &trainPersonNumMat ) ) return;
131
132        // project the test images onto the PCA subspace
133        projectedTestFace = (float *)cvAlloc( nEigens*sizeof(float) );
134//      for(i=0; i<nTestFaces; i++)
135//      {
136//              int iNearest, nearest, truth;
137
138                // project the test image onto the PCA subspace
139                cvEigenDecomposite(
140                        faceImg,
141                        nEigens,
142                        eigenVectArr,
143                        0, 0,
144                        pAvgTrainImg,
145                        projectedTestFace);
146
147                iNearest = findNearestNeighbor(projectedTestFace);
148                //truth    = personNumTruthMat->data.i[i];
149                nearest  = trainPersonNumMat->data.i[iNearest];
150
151                printf("nearest = %d\n", nearest);
152//      }
153}
154
155
156//////////////////////////////////
157// loadTrainingData()
158//
159//int loadTrainingData(CvMat ** pTrainPersonNumMat)
160int loadTrainingData(CvMat ** pTrainPersonNumMat)
161{
162        CvFileStorage * fileStorage;
163        int i;
164
165        // create a file-storage interface
166        fileStorage = cvOpenFileStorage( "facedata.xml", 0, CV_STORAGE_READ );
167        if( !fileStorage )
168        {
169                fprintf(stderr, "Can't open facedata.xml\n");
170                return 0;
171        }
172
173        nEigens = cvReadIntByName(fileStorage, 0, "nEigens", 0);
174        nTrainFaces = cvReadIntByName(fileStorage, 0, "nTrainFaces", 0);
175        *pTrainPersonNumMat = (CvMat *)cvReadByName(fileStorage, 0, "trainPersonNumMat", 0);
176        eigenValMat  = (CvMat *)cvReadByName(fileStorage, 0, "eigenValMat", 0);
177        projectedTrainFaceMat = (CvMat *)cvReadByName(fileStorage, 0, "projectedTrainFaceMat", 0);
178        pAvgTrainImg = (IplImage *)cvReadByName(fileStorage, 0, "avgTrainImg", 0);
179        eigenVectArr = (IplImage **)cvAlloc(nTrainFaces*sizeof(IplImage *));
180        for(i=0; i<nEigens; i++)
181        {
182                char varname[200];
183                sprintf( varname, "eigenVect_%d", i );
184                eigenVectArr[i] = (IplImage *)cvReadByName(fileStorage, 0, varname, 0);
185        }
186
187        // release the file-storage interface
188        cvReleaseFileStorage( &fileStorage );
189
190        return 1;
191}
192
193
194//////////////////////////////////
195// storeTrainingData()
196//
197void storeTrainingData()
198{
199        CvFileStorage * fileStorage;
200        int i;
201
202        // create a file-storage interface
203        fileStorage = cvOpenFileStorage( "facedata.xml", 0, CV_STORAGE_WRITE );
204
205        // store all the data
206        cvWriteInt( fileStorage, "nEigens", nEigens );
207        cvWriteInt( fileStorage, "nTrainFaces", nTrainFaces );
208        cvWrite(fileStorage, "trainPersonNumMat", personNumTruthMat, cvAttrList(0,0));
209        cvWrite(fileStorage, "eigenValMat", eigenValMat, cvAttrList(0,0));
210        cvWrite(fileStorage, "projectedTrainFaceMat", projectedTrainFaceMat, cvAttrList(0,0));
211        cvWrite(fileStorage, "avgTrainImg", pAvgTrainImg, cvAttrList(0,0));
212        for(i=0; i<nEigens; i++)
213        {
214                char varname[200];
215                sprintf( varname, "eigenVect_%d", i );
216                cvWrite(fileStorage, varname, eigenVectArr[i], cvAttrList(0,0));
217        }
218
219        // release the file-storage interface
220        cvReleaseFileStorage( &fileStorage );
221}
222
223
224//////////////////////////////////
225// findNearestNeighbor()
226//
227int findNearestNeighbor(float * projectedTestFace)
228{
229        //double leastDistSq = 1e12;
230        double leastDistSq = DBL_MAX;
231        int i, iTrain, iNearest = 0;
232
233        for(iTrain=0; iTrain<nTrainFaces; iTrain++)
234        {
235                double distSq=0;
236
237                for(i=0; i<nEigens; i++)
238                {
239                        float d_i =
240                                projectedTestFace[i] -
241                                projectedTrainFaceMat->data.fl[iTrain*nEigens + i];
242                        distSq += d_i*d_i / eigenValMat->data.fl[i];  // Mahalanobis
243                        //distSq += d_i*d_i; // Euclidean
244                }
245
246                if(distSq < leastDistSq)
247                {
248                        leastDistSq = distSq;
249                        iNearest = iTrain;
250                }
251        }
252
253        return iNearest;
254}
255
256
257//////////////////////////////////
258// doPCA()
259//
260void doPCA()
261{
262        int i;
263        CvTermCriteria calcLimit;
264        CvSize faceImgSize;
265
266        // set the number of eigenvalues to use
267        nEigens = nTrainFaces-1;
268
269        // allocate the eigenvector images
270        faceImgSize.width  = faceImgArr[0]->width;
271        faceImgSize.height = faceImgArr[0]->height;
272        eigenVectArr = (IplImage**)cvAlloc(sizeof(IplImage*) * nEigens);
273        for(i=0; i<nEigens; i++)
274                eigenVectArr[i] = cvCreateImage(faceImgSize, IPL_DEPTH_32F, 1);
275
276        // allocate the eigenvalue array
277        eigenValMat = cvCreateMat( 1, nEigens, CV_32FC1 );
278
279        // allocate the averaged image
280        pAvgTrainImg = cvCreateImage(faceImgSize, IPL_DEPTH_32F, 1);
281
282        // set the PCA termination criterion
283        calcLimit = cvTermCriteria( CV_TERMCRIT_ITER, nEigens, 1);
284
285        // compute average image, eigenvalues, and eigenvectors
286        cvCalcEigenObjects(
287                nTrainFaces,
288                (void*)faceImgArr,
289                (void*)eigenVectArr,
290                CV_EIGOBJ_NO_CALLBACK,
291                0,
292                0,
293                &calcLimit,
294                pAvgTrainImg,
295                eigenValMat->data.fl);
296
297        cvNormalize(eigenValMat, eigenValMat, 1, 0, CV_L1, 0);
298}
299
300
301//////////////////////////////////
302// loadFaceImgArray()
303//
304int loadFaceImgArray(char * filename)
305{
306        FILE * imgListFile = 0;
307        char imgFilename[512];
308        int iFace, nFaces=0;
309
310
311        // open the input file
312        if( !(imgListFile = fopen(filename, "r")) )
313        {
314                fprintf(stderr, "Can\'t open file %s\n", filename);
315                return 0;
316        }
317
318        // count the number of faces
319        while( fgets(imgFilename, 512, imgListFile) ) ++nFaces;
320        rewind(imgListFile);
321
322        // allocate the face-image array and person number matrix
323        faceImgArr        = (IplImage **)cvAlloc( nFaces*sizeof(IplImage *) );
324        personNumTruthMat = cvCreateMat( 1, nFaces, CV_32SC1 );
325
326        // store the face images in an array
327        for(iFace=0; iFace<nFaces; iFace++)
328        {
329                // read person number and name of image file
330                fscanf(imgListFile,
331                        "%d %s", personNumTruthMat->data.i+iFace, imgFilename);
332                // load the face image
333                faceImgArr[iFace] = cvLoadImage(imgFilename, CV_LOAD_IMAGE_GRAYSCALE);
334
335                if( !faceImgArr[iFace] )
336                {
337                        fprintf(stderr, "Can\'t load image from %s\n", imgFilename);
338                        return 0;
339                }
340        }
341
342        fclose(imgListFile);
343
344        return nFaces;
345}
346
347
348//////////////////////////////////
349// printUsage()
350//
351void printUsage()
352{
353        printf("Usage: eigenface <command>\n",
354               "  Valid commands are\n"
355               "    train\n"
356               "    test\n");
357}
Note: See TracBrowser for help on using the repository browser.