Previous Contents Next

Chapter 10  The Covariance Approach to Recognition:

How can we identify a person we are looking at with a video camera quickly? This has a lot of applications to maintaining secure access to an industrial site among other things. The technology here is based on what are called eigenfaces , a nice use of a thing called eigenvectors . We can also use these ideas to introduce the idea of searching a huge collection of images (such as NASA has stored at various sites) by the use of what might be called eigenimages .

10.1  The Basic Plan:

The idea here is pretty straightforward. Here are the steps:

10.1.1   Collect Images:

For the MTH SC 450 class during the Fall of 2000, we took 52 pictures of the people in the class. There were 11 students in the class and we added pictures of the instructor Jim, his wife Pauli and daughter Qaitlin. We took 5 pictures per person. We used 4 of these to create what might be called an average image of each person. We tried to make these first 4 pictures sort of uniform. Our approach was to take each picture from the same distance with the class room wall ( a nicely uniform blah color ) as the background. Each of the 4 pictures were supposed to be a bit different; lookng straightforward but with different facial expressions and so forth. The fifth picture was to be something different. Here each person looked to the side or something so that the fifth image was very distinct from the average of the first four.

We got all the pictures on a Kodak PhotoCD which turned out to be jpeg files that were fairly big, 1500 by 1000. So we preprocessed these in various ways to get images we would use in our recognition algorithm.

10.1.2  The Original Pauli Images:

For example, here are the original four images of the domestic engineer and goddess Pauli: these can be seen in Figure  10.1, Figure  10.2, Figure  10.3 and Figure  10.4.


Figure 10.1: Pauli Image 1





Figure 10.2: Pauli Image 2





Figure 10.3: Pauli Image 3





Figure 10.4: Pauli Image 4



Now the images you see are rotated -90 degrees from what was supplied on the CDROM and then resized to 1/8 of the original size. This resulted in a file size of 192 by 128. So how do we do this in Matlab? First, we would read in an image like so:
%read in the jpeg files from disk
>>I1 = imread('image1.jpg');
>>I2 = imread('image2.jpg');
>>I3 = imread('image3.jpg');
>>I4 = imread('image4.jpg');
We would then rotate the images and resize them, but the details of that code are important right now. So let's just assume the images we read in are the right size and orientation for now.

This reads the jpeg files into internal Matlab representations which consist of 192 by 128 three dimensional row vectors of the form [r, g, b]. The r, g and b values are of data type uint8 which is what is known as an unsigned integer of size 8. This means that an r value is represented by a string of 8 binary bits of the form [b1,b2,b3,b4,b5,b6,b7,b8] where each bit bi can be 0 or 1. This bit string is then interpreted as
b1*27 + b2*26 + b3*25 + b4*24 + b5*23 + b6*22 + b7*21 + b8

or vice-versa depending on how the computer architecture is set up.

This means that the smallest value is 0 and the largest is 255. The r is called the red value; the g is the green value and the last number of the triple, b is the blue value. The various combinations of these integers are then mapped into colors using a variety of color models. We thus call this the RGB color model for obvious reasons. The triple (0,0,0) is usually black and the triple (255,255,255) is white. For example, the entry at I1(42,67) might be the vector [217, 37, 98].

10.1.3  Computing the Pauli Average Image:

Matlab does not allow us to add data of type unit8 so to compute the average image, we convert the [r,g,b] values in the image matrices to double, manipulate as we desire and then convert back to uint8 to display. The Matlab code might be
% convert to double
>>ID1 = double(I1);
>>ID2 = double(I2);
>>ID3 = double(I3);
>>ID4 = double(I4);

% compute average
>> AV = (ID1+ID2+ID3+ID4)/4.0;
To display this average, we would type:
image( uint8(AV) );
The average of the domestic goddess images can be seen in Figure  10.5.


Figure 10.5: The Pauli Image



10.1.4  The Pauli Test Image:

Now the fifth image will not be used in the computation of an image and we will see later how we use this to test our recognition engine's accuracy.


Figure 10.6: The Pauli Test Image



10.2  Image Processing:

The 13 different people with their 4 images apiece thus give us 52 different images which are converted by the process above to 3 dimensional matrices of double. So there are a lot of numbers for each image!

Call these prepocessed images Ai.

10.2.1  Compute the Average of All Images:

We just compute the average of all the images as follows:
S =
1
52
5
å
p=1
2 Ap

This image looks like Figure  10.7:


Figure 10.7: The Average Image



10.2.2  Compute Difference Images:

Next, we compute the difference image
Di = Ai - S

10.2.3  Convert Image Matrices to Vectors:

Now these difference images consist of [r,g,b] triples of double each of which lie between -.75 × 255 and .75 × 255. So it is possible for some of the values in these difference triples to be negative. We will map these raw differences to the interval [0, 255] via
[r,g,b] ®
([r,g,b] + .75 × 255) ×
2
3

10.2.4  Convert The Difference Images to Base 255 Doubles:

We will convert these matrices of [r,g,b] type data to vectors as follows: first convert to a base 255 number:
[r,g,b] ® r × 2552 + g × 255 + b

Next, scale this to be in [[0,1]:
[r,g,b] ®
[r,g,b] ×
1
2553

We call these new matrices of double only Mi.

10.2.5  Convert the Double Matrices to Vectors:

We convert the matrix p by q matrix M to a vector V of size p × q by 1 as follows: for each row i and column j, we set
V(i-1)q + j = Mi,j

Each of the matrices Mi is converted in this fashion into a vector di.

These vectors are quite large!

10.2.6  Compute the Covariance Matrix:

Now find the covariance matrix
C =
1
52
A AT

where A is the 192 × 128 by 52 matrix
A = [d1 | d2 | ··· | d52]

This makes the matrix A AT 192 × 128 by 192 × 128 -- much to large for ease of computation!

10.2.7  Compute Eigenvectors of AT A:

Theory tells us that the eigenvectors and eigenvalues of the covariance matrix are important for image recognition. However, finding these things for such a huge matrix is way too hard! It turns out the eigenvalues and eigenvectors of the smaller 52 by 52 matrix AT A are just what we need. There are at most 52 of these and theory says the eigenvalues are nonnegative and the eigenvectors are 90 degrees apart. If we call these eigenvectors
v1 , ... , v52

then the vectors
A v1 , ... , A v52

turn out to be eigenvectors for the covariance matrix. These are called eigenfaces .

Now for all of our 52 images, we can do these computations and we can see the first ten resulting eigenfaces in Figure  10.8 to Figure  10.17.


Figure 10.8: EigenImage 1





Figure 10.9: EigenImage 2





Figure 10.10: EigenImage 3





Figure 10.11: EigenImage 4





Figure 10.12: EigenImage 5





Figure 10.13: EigenImage 6





Figure 10.14: EigenImage 7





Figure 10.15: EigenImage 8





Figure 10.16: EigenImage 9





Figure 10.17: EigenImage 10



10.2.8  Find Feature Vectors:

Now project each original difference vector di onto the subspace determined by a small number of these eigenfaces. For example, difference image d3 might look like
d3 = .22*Av1 + .34*Av2 -.67*Av3 + 46.7*Av4 + Z

where the first four pieces is the portion of d3 that lies in the plane determined by the first four eigenfaces and Z is the part of d3 that lies out of this plane. So we could associate d3 with a small vector called a feature vector:
f =
.22
.34
-.67
46.7

We can compute feature vectors for all of the 52 difference vectors for a given number of eigenvectors. For our problem of 52 images, we have usually chosen 25 eignevectors. Note in effect, we are assigning a small 25 dimensional vector to each large original image.

10.2.9  Compute Class Vectors:

Take the four feature vectors for each person and average them. This average feature vector is called the class vector for that face.

10.2.10  Compute The Test Feature Vector:

Now take a new picture of a person in the original group and convert it to a difference vector like usual.

For example, the test image of the domestic engineer and goddess Pauli is given in Figure  10.6 as previously mentioned. Then find its feature vector and calculate the the distance from this feature vector to all the class vectors. If it is sufficiently close to a class vector, we can say it is an image from the image class for the person the class represents.

For the Pauli test image, the projection of its difference vector to the eigenface subspace can be seen in Figure  10.18.


Figure 10.18: The Projected Pauli Test Image



Now this is just a start at this big subject of facial recognition. We can also use artificial neural technology and other things. This technique is statistically based and you really need some tools like Matlab to pull it off!

Also, how would we choose feature vectors so that we can describe all of the images in the NASA database in such a way that we could use search engines? We would like to be able to query the data base like this: Find us all images of the planet mars that have a spaceship like object in orbit . We have very little clue how to do this but techniques like the one discussed above and many others are being actively considered.

10.3  Implementing The Basic Plan in Matlab:

Now let's begin the task of putting together our implementation of the Covariance approach to Object Recognition using Matlab.

Currently, our implementation requires the following scripts:

10.4  Using the Functions In a Matlab Session:

A typical Matlab session is as follows:
% let's assume you already have the image files in 
% the right size stored on disk
%

%
%  set up paths
%
>> path(path,'/local2/petersj/eigenfaces/Images');
If not, we would have called the function PrcessFiles with code:

ProcessFiles.m
 1 function ProcessFiles(name)
 2 %
 3 % process files in given directory name
 4 %
 5 
 6 %
 7 %
 8 %
 9 cd(name);
10 
11 %
12 % read in full images
13 %
14 I1 = imread('image1.jpg');
15 I2 = imread('image2.jpg');
16 I3 = imread('image3.jpg');
17 I4 = imread('image4.jpg');
18 %
19 % rotate images -90 degrees
20 %
21 IR1 = imrotate(I1,-90);
22 IR2 = imrotate(I2,-90);
23 IR3 = imrotate(I3,-90);
24 IR4 = imrotate(I4,-90);
25 %
26 % resize images to 1/8 full size
27 %
28 IR1125 = imresize(IR1,.125);
29 IR2125 = imresize(IR2,.125);
30 IR3125 = imresize(IR3,.125);
31 IR4125 = imresize(IR4,.125);
32 %
33 % write out resized images to files
34 %
35 imwrite(IR1125,'image1125.jpg');
36 imwrite(IR2125,'image2125.jpg');
37 imwrite(IR3125,'image3125.jpg');
38 imwrite(IR4125,'image4125.jpg');
39 
40 cd('..');


syntax highlighted by Code2HTML, v. 0.8.8b

We then need to process things in the directories that store the files. We will use this function: function Av = ProcessAllDirectories which has code:

ProcessAllDirectories.m
 1 function Av = ProcessAllDirectories
 2 
 3 p = 192;
 4 q = 128;
 5 Av = zeros(p,q,3,13);
 6 
 7 B = GetDirectoryAverage('bayless');
 8 Av(1:p,1:q,1:3,1) = B;
 9 
10 B = GetDirectoryAverage('cole');
11 Av(1:p,1:q,1:3,2) = B;
12 
13 B = GetDirectoryAverage('digiuseppe');
14 Av(1:p,1:q,1:3,3) = B;
15 
16 B = GetDirectoryAverage('elmore');
17 Av(1:p,1:q,1:3,4) = B;
18 
19 B = GetDirectoryAverage('fawcett');
20 Av(1:p,1:q,1:3,5) = B; 
21 
22 B = GetDirectoryAverage('harris');
23 Av(1:p,1:q,1:3,6) = B;
24 
25 B = GetDirectoryAverage('jim');
26 Av(1:p,1:q,1:3,7) = B;
27 
28 B = GetDirectoryAverage('kashema');
29 Av(1:p,1:q,1:3,8) = B;
30 
31 B = GetDirectoryAverage('mcleod');
32 Av(1:p,1:q,1:3,9) = B;
33 
34 B = GetDirectoryAverage('pauli');
35 Av(1:p,1:q,1:3,10) = B;
36 
37 B = GetDirectoryAverage('qaitlin');
38 Av(1:p,1:q,1:3,11) = B;
39 
40 B = GetDirectoryAverage('terry');
41 Av(1:p,1:q,1:3,12) = B;
42 
43 B = GetDirectoryAverage('wilkins');
44 Av(1:p,1:q,1:3,13) = B;


syntax highlighted by Code2HTML, v. 0.8.8b

This uses the function function Av = GetDirectoryAverage(name) to do the work which has source:

GetDirectoryAverage.m
 1 function Av = GetDirectoryAverage(name)
 2 %
 3 % get average of images in directory
 4 %
 5 
 6 %
 7 % go to directory
 8 %
 9 cd(name);
10 
11 %
12 %  read in rotated 1/8 scale images
13 %
14 IR1125 = imread('image1125.jpg');
15 IR2125 = imread('image2125.jpg');
16 IR3125 = imread('image3125.jpg');
17 IR4125 = imread('image4125.jpg');
18 
19 %
20 % convert to doubles
21 %
22 ID1 = double(IR1125);
23 ID2 = double(IR2125);
24 ID3 = double(IR3125);
25 ID4 = double(IR4125);
26 
27 %
28 % write double images to files
29 %
30 fd = fopen('dimage1','w');
31 fwrite(fd,ID1,'double');
32 fclose(fd);
33 
34 fd = fopen('dimage2','w');
35 fwrite(fd,ID2,'double');
36 fclose(fd);
37 
38 fd = fopen('dimage3','w');
39 fwrite(fd,ID3,'double');
40 fclose(fd);
41 
42 fd = fopen('dimage4','w');
43 fwrite(fd,ID4,'double');
44 fclose(fd);
45 
46 %
47 % Find average
48 %
49 Av = (ID1+ID2+ID3+ID4)/4.0;
50 
51 cd('..');


syntax highlighted by Code2HTML, v. 0.8.8b

This function will compute the double versions of the images and save them to disk as dimage<k> for k  1:4 and compute the average and return it to the matlab session. So to do all this we just call the ProcessAllDirectories function:
%
% Process all directories, save double versions to
% disk and compute averages and store in 
% Av which is 192 x 128 x 3 x 13
%

>> Av = ProcessAllDirectories
And get the average by calling ComputeAverage which finds the average for all the images. This function has the source:

ComputeAverage.m
 1 function Average = ComputeAverage(Av)
 2 
 3 %
 4 % Av is 192 x 128 x 3 x 13
 5 %
 6 [p,q,r,s] = size(Av);
 7 Average = zeros(p,q,r);
 8 for count = 1:s
 9   Average = Average + Av(1:p,1:q,1:3,count);
10 end
11 Average = Average/s;


syntax highlighted by Code2HTML, v. 0.8.8b

The matlab call is
>> average = ComputeAverage;
\end{verbatgim}

If we want to, we can then display our average by typing
 
\begin{verbatim}
%
% Display average
%
>> image( uint8(average));
For later use, we can write this to disk with these lines:
%
% write average to disk
%
fd = fopen('average','w');
fwrite(fd,average,'double');
fclose(fd);
Next, we need to compute the difference images and convert them to vectors: we do this with a call to the function function [diff,v]= GetDiffs(name,S,Average) which has code:

GetDiffs.m
 1 function [diff,v]= GetDiffs(name,S,Average)
 2 %
 3 % get image-average of images in directory
 4 %
 5 
 6 %
 7 % go to directory
 8 %
 9 cd(name);
10 
11 %
12 %  read in rotated 1/8 scale images
13 %
14 IR1125 = imread('image1125.jpg');
15 IR2125 = imread('image2125.jpg');
16 IR3125 = imread('image3125.jpg');
17 IR4125 = imread('image4125.jpg');
18 
19 %
20 % convert to doubles
21 %
22 ID1 = double(IR1125);
23 ID2 = double(IR2125);
24 ID3 = double(IR3125);
25 ID4 = double(IR4125);
26 
27 %
28 % Find differences
29 %
30 [p,q,s] = size(ID1);
31 r = p*q;
32 diff = zeros(p,q,s,4);
33 diff(1:p,1:q,1:3,1) = ID1-Average;
34 diff(1:p,1:q,1:3,2) = ID2-Average;
35 diff(1:p,1:q,1:3,3) = ID3-Average;
36 diff(1:p,1:q,1:3,4) = ID4-Average;
37 
38 %
39 % convert rgb triples to doubles
40 % now the diff's are in the range (-.75*255, .75*255)
41 % the functoion rgb2double expects to see an
42 % input with entries in the range [0,1]
43 % so we process as 
44 % (diff(1:p,1:q,1:3,*)+ .75*255)*(2.0/3.0)
45 %
46 m1 = rgb2double((diff(1:p,1:q,1:3,1)+ .75*255)*(2.0/3.0));
47 m2 = rgb2double((diff(1:p,1:q,1:3,2)+ .75*255)*(2.0/3.0));
48 m3 = rgb2double((diff(1:p,1:q,1:3,3)+ .75*255)*(2.0/3.0));
49 m4 = rgb2double((diff(1:p,1:q,1:3,4)+ .75*255)*(2.0/3.0));
50 
51 %
52 % convert to vectors
53 %
54 [p,q] = size(m1);
55 r = p*q;
56 v = zeros(r,4);
57 v(1:r,1) = transpose(matrix2vector(m1));
58 v(1:r,2) = transpose(matrix2vector(m2));
59 v(1:r,3) = transpose(matrix2vector(m3));
60 v(1:r,4) = transpose(matrix2vector(m4));
61 
62 cd('..');


syntax highlighted by Code2HTML, v. 0.8.8b

The Matlab lines to do this are do directory by directory:
%
% so get all diffs
%
>> S = size(average);
>> [diff1,v1]= GetDiffs('bayless'   ,S,average   );
>> [diff2,v2]= GetDiffs('cole'      ,S,average   );
>> [diff3,v3]= GetDiffs('digiuseppe',S,average   );
>> [diff4,v4]= GetDiffs('elmore'    ,S,average   );
>> [diff5,v5]= GetDiffs('fawcett'   ,S,average   );
>> [diff6,v6]= GetDiffs('harris'    ,S,average   );
>> [diff7,v7]= GetDiffs('jim'       ,S,average   );
>> [diff8,v8]= GetDiffs('kashema'   ,S,average   );
>> [diff9,v9]= GetDiffs('mcleod'    ,S,average   );
>> [diff10,v10]= GetDiffs('pauli'     ,S,average   );
>> [diff11,v11]= GetDiffs('qaitlin'   ,S,average   );
>> [diff12,v12]= GetDiffs('terry'     ,S,average   );
>> [diff13,v13]= GetDiffs('wilkins'   ,S,average   );
Next, we set up the matrix of difference vectors T:
%
% Set Up Difference Matrix
%
>> [p,q] = size(v1);
>> T = zeros(p,52);
>> T(1:p,1:4) = v1;
>> T(1:p,5:8) = v2;
>> T(1:p,9:12) = v3; 
>> T(1:p,13:16) = v4; 
>> T(1:p,17:20) = v5;
>> T(1:p,21:24) = v6; 
>> T(1:p,25:28) = v7; 
>> T(1:p,29:32) = v8; 
>> T(1:p,33:36) = v9; 
>> T(1:p,37:40) = v10; 
>> T(1:p,41:44) = v11; 
>> T(1:p,45:48) = v12; 
>> T(1:p,49:52) = v13; 
Now we can compute the covariance matrix itself:
%
% Find Covariance
%
>> TT = transpose(T);
>> W = (TT*T)/52.0;
We can then write it to disk:
%
% write covariance to disk
%
fd = fopen('covariance','w');
fwrite(fd,W,'double');
fclose(fd);
Note if we wanted to read it back, we would type
fd = fopen('covariance','r');
S = size(W);
W = fread(fd,S,'double');
Then we find the first 20 eigenvalues and associated eigenvectors:
>> [EigenVs,EigenVals] = eigs(W,20);
>> EigenVals

EigenVals =

   1.0e+03 *

  Columns 1 through 7 

    6.2256         0         0         0         0         0         0
         0    0.1008         0         0         0         0         0
         0         0    0.0350         0         0         0         0
         0         0         0    0.0226         0         0         0
         0         0         0         0    0.0173         0         0
         0         0         0         0         0    0.0109         0
         0         0         0         0         0         0    0.0102
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0

  Columns 8 through 14 

         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
    0.0086         0         0         0         0         0         0
         0    0.0073         0         0         0         0         0
         0         0    0.0065         0         0         0         0
         0         0         0    0.0055         0         0         0
         0         0         0         0    0.0052         0         0
         0         0         0         0         0    0.0048         0
         0         0         0         0         0         0    0.0044
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0
         0         0         0         0         0         0         0

  Columns 15 through 20 

         0         0         0         0         0         0
         0         0         0         0         0         0
         0         0         0         0         0         0
         0         0         0         0         0         0
         0         0         0         0         0         0
         0         0         0         0         0         0
         0         0         0         0         0         0
         0         0         0         0         0         0
         0         0         0         0         0         0
         0         0         0         0         0         0
         0         0         0         0         0         0
         0         0         0         0         0         0
         0         0         0         0         0         0
         0         0         0         0         0         0
    0.0040         0         0         0         0         0
         0    0.0037         0         0         0         0
         0         0    0.0036         0         0         0
         0         0         0    0.0034         0         0
         0         0         0         0    0.0032         0
         0         0         0         0         0    0.0029
Then we can compute the EigenImages with a call to function EI = GetEigenImages(n,T,EigenVs) with code:

GetEigenImages.m
 1 function EI = GetEigenImages(n,T,EigenVs)
 2 
 3 [p,q] = size(T);
 4 [r,s] = size(EigenVs);
 5 EI = zeros(p,n);
 6 for count = 1:n
 7   A = T*EigenVs(1:r,count);
 8   length = norm(A);
 9   EI(1:p,count) = A/length;
10 end


syntax highlighted by Code2HTML, v. 0.8.8b

We type the following Matlab lines:
>> EI = GetEigenImages(10,T,EigenVs);
Next, we get the feature vectors by calling function F = GetFeatureVectors(n,v,EI) which has code:

GetFeatureVectors.m
1 function F = GetFeatureVectors(n,v,EI)
2 
3 F = zeros(n,4);
4 [p,q] = size(EI);
5 for count = 1:4
6   for row = 1:n
7       F(row,count) = transpose(v(1:p,count))*EI(1:p,row);
8     end
9 end


syntax highlighted by Code2HTML, v. 0.8.8b

In Matalb we type:
>> F = zeros(20,52);
>> F(1:20,1:4) = GetFeatureVectors(20,v1,EI);
>> F(1:20,5:8) = GetFeatureVectors(20,v2,EI); 
>> F(1:20,9:12) = GetFeatureVectors(20,v3,EI);
>> F(1:20,13:16) = GetFeatureVectors(20,v4,EI); 
>> F(1:20,17:20) = GetFeatureVectors(20,v5,EI);
>> F(1:20,21:24) = GetFeatureVectors(20,v6,EI);
>> F(1:20,25:28) = GetFeatureVectors(20,v7,EI); 
>> F(1:20,29:32) = GetFeatureVectors(20,v8,EI);
>> F(1:20,33:36) = GetFeatureVectors(20,v9,EI); 
>> F(1:20,37:40) = GetFeatureVectors(20,v10,EI);
>> F(1:20,41:44) = GetFeatureVectors(20,v11,EI); 
>> F(1:20,45:48) = GetFeatureVectors(20,v12,EI);  
>> F(1:20,49:52) = GetFeatureVectors(20,v13,EI);
So for example the feature vector for the first image in the first directory is
>> F(1:20,1)

ans =

  -85.8201
   -9.7383
   -1.3781
    4.3543
    0.5797
    3.0650
    1.0536
    2.2167
   -1.0532
   -0.1967
   -1.0027
    0.1949
    0.0793
    0.3115
    0.2228
   -1.9004
   -1.0676
    0.2727
    1.2976
   -0.6332
In this work we also use some other utility functions: matrix2vector, rgb2double and vector2matrix with codes

matrix2vector.m
 1 function V = matrix2vector(A)
 2 %
 3 % A is N x M matrix of doubles
 4 % we will convert as follows:
 5 % A(p,q) ==> V((p-1)*M + q
 6 % So first row of A goes to V(1) ...V(M)
 7 %    second row of A goes to V((M+1) to V(2M)
 8 %    last row of A goes to V( (N-1)*M ) to V(N*M)
 9 %
10 [N,M] = size(A);
11 size(A);
12 for p=1:N
13   for q=1:M
14     k = (p-1)*M+q;
15     V(k) = A(p,q);
16   end
17 end


syntax highlighted by Code2HTML, v. 0.8.8b rgb2double.m
 1 function B = rgb2double(A)
 2 %
 3 % A is M x N x 3 data
 4 % Each entry in A is a rgb triple, [r, g, b]
 5 % r, g and b are in [0,255]
 6 % The result is a M x N matrix B
 7 % whose entries are doubles given by
 8 % r* 256^2 + g*256 + b
 9 % which can be done more efficiently as
10 % 256*(256*r + g) + b
11 %
12 [M,N,P] = size(A);
13 R = 256*256*256;
14 B = zeros(M,N);
15 size(B);
16 for j=1:N
17   B(1:M,j) =  ( 256*( A(1:M,j,1)*256+A(1:M,j,2) ) + A(1:M,j,3))/R;
18 end


syntax highlighted by Code2HTML, v. 0.8.8b vector2matrix.m
 1 function A = vector2matrix(V,N,M)
 2 %
 3 % V is a N*M vector which will be
 4 % converted back to a N x M matrix of 
 5 % [r g b] values
 6 % we will convert as follows:
 7 % for index p in V, 
 8 %   V(p) =  (r*256^2 + g*256 + b)/256^3
 9 %   scale by 256^3 giving
10 %   x = r*256^2 + g*256 + b
11 %   compute 
12 %   y = x/256 = r*256 + g + fraction b/256
13 %   convert to int
14 %   yint = double(int16(y)) = r*256+g
15 %   compute 
16 %   b = x - 256*yint
17 %   compute
18 %   z = y/256 = r + g/256 + b/256^2
19 %   convert to int 
20 %   r = double(int16(z))
21 %   compute
22 %   g = yint - 256*r 
23 %
24 P = N*M;
25 A = zeros(N,M,3);
26 for n=1:N
27   for m = 1:M
28     p = (n-1)*M+m;
29     % V(p) is a double
30     x = V(p)*256*256*256;
31     y = x/256;
32     yint = double(int32(y));
33     b = x - 256*yint;
34     z = y/256;
35     r = double(int32(z));
36     g = yint - 256*r;
37     A(n,m,1) = r;
38     A(n,m,2) = g;
39     A(n,m,3) = b;
40     %check = (r*256*256+g*256+b)/(256*256*256)
41     %check2 = V(p) - check
42   end   
43 end


syntax highlighted by Code2HTML, v. 0.8.8b

10.5  Using the Build Functions:

%
%  A new set of scripts
%

%
%  set up paths
%
>> path(path,'/local2/petersj/eigenfaces/Images');

%
% Let's semi automate our building of the 
% covariance matrix
%
% we use the function BuildCovariance()
% So to build the covariance matrix, we just call this
% function.  We have put in some printed messages so we
% don't get bored looking at the prompt!!
% 
>> BuildCovariance(192,128);
process all directories
Getting Directory Averages in directory
bayless
Getting Directory Averages in directory
cole
Getting Directory Averages in directory
digiuseppe
Getting Directory Averages in directory
elmore
Getting Directory Averages in directory
fawcett
Getting Directory Averages in directory
harris
Getting Directory Averages in directory
jim
Getting Directory Averages in directory
kashema
Getting Directory Averages in directory
mcleod
Getting Directory Averages in directory
pauli
Getting Directory Averages in directory
qaitlin
Getting Directory Averages in directory
terry
Getting Directory Averages in directory
wilkins
get full average
write average to disk
Get all difference images
Getting Difference Images in directory
bayless
    read in double images from disk
    compute double difference images
    convert double difference images to matrices
    compute matrices to vectors
     write Vectors to disk
Getting Difference Images in directory
cole
    read in double images from disk
    compute double difference images
    convert double difference images to matrices
    compute matrices to vectors
     write Vectors to disk
Getting Difference Images in directory
digiuseppe
    read in double images from disk
    compute double difference images
    convert double difference images to matrices
    compute matrices to vectors
     write Vectors to disk
Getting Difference Images in directory
elmore
    read in double images from disk
    compute double difference images
    convert double difference images to matrices
    compute matrices to vectors
     write Vectors to disk
Getting Difference Images in directory
fawcett
    read in double images from disk
    compute double difference images
    convert double difference images to matrices
    compute matrices to vectors
     write Vectors to disk
Getting Difference Images in directory
harris
    read in double images from disk
    compute double difference images
    convert double difference images to matrices
    compute matrices to vectors
     write Vectors to disk
Getting Difference Images in directory
jim
    read in double images from disk
    compute double difference images
    convert double difference images to matrices
    compute matrices to vectors
     write Vectors to disk
Getting Difference Images in directory
kashema
    read in double images from disk
    compute double difference images
    convert double difference images to matrices
    compute matrices to vectors
     write Vectors to disk
Getting Difference Images in directory
mcleod
    read in double images from disk
    compute double difference images
    convert double difference images to matrices
    compute matrices to vectors
     write Vectors to disk
Getting Difference Images in directory
pauli
    read in double images from disk
    compute double difference images
    convert double difference images to matrices
    compute matrices to vectors
     write Vectors to disk
Getting Difference Images in directory
qaitlin
    read in double images from disk
    compute double difference images
    convert double difference images to matrices
    compute matrices to vectors
     write Vectors to disk
Getting Difference Images in directory
terry
    read in double images from disk
    compute double difference images
    convert double difference images to matrices
    compute matrices to vectors
     write Vectors to disk
Getting Difference Images in directory
wilkins
    read in double images from disk
    compute double difference images
    convert double difference images to matrices
    compute matrices to vectors
     write Vectors to disk
Set up T matrix: holds all difference vectors
write T to disk
Find Covariance
Write covariance to disk

%
%  Next we build the recognition engine
%
>> BuildRecognition(52,192,128,25);
   read in the covariance matrix
   read in the difference vectors

Get

N =

    25

eigenvalues and eigenvectors

eigs =

   1.0e+03 *

    6.2256
    0.1008
    0.0350
    0.0226
    0.0173
    0.0109
    0.0102
    0.0086
    0.0073
    0.0065
    0.0055
    0.0052
    0.0048
    0.0044
    0.0040
    0.0037
    0.0036
    0.0034
    0.0032
    0.0029


stopcrit =

   1.9147e-15

==========================
Get EigenImages
write eigenImages to disk
Get Feature Vectors
write Feature Vectors to disk
Get Class Vectors
write Class Vectors to disk

%
% Now read in average and EigenImages
%

>> fd = fopen('EigenImages');
>> EI = fread(fd,[192*128 25],'double');
>> fclose(fd);
>> size(EI)

ans =

       24576          25

>> fd = fopen('average');
>> fclose(fd);                   
>> average = ReadDoubleImages(192,128,'average');
>> size(average)

ans =

   192   128     3

%
% read in ClassVectors
%
>> fd = fopen('ClassVectors');
>> ClassVectors = fread(fd,[25 13],'double');
>> size(ClassVectors)

ans =

    25    13

%
% Now see if we can classify the test image in  say 'jim'
%
>> dist = TestImage(192,128,'jim','test.jpg',average,EI,ClassVectors);
get a test image from directory
jim
 with name
test.jpg
   rotate image -90 degress
   resize to 1/8 scale
   write new image to disk
  convert image to double
  compute difference image
convert rgb to double
  compute vector
  get test feature vector
   find distance to class vectors
>> dist

dist =

   45.0095
   45.0325
   32.1367
   23.9600
   34.6160
   44.4723
    7.7621
   30.8399
   27.8847
   39.7993
   36.1505
   42.4495
   41.5786

%
% The smallest distance is in component 7.
% Now the order that the directories are
% processed is
%

1.  'bayless'   
2.  'cole'      
3.  'digiuseppe'
4.  'elmore'    
5.  'fawcett'   
6.  'harris'    
7.  'jim'       
8.  'kashema'   
9.  'mcleod'    
10. 'pauli'    
11. 'qaitlin'  
12. 'terry'    
13. 'wilkins' 

%
%  So we classified the test 'jim' image as the 'jim'
%  class vector
%

% 
% Let's try 'kashema'
%

>> dist = TestImage(192,128,'kashema','test.jpg',average,EI,ClassVectors);
get a test image from directory
kashema
 with name
test.jpg
   rotate image -90 degrees
   resize to 1/8 scale
   write new image to disk
   convert image to double
   compute difference image
   convert rgb to double
   compute vector
   get test feature vector
   find distance to class vectors
>> dist

dist =

   25.4525
   25.0242
   16.2876
   21.1934
   17.1000
   24.5143
   27.3750
   12.1808
   15.2702
   20.6883
   20.5079
   20.6519
   20.1377

%
% the smallest is component 8 which is the 'kashema' data!
% Quite Cool!
%

Now here are our functions we have been using:
========================================================================
function BuildCovariance(rows,cols)

%
%  Process all directories
%
disp('process all directories');
Av = ProcessAllDirectories;

%
% Get complete average
%
disp('get full average');
average = ComputeAverage(Av);

%
% Write average to disk
%
disp('write average to disk');
WriteDoubleImages(rows,cols,average,'average');

%
%  Compute difference images
%  Convert to double images in [0 255] range
%  Convert to double 2D matrices in (r*256^2+g*256+b)/256^3 range
%  Convert to 1D vector
%
disp('Get all difference images');
S = size(average);
[diff1,v1]= GetDiffs('bayless'   ,S,average   );
[diff2,v2]= GetDiffs('cole'  ,S,average   );
[diff3,v3]= GetDiffs('digiuseppe',S,average   );
[diff4,v4]= GetDiffs('elmore'  ,S,average   );
[diff5,v5]= GetDiffs('fawcett'   ,S,average   );
[diff6,v6]= GetDiffs('harris'  ,S,average   );
[diff7,v7]= GetDiffs('jim'  ,S,average   );
[diff8,v8]= GetDiffs('kashema'   ,S,average   );
[diff9,v9]= GetDiffs('mcleod'  ,S,average   );
[diff10,v10]= GetDiffs('pauli'     ,S,average );
[diff11,v11]= GetDiffs('qaitlin'   ,S,average );
[diff12,v12]= GetDiffs('terry'     ,S,average );
[diff13,v13]= GetDiffs('wilkins'   ,S,average );

%
% Set Up T Matrix
%
disp('Set up T matrix: holds all difference vectors');
[p q] = size(v1);
T = zeros(p,52);
T(1:p,1:4) = v1;
T(1:p,5:8) = v2;
T(1:p,9:12) = v3; 
T(1:p,13:16) = v4; 
T(1:p,17:20) = v5;
T(1:p,21:24) = v6; 
T(1:p,25:28) = v7; 
T(1:p,29:32) = v8; 
T(1:p,33:36) = v9; 
T(1:p,37:40) = v10; 
T(1:p,41:44) = v11; 
T(1:p,45:48) = v12; 
T(1:p,49:52) = v13; 

%
% write T to disk
%
disp('write T to disk');
fd = fopen('DiffVectors','w');
fwrite(fd,T,'double');
fclose(fd);

%
% Find Covariance
%
disp('Find Covariance');
TT = transpose(T);
W = (TT*T)/52.0;

%
% write covariance to disk
%
disp('Write covariance to disk');
fd = fopen('covariance','w');
fwrite(fd,W,'double');
fclose(fd);

===================================================================
function BuildRecognition(datasize,rows,cols,N)

%
% read in covariance
%
disp('   read in the covariance matrix');
fd = fopen('covariance','r');
covariance = fread(fd,[datasize datasize],'double');
fclose(fd);

%
% read in T
%
disp('   read in the difference vectors');
fd = fopen('DiffVectors','r');
p = rows*cols;
T = fread(fd,[p datasize],'double');
fclose(fd);

%
% Get the desired number of eigenvectors and eigenvalues
%
disp('Get');
N 
disp('eigenvalues and eigenvectors');
[EigenVs,EigenVals] = eigs(covariance,N);

%
% Get EigenImages
%
disp('Get EigenImages');
EI = GetEigenImages(N,T,EigenVs);

%
% Write EigenImages to Disk
%
disp('write eigenImages to disk');
fd = fopen('EigenImages','w');
fwrite(fd,EI,'double');
fclose(fd);

%
% Get Feature Vectors
%
[p q] = size(T);
disp('Get Feature Vectors');
F = zeros(N,datasize);
F(1:N,1:4)   = GetFeatureVectors(N,T(1:p,1:4),EI);
F(1:N,5:8)   = GetFeatureVectors(N,T(1:p,5:8),EI); 
F(1:N,9:12)  = GetFeatureVectors(N,T(1:p,9:12),EI);
F(1:N,13:16) = GetFeatureVectors(N,T(1:p,13:16),EI); 
F(1:N,17:20) = GetFeatureVectors(N,T(1:p,17:20),EI);
F(1:N,21:24) = GetFeatureVectors(N,T(1:p,21:24),EI);
F(1:N,25:28) = GetFeatureVectors(N,T(1:p,25:28),EI); 
F(1:N,29:32) = GetFeatureVectors(N,T(1:p,29:32),EI);
F(1:N,33:36) = GetFeatureVectors(N,T(1:p,33:36),EI); 
F(1:N,37:40) = GetFeatureVectors(N,T(1:p,37:40),EI);
F(1:N,41:44) = GetFeatureVectors(N,T(1:p,41:44),EI);
F(1:N,45:48) = GetFeatureVectors(N,T(1:p,45:48),EI);
F(1:N,49:52) = GetFeatureVectors(N,T(1:p,49:52),EI);

%
% Write Feature Vectors to Disk
%
disp('write Feature Vectors to disk');
fd = fopen('FeatureVectors','w');
fwrite(fd,F,'double');
fclose(fd);

%
% Get Class Vectors
%
disp('Get Class Vectors');
ClassVectors = GetClassVectors(F);

%
% Write Class Vectors to Disk
%
disp('write Class Vectors to disk');
fd = fopen('ClassVectors','w');
fwrite(fd,ClassVectors,'double');
fclose(fd);

=======================================================================
function dist = TestImage(rows,cols,name,filename,average,EI,ClassVectors)

cd(name);
disp('get a test image from directory');
disp(name);
disp(' with name');
disp(filename);
test = imread(filename);

disp('   rotate image -90 degrees');
testrotated = imrotate(test,-90);

disp('   resize to 1/8 scale');
testR125 = imresize(testrotated,.125);

disp('   write new image to disk');
imwrite(testR125,'test125.jpg');

clear test;
clear testrotated;

disp('   convert image to double');
testD = double(testR125);

disp('   compute difference image');
testdiff = ((testD - average)+.75*255)*(2/3);

disp('   convert rgb to double');
testRGB2Double = rgb2double(testdiff);

disp('   compute vector');
testVector = matrix2vector(testRGB2Double);

%
% get test feature vector
%
disp('   get test feature vector');
TestFeature = GetTestFeature(testVector,EI);

 
%
% find distance from our test feature vector 
% to all ClassVectors
%
disp('   find distance to class vectors');
dist = getTestDistance(TestFeature,ClassVectors);

cd('..'); 

===================================================================
function WriteDoubleImages(rows,cols,Data,name)

%
% Write image data that is rows x cols x [rgb] to disk: 
%

%
% Set up temporary matrices to hold R, G, B data
%
R = zeros(rows,cols);
G = zeros(rows,cols);
B = zeros(rows,cols);

R = Data(1:rows,1:cols,1);
G = Data(1:rows,1:cols,2);
B = Data(1:rows,1:cols,3);

fid = fopen(name,'a');
fwrite(fid,R,'double');
fwrite(fid,G,'double');
fwrite(fid,B,'double');

fclose(fid);

================================================================
function A = ReadDoubleImages(rows,cols,name)

%
% Read image data that is in three separate
% sets of data 
% rows x cols for red
% rows x cols for green
% rows x cols for blue
% from disk
%

%
% Set up matrix to hold double image data
%
A = zeros(rows,cols,3);

fid = fopen(name,'r');
A(1:rows,1:cols,1) = fread(fid,[rows cols],'double');
A(1:rows,1:cols,2) = fread(fid,[rows cols],'double');
A(1:rows,1:cols,3) = fread(fid,[rows cols],'double');

fclose(fid);

================================================================


Previous Contents Next