CSE576 Project 4 :eigenfaces
Jacki Roberts
Turnin docs
Eigfaces.cpp: most of the additional content
Faces.cpp: eigenvector computations
Main.cpp: change to FindFace parameter list to incorporate user-specified max errors
Eigfaces.h: FindFace parm change
Main.h, Arguments.h, Main.cpp: minor changes to support an additional call to Main::computeEigenfacesAlt()
Executable: main.exe
Other documents:
.face and .user files for eigenspaces with 1-32 eigenfaces
--Of most interest: the 10-eigenface system .face and .user files.
Images:
Average face for 10-eigenface system of 25x25 pixel face images
Eigenfaces for this system
Sample eigenfaces for the speedup, using larger face dimensions.
Marked group images
group img_8267 from class
group of friends, which worked with mixed results (see discussion)
group of friends, which didn't work at all.
Cropped images
Myself -- an image that
worked well
Myself -- an image
that didn't work well.
Morphed images
Discussion
Testing Recognition with Cropped Class Images
The program's success rate improved only slightly for more than 10-12 eigenfaces, as this chart shows:
There was a slight rise at 12 over larger numbers because an image that wasn't recognized at 14 was recognized at 10 and 12. Ordinarily, I would expect the relationship to be monotonic.
While there is no single best number of eigenfaces to use, 10 seems to be a good lower bound. If the images are extremely consistent, a lower number can be used. Faces which didn't differ a lot between the nonsmiling and smiling images were recognized with one or two eigenfaces. Other were not recognized even with 32. This is because the training set is so small--there were no images with heads tilted or mouths wide open in the training set, so many of those "smiling" faces weren't even recognized as faces--for example s06. Thankfully, I only look like that on rare and very specific occasions. In several cases, but not all, the correct "smiling" faces were in the top 5 returned.
Cropping and Finding Faces
It was quite east to crop the Bush image. However, any image with faces at various distances and textureless backgrounds gave more problems. To find a face, it was necessary to restrict the max and min sharply, or to lower the acceptable error for a face. Otherwise, the code crawled while it compared hundreds of potential face matches for each pixel coordinate. Especially when I added in code to identify and remove duplicates (defined as an image that starts within 12 pixels of the upper right corner of an existing face subimage), the extra code required a huge additional computation cost.
When the face was isolated and neutral, as in the images below, the face was cleanly cropped.
When the face was exaggerated, the result got either the mouth or the eyes, but not both. It could be interesting to see whether a modified eigenface space that uses the mouth up and mouth down as separate components would be useful, as it's much easier for most people to change the shape of their lower face, but not their upper face.
Groups were a particular nightmare for getting a single stable max, min, step, or even max error value to work consistently. Especially with larger pixel sized-eigenspace images, the allowable error must be set quite high. If you use that on a simple picture, however, you will get a number of extraneous "faces", especially if you haven't implemented the low texture fix that uses the average face as a leveling function (as I did not).
The class groups were straight-forward, since all faces were face-front and at similar distances from the camera. The "smiling" faces were naturally less accurate than the neutral images. Note: any breaks in the green lines in these images are because of .gif compression for the web page.
Both images used scales of .4 to .55 and max errors of 1000.
The group image below shows several faces at different depths and angles to the camera. I had to run the process several times to get these results. A larger training set might fix the problem, as a number of the faces are rotated enough to skew far from eigenface space.
For the first image, I used min=.27, max = .43. I only got both faces shown by asking for n=14. In the second image, I used min=max=.43 and n=5. In both cases, I needed to set a face "max error" value at 900, so the function call was e.g. --findface cameragroup.tga nosmile_results10.face 800.0 0.43 0.43 0.01 mark 5 camera_marked.tga. The cropped pictures above returned results for error = 400. It is also interesting to note that the overlap that doesn't occur above does occur here. I have not tracked down that bug.
Additional:
Morphing Images
Straightforward, though I'd like to have color results. Instead of projecting down to face space, I computed the distance between the pixel values directly, and used the scale as a stepping function between each pair of pixel intensity values.
Eigenvector Speedup
Using the speedup was crucial to getting a better morph image. The one I show uses 25x25, but a more clear image would be available if I used 50x50 or larger. I did not get the speedup working in time to update the morph image.
I made the assumption that the eigenvector orders for the AATwere the same as for ATA. I don't think this is a correct assumption, so it throws the calculations off unless you use all of the available eigenfaces. This made it quite difficult to find the face on the otherwise easy Bush image.