我们知道 PCA 能够对信息(矩阵)进行压缩,图像数据也是矩阵形式,所以 PCA 也能够实现对图像数据压缩。
import matplotlib.pyplot as plt import numpy as np from sklearn.decomposition import PCA import os if __name__ == '__main__': _, axes = plt.subplots(1, 5, figsize=(20, 8)) data = plt.imread('data/img.webp') / 255 # 显示原图 axes[0].imshow(data) axes[0].set_title('原图') new_img = [] for index in range(3): # 保留图像信息 transfer = PCA(n_components=0.8) chanel = data[:, :, index] chanel = transfer.fit_transform(chanel) chanel = transfer.inverse_transform(chanel) new_img.append(chanel) # 显示压缩图 new_img = np.array(new_img).transpose([1, 2, 0]) # 将值截断到 0-1 之间 new_img = np.clip(new_img, 0, 1) axes[1].imshow(new_img) axes[1].set_title('压缩图') for index in range(3): axes[2 + index].imshow(new_img[:, :, index]) axes[2 + index].set_title('通道' + str(index + 1)) plt.show() plt.imsave('data/new_img.webp', new_img) print('原图大小:', os.path.getsize('data/img.webp')) print('压缩图大小:', os.path.getsize('data/new_img.webp'))
程序输出结果:
原图大小: 37848 压缩图大小: 18120
上面代码中,我们设置保留原始图像 0.8 的信息,输出图像的大小从 37848 变成了 18120。另外,PCA 对象中的 inverse_transform 函数可以将降维后的数据重新映射到原始空间,这是因为 PCA 后的数据是在新的坐标空间中的表示,图像的坐标都是以原始坐标表示的,为了能够正常显示出图像,所以需要这一步的操作。