使用奇异值分解(SVD)而不是协方差矩阵来计算特征脸。

5
我正在使用来自AT&T的40张人脸数据集(http://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html),尝试通过奇异值分解生成特征脸。

首先计算平均向量:

average

然后从训练集中的每个向量中减去平均向量,将新向量改变形状为一个n乘以(p*q)的矩阵x中的1乘以(p*q)列向量,并计算一个矩阵X使得X=(1/sqrt(n))*x。(问题出在这里: 我在X中得到的所有结果都四舍五入为0,导致特征脸产生黑色图像结果如下所示)

然后我计算该矩阵X的奇异值分解,并尝试通过将其重新变形为p乘以q矩阵来获取第一列的单元矩阵的第一个特征脸

然而,这是我的结果:

eigenface 1

有人能发现我的代码错误吗? 任何答案都将不胜感激。

n = 40;
%read images
A = double(imread('faces_training/1.pgm'));
f(:, :, 1) = A;
for j = 2:n
    f(:, :, j) = double(imread(['faces_training/',num2str(j),'.pgm']));
    A = A + f(:, :, j);
end
%calculate average
a = (1/n)*A;
%imshow(uint8(a))
for i = 1:n
%subtract from images
    x_vector(:, i) = reshape(f(:, :, i) - a, [], 1);
end
X = (1/sqrt(n))*x_vector;
%svd
[U S V] = svd(X);
B = reshape(U(:, 1), [size(a, 1) size(a, 2)]);
imshow(uint8(B))

使用imshow(B)而不是imshow(uint8(B))可以吗? - Luis Mendo
不行,因为B基本上只是一个小于1的double数组,所以最终得到的是相同的黑色图像。 - mic
1
如果它是一个介于0和1之间的双精度数组,您不应该应用uint8,因为您将得到所有的零。要么使用imshow(B),要么使用imshow(uint8(255*B))都可以。 - Luis Mendo
抱歉,我应该说明一下。每个双精度浮点数都明显小于1(事实上,整个向量中的最大值为0.0271),因此它们最终都会变成0。我再次尝试了您的两个代码片段,结果都是黑色的。 - mic
1
那么在计算 B 时可能是一个归一化问题。我已经添加了图像处理标签,这样你就可以得到更多的帮助。 - Luis Mendo
1个回答

4

我也做同样的事情,也遇到了同样的问题。简单来说,你需要对特征向量进行归一化处理以获得更好的图像效果。在进行归一化之前,你会发现特征向量的值非常接近于0(可能是由于svd的计算方式导致),这可能意味着它们接近黑色。

无论如何,使用以下公式对要转换的特征向量进行处理: newpixel[i,j]=(oldpixel[i,j]-min(oldpixel[:,j]))/(max(oldpixel[:,j])--min(oldpixel[:,j]))


谢谢!我模糊地记得这也是我发现的问题——像素值太接近0,所以我不得不在事后进行转换。感谢您清晰简洁的回答!(欢迎来到SO :)) - mic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接