4

我正在尝试使用 python 通过主成分分析 (PCA) 实现人脸识别。我正在按照本教程中的步骤操作:http: //onionesquereality.wordpress.com/2009/02/11/face-recognition-using-eigenfaces-and-distance-classifiers-a-tutorial/

这是我的代码:

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)

我收到一个错误: 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)

我试图.flatten()从步骤 1 中删除,但这在计算特征值和特征向量时产生了另一个错误: 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

我还尝试添加.flatten()到第 7 步,但在计算输入图像的特征值和特征向量时也产生了另一个错误: 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

有人可以帮忙吗??

4

1 回答 1

3

我终于看了您提供的教程,似乎作者建议您将图像展平。您现在最好继续使用扁平数组,因为它与该教程更匹配。

我相信修复它的地方是在第 7 步,在那里你有输入图像的协方差。但是,输入图像的协方差矩阵将是一个标量,您无法找到它的特征值和特征向量。您可以将其投影为大小为 的 2d 矩阵(1,1),但您的特征值将只是协方差,而特征向量将是[[1]]

也就是说,例如,

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

所以我们重塑c为 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

所以现在我们可以找到特征:

In [572]: ceigval, ceigvec = linalg.eig(cmat)

但是对于一元矩阵,只有一个特征值和一个特征向量,而特征值是矩阵的元素,特征向量是长度为1的单位向量/单位,所以我不确定这真的是什么你想为你的人脸识别做些什么。

In [573]: ceigval
Out[573]: array([ 0.08280644])

In [574]: ceigvec
Out[574]: array([[ 1.]])

In [576]: np.isclose(c, ceigval)
Out[576]: True

顺便说一句,这就是我们必须制作c2d 的原因:

In [577]: linalg.eig(c)
---------------------------------------------------------------------------
LinAlgError: 0-dimensional array given. Array must be two-dimensional

另一方面,您可以获得未展平的 input_image 的协方差,然后您将获得N特征值和N特征向量:

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)
于 2013-04-15T17:11:09.417 回答