In this project you will create a facial recognition system. The program reduces each facial image to a vector, then uses Principal Component Analysis to find the space of faces. This space is spanned by just a few vectors, which means each face can be defined by just a set of coefficients weighting these vectors.
You are given a skeleton program that provides a sophisticated command-line interface as well as most of the image and vector classes and operations you will need. Your job will be to fill in the functions that do PCA, projection into face space, determining if a vector represents a face, verifying a user based on a face, finding a face match given a set of user face information, and finding the size and position of a face in an image.
PCA is a technique by which we reduce the dimensionality of data points. For example, consider the space of all 20 by 30 pixel grayscale images. This is 600 dimensional space because 600 data points are required to represent the values of the 600 pixels. But suppose we only consider images that are valid faces. Such images may lie in a small subspace of the set of all images. If this subspace is a hyperplane spanned by k vectors, then we can represent any point that lies on this plane with only a set of k coefficients.
To use PCA to do pattern recognition you first take a representative sample of data points and find the subspace with the desired dimensionality that best fits the sample data. This step needs to be done only once. Once it has been done, you can determine if a new point is a valid data point by projecting it onto the subspace and measuring the distance between the point and its projection.To use PCA for facial recognition we must represent each face image as a vector of pixel values. To generate this vector the face image must be cropped and scaled, and its intensity must be normalized. The cropping can either be done by hand or by searching images for faces. This second option is only possible once the face recognition algorithm has already been trained with some input faces.
The input data you will be using is divided into several sets. They are included as folders in the skeleton code zip file:
class_smiling_cropped: Already cropped images of smiling vision students, taken in class.
class_nonsmiling_cropped: Already cropped in-class images of vision students wearing their normal sullen expressions.
class_ugrads_cropped: The images of most of the students in the class from the undergrads database, already cropped.
ugrads_cropped: The first (alphabetically) hundred undergrads, already cropped.
ugrads_uncropped: 391 uncropped undergrads. You can try cropping some (or all) of these using the face finding algorithm you will write.
eigenfaces_skeleton.zip: Skeleton code
files.zip:
All the images (66.6 MB). You should unzip them and put them in the files folder of the skeleton code.
The skeleton code is large, but please take the time to get some familiarity
with the classes and methods it provides. There is a lot of useful
functionality included, like vector and image operations, which would take a
lot of time to write yourself. The program uses a simple command line
interface, and it is simple to add your own functionality in case you want to
tackle some extra credit, or add commands to facilitate your experimentation.
At the minimum you will only need to modify two files, faces.cpp, and
eigfaces.cpp, but you will still need to understand the contents of most of the
other classes.
Here is a description of the classes in the skeleton code. You will need to read this page to understand the organization of the code. It also gives information on numerous methods that you will need to call in your code, so please read it very carefully.
All the required work can be done in eigfaces.cpp and faces.cpp. The functions you must fill in are members of classes Faces and EigFaces. A Faces object stores a set of user faces loaded from images. EigFaces is derived from Faces. An EigFaces object stores a set of eigenfaces as well as the average face.
Most of the methods you will have to implement are called from main.cpp, so you should study main.cpp closely to see how these methods are used.
Each of the items below have an upper bound on the number of lines of code needed, not including comments. If you have many more lines of code for a given step than the upper bound, then you may be doing something wrong, or at least making more work for yourself. Be sure to look in vector.h, image.h, and face.h to see what useful functions are already provided for you.
Note that points will not be taken off for making your code longer than necessary, as long as it is correct and well coded. However, you should try your best not to go too far over the upper bound, as it means unnecessary work for you and will make your code more difficult to read and harder to grade.
This is a complicated problem, so don't expect to get perfect results. As you can see, I'm the only CSE 142 TA without a face:
Lines required: 78
Here are general tips, requirements, and things to watch out for that may come in handy as you are coding your project or running your experiments.
See the usage function in Main for a list of commands and their parameters. Or you can just run the program with no arguments and this usage info will be output. There are examples of every command listed in ReadMe.txt. If you add any of your own commands please modify the usage info and ReadMe.txt.
Use eigenface width and height of 25 by 25 or greater for your experiments. You can use smaller eigenfaces such as 15 by 15 for debugging so you won't have to wait a long time. Note that if the eigenfaces you use are too large, Jacobi will run too slowly to get results in any reasonable number of days (or even years!).
Always resize a Face to the proper size before loading a targa file into it. You don't need to worry about this when loading into an Image, as images just resize automatically to the size of the loaded image.
If you do anything non-obvious in your code, comment it. Otherwise your TA won't be able to figure out what you were trying to do and won't be able to give you partial credit if it has a bug.
To aid you in debugging it is helpful to output debug images that you can look at and verify that the image contains what you expect. Use the saveTarga function to save Image or Face objects to file. For images such as eigenfaces which may not have pixel values arranged neatly from zero to 255, you will have to normalize to between 0.0 and 255.0 first by calling the normalize method.
The working directory when running from inside Visual Studio is eigenfaces\files. Thus any filename arguments you give should be relative to this directory. Of course you can change the working directory if you want to.
It is recommended that you don't try computing eigenfaces or doing face detection in debug mode, your code will run too slowly. If you need to debug something you might want to modify the code to skip to the point you want to debug so that you don't have to wait too long.
Your turned-in executable MUST be compiled in Release mode, NOT debug mode!
You must complete all of the following experiments to test your code. The results of each experiment, including the answers to all the questions, should be written in your Write-up, along a discussion of why you think the experiment turned out the way it did, as well as any unexpected results.
Note that some of the experiments may require you to run a command over and over again. One way to accomplish this is to use a batch file. Or, if you wish, you can easily add your own command that takes the place of a string of commands. See the description of class Main above to find out how to do this.
Your write-up should be an HTML document. Besides describing the results of your experiments and answering the questions, you must also include sample output images. Make sure any images that need it are normalized so they can be seen clearly. As a minimum you should include:
The eigenfaces created from class images and the undergraduate images along with the average faces for these sets.
Your two images showing the results of face detection
Some results of successful and unsuccessful automatic image cropping attempts
Some examples of image recognition attempts that failed (if there were any) and some that succeeded.
Feel free to put your write-up in multiple files if you want, but make sure that they are all accessible via links from the main page.
Implement morphing. Make a video from your morphed faces using Adobe Premier. Try morphing an image away from another image instead of towards it.
Try using eigenfaces to recognize images other than faces or to recognize animal faces.
Experiment with using different numbers of eigenvectors. Find the minimum number required to still get good reconstruction results.
Implement verifyFace as described in the list of methods to implement above. Perform the following experiment:
Replace Jacobi with a routine that is fast for the huge matrices we are using. Note that since we're only using the first few eigenvectors it is a waste to compute all the others as well. You can look into using routines that only compute the eigenvectors with the largest eigenvalues. A good starting point is this copy of Numerical Recipes in pdf. You can copy and paste C code directly from the pdf files. Show some results of computing nice large eigenfaces! How big can you reasonably get before things get too slow to be practical again?
Try using PCA to do voice recognition. Talk to Dewey if you would like to borrow his voice recognition book, or a copy of the TIMIT speech database for testing. Credit will be assigned based on the quality of the result and amount of effort put into the project. Dewey did voice recognition work at JPL, so ask him if you have questions.