本示例通过浣熊脸图像来展示如何利用KBinsDiscretizer工具对图像进行向量量化处理。向量量化是一种压缩技术,它通过减少图像的灰度级别来降低图像的存储空间。例如,可以使用8个灰度值代替原来的256个,从而将每个像素的编码从8位减少到3位,理论上可以减少大约2.5倍的内存使用。
首先从SciPy库中加载浣熊脸图像,并检查图像的一些基本信息,如尺寸和存储数据类型。根据SciPy的版本,需要调整导入方式,因为返回图像的函数可能不在同一个模块中。此外,SciPy版本大于等于1.10时,需要安装pooch包。
try:
# Scipy >= 1.10
from scipy.datasets import face
except ImportError:
from scipy.misc import face
raccoon_face = face(gray=True)
print(f"图像的尺寸是 {raccoon_face.shape}")
print(f"用于编码图像的数据类型是 {raccoon_face.dtype}")
print(f"图像在RAM中占用的字节数是 {raccoon_face.nbytes}")
浣熊脸图像是一个768像素高、1024像素宽的二维数组。每个像素值是一个8位无符号整数,意味着图像使用8位来编码每个像素。图像总共占用了786432字节的内存。使用8位无符号整数编码意味着图像最多可以使用256种不同的灰度。可以通过直方图来检查这些灰度值的分布。
向量量化压缩的核心思想是通过减少灰度级别来表示图像。例如,可以使用8个灰度值代替256个。这意味着可以有效地使用3位而不是8位来编码单个像素,从而减少内存使用约2.5倍。将在后面讨论这种内存使用情况。
压缩可以通过KBinsDiscretizer实现。需要选择一个策略来定义8个灰度值进行子采样。最简单的策略是将它们等间距定义,这对应于设置strategy="uniform"。从之前的直方图中知道,这种策略肯定不是最优的。
from sklearn.preprocessing import KBinsDiscretizer
n_bins = 8
encoder = KBinsDiscretizer(n_bins=n_bins, encode="ordinal", strategy="uniform", random_state=0)
compressed_raccoon_uniform = encoder.fit_transform(raccoon_face.reshape(-1, 1)).reshape(raccoon_face.shape)
通过上述代码,可以看到压缩后的图像在视觉上仍然保持了较好的质量,尽管在某些小区域可以看到压缩的效果(例如右下角的树叶)。然而,像素值的分布已经被映射到了8个不同的值。可以检查这些值与原始像素值之间的对应关系。
之前提到,应该节省8倍的内存。让验证一下。
print(f"压缩后的图像在RAM中占用的字节数是 {compressed_raccoon_kmeans.nbytes}")
print(f"压缩比率: {compressed_raccoon_kmeans.nbytes / raccoon_face.nbytes}")
压缩后的图像在RAM中占用的字节数是6291456,压缩比率为8.0。这个结果与预期相反,原因是用来编码图像的数据类型。KBinsDiscretizer的输出是一个64位浮点数数组,这意味着它占用的内存是原来的8倍。然而,使用这种64位浮点数表示来编码8个值。实际上,只有在将压缩后的图像转换为3位整数数组时才能节省内存。可以使用numpy.ndarray.astype方法。但是,3位整数表示不存在,为了编码8个值,也需要使用8位无符号整数表示。