Peter Weisbeck

Computer Vision (CSE 455), Winter 2012

Project 4: Eigenfaces

Project Abstract

Objectives

In this project, we applied PCA to find the eigenface vectors, and then used those vectors to find the "face space" of accepted faces. When looking at a new face, especially one that is not in the database, checking to see whether the face falls within the acceptable face space is how we determine if it is a face or not.

Challenges

My biggest problem stemmed from the fact that I did the optimization for the eigenfaces first, but didn't realize that I needed to normalize it to a unit vector, so all of my methods after that were producing incorrect output for a correct implementation.

Lessons Learned

I learned how facial recognition programs work, which is pretty awesome.

Implementation

The project is structured as follows:

Experiment: Recognition

Methodology

I ran a script that checked each smiling face in the database to see whether it is a face, using a database of eigenfaces containing a variable amount.

Questions

Question 1: Describe the trends you see in your plots. Discuss the tradeoffs; how many eigenfaces should one use? Is there a clear answer?

The ratio of recognized faces is interesting... I don't know how correct it is though. The number of faces dramatically increases at the start and then plateaus, I would think that it should keep on increasing (if slower) and the recognition of faces does reach its maximum (of 23) towards the end, but it isn't as much as I would have liked.

Kinda seems as if 10 is the magic number (I got 22 faces recognized with 10), although anything past that is probably fine too. What might account for the irregular number of faces being recognized is that as you add more faces, it might introduce different projections into the face space that causes the face not to be recognized.

Question 2: You likely saw some recognition errors in step 3; show images of a couple. How reasonable were the mistakes? Did the correct answer at least appear highly in the sorted results?

These are some of the faces that were not recognized. This is probably due to the dramatic transformation of the face from neutral to smiling.

Sample Results

The first image above is the average face and the rest are the eigenfaces, I think they turned out pretty well.

Experiment: Find Faces

Methodology

I found interesting images and played around with parameters to get the best number of results. I did a little conversion at the start to see how big the face of the people in the images are and take the ratio of that with the size of the eigenfaces to get a ballpark ratio of where to look for the correct parameters.

Questions

Question 1: What min_scale, max_scale, and scale step did you use for each image?

Elf: 0.45 0.50 0.01, Group: 0.8 0.85 0.01, Obama: 0.01 0.20 0.01, Class: 0.13 0.14 0.005

Question 2: Did your attempt to find faces result in any false positives and/or false negatives? Discuss each mistake, and why you think they might have occurred.

I got 7/16 of the faces in this part of the class. It appears as if a hem of dark color and then a lighter color underneath (as can be seen on the people that it mistagged and at the top where the projector screen is) gets it confused. That is usually where the eyes/eyebrows are so maybe that has something to do with it. And then for the random box to the right has a similar problem but just not as dramatic of a change in intensity.

Sample Results

main --findface elf.tga eig10.face 0.45 0.50 0.01 crop 1 cropped_elf.tga

Used the parameters given in the spec and was able to crop out the baby's face.

main --findface group\group_neutral5.tga eig10.face 0.8 0.85 0.01 mark 3 marked_group.tga

Got all of the faces in the group, although I definitely had to play around with the parameters.

main --findface obama.tga eig10.face 0.01 0.20 0.01 mark 1 marked_obama.tga

It wasn't all that hard to find Obama's face, as can be seen by the huge scan range that I am using.

main --findface group\class5.tga eig10.face 0.13 0.14 0.005 mark 16 marked_group.tga

(Open this image in a new tab to see the tagged faces.)

I got 7/16 of the faces in this part of the class. The false negatives were discussed in the above question section.

Experiment: Verify Faces

Methodology

I gathered the outputted MSE's from the compared neutral face with each smiling face, and then with a face that wasn't its own (the previous in the sequence).

Questions

Question 1: What MSE thresholds did you try? Which one worked best? What search method did you use to find it?

Well at the start I just used the default 60000, and with the data written down, I simply looked and found the threshold that would give me the least from that dataset.

Question 2: Using the best MSE threshold, what was the false negative rate? What was the false positive rate?

Using 88000 as the threshold, I got a both a false negative rate and a false positive rate of 3.

Sample Results

main --verifyface smiling_cropped\smiling-27.tga base.user nonsmiling_cropped\neutral-27 eig6.face 88000.0

main --verifyface smiling_cropped\smiling-27.tga base.user nonsmiling_cropped\neutral-28 eig6.face 88000.0

The above result is interesting because it demonstrates the ramjet scrambling property of the hunter-seeker probe. This was problematic because tipsy turtles, which we solved by varying the Stradvarius parameters.

Bells & Whistles

Fast Eigenfaces Computation

Access this function using the parameters: --fasteigenfaces <p> <width> <height> <textfile image list> <outfile for eigenfaces>

While computing the eigenfaces, the product of A and A transpose is needed because the eigenvectors of that matrix form the eigenfaces. However, the size of this matrix is huge (image height*width) and can take awhile to compute. What the speedup does is instead of multiplying the in the order A*A(t) it multiplies them A(t), which makes the resulting matrix a lot smaller, namely having its width and height the same as the number of input faces there are. After computing this product and finding the eigenvectors, the resulting eigenvectors must be multiplied by A and normalized to unit vectors to get an equivalent eigenvector of the matrix A*A(t).

It took me the longest time to figure out that I needed to make make corresponding vector a unit vector, but this makes sense because when you multiply the matrix A to transform the eigenvectors of A(t)*A to eigenvectors of A*A(t) it introduces some sort of constant factor of error (possibly unless A is a unit vector?) and the jacobi is supposed to return unit vectors, so dividing each new eigvector by its magnitude arrives at the same eigenvectors as the slower version.

Since the matrix involved in the jacobi is smaller in this faster version, the resulting speed makes this function compute a great deal faster. When computing 10 eigenfaces it took this function under a second what took the standard version about 30 seconds.

Morph Faces

Access this function using the parameters: --morphfaces <targa filename1> <targa filename2> <eigenfaces filename> <distance (0.0=first, 1.0=second, in between is a morph)> <outfile name>

Implemented the morph faces routine, which allows varying degrees of the combination of two faces.

Pretty simple function, but interesting to see the results that it produces. The following images are at distances: 0.00, 0.33, 0.66, 1.00