Reputation: 1559
I am trying to implement face recognition by Principal Component Analysis (PCA) using python. I am following the steps in this tutorial: http://onionesquereality.wordpress.com/2009/02/11/face-recognition-using-eigenfaces-and-distance-classifiers-a-tutorial/
Here is my code:
import os
from PIL import Image
import numpy as np
import glob
import numpy.linalg as linalg
#Step1: put database images into a 2D array
filenames = glob.glob('C:\\Users\\Karim\\Downloads\\att_faces\\New folder/*.pgm')
filenames.sort()
img = [Image.open(fn).convert('L').resize((90, 90)) for fn in filenames]
images = np.asarray([np.array(im).flatten() for im in img])
#Step 2: find the mean image and the mean-shifted input images
mean_image = images.mean(axis=0)
shifted_images = images - mean_image
#Step 3: Covariance
c = np.cov(shifted_images)
#Step 4: Sorted eigenvalues and eigenvectors
eigenvalues,eigenvectors = linalg.eig(c)
idx = np.argsort(-eigenvalues)
eigenvalues = eigenvalues[idx]
eigenvectors = eigenvectors[:, idx]
#Step 5: Only keep the top 'num_eigenfaces' eigenvectors
num_components = 20
eigenvalues = eigenvalues[0:num_components].copy()
eigenvectors = eigenvectors[:, 0:num_components].copy()
#Step 6: Finding weights
w = eigenvectors.T * np.asmatrix(shifted_images)
#Step 7: Input image
input_image = Image.open('C:\\Users\\Karim\\Downloads\\att_faces\\1.pgm').convert('L').resize((90, 90))
input_image = np.asarray(input_image)
#Step 8: get the normalized image, covariance, eigenvalues and eigenvectors for input image
shifted_in = input_image - mean_image
cov = np.cov(shifted_in)
eigenvalues_in, eigenvectors_in = linalg.eig(cov)
I am getting an error:
Traceback (most recent call last):
File "C:/Users/Karim/Desktop/Bachelor 2/New folder/new3.py", line 47, in <module>
shifted_in = input_image - mean_image
ValueError: operands could not be broadcast together with shapes (90,90) (8100)
I tried to remove .flatten()
from step 1 but this generated another error when calculating eigenvalues and eigenvectors:
Traceback (most recent call last):
File "C:/Users/Karim/Desktop/Bachelor 2/New folder/new3.py", line 25, in <module>
eigenvalues,eigenvectors = linalg.eig(c)
File "C:\Python27\lib\site-packages\numpy\linalg\linalg.py", line 1016, in eig
_assertRank2(a)
File "C:\Python27\lib\site-packages\numpy\linalg\linalg.py", line 155, in _assertRank2
'two-dimensional' % len(a.shape))
LinAlgError: 4-dimensional array given. Array must be two-dimensional
I also tried adding .flatten()
to Step 7 but also it generated another error when calculating eigenvalues and eigenvectors of the input image:
Traceback (most recent call last):
File "C:/Users/Karim/Desktop/Bachelor 2/New folder/new3.py", line 49, in <module>
eigenvalues_in, eigenvectors_in = linalg.eig(cov)
File "C:\Python27\lib\site-packages\numpy\linalg\linalg.py", line 1016, in eig
_assertRank2(a)
File "C:\Python27\lib\site-packages\numpy\linalg\linalg.py", line 155, in _assertRank2
'two-dimensional' % len(a.shape))
LinAlgError: 0-dimensional array given. Array must be two-dimensional
Anyone can help??
Upvotes: 4
Views: 1813
Reputation: 46530
I have finally looked at the tutorial you supplied, and it seems that the author suggests you flatten the images. You may as well continue with the flattened arrays for now, since it matches better with that tutorial.
I believe that the place to fix it is in step 7, where you have the covariance of the input image. However, the covariance matrix of the input image is going to be a scalar, and you cannot find the eigenvalues and eigenvectors of it. You can project it to be a 2d matrix of size (1,1)
, but then your eigenvalue of that will simply be the covariance, and the eigenvector will be [[1]]
.
That is, for example,
In [563]: input_image = np.random.rand(90,90).flatten()
In [564]: c = np.cov(input_image)
In [565]: c
Out[565]: array(0.08280644230318886)
In [566]: c.shape
Out[566]: ()
In [567]: c.ndim
Out[567]: 0
So we reshape c
to be 2d:
In [568]: cmat = c.reshape(1,1) # equivalent to cmat = c[...,np.newaxis,np.newaxis]
In [569]: cmat
Out[569]: array([[ 0.08280644]])
In [570]: cmat.shape
Out[570]: (1, 1)
In [571]: cmat.ndim
Out[571]: 2
So now we can find the eigen's:
In [572]: ceigval, ceigvec = linalg.eig(cmat)
But for a one-elemnt matrix, there is only one eigenvalue and one eigenvector, and the eigenvalue is the element of the matrix, and the eigenvector is the length-1 unit vector / identity, so I'm not sure this is really what you want to be doing for your face recognition.
In [573]: ceigval
Out[573]: array([ 0.08280644])
In [574]: ceigvec
Out[574]: array([[ 1.]])
In [576]: np.isclose(c, ceigval)
Out[576]: True
By the way, this is why we had to make c
2d:
In [577]: linalg.eig(c)
---------------------------------------------------------------------------
LinAlgError: 0-dimensional array given. Array must be two-dimensional
On the other hand, you could get the covariance of the un-flattened input_image, then you'll have N
eigenvalues and N
eigenvectors:
In [582]: input_image = np.random.rand(90,90)
In [583]: c = np.cov(input_image)
In [584]: c.shape
Out[584]: (90, 90)
In [585]: ceigval, ceigvec = linalg.eig(c)
In [586]: ceigval.shape
Out[586]: (90,)
In [587]: ceigvec.shape
Out[587]: (90, 90)
Upvotes: 3