• 【阿旭机器学习实战】【19】如何在不减少分辨率的情况下降低图片存储空间?K-Means算法进行图片颜色点分类存储


    【阿旭机器学习实战】系列文章主要介绍机器学习的各种算法模型及其实战案例,欢迎点赞,关注共同学习交流。

    本文使用无监督学习算法K-means聚类算法通过对图片颜色点进行聚类的方式,达到降低图片存储空间的目的

    对于KMeans聚类算法原理的介绍,请参考之前的博文《【阿旭机器学习实战】【16】KMeans算法介绍及实战:利用KMeans进行足球队分类》

    前言

    在如今的互联网时代,网络上充满了海量的数据,当然也包括很多图片。因此图像压缩技术对于压缩图像和减少存储空间变得至关重要。

    本文我们将使用无监督学习算法K-means聚类算法通过对图片颜色点进行聚类的方式,达到降低图片存储空间的目的

    图像由称为像素的几个强度值组成。在彩色图像中, 每个像素为3个字节, 每个像素包含RGB(红-蓝-绿)值, 该值具有红色强度值, 然后是蓝色, 然后是绿色强度值。

    具体方法如下:

    1. 使用K均值聚类算法将图片相似的颜色归为不同的” k”个聚类(例如k = 64),每个簇质心(RGB值)代表其各自簇的RGB颜色空间中的颜色矢量。

    2. 根据Kmeans算法找出图片上每个像素点对应的簇质心(RGB值)的标号值。

    3. 图片存储时,我们只需存储每个像素的标签编号, 并保留每个聚类中心的颜色向量的记录,根据编号及这个聚类中心颜色向量就可以告诉该像素所属的集群,即RGB值。

    由上述存储方式可以看出,图片单个像素点的存储由RGB的3个字节,变为了只需存储一个标签编号的数字。存储空间只需原来的30%左右。

    1. 加载图片及特征处理

    from sklearn import datasets
    import numpy as np
    import matplotlib.pyplot as plt
    %matplotlib inline
    
    • 1
    • 2
    • 3
    • 4
    # 加载图片
    china = datasets.load_sample_image("china.jpg")
    plt.imshow(china)
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    china.dtype
    
    • 1
    dtype('uint8')
    
    • 1
    china.shape
    
    • 1
    (427, 640, 3)
    
    • 1
    # 除以255,将像素点的值变为0-1之间
    china = china/255
    
    • 1
    • 2
    h,w,d = china.shape
    
    • 1
    # 把像素点展开
    img_array = china.reshape((h*w,d))
    
    • 1
    • 2
    img_array.shape
    
    • 1
    (273280, 3)
    
    • 1
    # 把像素点随机打乱
    from sklearn.utils import shuffle
    img_array_shuffle = shuffle(img_array,random_state=0)
    
    • 1
    • 2
    • 3
    plt.imshow(img_array_shuffle.reshape((h,w,d)))
    
    • 1

    在这里插入图片描述

    2. 进行KMeans聚类建模

    from sklearn.cluster import KMeans
    # 用64个聚类来划分这些像素点
    km = KMeans(n_clusters=64,random_state=0)
    
    • 1
    • 2
    • 3
    # 仅用前1000个像素点进行模型训练
    km.fit(img_array_shuffle[:1000])
    
    • 1
    • 2
    KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300,
        n_clusters=64, n_init=10, n_jobs=1, precompute_distances='auto',
        random_state=0, tol=0.0001, verbose=0)
    
    • 1
    • 2
    • 3
    # 表示这1000个样本对应的聚类标签,展示前100个标签编号
    km.labels_[:100]
    
    • 1
    • 2
    array([22, 36,  8, 56, 38, 42, 22, 31,  7,  2, 55, 31, 62, 21, 52, 43, 31,
           18,  2,  4, 31, 56, 21,  2, 15,  5,  6, 49, 57, 13,  5, 21, 21,  3,
           21, 47, 21,  2, 47, 32,  5, 42,  5, 33, 45, 56,  5, 57,  2, 38, 47,
            6, 50, 50, 27, 62, 56, 57, 30, 28,  6,  5, 26, 24, 58, 44,  8, 21,
           58, 60, 10, 56, 31, 10, 41,  5, 62, 41, 22,  6, 38, 25, 57, 36, 28,
           21, 49,  2, 21, 48, 14, 15, 57, 22, 47, 63, 47,  2, 41, 34])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    # # 用聚类中心点的颜色来代表这个聚类的颜色,展示前10个聚类中心
    km.cluster_centers_[:10] 
    
    • 1
    • 2
    array([[0.62570806, 0.60261438, 0.53028322],
           [0.15546218, 0.1557423 , 0.12829132],
           [0.82063983, 0.89896801, 0.98462332],
           [0.42039216, 0.43843137, 0.2227451 ],
           [0.69527105, 0.74994233, 0.76516724],
           [0.92174422, 0.9556336 , 0.99514194],
           [0.07058824, 0.0754637 , 0.0508744 ],
           [0.28205128, 0.26395173, 0.19638009],
           [0.46509804, 0.43372549, 0.36901961],
           [0.71328976, 0.41960784, 0.31851852]])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3. 使用算法对原始图片进行聚类

    # 用km模型去对原图进行聚类
    labels = km.predict(img_array)
    
    • 1
    • 2

    创建一个函数用于重新合成图片

    def recreate_img(centers,labels,h,w):
        # 行数的作用是将每个像素点的值,用对应编号的聚类中心代替
        # 按照h和w创建一个空白图片
        img = np.zeros((h,w,3))
        # 通过for循环,遍历img中每一个点,并且从labels中取出下标对应的聚类重新给img赋值
        label_index = 0
        for i in range(h):
            for j in range(w):
                img[i][j] = centers[labels[label_index]]
                label_index += 1
        return img
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    img_re = recreate_img(km.cluster_centers_, labels, h, w)
    
    • 1

    4. 展示原始图片与使用64个聚类中心聚类后的图片

    plt.figure(figsize=(12,6))
    axes1 = plt.subplot(121)
    axes1.imshow(china)
    axes1.set_title("Instaces")
    
    axes2 = plt.subplot(122)
    axes2.imshow(img_re)
    axes2.set_title("64 colors,K-Means")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    Text(0.5,1,'64 colors,K-Means')
    
    • 1

    在这里插入图片描述

    5. 图片存储方式

    1. 存储上面的图片每个像素点对应的聚类编号:labels, 形状为:(273280,)
    2. 存储每个聚类编号对应聚类中心RGB值:km.cluster_centers_。形状为:(64, 3)

    依据以上labels与km.cluster_centers_,我们即可还原出聚类之后的图片。相对于原始数据存储量降低了60%以上。

    如果内容对你有帮助,感谢记得点赞+关注哦!

    欢迎关注我的公众号:阿旭算法与机器学习,共同学习交流。
    更多干货内容持续更新中…

  • 相关阅读:
    栈、共享栈、链式栈(C++实现)
    第五课 Shell脚本编程-awk用法
    通过ELRepo修改CentOS 7内核版本的详细步骤
    VBA技术资料MF72:利用函数判断文件及工作表存在
    SOC-hello world
    计算机网络--HTTP 协议的请求方式 GET 和 POST
    Baumer工业相机堡盟工业相机如何联合GAPI SDK和OpenCV实现相机图像将图像转换为Mat格式再转为Bitmap图像进行显示(C#)
    Charles的Map Remote功能
    MySQL 全文检索的实现
    【LeetCode】寻找两个正序数组的中位数 [H](二分法)
  • 原文地址:https://blog.csdn.net/qq_42589613/article/details/127682902