note_8:PCA特征脸

PCA特征脸


参考



ATTENTION:

1. 由于作业中并不需要区分训练图片和测试图片,所以以下处理全部都是基于同一组图片的。但这样其实是不严谨的。所以,如果是真正要做PCA的人脸识别,需要分开训练集和测试集,如果测试集掺杂在训练集里面,测试结果将会不公平。 2. 这里只是介绍获取特征脸以及图像恢复,并不涉及后续利用最短欧氏距离的人脸识别。


1. 预处理

从Yale人脸识别数据集上下载了165张图片,每一张是64x64像素。

  • 首先,将每一张图片转换成4096x1的列向量,也就是说把每一列的像素加到末尾,使原来的矩阵形成一个大的列向量(行向量也可以,但是下面都是用的列向量当例子)。所以整个图片矩阵是4096x165的。

这里写图片描述

  • 显示图片的时候,可以借助imshow(x,[])reshape函数,将列向量转换成64x64的矩阵。reshape函数可以将矩阵的维数进行转换,只要确保转换前后矩阵的包含的数值数目相同即可。
% 显示前九张
for j=1:9
	subplot(3,3,j);
	imshow(reshape(X(:,11*(j-1)+1),[64 64]),[]);
end

这里写图片描述

  • 如果直接用imshow(x)来操作的话,x矩阵必须是uint8类型,如果是double类型的话,图片将无法显示。如果用imshow(x,[]),就不需要考虑uint8和double类型。由于后续求特征向量的时候,向量的数值都会偏小,所以要到函数imshow(x,[]),并且[]里面直接为空,不需要填任何参数,因为该函数具有自动校正功能。如果加了参数,特征脸会变得很暗,几乎看不到。如果将x矩阵强行转换成uint8类型,效果也是特别不好,看到的基本上是一片漆黑。

2. 平均脸

  • 求平均脸,是将所有列加起来再除以165,得到一个4096x1的列向量,这个列向量转换成64x64矩阵打印出来就是一张平均脸。
  • 由于不能直接对原图片矩阵进行操作,所以需要另外开一个矩阵存储图片。
  • 求平均值的时候可以用到mean函数,直接使用mean(x)表示将所有行加起来求平均值。如果使用mean(x,2),表示将所有列加起来求平均值。
Y = X;

%平均脸
meanface = mean(Y,2);
subplot(2,3,1);
imshow(reshape(meanface(:,1),[64 64]),[]);

这里写图片描述


3. 规范化

  • 为了使数据分布更为均匀,使数据便于后续的计算,所以要处理数据。首先要减去平均脸,然后要进行归一化,也就是除以标准差。
  • bsxfun函数是一个功能强大的函数,尤其是对于这种列操作或行操作的运算十分方便。其中@plus@minus@times@rdivide是表示加减乘除运算。
%减去平均脸
Y = bsxfun(@minus,Y,meanface);

%归一化
sig = std(Y);
Y = bsxfun(@rdivide,Y,sig);

4. 特征脸

特征脸就是特征向量转化成图片矩阵显示出来的图像。

  • 求特征脸有两种方法,一种是直接使用svd函数分解图片矩阵Y,另一种方法是用eig函数求Y的协方差矩阵的特征向量。
  • 因为图片的张数比图片的像素小很多(165 << 4096),所以采用第一种方法,运行速度会快很多。

(1)svd

  • 直接取前五个最大的特征向量。svd分解矩阵以后,矩阵U就是特征向量矩阵,矩阵S就是特征值矩阵。特征值矩阵S是一个对角矩阵。一般情况下,特征向量矩阵和特征值矩阵都是按列从大到小的降序排列,所以不需要利用fliplr(x)对矩阵进行处理。
%特征向量
[U,S,V] = svd(Y);

%取前5个特征向量
Ureduce = U(:,1:5);

% 显示特征脸
for j=1:5
	subplot(2,3,j+1);
	imshow(reshape(Ureduce(:,j),64,64),[]);
end
  • 其中第一张是平均脸,后面的五张就是特征向量打印出来的特征脸。

这里写图片描述

  • 观察Ureduce矩阵,其实可以发现特征向量里面是有很多负数的。但是这些负数是正常的,而且绝对不可以粗暴地用uint8来转化,不然就会出现一片黑。就像前面说的,放心用imshow(x,[]),它会帮忙矫正的。

这里写图片描述

(2)eig

  • 利用eig的话,首先得求整个图片矩阵Y的协方差矩阵。
  • 利用公式: S = 1 n ∑ i = 1 n x i x i T S=\frac{1}{n}\sum_{i=1}^nx_ix_i^T S=n1i=1nxixiT 进行计算。其中n表示一张图片的像素数,即4096。
%协方差矩阵
covmat = 1/4096 * Y * Y';

这里写图片描述

  • 对协方差矩阵求解特征向量,并且提取前五个最大的特征向量。因为eig函数求出来的特征向量矩阵V和特征值矩阵D也是按列的从大到小降序排列,所以可以直接选取前五列。
%特征向量
[V,D] = eig(covmat);

%取前5个特征向量
Vreduce = V(:,1:5);


%显示特征脸
for j=1:5
	subplot(2,3,j+1);
	imshow(reshape(Vreduce(:,j),64,64),[]);
end
  • 其中第一张是平均脸,后面的五张就是特征向量打印出来的特征脸。

这里写图片描述

  • 观察Vreduce矩阵,其实可以发现特征向量和Ureduce矩阵的刚好是相反数。

这里写图片描述


5. 重构

将上一步得到的特征向量矩阵用于对图片矩阵Y进行降维操作,然后再对图片矩阵Y升维,并且乘回标准差,加回平均脸。

(1)10维

  • 10维是指获取前十个最大特征向量进行降维操作然后再重构。
  • 降维操作是利用4096*10的Uk矩阵的转置乘上矩阵Y,得到Yp的维数是5x165。然后再用4096x10的Uk乘上Yp,恢复Yp的维数:4096x165。
%降到10维
dim = 10;
Uk = U(:,1:dim);

%列向量 所以Uk要转置
Yp = Uk' * Y;
Yp = Uk * Yp;

%还原特征
Yp = bsxfun(@times,Yp,sig);
Yp = bsxfun(@plus,Yp,meanface);

for j=1:3
	subplot(3,2,2*(j-1)+1);
	imshow(reshape(X(:,j),64,64),[]);
	subplot(3,2,2*(j-1)+2);
	imshow(reshape(Yp(:,j),64,64),[]);
end
  • 左边是原图,右边就是恢复出来的图片。

这里写图片描述

  • 10维恢复出来的图片,其实大部分轮廓线还是明显地保留了。但是很多细节是丢失的,第二张图张嘴的位置就很明显可以看出来,恢复的图片在张嘴的位置是黑的。

(2)100维

  • 道理和10维的一样,只不过将提取的特征向量由前十大变成前一百大。
%降到100维
dim = 100;
Uk = U(:,1:dim);

%列向量 所以Uk要转置
Yp = Uk' * Y;
Yp = Uk * Yp;

%还原特征
Yp = bsxfun(@times,Yp,sig);
Yp = bsxfun(@plus,Yp,meanface);

for j=1:3
	subplot(3,2,2*(j-1)+1);
	imshow(reshape(X(:,j),64,64),[]);
	subplot(3,2,2*(j-1)+2);
	imshow(reshape(Yp(:,j),64,64),[]);
end
  • 左边是原图,右边就是恢复出来的图片。

这里写图片描述

  • 100维的恢复效果已经很好了,不光是轮廓线,连大部分的细节都已经出来了。肉眼上看,和原图并没有相差很大。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值