當我們要用一張圖片跟大量圖片對比尋找最相似(最小歐幾里得距離等)時用本文的方法能減少內存使用量加快運算速度。
優化的歐幾里得距離計算方法:
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));
獲得的A矩陣就是減去平均臉後的矩陣,這也是我們後續要比對的數據庫了。
(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;
test_weightCols即爲對比圖像在上述基底上的投影,注意我們在這裏用了matlab裏特有的“ \ ”運算。
(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
現在我們取得最優解的index。
[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的功能)