基于PCA的人脸识别
实验简介
使用PCA通过MATLAB实现简单的人脸识别。使用的是ORL人脸库,里面共40个人,每人10张照片。主要通过两种分组方式来实现人脸识别。
- 分组一:每个人的任意 5/8 张照片作为训练并作为测试样本库,其它 5/2 张作为测试待识别图片。
- 分组二:前 30/38 个人作为训练,后 10/2 个人作为测试,其中测试库中每个人的任意 5/8 张照片为测试样本库,其它 5/2 张照片作为待识别图片。
PCA算法分析
分组一流程图
分组二流程图
主成分分析法(PCA)又称特征脸方法,实质是通过K-L变换来实现的。PCA的目的是使各个维度上的方差尽可能大,不同维度间的相关性尽可能小,以使降维同时最大程度保持数据原始特征。以上是我对使用PCA进行人脸识别的两种分组的大致步骤框图,可能表述不准确。
PCA实现具体步骤
构造特征空间
- 选择n张图片进行训练,每张图片的像素值为ab(c=ab);
- 将每张图片的ab矩阵以列转换成c1的向量,构成n列的矩阵X(c*n);
- 对矩阵X进行均值、中心化操作,并求得协方差矩阵;
- 求取协方差矩阵的特征值,并选取k个特征值(k:取决于定义的条件。如,本文采取的是使累计贡献率>95%的数量),得到k个特征向量V(特征脸);
- 将k个特征向量合并成特征空间W(c*k)(分组一与分组二在此步骤有别)。
识别
- 测试样本投影到特征子空间,得到一组投影系数(相当于一个位置坐标,一组坐标对应一张图,同样一张图能找到一组对应的坐标);
- 将其与特征空间中的点求欧氏距离,距离最近的即为相似度最高的。
PCA方法的优劣
优势
- 把人脸作为一个整体来编码,不关心眼、鼻、嘴等单个特征,大大降低识别的复杂度;
- 图像的原始灰度数据可直接原来学习和识别,不需要处理;
- 可消除评价指标之间的相关影响;
劣势
- 需要计算协方差矩阵,计算量大,没有快速算法;
- 忽略贡献率小的成分可能会引起较大误差,所忽略的可能刚好包括了重要的信息。
实验步骤
训练
- 将库里的400张图片(40*10)分成两组,一组作为训练,一组作为测试,并将照片按顺序重命名。具体的训练方式可分为以下两种:
- 每个人的任意 5/8 张照片作为训练并作为测试样本库,其它 5/2 张作为测试待识别图片。(详见图1-1)
- 前 30/38 个人作为训练,后 10/2 个人作为测试,其中测试库中每个人的任意 5/8 张照片为测试样本库(与特征脸矩阵构成特征脸空间),其它 5/2 张照片作为待识别图片。(详见图1-2)
- 库照片处理
- 将每一张库的照片转化成 N 维的向量,然后把这些向量存入一个矩阵里。可将这 200个向量以列的形式存在矩阵里。即
X=[x1 x2 … x200] - 将这 200 个向量的每个元素相加起来求出平均值。再用 X 里的每一个向量减去这个平均值得到每个的偏差。
平均值
偏差
最后得到 - 中心化并计算协方差矩阵。
- 利用协方差矩阵进行主成分分析,提取特征脸,获取训练样本特征数据。
- 将每一张库的照片转化成 N 维的向量,然后把这些向量存入一个矩阵里。可将这 200个向量以列的形式存在矩阵里。即
测试
对于测试样本,读取图像,将其变换至PCA空间,利用近邻法识别。
计算识别准确率
对待识别的每一张照片进行测试,与训练样本库中的每一张照片进行比对,若得到的最小距离的照片与待识别的照片为同一组(根据输入的每组照片训练数目判断),则标记为正确。定义准确率公式为正确数/总待识别数。
显示结果
- 对每一幅测试图像显示距离排名在前三位的识别结果;
- 显示前五张特征脸;
- 显示识别准确率折线图。
核心代码
分组一
- 训练:将照片分为两类,一类作为测试,一类作为训练。
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global W %特征脸空间
global V %特征脸
global img_pj %均值
global wts %训练的样本总数
global train_num %每个人训练的照片
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=['人脸库地址',sprintf('%d',i),'\',sprintf('%d',j),'.pgm'];
Filesave=['训练集地址','\',sprintf('%03d',p),'.pgm'];
copyfile(File,Filesave)
p = p + 1; %训练样本总数
end
for h = train_num+1:10
j= Ind(1,h);
File=['人脸库地址',sprintf('%d',i),'\',sprintf('%d',j),'.pgm'];
Filesave=['测试集地址','\',sprintf('%03d',n),'.pgm'];
copyfile(File,Filesave)
n = n + 1; %测试样本总数
end
end
%批量读取指定文件夹下的图片
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] = 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);
%显示前5的特征脸
A=reshape(V(:,1),[112 92]); %每张图片大小为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])
D=reshape(V(:,4),[112 92]);
D=mat2gray(D);
axes( handles.axes4 )
imshow([D])
E=reshape(V(:,5),[112 92]);
E=mat2gray(E);
axes( handles.axes5 )
imshow([E])
% 训练样本在 PCA 特征空间下的表达矩阵 k*M
W= V'*imagedata;
msgbox(['训练完成'])
- 识别:选择test文件中的照片进行识别,选取距离前三近的图片呈现。
function pushbutton2_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton2 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global im;
[filename, path] = uigetfile({
'*.pgm'},'choose photo');
str = [path, filename];
im = imread(str);
axes( handles.axes6);
imshow(im);
% --- Executes on button press in pushbutton3.
function pushbutton3_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton3 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global im %待识别的图片
global V
global W
global img_pj
global wts
im1 = double(im(:));
objectone = V'*(im1 - img_pj); %计算待识别图片的投影
%最小距离法,寻找和待识别图片最为接近的训练图片
for k = 1:wts
temp1(k) = norm(objectone - W(:,k)); %欧氏距离
end
[s_temp,id]=sort(temp1,'ascend'); %筛选出距离前三小的
axes( handles.axes7 )
imshow(['训练集地址','\',sprintf('%03d',id(1)),'.pgm'])
axes( handles.axes8 );
imshow(['训练集地址','\',sprintf('%03d',id(2)),'.pgm'])
axes( handles.axes9 )
imshow(['训练集地址','\',sprintf('%03d',id(3)),'.pgm'])
- 准确率:准确率=正确数/待识别总数,对test文件中的照片进行遍历。
function pushbutton4_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton4 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global V
global W
global train_num
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;
set(handles.edit2,'String',num2str(accuracy));
- 折线图:显示准确率曲线
x=2:1:9;
a=[0.74375,0.85,0.89167,0.915,0.93125,0.95,0.96245,1]; %数据
plot(x,a,'-*b'); %线性,颜色,标记
axis([2,9,0.7,1])
set(gca,'XTick',[2:1:9])
set(gca,'YTick',[0.7:0.05:1])
xlabel('训练数目(n/10)')
ylabel('准确率(%)')
- 新建、删除文件夹:照片分组的文件夹
% 新建train和test文件夹
% --- Executes on button press in pushbutton6.
function pushbutton6_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton6 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
cd('C:\Users\Administrator\Desktop\实验四');
mkdir train;
mkdir test;
%删除文件夹
% --- Executes on button press in pushbutton7.
function pushbutton7_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton7 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
cd('C:\Users\Administrator\Desktop\实验四');
%delete('*.pgm')
rmdir train s
rmdir test s
分组二
- 训练:将照片分为三类,一类为train(训练),一类为yanzheng(验证集,与特征脸V生成特征空间W),一类为test(待识别)。生成V的方式与分组一相同,注意图片选取问题即可;生成W1(W1= V’*imagedata1)的imagedata1为验证集中的照片。以下仅为照片分组与生成W1的代码。
%分成train、test、yanzheng三个文件夹,并且图片重命名
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=['人脸库地址',sprintf('%d',i),'\',sprintf('%d',j),'.pgm'];
Filesave=['训练集地址','\',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=['人脸库地址',sprintf('%d',i),'\',sprintf('%d',j),'.pgm'];
Filesave=['验证集地址','\',sprintf('%03d',m),'.pgm'];
copyfile(File,Filesave)
m = m + 1; %测试样本总数
end
for h = 6:10
j= Ind(1,h);
File=['人脸库地址',sprintf('%d',i),'\',sprintf('%d',j),'.pgm'];
Filesave=['测试集地址','\',sprintf('%03d',n),'.pgm'];
copyfile(File,Filesave)
n = n + 1; %待识别总数
end
End
% --- Executes on button press in pushbutton5.
function pushbutton5_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton5 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global V
global W1
global img_pj1
%批量读取指定文件夹下的图片
path = uigetdir; %打开一个模态对话框
img_path = dir(strcat(path,'\*.pgm')); %列出.pgm文件
img_num = length(img_path); %img_num:文件夹中的总数
imagedata1 = []; %一张图片为一列
if img_num >0
for j = 1:img_num
img_name = img_path(j).name;
temp = imread(strcat(path, '/', img_name));
temp = double(temp(:));
imagedata1 = [imagedata1, temp];
end
end
%中心化并计算协方差矩阵
wts = size(imagedata1,2); %imagedata的列数(等于训练的样本数)
img_pj1= mean(imagedata1,2); %均值
for i = 1:wts
imagedata1(:,i) = imagedata1(:,i) - img_pj1; %中心化
end
size(imagedata1)
% 训练样本在 PCA 特征空间下的表达矩阵 k*M
W1= V'*imagedata1;
msgbox(['训练2完成'])
实验结果
说明
以上仅个人拙见,欢迎共同学习交流。
源码
今天的文章基于PCA的人脸识别分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/32927.html