当我们要用一张图片跟大量图片对比寻找最相似(最小欧几里得距离等)时用本文的方法能减少内存使用量加快运算速度。
优化的欧几里得距离计算方法:
function d = EuclideanDistance(a,b)
% DISTANCE - computes Euclidean distance matrix
%
% E = EuclideanDistance(A,B)
%
% A - (MxD) matrix
% B - (NxD) matrix
%
% Returns:
% E - (MxN) Euclidean distances between vectors in A and B
%
%
% Description :
% This fully vectorized (VERY FAST!) m-file computes the
% Euclidean distance between two vectors by:
%
% ||A-B|| = sqrt ( ||A||^2 + ||B||^2 - 2*A.B )
%
% Example :
% A = rand(100,400); B = rand(200,400);
% d = EuclideanDistance(A,B);
% Author : Roland Bunschoten
% University of Amsterdam
% Intelligent Autonomous Systems (IAS) group
% Kruislaan 403 1098 SJ Amsterdam
% tel.(+31)20-5257524
% [email protected]
% Last Rev : Oct 29 16:35:48 MET DST 1999
% Tested : PC Matlab v5.2 and Solaris Matlab v5.3
% Thanx : Nikos Vlassis
% Copyright notice: You are free to modify, extend and distribute
% this code granted that the author of the original code is
% mentioned as the original author of the code.
if (nargin ~= 2)
b=a;
end
if (size(a,2) ~= size(b,2))
error('A and B should be of same dimensionality');
end
aa=sum(a.*a,2); bb=sum(b.*b,2); ab=a*b';
d = sqrt(abs(repmat(aa,[1 size(bb,1)]) + repmat(bb',[size(aa,1) 1]) - 2*ab));
这两天在学习PCA在人脸识别里的作用,并试图用matlab实现,在做到eigenface的时候由于对线性代数和SVD分解的半知不解,所以一直不能实现图像的正确匹配。网上的文章没有直接解决我遇到的困难,所以写一篇文章,希望给后来者一些提示,以此少走一些弯路。
在其他很多文章里都详细介绍了PCA和SVD的原理,我这里就不在赘述,而是直接解释怎么用matlab代码实现这个步骤。
(1)、假设我们现在有待匹配数据的集合rawFaceMatrix,其中假设size(rawFaceMatrix)= 12000*90,rawFaceMatrix的每一列都是一张unroll的图片,有90行代表有90张图片。现在我们要求出这个矩阵的平均值即为平均脸,并且将数据减去这个平均值(This will prevent PCA from representing patterns that are the same in every image.)
meanFace = zeros(size(rawFaceMatrix,1),1);
meanFace = mean(rawFaceMatrix,2);
A = zeros(size(rawFaceMatrix));
A = rawFaceMatrix - repmat(meanFace,1,size(rawFaceMatrix,2));
(2)、给定一张相同大小的图片testImg,size(testImg)= 100*120,我们现在把它由一行变成一列,同样的减去平均脸。
unroll_img = testImg(:);
testImg = unroll_img - meanFace;
(3)、对A矩阵即为数据库进行SVD分解以压缩数据,我这里给出一个matlab的子程序doPCA.m。
function [prinComponents, weightCols] = doPCA(A, numComponentsToKeep)
weightCols = zeros(numComponentsToKeep, size(A,2));
prinComponents = zeros(size(A,1), numComponentsToKeep);
[U,S,V] = svd(A,'econ'); %it is much more efficient when we only need the top few components, as we do here.
U = U(:,1:numComponentsToKeep);
S = S(1:numComponentsToKeep,1:numComponentsToKeep);
V = V(:,1:numComponentsToKeep);
prinComponents = U;
weightCols = S*V';
end
(4)、求出我们需要对比的图片在上述基底上的投影,这样我们就能将其与数据库里的图像进行对比(也就是跟weightCols进行对比)。
test_weightCols = prinComponents\testImg;
(5)、现在我们已经将待对比图片和数据库都进行了简化处理,它们之间可以直接求欧氏距离,我们取最小值就能得到最优解。这里给一个子程序求欧氏距离(可以替换成文章开头给出的欧几里得距离优化算法)跟对应的index。
function [minDist, indexOfClosest] = indexOfClosestColumn(A, test_weightCols)
n = size(A,2);
minDist = Inf;
for i = 1 : n
temp = sum((A(:,i)-test_weightCols).^2);
dist = sqrt(temp);
if dist < minDist
minDist = dist;
indexOfClosest = i;
end
end
end
[minDist, indexOfClosestMatch] = indexOfClosestColumn(weightCols, test_weightCols);
viewFace( rawFaceMatrix(:,indexOfClosestMatch), imgHeight);
function viewFace( faceColumn, imgHeight)
imshow(reshape(faceColumn,imgHeight, []),[0 255]);
end
至此简单的matlab代码实现主成分分析在人脸识别中的应用就完成了。(将其中doPCA替换成相应的Fisherface代码就能实现Fisherface的功能)