Contents

Simple face recognition using OpenCV

OpenCV is an open-source library for computer vision. It has hooks in C, C++ and Python, numerous artificial vision routines and is portable across systems. If you want to develop an open-source computer-vision program, OpenCV is a library of choice.

Face recognition

As a personal project, I want to build a face recognition program for videos. As a first step, I want to recognize faces in still images, where several faces are present. Two steps are necessary using common methods:

  1. Detect faces and extract them
  2. Recognize extracted faces

The first step is well documented in OpenCV wiki. For the second one, Cognotics have a nice series of articles about the theory and implementation of the eigenfaces algorithm using OpenCV. There is, however, no readily available implementation of this algorithm.

So, I decided to piece together the Cognotics articles to have a fully-functional implementation of the eigenfaces algorithm. The result is just below:

#include 
#include 
#include 
#include 
#include 

//// Global variables
int nTrainFaces = 0; // number of training images
int nEigens = 0; // number of eigenvalues
IplImage ** faceImgArr = 0; // array of face images
CvMat * personNumTruthMat = 0; //array of person numbers
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();

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]);
 }
 return 0;
}

void printUsage()
{
 printf("Usage: eigenface \n",
 "  Valid commands are\n"
 "    train\n"
 "    test\n");
}

void learn()
{
 int i;

 // 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);
 for(i=0; idata.fl + i*nEigens);
 }
 // store the recognition data as an xml file
 storeTrainingData();
}

int loadFaceImgArray(char * filename)
{
 FILE * imgListFile = 0;
 char imgFilename[512];
 int iFace, nFaces=0;

 // open the input file
 imgListFile = fopen(filename, "r");

 // 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);
 }

 fclose(imgListFile);

 return nFaces;
}

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);
}

void storeTrainingData()
{
 CvFileStorage * fileStorage;
 int i;

 // create a file-storage interface
 fileStorage = cvOpenFileStorage( "facedata.xml", 0, CV_STORAGE_WRITE );

 // store all the data
 cvWriteInt( fileStorage, "nEigens", nEigens );
 cvWriteInt( fileStorage, "nTrainFaces", nTrainFaces );
 cvWrite(fileStorage, "trainPersonNumMat", personNumTruthMat, cvAttrList(0,0));
 cvWrite(fileStorage, "eigenValMat", eigenValMat, cvAttrList(0,0));
 cvWrite(fileStorage, "projectedTrainFaceMat", projectedTrainFaceMat, cvAttrList(0,0));
 cvWrite(fileStorage, "avgTrainImg", pAvgTrainImg, cvAttrList(0,0));
 for(i=0; idata.i[i];
 nearest = trainPersonNumMat->data.i[iNearest];

 printf("nearest = %d, Truth = %d\n", nearest, truth);
 }
}

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];
 }

 if(distSq < leastDistSq)
 {
 leastDistSq = distSq;
 iNearest = iTrain;
 }
 }

 printf("%f", leastDistSq);
 return iNearest;
}

Save this code into a file named facerecog.cpp and compile it using g++ -o facerecog facerecog.cpp -lcv -lhighgui -lcvaux

comments powered by Disqus