主成分分析实战-图片压缩

数据集

开源的 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
18
import 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
4
X = 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
24
def 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.600.700.800.900.950.970.99
主成分数量3998251685125517002575

如果只是将图像用于进一步的处理,保存 0.70 至 0.80 的相关系数已经可以展示主要特征。原图和对比图如下:

https://images.shwst.one/image-L (11)_5da237b97146f1e755dc56f3eff8077b.png
https://images.shwst.one/modify-0.80 (11)_8b7339803fd31d684bbe920e4ce3c99e.png