《模式识别》大作业人脸识别方法
---- 基于 PCA 和欧几里得距离判据的模板匹配分类器
一、 理论知识
1、主成分分析
主成分分析是把多个特征映射为少数几个综合特征的一种统计分析方法。在多特征的研
究中,往往由于特征个数太多,且彼此之间存在着一定的相关性,因而使得所观测的数据在
一定程度上有信息的重叠。当特征较多时,在高维空间中研究样本的分布规律就更麻烦。主
成分分析采取一种降维的方法,找出几个综合因子来代表原来众多的特征,使这些综合因子
尽可能地反映原来变量的信息,而且彼此之间互不相关,从而达到简化的目的。主成分的表
示相当于把原来的特征进行坐标变换(乘以一个变换矩阵),得到相关性较小(严格来说是
零)的综合因子。
1.1 问题的提出
一般来说,如果 N 个样品中的每个样品有 n 个特征 1
,
x x
2
,
x ,经过主成分分析,将
n
它们综合成 n 综合变量,即
y
1
y
2
c x
11 1
c x
21 1
y
n
c x
1 1
n
c x
12 2
c x
22 2
c x
2 2
n
c x
1
n n
c x
2
n n
c x
nn n
ijc 由下列原则决定:
j ,i,j = 1,2,...n)相互独立;
1、 iy 和 jy (i
2、y 的排序原则是方差从大到小。这样的综合指标因子分别是原变量的第 1、第 2、……、
第 n 个主分量,它们的方差依次递减。
1.2 主成分的导出
我们观察上述方程组,用我们熟知的矩阵表示,设
X
x
1
x
2
x
n
是一个 n 维随机向量,
Y
y
1
y
2
y
n
是满足上式的新变量所构成的向量。于是我们可以写成 Y=CX,C 是一个正交矩阵,
满足 CC’=I。
坐标旋转是指新坐标轴相互正交,仍构成一个直角坐标系。变换后的 N 个点在 1y 轴上
有最大方差,而在 ny 轴上有最小方差。同时,注意上面第一条原则,由此我们要求 iy 轴和 jy
轴的协方差为零,那么要求
TYY
1
2
n
令
R XX
T
,则 T
RC
T
C
经过上面式子的变换,我们得到以下 n 个方程
r c
1
1
n
r c
2
1
n
)
c
1
11
(
r
22
(
r
11
r c
21 11
0
0
n
n
r c
12 12
)
c
1
12
1.3 主成分分析的结果
r c
1 11
n
r c
2 12
n
(
r
nn
)
c
1
1
n
0
我们要求解出 C,即解出上述齐次方程的非零解,要求 ijc 的系数行列式为 0。最后得出
结论 i是|
R
I
| 0
的根, iy 的方差为 i。然后选取前面 p 个贡献率大的分量,这样就
实现了降维。也就是主成分分析的目标。
二、 实现方法
1、 获取数据。在编程时具体是把一幅二维的图像转换成一维的;
2、 减去均值。要使 PCA 正常工作,必须减去数据的均值。减去的均值为每一维的平均,
所有的 x 值都要减去,同样所有的 y 值都要减去,这样处理后的数据都具有 0 均值;
3、 计算协方差矩阵;
4、 计算协方差矩阵的特征矢量和特征值。因为协方差矩阵为方阵,我们可以计算它的特征
矢量和特征值,它可以告诉我们数据的有用信息;
5、选择成分组成模式矢量
现在可以进行数据压缩降低维数了。如果你观察上一节中的特征矢量和特征值,会注意
到那些特征值是十分不同的。事实上,可以证明对应最大特征值的特征矢量就是数据的主成
分。
对应大特征值的特征矢量就是那条穿过数据中间的矢量,它是数据维数之间最大的关
联。
一般地,从协方差矩阵找到特征矢量以后,下一步就是按照特征值由大到小进行排列,
这将给出成分的重要性级别。现在,如果你喜欢,可以忽略那些重要性很小的成分,当然这
会丢失一些信息,但是如果对应的特征值很小,你不会丢失很多信息。如果你已经忽略了一
些成分,那么最后的数据集将有更少的维数,精确地说,如果你的原始数据是 n 维的,你选
择了前 p 个主要成分,那么你现在的数据将仅有 p 维。
现在要做的是你需要组成一个模式矢量,这只是几个矢量组成的矩阵的一个有意思的名
字而已,它由你保持的所有特征矢量构成,每一个特征矢量是这个矩阵的一列。
6、获得新数据
这是 PCA 最后一步,也是最容易的一步。一旦你选择了须要保留的成分(特征矢量)
并组成了模式矢量,我们简单地对其进行转置,并将其左乘原始数据的转置:
其中 rowFeatureVector 是由特征矢量作为列组成的矩阵的转置,因此它的行就是原来的
特征矢量,而且对应最大特征值的特征矢量在该矩阵的最上一行。rowdataAdjust 是减去均
值后的数据,即数据项目在每一列中,每一行就是一维。FinalData 是最后得到的数据,数
据项目在它的列中,维数沿着行。
FinalData = rowFeatureVector * rowdataAdjust
这将仅仅给出我们选择的数据。我们的原始数据有两个轴(x 和 y),所以我们的原始数
据按这两个轴分布。我们可以按任何两个我们喜欢的轴表示我们的数据。如果这些轴是正交
的,这种表达将是最有效的,这就是特征矢量总是正交的重要性。我们已经将我们的数据从
原来的 xy 轴表达变换为现在的单个特征矢量表达。如果我们已经忽略了一些特征矢量,则
新数据将会用我们保留的矢量表达。
三、 matlab 编程
matlab 程序分为三部分。程序框图如下图所示。
main
CreatDataBase
EigenfaceCore
Recognition
这个函数首先得到二维数
组,包括所有的训练样本
向量并且从训练样本中返
回 3 个输出量
这个函数将源图像提取成
特征脸,然后比较它们之
间的欧几里得距离
这个函数将所有训练样本
的二维图像转换成一维列
向量。接着,它把这些一
维列向量组合到一行里面
构造出二维向量 T,即每个
单元的信息量是一幅图片
四、 总结
从书里看我觉得最让人明白模板匹配分类器的一段话,就是“譬如 A 类有 10 个训练样
品,就有 10 个模板,B 类有 8 个训练样品,就有 8 个模板。任何一个待测样品在分类时与
这 18 个模板都算一算相似度,找出最相似的模板,如果该模板是 B 类中的一个,就确定待
测样品为 B 类,否则为 A 类。”意思很简单吧,算相似度就是算距离。就是说,模板匹配就
要用你想识别的样品与各类中每个样品的各个模板用距离公式计算距离,距离最短的那个就
是最相似的。
这样的匹配方法明显的缺点就是在计算量大,存储量大,每个测试样品要对每个模板计
算一次相似度,如果模板量大的时候,计算量就十分的大。
五、 附录(matlab 程序代码)
第一部分:CreatDatabase.m
function T = CreatDatabase(TrainDatabasePath)
%一系列人脸(训练样本 T1,T2,……,TM)
%函数描述:这个函数将所有训练样本的二维图像转换成一维列向量。接着,它把这些一维
列向量组合到一行里面构造出二维向量 T,即每个单元的信息量是一幅图片
%参数: TrainDatabasePath --- 训练数据库的路径
%返回值:T
%一个二维矩阵,包含了所有一维向量。假设所有在训练样本的 P 幅图像拥有相同的大小
(M*N)。因此,这些一维向量的长度是 M*N 而且 T 将是一个 MN*P 的二维
%矩阵
---
%%%%%%%%%%%%%%文件处理%%%%%%%%%%%%%%%%%
TrainFiles = dir(TrainDatabasePath);
Train_Number = 0;
for i = 1:size(TrainFiles,1)
t = size(TrainFiles,1);
if
not(strcmp(TrainFiles(i).name,'.')|strcmp(TrainFiles(i).name,'..')|strcmp(TrainFiles(i).name,'Thumb
s.db'))
Train_Number = Train_Number + 1;
end
end
%%%%%%%%%从一维数组构造成二维数组%%%%%%%%%%%%
T = [];
for i = 1: Train_Number
str = int2str(i);
str = strcat('\',str,'.pgm');
str = strcat(TrainDatabasePath,str);
img = imread(str);
[irow icol] = size(img);
temp = reshape(img',irow*icol,1);%将二维数组变成一维数组
T = [T temp];
end
第二部分:EigenfaceCore.m
function [m,A,Eigenfaces] = EigenfaceCore(T)
%利用主成分分析(PCA)的方法在各张人脸中决定最明显的特征
%描述:这个方程首先得到二维数组,包括所有的训练样本向量并且从训练样本中返回 3 个
输出量
--- 一个二维矩阵,包含了所有一维向量。假设所有在训练样本的 P
%参数:T
幅图像拥有相同的大小(M*N)。因此,这些一维向量的长度是 M*N 而且 T 将是一个 MN*P
的二维
%矩阵
%返回值: m
%
%
Eigenfaces
A
---(M*Nx1)训练样本的均值
--- (M*Nx(P-1))训练样本协方差矩阵的特征向量
--- (M*NxP) 中心向量的矩阵
%%%%%%%%%计算均值%%%%%%%%%%%
m = mean(T,2); %计算样本平均值 m = (1/P)*sum(Tj's)
Train_Number = size(T,2);
%%%%%%%%%计算每个图像与均值的差%%%%%%%%%
%%%要使 PCA 正常工作,必须减去数据的均值。减去的均值为每一维的平均,所有的 x
值都要减去,同样所有的 y 值都要减去%%%
%%%这样处理后的数据都具有 0 均值%%%
A = [];
for i = 1 : Train_Number
temp = double(T(:,i)) - m;
A = [A temp]; %再次合并矩阵
end
%%%%%%%计算协方差矩阵%%%%%%%%%%
%%%%%%%计算协方差矩阵的特征矢量和特征值%%%%%%%%
L = A'*A;
[V D] = eig(L);%计算矩阵 A 的特征值 D(eigenvalues)和特征矩阵 V(eigenvectors)
%L 代表协方差矩阵 C = A*A'.
%%%%%%选择成分组成模式矢量%%%%%%%%%%%
L_eig_vec = [];
for i = 1:size(V,2)
if(D(i,i)>1)
L_eig_vec = [L_eig_vec V(:,1)];
end
end
%%%%%%计算协方差矩阵的特征向量%%%%%%%%%%
Eigenfaces = A * L_eig_vec;
第三部分:Recognition.m
function OutputName = Recognition(TestImage, m, A, Eigenfaces)
%函数描述:这个函数将源图像提取成特征脸,然后比较它们之间的欧几里得距离
%输入量: TestImage
%
%
%
m
Eigenfaces
A
---测试样本的路径
---(M*Nx1)训练样本的均值
--- (M*Nx(P-1))训练样本协方差矩阵的特征向量
--- (M*NxP) 中心向量的矩阵
%返回值: OutputName
---在训练样本中的被识别的图像的名字
%%%%%%%%%%从中心向量中提取特征脸%%%%%%%%%%%%%%
ProjectedImages = [];
Train_Number = size(Eigenfaces,2);
for i = 1:Train_Number
temp = Eigenfaces' * A(:,i)
ProjectedImages = [ProjectedImages temp];
end
%%%%%%%%%%%%%%%%从测试样本中提取 PCA 特征%%%%%%%%%%%%%%%
InputImage = imread(TestImage);
temp = InputImage(:,:,1);
[irow icol] = size(temp);
InImage = reshape(temp',irow*icol,1);
Difference = double(InImage) - m;
ProjectedTestImage = Eigenfaces'*Difference;
%%%%%%%%%%%%%计算欧几里得几何距离%%%%%%%%%%%%%%%%%%%%%%
Euc_dist = [];
for i = 1 : Train_Number,
q = ProjectedImages(:,i);
temp = (norm(ProjectedTestImage - q))^2;
Euc_dist = [Euc_dist temp];
end
%找出 A 中最小元素及其索引,把最小值返回给 C,最小值索引返回给 I。
%如果有几个相同的最小值,那么返回第一个被发现的索引。
[Euc_dist_min, Recognized_index] = min(Euc_dist);
OutputName = strcat(int2str(Recognized_index),'.pgm');
主程序
clear all
clc
close all
TrainDatabasePath = uigetdir('C:\MATLAB7\work\PCA', 'Select training database path' );
TestDatabasePath = uigetdir('C:\MATLAB7\work\PCA', 'Select test database path');
prompt = {'Enter test image name(a number between 1 to 10):'};
dlg_title = 'Input of PCA_Based Face Recognition System';
num_lines = 1;
def = {'1'};
TestImage = inputdlg(prompt,dlg_title,num_lines,def);
TestImage = strcat(TestDatabasePath,'\',char(TestImage),'.pgm');
im = imread(TestImage);
T = CreatDatabase(TrainDatabasePath);
[m, A, Eigenfaces] = EigenfaceCore(T);
OutputName = Recognition(TestImage, m, A, Eigenfaces);
SelectedImage = strcat(TrainDatabasePath,'\',OutputName);
SelectedImage = imread(SelectedImage);
imshow(im)
title('Test Image');
figure, imshow(SelectedImage);
title('Equivalent Image');
str = strcat('Matched image is : ', OutputName);
disp(str)