●为什么要降维:
原始观察空间中的样本具有极大的信息冗余;
样本的高维数引发分类器设计的“维数灾难”;
数据可视化、特征提取、分类与聚类等任务需求;
●线性降维
通过特征的线性组合来降维
本质上是把数据投影到低维线性子空间
线性方法相对比较简单且容易计算
代表方法有:主成分分析(PCA),线性判别分析(LDA),多维尺度变换(MDS)
●LDA
寻找最能把两类样本分开的投影,使投影后两类样本的均值之差与投影样本的总类散度的比值最大。把原问题转化为关于样本集总类内散度矩阵和总类间散度矩阵的广义特征值问题。
●PCA降维整体思想
寻找能够保持采样数据方差的最佳投影子空间。对样本的散度矩阵进行特征值分解,所求子空间为经过样本均值,以最大特征值所对应的特征向量为方向的子空间。这样也就相当于只保留包含绝大多数方差的维度特征。实现数据特征的降维处理。PCA对于椭球状分布的样本有很好的效果,学习所得的主方向就是椭球的主轴方向。但PCA是一种非监督算法,能找到很好代表所有样本的方向,但这个方向对于分类未必是最有利的。
●PCA算法步骤:
设有m条n维数据
① 将原始数据按列组合成n行m列的矩阵A,每一列代表一个样本
② 将A的每一行(代表同一个属性的字段)进行零均值化,即减去这一行的均值
③ 求出协方差矩阵C=1/m ·A·AT
④ 求出协方差矩阵的特征值及对应特征向量
⑤将特征向量对应的特征值大小从上到小按行排列成矩阵,取前k行组成矩阵P
⑥Y=P·A即为降维到k维后的数据
①将训练数据库中的每个人脸用一个列向量表示,该向量长为N2=WH。如像素128x128的照片,用每个像素的灰度作为一个原始特征,N^2=128x128。M是数据库中人脸的个数。
②计算平均脸,把每一个列向量按行求平均,即得平均脸的原始特征向量。
③然后将训练集中的每个脸的的原始特征向量减去平均脸,并把这些向量按列组合成一个N2xM的矩阵[a,b,c,d,e,f,g,h]。
④找出矩阵协方差矩阵的特征值,Cov=A·AT。
显然这个矩阵维数将达到N2xN2,计算量非常庞大。
但我们只对之多M个特征值感兴趣。
所以可以计算L=AT·A,Cov的特征向量与L的特征向量是等价的。
而L是M·M矩阵,运算量小很多。从L得到特征向量V。
⑤U=A·V,得到特征空间的基。
⑥计算每一张脸映射到特征空间的表示。
计算数据库的门槛
⑦识别一张脸:
得到该脸的列向量表示,将表达该脸的列向量减去训练集的平均脸。
计算它映射到特征空间中的结果
然后在特征空间上计算它与数据库所有已知脸的距离
从特征脸中重构这张脸,并计算重构结果与原始脸的距离
若,ξ≥θ,说明这不是一张脸
若,ξ<θ 且 εi≥θ,i=1,……,M,说明这是一张新脸
若,ξ<θ 且 min{εi}<θ,说明这是一张已知的脸
Eigenface流程:
这里使用MATLAB编程
因为MATLAB有很多方便使用的处理图像的函数。而且使用MATLAB进行矩阵运算非常方便。
clear all
s = dir('trainingset'); % 打开文件
s(1:2) = []; % 因为前两项为“.""..",删去前两项
d = 128 * 128; % 每张图片像素总数
M = length(s); % 训练集内照片总数
A = zeros(d, M); % d*n矩阵
for k = 1:M
image = strcat('trainingset/', s(k).name);%每次循环image为一张图片
facek = imread(image);%从指定文件中读取图像,返回M*N数组
facek = imresize(facek, [128, 128]);%改变图片的大小
facek = reshape(facek, [d, 1]);%将f重新排序为矩阵d*1
facek = im2double(facek);%缩放到[0,1]
A(:, k) = facek;%放入第k列
end
m = mean(A, 2);%返回每一行均值的列向量
aver=reshape(m,[128,128]);
aver=imresize(aver,[231,195]);%原图片为231*195
subplot(1, 4, 1);
imshow((aver));
title('平均脸');
for k = 1:M
A(:, k) = A(:, k) - m; %减去均值
end
[V, a, explained] = pcacov(A' * A);%V特征向量,a特征值,特征值占比
%特征值大小已经被排序
U = A * V; %新空间的基
new_dim = 0; %特征空间的维度
per = 0;
while(per<90) %取特征值占比超过95%的
new_dim = new_dim + 1;
per = per + explained(new_dim);
end
U = U(:, 1:new_dim);%选择前new_dim个特征向量组成特征空间
W=U;
for k = 1:new_dim
U(:, k) = U(:, k)/norm(U(:, k)); %模长变为1
end
eigenface = zeros(new_dim, M); % 人脸图像在特征空间的表达
for k = 1:M
eigenface(:, k) = U' * A(:, k);
end
%打开选择文件对话框
[file, image] = uigetfile({'*.*', 'All Files'}, '选择您要识别的图片:');
image = strcat(image,file);
facek = imread(image);%从指定文件中读取图像,返回M*N数组
subplot(1, 4, 2);
imshow(facek);
title('要识别的图片');
facek = imresize(facek, [128, 128]);
rm = reshape(facek, [d, 1]);
rm = im2double(rm);
facek = rm - m;%减去平均脸
facek = U' * facek; % 投影到特征空间上
S=U*facek;
aver=reshape(S,[128,128]);
aver=imresize(aver,[231,195]);%原图片为231*195
subplot(1, 4, 3);
imshow((aver));
title('重构脸');
% 在数据库中找寻与识别图片最相近的图片
distance = Inf;%初始化为无穷大
best_k = 0;
for k = 1:M
d = norm(facek - eigenface(:, k));%取模
if(distance > d)
best_k = k;
distance = d;
end
end
image = strcat('trainingset/', s(best_k).name);
subplot(1, 4, 4);
imshow(image);
title('训练集中最接近的图片');
%特征向量还原为像素排列,生成特征脸
figure;
for i=1:4
for j=1:8
aver=reshape(W(:,8*(i-1)+j),[128,128]);
aver=imresize(aver,[231,195]);%原图片为231*195
subplot(4, 8,8*(i-1)+j );
imshow((aver));
end
end
在脚本程序的同目录下,创建一个trainingset文件夹(文件名和程序中的匹配就行),用来存放训练集、或者说是数据库。testset里存放将要识别的图片。
程序只能识别黑白图片,若要识别彩色图片。可加入一个灰度函数
f=imread(image);
if(numel(size(f)) == 3)%若为彩图
f = rgb2gray(f); %若为彩色图片,灰度化
end
不过我测试过一些彩色图片,识别结果不是很理想。