function RunFaceRecog()
dbType = 'UMIST';
frAlgorithm = 'eigen';
nEigFace = 21;
maxFishEigFace = 41;
threshFace = 15;
threshClass = 8;
train.forceReread = 0;
train.forceNewSvd = 0;
train.forceNewScat = 0;
plots.intermediateOn = 1;
plots.finalOn = 1;
plots.savePlotsOn = 1;
f = filesep;
switch dbType
case 'UMIST'
basePath = ['C:\Documents and Settings\alanb\My Documents\NWU\' ...
'ECE 432\final project\face_databases\UMIST'];
db = 'croppedConsolPng23x28_subset';
imType = 'png';
case 'ALAN'
if isunix
basePath = ['/Users/alanb/Documents/Riting & Labs/' ...
'Northwestern/Year 2 Q3 (Spring)/' ...
'EE 432 Computer Vision/final project/' ...
'face_databases/MUstudentPhotos'];
else
basePath = ['C:\Documents and Settings\alanb\My Documents\' ...
'NWU\ECE 432\final project\face_databases\' ...
'MUstudentPhotos'];
end
db = 'tmbwClassOval40x60_2';
imType = 'png';
otherwise
error(sprintf('%s database type not understood.',dbType))
end
train.path = fullfile(basePath,[db f 'train']);
recog.path = fullfile(basePath,[db f 'recog']);
di = dir(fullfile(train.path,['*.' imType]));
if isempty(di)
fprintf('Err: Couldn''t find any %s files in training path:\n\t%s\n',...
imType,train.path)
return
end
inputTrainFile = fullfile(train.path,'storedInputs.mat');
foundCache = exist(inputTrainFile,'file');
if foundCache & ~train.forceReread
trainNow = train;
load(inputTrainFile)
trainNow.I = train.I;
trainNow.classNameTrue = train.classNameTrue;
trainNow.classTrue = train.classTrue;
train = trainNow;
clear trainNow
else
info = imfinfo(fullfile(train.path,di(1).name));
Nx = info.Height;
Ny = info.Width;
M = length(di);
train.I = uint8(zeros(Nx,Ny,M));
numOfClass = 0;
classBoundary = 0;
prevIndex = 1;
for i = 1:M
[I,mp] = imread(fullfile(train.path,di(i).name),imType);
train.I(:,:,i) = I;
train.classNameTrue{i} = di(i).name(1:end-4);
train.classTrue(i) = i;
if i>1
if ~strcmp(di(i-1).name(1:2),di(i).name(1:2))
j = i;
classBoundary = 1;
end
end
if i==M
j = i+1;
classBoundary = 1;
end
if classBoundary
numOfClass = numOfClass + 1;
trainClass.className{numOfClass} = ['class_' di(j-1).name(1:2)];
trainClass.num(numOfClass) = j-prevIndex;
X = double(reshape(...
train.I(:,:,prevIndex:(j-1)),[Nx*Ny j-prevIndex]))./256;
trainClass.mean{numOfClass} = mean(X,2);
trainClass.classStartIndex(numOfClass) = prevIndex;
trainClass.classEndIndex(numOfClass) = j-1;
prevIndex = j;
clear X;
classBoundary = 0;
end
end
save(inputTrainFile,'train','Nx','Ny','M','mp','trainClass')
end
di = dir(fullfile(recog.path,['*.' imType]));
if isempty(di)
fprintf('Err: Couldn''t find any %s files in recog path:\n\t%s\n',...
imType,recog.path)
return
end
info = imfinfo(fullfile(recog.path,di(1).name));
if (info.Height ~= Nx) | (info.Width ~= Ny)
error('recog images must be same size as training images')
end
M2 = length(di);
recog.I = uint8(zeros(Nx,Ny,M2));
for i = 1:M2
[I,mp] = imread(fullfile(recog.path,di(i).name),imType);
recog.I(:,:,i) = I;
recog.classNameTrue{i} = di(i).name(1:end-4);
switch dbType
case 'ALAN'
recog.classTrue{i} = ...
strmatch(recog.classNameTrue{i}(1:end-1),train.classNameTrue);
case 'UMIST'
recog.classTrue{i} = ...
strmatch(recog.classNameTrue{i}(1:2),train.classNameTrue);
end
recog.classEst(i) = NaN;
end
if plots.intermediateOn
figure,montage(reshape(train.I,[Nx Ny 1 M]),mp),title('training images')
if plots.savePlotsOn, saveas(gcf,'training_images','png'), end
figure,montage(reshape(recog.I,[Nx Ny 1 M2]),mp),title('recog images')
if plots.savePlotsOn, saveas(gcf,'recog_images','png'), end
end
switch frAlgorithm
case 'eigen'
[P,train] = computeEigenfaces(train,nEigFace,plots);
[recog] = classifyFaces(recog,train,P,threshFace,threshClass,plots);
case 'fisher'
MpFish = M-length(trainClass.num);
MpFish = min(MpFish,maxFishEigFace);
[P1,train1] = computeEigenfaces(train,MpFish,plots);
[P2,train2] = computeFisherfaces(train,trainClass,plots,P1);
[recog] = classifyFaces(recog,train2,P2,threshFace,threshClass,plots);
otherwise
error(['I don''t know face recognition algorithm "' ...
frAlgorithm '"'])
end
if plots.finalOn
nTopMatch = 3;
nCh = 6;
p = 1;
f = 0;
nRowsMax = 7;
nSubF = ceil(M2/nRowsMax);
for i = 1:M2
if rem(i-1,nRowsMax) == 0
f = f+1;
hf(f) = subfigure(1,nSubF,f); set(hf,'Color',1*[1 1 1])
p = 1;
end
subplot(nRowsMax,nTopMatch+2,p)
imshow(recog.I(:,:,i),mp)
if p==1, title('inputs'); end
nc = min(nCh,length(recog.classNameTrue{i}));
text(0,0,recog.classNameTrue{i}(1:nc),'FontSize',7,'Color','b')
p = p+2;
[val,ndx] = sort(recog.euDis(:,i));
for j = 1:nTopMatch
subplot(nRowsMax,nTopMatch+2,p)
imshow(train.I(:,:,ndx(j)),mp)
if p==3 & j==1
title(sprintf('top %d matches ...',nTopMatch));
end
if strncmp(train.classNameTrue{ndx(j)},recog.classNameTrue{i},2)
c = 'b';
else
c = 'r';
end
nc = min(nCh,length(train.classNameTrue{ndx(j)}));
text(0,0,train.classNameTrue{ndx(j)}(1:nc),...
'FontSize',7,'Color',c)
p = p+1;
end
end
if plots.savePlotsOn
for i=1:f
saveas(hf(i),sprintf('top3_matches_%d',i),'png')
end
end
end
save workspace_dump
disp('done')
function [P,train] = computeEigenfaces(train,Mp,plots)
[Nx Ny M] = size(train.I);
if Mp>M
warning(sprintf(...
['Can''t use more principal comp than input imgaes!\n'...
' -> Using %d components.'],M))
Mp = M;
end
svdFile = fullfile(train.path,'storedSvd.mat');
foundCache = exist(svdFile,'file');
if foundCache & ~train.forceNewSvd
load(svdFile)
else
X = double(reshape(train.I,[Nx*Ny M]))./256;
me = mean(X,2);
A = X - repmat(me,[1 M]);
clear X
[U,E,V] = svd(A,0);
eigVals = diag(E);
eigVecs = U;
clear U V
save(svdFile,'eigVecs','eigVals','me','A')
end
P = eigVecs(:,1:Mp);
lambda = eigVals(1:Mp);
train.mean = me;
train.wt = P'*A;
R = P*train.wt + repmat(train.mean,[1 M]);
if plots.intermediateOn
figure,imshow(reshape(train.mean,[Nx Ny])),title('avg face')
if plots.savePlotsOn, saveas(gcf,'avg_face','png'), end
figure,plot([1:length(eigVals)], eigVals,'x-'),title('\lambda strength')
if plots.savePlotsOn, saveas(gcf,'eigval_strength','png'), end
end
if plots.intermediateOn
I = reshape(P,[Nx Ny 1 Mp]);
for i = 1:Mp
mx = max(P(:,i));
mi = min(P(:,i));
I(:,:,1,i) = (I(:,:,1,i)-mi)./(mx-mi);
end
figure,montage(I),title('eigenfaces');
if plots.savePlotsOn, saveas(gcf,'eigenfaces','png'), end
end
err = sum(eigVals(Mp+1:M).^2);
if plots.intermediateOn
I = reshape(R,[Nx Ny 1 M]);
for i = 1:M
mx = max(R(:,i));
mi = min(R(:,i));
I(:,:,1,i) = (I(:,:,1,i)-mi)./(mx-mi);
end
figure,montage(I),title('reconst training images')
if plots.savePlotsOn, saveas(gcf,'reconst_training_images','png'), end
end
function [P,train] = computeFisherfaces(train,trainClass,plots,P1)
[Nx Ny M] = size(train.I);
X = double(reshape(train.I,[Nx*Ny M]))./256;
me = mean(X,2);
A = X - repmat(me,[1 M]);
scatFile = fullfile(train.path,'storedScat.mat');
foundCache = exist(scatFile,'file');
numOfClass = length(trainClass.num);
if foundCache & ~train.forceNewScat
load(scatFile)
else
prod = zeros(Nx*Ny);
Sb = zeros(Nx*Ny);
for i = 1:numOfClass
row = trainClass.mean{i} - me;
prod = row * row';
Sb = Sb + prod;
end
Sw = zeros(Nx*Ny);
for i = 1:numOfClass
for j = (trainClass.classStartIndex(i)):(trainClass.classEndIndex(i))
row = X(:,j) - trainClass.mean{i};
prod = row * row';
Sw = Sw + prod;
end
end
clear prod row
save(scatFile,'Sb','Sw')
end
Sbb = P1.'*Sb*P1;
Sww = P1.'*Sw*P1;
clear Sb Sw
[V,D] = eig(Sbb,Sww);
Ds = diag(D);
[tmp,ndx] = sort(abs(Ds));
ndx = flipud(ndx);
eigVals = Ds(ndx);
eigVecs = P1*V(:,ndx);
clear D Ds V
Mp = numOfClass-1;
lambda = eigVals(1:Mp);
P = eigVecs(:,1:Mp);
P = P./repmat(sum(P.^2).^0.5,Nx*Ny,1);
train.mean = me;
train.wt = P.'*A;
R = P*train.wt + repmat(train.mean,[1 M]);
if plots.intermediateOn
figure,plot([1:length(eigVals)], eigVals,'x-'),title('\lambda strength')
if plots.savePlotsOn, saveas(gcf,'fish_eigval_strength','png'), end
end
if plots.intermediateOn
I = reshape(P,[Nx Ny 1 Mp]);
for i = 1:Mp
mx = max(P(:,i));
mi = min(P(:,i));
I(:,:,1,i) = (I(:,:,1,i)-mi)./(mx-mi);
end
figure,montage(I),title('fisherfaces')
if plots.savePlotsOn, saveas(gcf,'fisherfaces','png'), end
end
if plots.intermediateOn
I = reshape(R,[Nx Ny 1 M]);
for i = 1:M
mx = max(R(:,i));
mi = min(R(:,i));
I(:,:,1,i) = (I(:,:,1,i)-mi)./(mx-mi);
end
figure,montage(I),title('reconst training images')
if plots.savePlotsOn, saveas(gcf,'fish_reconst_trainign_images','png')
end
end
function [recog] = classifyFaces(recog,train,P,threshFace,threshClass,plots)
[Nx Ny M] = size(train.I);
[Nx Ny M2] = size(recog.I);
Mp = length(P(1,:));
X2 = double(reshape(recog.I,[Nx*Ny M2]))./256;
A2 = X2 - repmat(train.mean,[1 M2]);
recog.wt = P'*A2;
R = P*recog.wt + repmat(train.mean,[1 M2]);
if plots.intermediateOn
I = reshape(R,[Nx Ny 1 M2]);
for i = 1:M2
mx = max(R(:,i));
mi = min(R(:,i));
I(:,:,1,i) = (I(:,:,1,i)-mi)./(mx-mi);
end
figure,montage(I),title('reconst recog images')
if plots.savePlotsOn, saveas(gcf,'reconst_recog_images','png'), end
end
recog.euDis = zeros(M,M2);
for i = 1:M2
for j = 1:M
recog.euDis(j,i) = sqrt(sum((recog.wt(:,i) - train.wt(:,j)).^2));
end
end
[minDis ndx] = min(recog.euDis);
fprintf('Results of face recognition:\n')
for i = 1:M2
if minDis(i) > threshFace
recog.classNameEst{i} = 'NonFace';
elseif minDis(i) > threshClass
recog.classNameEst{i} = 'UnknownFace';
else
recog.classNameEst{i} = train.classNameTrue{ndx(i)};
recog.classEst(i) = ndx(i);
end
recog.isCorrectClass(i) = ...
any(recog.classEst(i) == recog.classTrue{i});
fprintf('\trecognized %s as %s\n',...
recog.classNameTrue{i},recog.classNameEst{i});
end
numCorrect = sum(recog.isCorrectClass);
fprintf('\t%d of %d (%d%%) faces correctly classified\n',...
numCorrect,M2,round(numCorrect/M2*100));