我们我们先来导入相应的模块,并看看要压缩的图片:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.metrics import pairwise_distances_argmin#对两个序列中的点进行距离匹配的函数
from sklearn.datasets import load_sample_image#导入图片数据所用的类
from sklearn.utils import shuffle #洗牌plt.figure(figsize=(10,10))
plt.axis('off')
plt.title('Original image (96,615 colors)')
plt.imshow(china)
我们再来看看计算机是如何读取这幅图片的:
这是一个三维数组,图片长*宽一共有640*427 = 273280个像素点,每个像素点有3个特征(颜色三通道)。在进行Kmeans聚类时我们需要把三维数组转换成二维数组:
同时删除掉重复颜色,我们发现实际上只有九万多种颜色:
因为plt.imshow在浮点数上表现非常优异,因此我们把newimage中的数据,转换为浮点数,压缩到[0,1]之间:
newimage = np.array(newimage, dtype=np.float64) / newimage.max()
因为在图像处理中,一个像素的颜色是由它的红、绿、蓝三个通道的值相对于其他像素的这些值来决定的。即使我们将所有像素通道值都除以某个数,只要它们的相对大小保持不变,图像的颜色就会看起来一样,因此不用担心颜色会变化的问题。
接下来,我们来找质心。因为数据量太大,我们随机抽取1000个样本点来聚类,剩余的样本点在质心上继续聚类。这里我们使用shuffle函数:
#首先,先使用1000个数据来找出质心
n_clusters = 64
image_array_sample = shuffle(image_array, random_state=0)[:1000]
kmeans = KMeans(n_clusters=n_clusters, random_state=0).fit(image_array_sample)
可以看到这是生成了64个质心的数据坐标,接下来我们用这64个质心去聚类全部数据:
labels的返回值是273280条数据各自聚类的质心的索引,用set()函数去重后:
接下来我们把样本点的特征都换成所在簇的质心的特征:
image_kmeans = newimage.copy()
for i in range(w*h):image_kmeans[i] = kmeans.cluster_centers_[labels[i]] #把所有的样本点都替换成质心
可以看到,替换过后只剩下64种独一无二的颜色了。接下来我们恢复图片的结构:
画出图片:
plt.figure(figsize=(10,10))
plt.axis('off')
plt.title('Quantized image (64 colors, K-Means)')
plt.imshow(image_kmeans)
可以看到和原始图片相比,没有太大的区别。