PCA分析
PCA分析
Sheldon ZhengEigenface
PCA有很多作用,比如在人脸识别领域,拾取人脸得关键特征。最著名的一个例子是所谓的eigenface。
顾名思义,eigenface就是脸的eigenvalue
,即脸的特征(其实任意图片都有特征,但是使用一类图片比如人脸图片较为好比较)。
使用PCA提取人脸图片的特征,并且将其重新组成图片,过程如下。
- 获取
张同一个人不同的人脸照片,比如192x168像素的照片,用灰度表示(比较简单,这样每一个pixel就只有一个值而不是3个值了)。 - 将每一张照片变成列向量,每一列代表一个照片,构成一个矩阵
,即矩阵 的维度是 。 - 计算矩阵
的每一行的平均值,得到一个 的列向量,然后将这个列向量扩充成矩阵,变成 的矩阵,每一列的值都相同,这个矩阵称之为均值矩阵 。 - 通过公式
算出去平均值后的矩阵 - 将
进行SVD分解得到 其中,矩阵 就是eigenface矩阵,每一列就是每张照片的eigenface,每一张都记录了不同方面的信息
以上五步就可以的出来eigenface,下面发一个代码,以及本人靓照:

使用eigenfaces可以拟合出来原图,选取秩数的不同会得到不同的还原度,而且即便用于测试的图片非常不一样,下图我用了一张类似的照片做测试。
注意上图最后一张,也许是使用了
matlab
的svd(,'econ')
命令导致的,最后一张的图像总会得到类似于马赛克的效果。

图片原图:
我用于测试的图片:
代码:
1 | clear all, close all, clc |
帅的人都很细心地发现了上面的图片都只动了我的慧眼,其他部分保持了不变,这是因为SVD对于图片处理有天然的缺陷。即SVD 对图像进行分析的时候受到图像的排放方式影响很大。

图片来源于:
SVD受到图像内主体的排列方位影响很大,因为这直接导致了整个图像矩阵奇异值改变。而奇异值分解是对图像进行操作的主要办法,通过获取不同程度的秩的图像,可以得到不同还原度的原图像。

如何选取最优秩r作为分界线实现图片压缩
对于使用SVD方法对图像进行压缩,其实实质上是我们不需要将所有的奇异值都给弄出来用作压缩图片使用,因为奇异值和奇异向量是按照其重要程度排序的,而且其奇异值矩阵中,前面一小部分奇异值的重要性是是超过后面大部分奇异值重要性之和的。因此,在压缩图像的时候,我们只需要前面
硬分界线r
我们设法搞一个分界线,这个分界线以使用奇异值矩阵秩的数量
有一种方法是最优硬分界线,选取秩r大于该分界线的部分最为Truncated SVD,往往最有效率。

那么最优硬分界线划分假设被分解的矩阵
如果
,即 是个方阵,而且$已 知 则 硬 分 界 线 为 : $如果
,且 即 是个非常细长的矩阵,则 替换成 :如果
,而且$未 知 , 则 最 优 硬 分 界 线 为 : $其中
是奇异值的中位数, 由下式解出:
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48clear all, close all, clc
%% 造出来一个真实X
t = (-3:.01:3)';
Utrue = [cos(17*t).*exp(-t.^2) sin(11*t)];
Strue = [2 0; 0 .5];
Vtrue = [sin(5*t).*exp(-t.^2) cos(13*t)];
X = Utrue*Strue*Vtrue';
figure, imshow(X);
%% 加噪音
sigma = 1;
Xnoisy = X+sigma*randn(size(X));
figure, imshow(Xnoisy);
%% 使用硬分界线产生一个clean matrix
[U,S,V] = svd(Xnoisy);
N = size(Xnoisy,1);
cutoff = (4/sqrt(3))*sqrt(N)*sigma; % Hard threshold
r = max(find(diag(S)>cutoff)); % Keep modes w/ sig > cutoff
Xclean = U(:,1:r)*S(1:r,1:r)*V(:,1:r)';
figure, imshow(Xclean)
%% 找到90%累计能量
cdS = cumsum(diag(S))./sum(diag(S)); % Cumulative energy
r90 = min(find(cdS>0.90)); % Find r to capture 90% energy
X90 = U(:,1:r90)*S(1:r90,1:r90)*V(:,1:r90)';
figure, imshow(X90)
%% plot singular values 画图
semilogy(diag(S),'-ok','LineWidth',1.5), hold on, grid on
semilogy(diag(S(1:r,1:r)),'or','LineWidth',1.5)
plot([-20 N+20],[cutoff cutoff],'r--','LineWidth',2)
axis([-10 610 .003 300])
rectangle('Position',[-5,20,100,200],'LineWidth',2,'LineStyle','--')
figure
semilogy(diag(S),'-ok','LineWidth',1.5)
hold on, grid on
semilogy(diag(S(1:r,1:r)),'or','LineWidth',1.5)
plot([-20 N+20],[cutoff cutoff],'r--','LineWidth',2)
axis([-5 100 20 200])
figure
plot(cdS,'-ok','LineWidth',1.5)
hold on, grid on
plot(cdS(1:r90),'ob','LineWidth',1.5)
plot(cdS(1:r),'or','LineWidth',1.5)
set(gca,'XTick',[0 300 r90 600],'YTick',[0 .5 0.9 1.0])
xlim([-10 610])
plot([r90 r90 -10],[0 0.9 0.9],'b--','LineWidth',1.5)

