【机器学习】案例1.6——K-Means聚类,实现图像压缩

一、项目背景

传统图像存储中,每个像素的RGB三通道各占8位(共24位/像素),高分辨率图像会占用大量存储空间,且传输时消耗更多带宽。本项目基于矢量量化(Vector Quantization) 思想,采用K-Means聚类算法实现图像压缩:将图像中相似的颜色像素聚为一类,用聚类中心(码本)替代原像素的颜色值,仅存储每个像素对应的聚类标签(而非完整RGB值),从而大幅降低存储体积;解压时通过标签索引聚类中心,重构出原始图像的近似版本。
在这里插入图片描述

二、解决方案

1. 压缩阶段(img_compress.py)
  • 读取原始图像并可视化,确认图像完整性;
  • 将图像从「行×列×3」的三维矩阵重塑为「总像素数×3」的一维像素列表(每个元素为一个RGB像素点);
  • 用K-Means对所有RGB像素点聚类(设置128个聚类中心),得到每个像素的聚类标签和聚类中心(码本);
  • 保存聚类中心(码本)为.npy文件,将标签重塑为原图像尺寸后保存为压缩图像.png文件。
2. 解压阶段(image_decompress.py)
  • 加载保存的聚类中心(码本)和压缩后的标签图像;
  • 遍历标签图像的每个像素,通过标签索引码本中的RGB值,重构完整的RGB图像;
  • 保存并可视化重构后的图像。

三、代码版本

(一)带详细注释的版本
1. img_compress.py
# -*- coding: utf-8 -*-
# 图像压缩脚本:基于K-Means聚类实现图像颜色量化压缩
# 核心逻辑:将相似颜色聚类,用聚类中心替代原像素,仅存储标签降低存储量

# 导入必要库:skimage.io用于图像读写/可视化,KMeans用于聚类,numpy用于数组操作
from skimage import io
from sklearn.cluster import KMeans
import numpy as np

# 1. 读取原始图像(tiger.png需放在脚本同目录)
image = io.imread('tiger.png')

# 2. 可视化原始图像(验证读取成功)
io.imshow(image)
io.show()

# 3. 获取图像的行、列尺寸(用于后续重塑标签)
rows = image.shape[0]  # 图像高度(行数)
cols = image.shape[1]  # 图像宽度(列数)
print(f"图像尺寸:{rows} 行 × {cols} 列")

# 4. 重塑图像数组:将三维矩阵(rows, cols, 3)转为二维矩阵(rows*cols, 3)
# 目的:K-Means仅支持二维数据输入,每一行代表一个像素的RGB值
image = image.reshape(image.shape[0] * image.shape[1], 3)

# 5. 初始化并训练K-Means模型
# n_clusters=128:设置128个颜色聚类中心(聚类数越少压缩比越高,图像失真越明显)
# n_init=10:多次初始化聚类中心(避免局部最优),取最优结果
# max_iter=200:单次聚类的最大迭代次数(保证聚类收敛)
kmeans = KMeans(n_clusters=128, n_init=10, max_iter=200)
kmeans.fit(image)  # 对所有像素的RGB值聚类

print("K-Means聚类训练完成")

# 6. 提取聚类结果:聚类中心(码本)和每个像素的聚类标签
# 聚类中心:128个RGB值,作为颜色码本;转换为uint8(符合图像像素值范围0-255)
clusters = np.asarray(kmeans.cluster_centers_, dtype=np.uint8)
# 聚类标签:每个像素对应的聚类中心索引;转换为uint8节省空间
labels = np.asarray(kmeans.labels_, dtype=np.uint8)
# 将标签重塑为原图像的行列尺寸(用于保存压缩图像)
labels = labels.reshape(rows, cols)

# 7. 保存压缩结果:码本和标签图像
np.save('codebook_tiger.npy', clusters)  # 保存聚类中心(解压时需要)
io.imsave('compressed_tiger.png', labels)  # 保存标签图像(压缩后的核心文件)

print("图像压缩完成,已生成:codebook_tiger.npy(码本)、compressed_tiger.png(压缩图像)")
2. image_decompress.py
# -*- coding: utf-8 -*-
# 图像解压脚本:基于K-Means聚类中心重构原始图像

# 导入必要库:skimage.io用于图像读写/可视化,numpy用于数组操作
from skimage import io
import numpy as np

# 1. 加载压缩阶段保存的聚类中心(码本)
# 码本存储了128个聚类中心的RGB值,是重构图像的核心
centers = np.load('codebook_tiger.npy')

# 2. 加载压缩后的标签图像
# 标签图像的每个像素值是聚类中心的索引(0-127)
c_image = io.imread('compressed_tiger.png')

# 3. 初始化重构图像的数组
# 尺寸与压缩图像一致,通道数为3(RGB),数据类型uint8(0-255)
image = np.zeros((c_image.shape[0], c_image.shape[1], 3), dtype=np.uint8)

# 4. 遍历每个像素,通过标签索引码本重构RGB值
for i in range(c_image.shape[0]):  # 遍历每一行
    for j in range(c_image.shape[1]):  # 遍历每一列
        # 用当前像素的标签(c_image[i,j])索引码本,赋值给重构图像的对应位置
        image[i, j, :] = centers[c_image[i, j], :]

# 5. 保存并可视化重构后的图像
io.imsave('reconstructed_tiger.png', image)  # 保存重构图像
io.imshow(image)  # 可视化重构图像
io.show()

print("图像解压完成,已生成:reconstructed_tiger.png(重构图像)")
(二)无注释的版本
1. img_compress.py
# -*- coding: utf-8 -*-
from skimage import io
from sklearn.cluster import KMeans
import numpy as np

image = io.imread('tiger.png')
io.imshow(image)
io.show()

rows = image.shape[0]
cols = image.shape[1]
print(rows, cols)

image = image.reshape(image.shape[0]*image.shape[1], 3)
kmeans = KMeans(n_clusters=128, n_init=10, max_iter=200)
kmeans.fit(image)
print("finished kmeans")

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

np.save('codebook_tiger.npy', clusters)
io.imsave('compressed_tiger.png', labels)
print("done")
2. image_decompress.py
# -*- coding: utf-8 -*-
from skimage import io
import numpy as np

centers = np.load('codebook_tiger.npy')

c_image = io.imread('compressed_tiger.png')

image = np.zeros((c_image.shape[0], c_image.shape[1], 3), dtype=np.uint8)
for i in range(c_image.shape[0]):
    for j in range(c_image.shape[1]):
            image[i, j, :] = centers[c_image[i, j], :]
    
io.imsave('reconstructed_tiger.png', image)
io.imshow(image)
io.show()

四、补充说明

  1. 压缩比:原图像每个像素占24位,压缩后标签仅占7位(128个聚类中心需2^7=128),理论压缩比约3.4:1(未计算码本体积,码本仅128×3×8=3072位,可忽略);
  2. 聚类数调整:n_clusters越小,压缩比越高,但图像失真越明显;反之则失真降低,压缩比下降;
  3. 依赖安装:需执行pip install scikit-image scikit-learn numpy安装依赖库;
  4. 图像路径:确保tiger.png放在脚本同目录,否则需修改文件路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值