基于经典的机器学习k-means聚类算法实现对三通道图片的压缩操作

https://www.toutiao.com/a6573221465104056846/

 

压缩图片的原理

k-means算法实现图像的压缩是k-means聚类算法的一个经典的应用,它把一个彩色图压缩成了灰度图,此时的灰度图不再使用三个通道,而使用单通道图,这样就可以节省彩色图片的存储空间,那么单通道图片和多通道图片有什么区别呢?

单通道图片

什么是单通道图片?单通道图片俗称灰度图,每个像素点只能有一个值表示颜色,它的像素值在0到255之间,0是黑色,255是白色,中间值是一些不同等级的灰色,在计算机中的表示如下所示:

基于经典的机器学习k-means聚类算法实现对三通道图片的压缩操作

计算机中的单通道图

假如现在有一个单通道的图片,我们在计算机中输出它的维度(shape)信息,它的shape为(297L, 364L),这个表示这张图片的数据表示有297行,364列,这是一个二维数组,这就是单通道图片在计算机中的表示形式。

三通道图片

什么是三通道图片?我们可以简单的理解为彩色图片,每个像素点都有3个值表示 ,所以就是3通道。例如RGB图片即为三通道图片,RGB色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。总之,每一个点由三个值表示

基于经典的机器学习k-means聚类算法实现对三通道图片的压缩操作

计算机中的三通道图片

如上所示就是一张三通道图片在计算机中的表示,我们输出这张图片的维度(shape),其值为:(297L, 364L, 3L),相对于单通道图片的维度来说,此时的图片的维度信息多了一个3L,这个就是三通道的意思,在计算机中值的范围是0~255,比如[245 255 244]这三个就表示红245、绿255、蓝244,那么这三个通道组合而成就是对应的颜色了。

使用聚类的方法来实现图片的压缩操作

我们先来看一下原始图片是什么样的?如下所示,这是一张彩色的三通道图片

基于经典的机器学习k-means聚类算法实现对三通道图片的压缩操作

彩色的三通道图片

如果在计算机中输出这张图片的维度信息,它的shape是(297L, 364L, 3L),此时的图片结构为:

基于经典的机器学习k-means聚类算法实现对三通道图片的压缩操作

计算机中的图片表示

如果我们将其维度改变为(297*364,3),那么就实现了图片的压缩操作,那么此时我们的图片结构变为:

基于经典的机器学习k-means聚类算法实现对三通道图片的压缩操作

(297*364,3)

之所以变成这样就是因为比较方便,这样可以认为有297*364个样本,每个样本是有3个特征。每个特征的值的范围是0~255,下面我们使用聚类算法,将这297*364个样本聚成128簇,为什么要聚成128簇呢?

因为我们知道,图片的像素值得单位是0~255,所以我们的特征值的范围是0~255,这就相当于是256个值,我们聚成128个簇,以后的每个样本所属的簇就作为压缩图片的像素值了,那么像素值最大为128,这样就是实现了图像的压缩,这就是k-means压缩图片的原理。

核心代码

kmeans = KMeans(n_clusters=128, n_init=10, max_iter=200)

  • n_clusters聚类数量,本例我们聚成128, 这个参数根据自己的需要反复调整
  • max_iter=200 在查找聚类时,需要进行迭代,将各个点分配到矩心,然后移动矩心,然后重新分配这些点,重新移动矩心,max_iter表示进行迭代的次数,200一般足够了。
  • n_init=10 控制算法初始化的次数,提出聚类的次数,k-means聚类有一个挑战,完全取决于初始状况,你有时最终会得到不同的聚类结果,然后,你需要多次重复该算法。尽管任意这些聚类可能都不对,但所有聚类的集合总会有满足你要求的聚类。 如果觉得你的聚类特别容易出现糟糕或艰难的初始化过程,就需要调整这个参数

clusters = np.asarray(kmeans.cluster_centers_, dtype=np.uint8)labels = np.asarray(kmeans.labels_, dtype=np.uint8)

以上表示将聚类完成之后的聚类中心和聚类之后的标签封装成一个数组,clusters为聚类中心,有128个,labels为每个样本属于哪一簇,共有297*364个,这二者的结果为:

基于经典的机器学习k-means聚类算法实现对三通道图片的压缩操作

128个聚类中心

基于经典的机器学习k-means聚类算法实现对三通道图片的压缩操作

108个样本所属的簇

labels = labels.reshape(rows, cols);

接下来就是最重要的一步,就是将labels也就是[4 4 69 ...29 29 29]转换成row*cols,也就是297*364,那么此时的labels值就是每个像素的值,范围是0~128,那么此时的图片就是我们压缩完的图片,它和原图片相比有以下特点

  1. 原图片shape是(297L, 364L, 3L),而现在的图片是297*364,也就是由彩色图变成了灰度图
  2. 原图片上每个像素值的大小是0~255,现在的图片的像素大小是0~128

压缩之后的图片效果为:

基于经典的机器学习k-means聚类算法实现对三通道图片的压缩操作

压缩之后的图片效果

全部代码

# -*- coding:utf-8 -*-
from skimage import io
from sklearn.cluster import KMeans
import numpy as np
image = io.imread('test.jpg')
io.imshow(image)
io.show()
rows = image.shape[0]
cols = image.shape[1]
image = image.reshape(image.shape[0]*image.shape[1],3)
kmeans = KMeans(n_clusters=128, n_init=10, max_iter=200)
kmeans.fit(image)
clusters = np.asarray(kmeans.cluster_centers_, dtype=np.uint8)
labels = np.asarray(kmeans.labels_, dtype=np.uint8)
labels = labels.reshape(rows, cols);
io.imsave('compressed_test.jpg', labels)
image = io.imread('compressed_test.jpg')
io.imshow(image)
io.show()

以上就是基于聚类算法完成彩色图片压缩的全部原理及其代码实现