【图像压缩】基于主成分分析PCA算法实现图像压缩matlab源码

268 阅读5分钟

一、PCA简介

主成分分析(Principal Component Analysis,PCA), 是一种统计方法。通过正交变换将一组可能存在相关性的变量转换为一组线性不相关的变量,转换后的这组变量叫主成分。

二、PCA提出的背景

在许多领域的研究与应用中,往往需要对反映事物的多个变量进行大量的观测,收集大量数据以便进行分析寻找规律。多变量大样本无疑会为研究和应用提供了丰富的信息,但也在一定程度上增加了数据采集的工作量,更重要的是在多数情况下,许多变量之间可能存在相关性,从而增加了问题分析的复杂性,同时对分析带来不便。如果分别对每个指标进行分析,分析往往是孤立的,而不是综合的。盲目减少指标会损失很多信息,容易产生错误的结论。

因此需要找到一个合理的方法,在减少需要分析的指标同时,尽量减少原指标包含信息的损失,以达到对所收集数据进行全面分析的目的。由于各变量间存在一定的相关关系,因此有可能用较少的综合指标分别综合存在于各变量中的各类信息。主成分分析与因子分析就属于这类降维的方法。

三、PCA的推导

主成分的意思就是数据的主要成分,对于给定的一些数据,我们一般来说关心的是数据中变化的部分,变化的越多,我们得到的信息也就越多,而数据中不变的地方,我们能收集到的信息非常有限,所以,数据中变化较多的部分就构成了数据的主成分。

为了说明什么是数据的主成分,先从数据降维说起。数据降维是怎么回事儿?假设三维空间中有一系列点,这些点分布在一个过原点的斜面上,如果你用自然坐标系x,y,z这三个轴来表示这组数据的话,需要使用三个维度,而事实上,这些点的分布仅仅是在一个二维的平面上,那么,问题出在哪里?如果你再仔细想想,能不能把x,y,z坐标系旋转一下,使数据所在平面与x,y平面重合?这就对了!如果把旋转后的坐标系记为x’,y’,z’,那么这组数据的表示只用x’和y’两个维度表示即可!当然了,如果想恢复原来的表示方式,那就得把这两个坐标之间的变换矩阵存下来。这样就能把数据维度降下来了!但是,我们要看到这个过程的本质,如果把这些数据按行或者按列排成一个矩阵,那么这个矩阵的秩就是2!这些数据之间是有相关性的,这些数据构成的过原点的向量的最大线性无关组包含2个向量,这就是为什么一开始就假设平面过原点的原因!那么如果平面不过原点呢?这就是数据中心化的缘故!将坐标原点平移到数据中心,这样原本不相关的数据在这个新坐标系中就有相关性了!有趣的是,三点一定共面,也就是说三维空间中任意三点中心化后都是线性相关的,一般来讲n维空间中的n个点一定能在一个n-1维子空间中分析!

上一段文字中,认为把数据降维后并没有丢弃任何东西,因为这些数据在平面以外的第三个维度的分量都为0。现在,假设这些数据在z’轴有一个很小的抖动,那么我们仍然用上述的二维表示这些数据,理由是我们可以认为这两个轴的信息是数据的主成分,而这些信息对于我们的分析已经足够了,z’轴上的抖动很有可能是噪声,也就是说本来这组数据是有相关性的,噪声的引入,导致了数据不完全相关,但是,这些数据在z’轴上的分布与原点构成的夹角非常小,也就是说在z’轴上有很大的相关性,综合这些考虑,就可以认为数据在x’,y’ 轴上的投影构成了数据的主成分。

PCA的思想是将n维特征映射到k维上(k<n),这k维是全新的正交特征。这k维特征称为主成分,是重新构造出来的k维特征,而不是简单地从n维特征中去除其余n-k维特征。

 

总结一下,做PCA的主要步骤如下:

设有m条n维数据。

1)将原始数据按照m行n列排列的,如matlab和Python中都是这样(每一列代表一个特征)

2)将X的每一列(代表一个属性字段)进行零均值化,即减去这一列的均值

3)求出协方差矩阵

4)求出协方差矩阵的特征值及对应的特征向量

5)将上一步得到的特征向量组成矩阵V

6)求Y=XV,再取Y的前k列得到Y'即为要求的矩阵

 

这里注释一下以上矩阵的维数便于理解,在编程时防止矩阵相乘时的维数错误:

矩阵X:m x n (n维m个数据)

矩阵V:n x n

矩阵Y:m x n(n维m个数据)

矩阵Y':m x k(k维m个数据)

clc; clear all; close all;
I=imread('liftingbody.png');
k=1;
figure('Units', 'Normalized', 'Position', [0 0 1 1]);
for p=1:5:20
    [Ipca,ratio,contribution]=pcaimage(I,p,[24 24]);
    subplot(2,2,k);    
    imshow(Ipca)
    title(['主成分个数=',num2str(p),...
        ',压缩比=',num2str(ratio),...
        ',贡献率=',num2str(contribution)],'fontsize',14);
    k=k+1;
end