托马斯·哈代又来送诗啦,搬好小凳几~~~
Sky seems to end its track;
But no.
The road trails down the hill at the back.
Ever the road!
Purpose
- Learn how to use PCA
- Preliminarily understand face recognition features
- Get more proficient in the use of MATLAB
Principle
-
The introduction of PCA
PCA 的基本原理是利用离散 K-L 变换提取人脸的主要成分,从而构成特征脸空间,识别时把测试样本投影到该空间,构成一组投影系数,通过与特征脸的距离比较,距离最小的特征脸对应的即是识别结果。 -
Face recognition based on PCA
基于 PCA 的人脸识别分为三个阶段:第一个阶段利用训练样本集构建特征脸空间;第二个阶段是训练阶段,主要是将训练图像投影到特征脸子空间上;第三个阶段是识别阶段,将测试样本集投影到特征脸子空间,然后与投影后的训练图像相比较,距离最小的为识别结果。
基于 PCA 的人脸识别其实一种统计性的模板比配方法,原理简单,易于实现,但也有不足,它的识别率会随着关照,人脸角度,训练样本集的数量而变换,但仍不失为一种比较好的方法。
Procedure
- Basic steps of PCA algorithm
1:Structure feature space
2:Recognize
- Train
1:Training methods
库里一共有400张照片,有40个子文件夹,每个子文件夹对应一个人的10张不同照片,将照片重新划分并按照顺序命名。
① 每个人的任意5-8张照片作为训练并作为测试样本库,其余的5-2张图片作为测试的待识别的照片;
② 前30-38个人的照片作为训练,后10-2个人作为测试,其中测试中每个人的任意5-8张照片作为测试样本库,即与特征脸矩阵构成特征脸空间,其余的5-2张照片作为待识别的图片。
n = 1;
p = 1;
%分成train和test两个文件夹,且图片重命名
for i = 1:40 % 一共40个人
a = 1:10; % 每个人都是10张
Ind = a(:,randperm(size(a,2))); % size:取矩阵的列数 randperm:打乱顺序
for h = 1:train_num
j= Ind(1,h);
File = ['C:\Users\Lenovo\Desktop\人脸识别images\s',sprintf('%d',i),'\',sprintf('%d',j),'.pgm'];
Filesave = ['C:\Users\Lenovo\Desktop\train','\',sprintf('%03d',p),'.pgm'];
copyfile(File,Filesave)
p = p + 1; % 训练样本总数
end
for h = train_num+1:10
j= Ind(1,h);
File = ['C:\Users\Lenovo\Desktop\人脸识别images\s',sprintf('%d',i),'\',sprintf('%d',j),'.pgm'];
Filesave = ['C:\Users\Lenovo\Desktop\test','\',sprintf('%03d',n),'.pgm'];
copyfile(File,Filesave)
n = n + 1; % 测试样本总数
end
end
对于训练2的方式,这里需要分成三个部分:训练集、验证集和测试集。
n = 1;
m = 1;
p = 1;
% 分成train、test、validate三个文件夹,且图片重命名
for i = 1:train_num % 前n个人
a = 1:10; % 每个人10张
Ind = a(:,randperm(size(a,2))); % size:取矩阵的列数 randperm:打乱顺序
for h = 1:10
j = Ind(1,h);
File = ['C:\Users\Lenovo\Desktop\人脸识别images\s',sprintf('%d',i),'\',sprintf('%d',j),'.pgm'];
Filesave = ['C:\Users\Lenovo\Desktop\train','\',sprintf('%03d',p),'.pgm'];
copyfile(File,Filesave)
p = p + 1; % 训练样本总数
end
end
for i = train_num + 1 :40 % 后40-n个人的前5张
a = 1:10;
Ind = a(:,randperm(size(a,2)));
for h = 1:5
j= Ind(1,h);
File = ['C:\Users\Lenovo\Desktop\人脸识别images\s',sprintf('%d',i),'\',sprintf('%d',j),'.pgm'];
Filesave = ['C:\Users\Lenovo\Desktop\validate','\',sprintf('%03d',m),'.pgm'];
copyfile(File,Filesave)
m = m + 1; % 测试样本总数
end
for h = 6:10
j= Ind(1,h);
File = ['C:\Users\Lenovo\Desktop\人脸识别images\s',sprintf('%d',i),'\',sprintf('%d',j),'.pgm'];
Filesave = ['C:\Users\Lenovo\Desktop\test','\',sprintf('%03d',n),'.pgm'];
copyfile(File,Filesave)
n = n + 1; % 待识别总数
end
end
2:The process of the photos in library
① 将每一张库的照片转化成N维的向量,然后把这些向量存入一个矩阵里,可将这些向量以列的形式存在矩阵X里;
② 将矩阵里向量的每个元素加起来求出平均值,再用矩阵X中的每个向量减去这个平均值从而得到每个向量的偏差,最后得到了偏差矩阵X’;
③ 中心化并计算协方差矩阵;
④ 利用协方差矩阵进行主成分分析,提取特征脸,获取训练样本特征数据。
以下实验源代码是针对的训练方式1,训练方式2在形成特征脸与特征空间时稍有所不同。
%批量读取指定文件夹下的图片
path = uigetdir; % 打开一个模态对话框
img_path = dir(strcat(path,'\*.pgm')); % 列出.pgm文件
img_num = length(img_path); % img_num:文件夹中的总数
imagedata = []; % 一张图片为一列
if img_num >0
for j = 1:img_num
img_name = img_path(j).name;
temp = imread(strcat(path, '/', img_name));
temp = double(temp(:));
imagedata = [imagedata, temp];
end
end
%中心化并计算协方差矩阵
wts = size(imagedata,2); % imagedata的列数(等于训练的样本数)
img_pj= mean(imagedata,2); % 均值
for i = 1:wts
imagedata(:,i) = imagedata(:,i) - img_pj; % 中心化
end
covMat = imagedata'*imagedata; % 转置
% 利用协方差矩阵进行主成分分析,提取特征脸,获取训练样本特征数据
% COEFF:系数矩阵
% latent:特征值的大小(从大到小)构成的向量
% explained:贡献率
[COEFF, latent, explained] = pcacov(covMat);
% 留下使累计贡献量达95%的k个特征向量
i = 1;
proportion = 0;
while(proportion < 95)
proportion = proportion + explained(i);
i = i+1;
end
k = i - 1;
% 求出原协方差矩阵的特征向量,即特征脸
V = imagedata*COEFF; % N*M阶
V = V(:,1:k);
%显示前3的特征脸
A = reshape(V(:,1),[112,92]);
A = mat2gray(A);
axes( handles.axes1 )
imshow([A]);
B = reshape(V(:,2),[112,92]);
B = mat2gray(B);
axes( handles.axes2 )
imshow([B]);
C = reshape(V(:,3),[112,92]);
C = mat2gray(C);
axes( handles.axes3 )
imshow([C]);
% 训练样本在 PCA 特征空间下的表达矩阵 k*M
W = V'*imagedata;
- Test
对于测试样本,先读取图像,将其变换到PCA空间再利用近邻法识别。
1:Read a photo
[filename, path] = uigetfile({'*.pgm'},'choose photo');
str = [path, filename];
im = imread(str);
axes( handles.axes4);
imshow(im);
2:Nearest neighbor recognition
im1 = double(im(:));
objectone = V'*(im1 - img_pj); %计算待识别图片的投影
size(objectone)
%最小距离法,寻找和待识别图片最为接近的训练图片
for k = 1:wts
temp1(k) = norm(objectone - W(:,k)); %欧氏距离
end
- Calculate the accuracy and display the recognition results
对需要识别的每一张照片进行测试,与训练样本库中的每一张照片进行对比,若得到的最小距离的照片与待识别的照片为同一组(根据输入的每组照片训练数目判断),就标记正确,准确率=正确数/总待识别数。
为了便于分析,对每一幅测试图像显示距离排名在前三位的识别结果。
1:Display the top 3 recognition results
[s_temp,id]=sort(temp1,'ascend'); %筛选出距离前三小的
axes( handles.axes5 )
imshow(['C:\Users\Lenovo\Desktop\train','\',sprintf('%03d',id(1)),'.pgm'])
axes( handles.axes6 );
imshow(['C:\Users\Lenovo\Desktop\train','\',sprintf('%03d',id(2)),'.pgm'])
axes( handles.axes7 )
imshow(['C:\Users\Lenovo\Desktop\train','\',sprintf('%03d',id(3)),'.pgm'])
2:Acquire accuracy
col_of_data = 40*train_num;
pathname = uigetdir;
img_path_list = dir(strcat(pathname,'\*.pgm'));
img_num = length(img_path_list);
testdata = [];
if img_num >0
for j = 1:img_num
img_name = img_path_list(j).name;
temp = imread(strcat(pathname, '/', img_name));
temp = double(temp(:));
testdata = [testdata, temp];
end
end
col_of_test = size(testdata,2); %col_of_test:待测样本数
img_pj= mean(testdata,2);
for i = 1:size(testdata,2)
testdata(:,i) = testdata(:,i) - img_pj;
end
object =V'* testdata;
num = 0;
for j = 1:col_of_test
distance = 1e8;
for k = 1:col_of_data %col_of_data:训练样本总数
temp = norm(object(:,j) - W(:,k));
if(distance>temp)
aimone = k; %取出距离最小的
distance = temp;
end
end
if ceil(j/(10-train_num))==ceil(aimone/(train_num))
num = num + 1; %TP:预测和真实值都为1
end
end
accuracy = num/col_of_test;
3:Line chart to show accuracy
ps:图中显示数据是自己多次人工验证的数据。
axes( handles.axes8 )
x=5:1:8;
a=[0.920,0.956,0.967,0.975]; %数据
plot(x,a,'-*b'); %线性,颜色,标记
set(gca,'XTick',[5:1:8])
set(gca,'YTick',[0.75:0.05:1])
xlabel('训练数目(n/10)')
ylabel('准确率')
Result and Analysis
- Result
1:The first method
2:The second method
- Analysis
从上面的运行结果可以看出,PCA方法通过特征脸空间根据近邻法可以找到所属的人,并且从最后的准确率折线图可以看出:随着训练样本库照片的增加,所对应的准确率逐步增大,对于训练1方式,当选取的每个人的8张照片作为训练样本库时,识别的准确率已经达到了97.5%;对于训练2方式,当选取40个人的前35个人作为训练样本库,剩余5个人中的5张照片作为验证集,5张照片作为测试集时,识别的准确率已经达到了1,总体来说PCA的方法可以较好地识别人脸。
PCA主成分分析法通过将人脸作为一个整体来编码,不关心人脸五官的局部特征,从而可以大大地降低识别的复杂度,且图像的原始灰度数据可以直接学习识别,不需进一步的处理,同时可消除评价指标之间的相关影响;但可以看出实现过程中需要计算协方差矩阵,计算量很大,速度较慢,由于忽略了贡献率小的成分,其可能包含特征的重要信息,从而会引起较大的误差。
Conclusion
emm这是一个图像处理方面的简单实验,其中部分代码是老师提供的,就是用PCA去实现一个简单的人脸识别,并用MATLAB做出一个GUI界面来显示结果。This is just a 实验总结,所以没有写出详细原理,想要详细了解的话可以找阿度~~~
其实我本来立下了“宏伟”big志,写一篇全英文Blog,但是嘎嘎嘎flag倒了,想要将所有内容用英语准确连贯,实在是太费brain了,哭唧唧-- --,莫名瞧不起自己哈哈。
当然,对于其中处理不当的地方,还请大家指出,希望可以一起学交流习,想要代码的可以在下面留言,要是我不busy的话可以邮箱给你嘻嘻嘻!