主成分分析实战-图片压缩
数据集
开源的 Anime Faces。放缩到 \(64 \times 64\)。
目标
通过主成分分析方法,对图像进行压缩,用远少于 4096 维的数据表示图像的主要特征。
分析
读入
数据已经放缩到相同尺寸,直接读入即可。
使用 pillow
读入后转成灰度矩阵,将图像的灰度值转为 4096 维的向量并保存。
整个数据集存为一个 4096 行的矩阵。对于每一行,分别进行标准化操作,以使用相关系数矩阵做主成分分析。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18import numpy as np
from PIL import Image
import pickle
def read() :
X = []
for i in range(1,21545) :
X.append(
np.array(
Image.open("D:\\shw\\anime-faces\\image (%d).png" % i, "r")
.convert("L")
).flatten().astype(np.float64)
)
X = np.array(X).T
for i in range(X.shape[0]) :
X[i,:] -= np.mean(X[i,:])
X[i,:] /= np.var(X[i,:]) ** 0.5
return X
计算
由于数据已经标准化,\(XX^T\) 就是相关系数矩阵。
用 numpy
对这个矩阵进行特征值分解。1
2
3
4X = read()
eigVal, eigVec = np.linalg.eig(np.dot(X, X.T))
eigVal = np.real(eigVal)
eigVec = np.real(eigVec)
降维与复原
将特征值较小(相关系数贡献之和不足 $ 1-$)的主成分舍去。用 \(p_i^Tx_j\) 计算样本在第 \(i\) 个主成分上的分量,再将主成分根据分量累加,实现图像的复原。
即计算 \(\sum_{i \in S}(p_i^Tx_j)p_i\)。其中 \(S\) 是保留的主成分下标集合。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24def write(alpha) :
for id in range(11,12) :
im = Image.new("L", (64, 64))
pix = im.load()
X1 = np.array(Image.open("image (%d).png" % id, "r").convert("L")).flatten().astype(np.float64)
tX1 = np.zeros(64 * 64)
sum, cnt = 0, 0
for i in np.argsort(eigVal)[::-1]:
tX1 += (np.dot(eigVec[:,i].reshape(1, -1), X1.reshape(-1,1)) * eigVec[:,i]).flatten()
sum += eigVal[i]
cnt += 1
if sum / np.sum(eigVal) > alpha :
break
for i in range(64) :
for j in range(64) :
pix[j,i] = int(tX1[i * 64 + j])
im.save("(11)/modify-cov-%.2f (%d).png" % (alpha, id))
print("%.2f: %d" % (alpha, cnt))
for a in range(96, 100, 1) :
write(a / 100)
效果
降维效果明显:
相关系数占比 | 0.60 | 0.70 | 0.80 | 0.90 | 0.95 | 0.97 | 0.99 |
---|---|---|---|---|---|---|---|
主成分数量 | 39 | 98 | 251 | 685 | 1255 | 1700 | 2575 |
如果只是将图像用于进一步的处理,保存 0.70 至 0.80 的相关系数已经可以展示主要特征。原图和对比图如下: