引言

当想要压缩一张彩色图像时,彩色图像通常由数百万个颜色值组成,每个颜色值都由红、绿、蓝三个分量组成。因此,如果我们直接对图像的每个像素进行编码,会导致非常大的数据量。为了减少数据量,我们可以尝试减少颜色的数量,从而降低存储需求。

1.主要原理

(一)颜色聚类(Color Clustering):

首先,使用 KMeans 聚类算法将图像中的颜色值聚类为较少数量的颜色簇。聚类的数量由 n_clusters 参数指定。每个像素被归类到与其最接近的聚类中心所代表的颜色簇。颜色聚类的过程大致如下:

  1. 图像转换: 首先,彩色图像被转换为一个包含所有像素颜色值的数据集。每个像素的颜色通常由红、绿、蓝三个分量组成,因此数据集中的每个样本都是一个三维向量,表示一个像素的颜色。
  2. 选择聚类数量: 在应用 KMeans 算法之前,需要确定聚类的数量。这个数量通常由用户指定,通过参数 n_clusters 控制。
  3. 应用 KMeans 算法: 将 KMeans 算法应用于颜色数据集,将颜色值聚类为指定数量的簇。每个簇的质心代表了该簇的平均颜色。
  4. 像素映射: 每个像素的颜色被映射到最接近的簇的质心所代表的颜色。这样,整个图像被转换为由较少数量的颜色值表示的压缩图像。

通过颜色聚类,彩色图像的颜色数量得以减少,从而实现了数据的压缩。压缩后的图像仍然能够保持视觉上的相似性,同时大大降低了存储空间的需求。

(二)动态规划量化(Dynamic Programming Quantization):

接下来,通过动态规划量化算法对颜色进行压缩。这个算法会进一步减少颜色的数量,并尽可能保持图像的质量。参数 max_colors 指定了压缩后图像中的最大颜色数量。算法会尽量选择与原始图像相似的颜色进行保留,以最大程度地保持图像的质量。而在这部分动态规划量化过程大致如下:

  1. 初始化: 首先,初始化状态数组,表示不同颜色数量下的最优颜色组合。通常,初始状态可以是一个空数组或者包含少量颜色的数组。
  2. 状态转移: 根据动态规划的思想,从初始状态开始逐步扩展,计算每个状态下的最优颜色组合。这个过程通常涉及到对每种可能的颜色组合进行评估,并根据优化准则选择最优的组合。
  3. 选择最优解: 最终,选择最优的颜色组合作为压缩后的图像的颜色集合。这个颜色集合将用于替换原始图像中的颜色,从而实现图像的压缩。
  4. 压缩数据保存: 压缩后的图像数据以及相关信息(如原始图像的尺寸、选择的颜色集合等)被保存为 NumPy 数组,并通过 np.savez_compressed() 函数保存到指定路径。

通过动态规划量化,我们能够选择一组颜色,使得压缩后的图像在尽可能减少颜色数量的情况下,仍然能够保持与原始图像相似的视觉效果。这样就实现了对图像数据的进一步压缩。

(三)压缩数据保存:

压缩后的图像数据以及相关信息(如原始图像的尺寸、聚类数、最大颜色数、聚类中心颜色等)被保存为 NumPy 数组,并通过 np.savez_compressed() 函数保存到指定路径。

(四)解压缩过程:

解压缩过程与压缩过程相反。首先加载压缩后的图像数据,然后根据聚类中心颜色替换像素颜色,最后将重构后的图像数据重塑为原始形状,并恢复图像的原始尺寸。

2.彩色图像压缩类

(一)类结构介绍

将上面所述的一个彩色图像的压缩功能整合为一个名为’ColorfulImageCompressor’的类,在这个类中有四个函数,它们的函数名称、接受参数以及介绍如下:

ColorfulImageCompressor类

  • __init__(self, n_clusters, max_colors, resize_factor=0.5): 初始化彩色图像压缩器对象。
  • compress(self, image_path, compressed_file_path): 压缩彩色图像并保存到指定路径。
  • decompress(self, compressed_file_path): 解压缩彩色图像并返回解压缩后的图像对象。
  • _dynamic_programming_quantization(self, image_array): 动态规划量化,将彩色图像颜色量化为指定数量的颜色。

(二)初始化参数

在创建一个彩色图像压缩类的时候需要传入以下三个参数,进行参数的初始化。

  • n_clusters:聚类数,用于 KMeans 算法,指定图像中的颜色数量。
  • max_colors:最大颜色数,用于动态规划量化,指定压缩后图像中的最大颜色数量。
  • resize_factor:缩放因子,用于调整图像尺寸,默认为 0.5,表示将图像尺寸缩小到原始的一半。

(三)函数介绍

(1)compress(self, image_path, compressed_file_path)

  1. 介绍:

    该函数的作用是压缩彩色图像并保存到指定路径。

  2. 参数:

    image_path:原始图像文件路径。

    compressed_file_path:压缩后的图像文件路径。

  3. 函数体:

    def compress(self, image_path, compressed_file_path):
"""
压缩彩色图像并保存到指定路径。 参数:
- image_path:原始图像文件路径。
- compressed_file_path:压缩后的图像文件路径。
"""
# 打开图像并转换为 RGB 模式
image = Image.open(image_path)
image = image.convert('RGB') # 根据缩放因子调整图像大小
new_size = (int(image.width * self.resize_factor), int(image.height * self.resize_factor))
image = image.resize(new_size) # 将图像转换为 NumPy 数组并重塑为二维数组
np_image = np.array(image)
original_shape = np_image.shape
np_image = np_image.reshape(-1, 3) # 使用动态规划量化对图像进行压缩
compressed_data = self._dynamic_programming_quantization(np_image) # 保存压缩后的图像数据到指定路径
np.savez_compressed(compressed_file_path, np_image=compressed_data['np_image'], original_shape=original_shape, n_clusters=self.n_clusters, max_colors=self.max_colors, center_colors=compressed_data['center_colors'])

(2)decompress(self, compressed_file_path)

  1. 介绍:

    解压缩彩色图像并返回解压缩后的图像对象。
  2. 参数:

    compressed_file_path:压缩后的图像文件路径。

    返回:

    reconstructed_image:解压缩后的图像对象。
  3. 函数体:
    def decompress(self, compressed_file_path):
"""
解压缩彩色图像并返回解压缩后的图像对象。 参数:
- compressed_file_path:压缩后的图像文件路径。 返回:
- reconstructed_image:解压缩后的图像对象。
"""
# 加载压缩后的图像数据
compressed_data = np.load(compressed_file_path)
np_image = compressed_data['np_image'].reshape(-1, 3)
center_colors = compressed_data['center_colors'] # 根据聚类中心替换像素颜色
for i in range(self.n_clusters):
np_image[np_image[:, 0] == i] = center_colors[i] # 将重构后的图像数据重塑为原始形状
original_shape = compressed_data['original_shape']
reconstructed_image = np_image.reshape(*original_shape).astype('uint8')
reconstructed_image = Image.fromarray(reconstructed_image, 'RGB') # 恢复图像原始尺寸
original_size = (int(reconstructed_image.width / self.resize_factor), int(reconstructed_image.height / self.resize_factor))
reconstructed_image = reconstructed_image.resize(original_size) return reconstructed_image

(3)_dynamic_programming_quantization(self, image_array)

  1. 介绍:

    动态规划量化,将彩色图像颜色量化为指定数量的颜色。
  2. 参数:

    image_array:图像数据的 NumPy 数组表示。

    返回:

    compressed_data:包含压缩后图像数据及相关信息的字典。
  3. 函数体:
    def _dynamic_programming_quantization(self, image_array):
"""
动态规划量化,将彩色图像颜色量化为指定数量的颜色。 参数:
- image_array:图像数据的 NumPy 数组表示。 返回:
- compressed_data:包含压缩后图像数据及相关信息的字典。
"""
# 使用 KMeans 进行聚类
kmeans = KMeans(n_clusters=self.n_clusters)
labels = kmeans.fit_predict(image_array)
quantized_image = np.zeros_like(image_array) # 遍历每个聚类簇
for i in range(self.n_clusters):
# 获取当前簇的像素颜色及其出现次数
cluster_pixels = image_array[labels == i]
unique_colors, color_counts = np.unique(cluster_pixels, axis=0, return_counts=True) # 选取出现次数最多的前 max_colors 个颜色作为量化后的颜色
color_indices = np.argsort(color_counts)[::-1][:self.max_colors]
quantized_colors = unique_colors[color_indices] # 计算聚类中像素与量化后颜色的距离
distances = np.linalg.norm(cluster_pixels[:, None] - quantized_colors, axis=2)
quantized_indices = np.argmin(distances, axis=1) # 使用量化后颜色替换聚类中的像素颜色
quantized_image[labels == i] = quantized_colors[quantized_indices] # 存储聚类中心颜色
center_colors = kmeans.cluster_centers_.astype('uint8') return {'np_image': quantized_image, 'n_clusters': self.n_clusters, 'max_colors': self.max_colors, 'center_colors': center_colors}

(四)使用说明

# 创建压缩器对象
compressor = ColorfulImageCompressor(n_clusters=4, max_colors=2, resize_factor=0.5) # 压缩彩色图像
image_path = "./img/image2.jpg"
compressed_file_path = "./npz/compressed_image2_n4_c2.npz"
compressor.compress(image_path, compressed_file_path) # 解压缩图像并显示
reconstructed_image = compressor.decompress(compressed_file_path)
reconstructed_image.show()
reconstructed_image.save("./img/reconstructed_image2_n4_c2.jpg")

3.测试结果

测试图片我们使用的采用的一张818*818分辨率,大小为79.49KB的彩色图片。分别使用不同的聚类数量和颜色数量来进行测试。

原始图片 聚类数为8,颜色为2的压缩图片

详细运行数据如下表(下面文件名中的n为聚类数,而c为颜色数):

文件名 原始大小(KB) 压缩后的中间文件大小(KB) 解压缩后的图片大小 (KB)
reconstructed_image2_n4_c2 79.49 29.5 41.7
reconstructed_image2_n4_c4 79.49 49.3 45.2
reconstructed_image2_n4_c8 79.49 70.9 51.3
reconstructed_image2_n4_c16 79.49 94.3 59.3
reconstructed_image2_n8_c2 79.49 48.3 48.7
reconstructed_image2_n8_c4 79.49 73.3 52.5
reconstructed_image2_n8_c8 79.49 101 59.1
reconstructed_image2_n8_c16 79.49 125 61.1

结束语

如果有疑问欢迎大家留言讨论,你如果觉得这篇文章对你有帮助可以给我一个免费的赞吗?你们的认可是我最大的分享动力!

【Python】基于动态规划和K聚类的彩色图片压缩算法的更多相关文章

  1. [python] 基于词云的关键词提取:wordcloud的使用、源码分析、中文词云生成和代码重写

    1. 词云简介 词云,又称文字云.标签云,是对文本数据中出现频率较高的“关键词”在视觉上的突出呈现,形成关键词的渲染形成类似云一样的彩色图片,从而一眼就可以领略文本数据的主要表达意思.常见于博客.微博 ...

  2. Python基于回溯法解决01背包问题实例

    Python基于回溯法解决01背包问题实例 这篇文章主要介绍了Python基于回溯法解决01背包问题,结合实例形式分析了Python回溯法采用深度优先策略搜索解决01背包问题的相关操作技巧,需要的朋友 ...

  3. 用Python基于Google Bard做一个交互式的聊天机器人

    用Python基于Google Bard做一个交互式的聊天机器人 之前已经通过浏览器试过了 Google Bard ,更多细节请看: Try out Google Bard, Will Google ...

  4. python基于LeanCloud的短信验证

    python基于LeanCloud的短信验证 1. 获取LeanCloud的Id.Key 2. 安装Flask框架和Requests库 pip install flask pip install re ...

  5. Python实现kNN(k邻近算法)

    Python实现kNN(k邻近算法) 运行环境 Pyhton3 numpy科学计算模块 计算过程 st=>start: 开始 op1=>operation: 读入数据 op2=>op ...

  6. 纠错:基于FPGA串口发送彩色图片数据至VGA显示

    今天这篇文章是要修改之前的一个错误,前面我写过一篇基于FPGA的串口发送图片数据至VGA显示的文章,最后是显示成功了,但是显示的效果图,看起来确实灰度图,当时我默认我使用的MATLAB代码将图片数据转 ...

  7. Python基于共现提取《釜山行》人物关系

    Python基于共现提取<釜山行>人物关系 一.课程介绍 1. 内容简介 <釜山行>是一部丧尸灾难片,其人物少.关系简单,非常适合我们学习文本处理.这个项目将介绍共现在关系中的 ...

  8. Python 基于Python实现的ssh兼sftp客户端(上)

    基于Python实现的ssh兼sftp客户端   by:授客 QQ:1033553122 实现功能 实现ssh客户端兼ftp客户端:实现远程连接,执行linux命令,上传下载文件 测试环境 Win7 ...

  9. 聚类-DBSCAN基于密度的空间聚类

    1.DBSCAN介绍 DBSCAN(Density-Based Spatial Clustering of Applications with Noise,具有噪声的基于密度的聚类方法)是一种基于密度 ...

  10. Python基于socket模块实现UDP通信功能示例

    Python基于socket模块实现UDP通信功能示例 本文实例讲述了Python基于socket模块实现UDP通信功能.分享给大家供大家参考,具体如下: 一 代码 1.接收端     import ...

随机推荐

  1. ide构建SpringMVC框架

    框架原理图如下: 1. 创建如图项目 2. 在lib中所需导入jar包 3. 配置变量 (1) (2)add library (3)选择web app libraries 4. 配置web.xml文件 ...

  2. github、gitee冲突配置ssh key

    背景 当有多个git账号时,比如: a. 两个gitee,一个账号是用于公司内部的工作开发,一个账号是自己学习的个人账号: b. 一个github,用于自己进行一些开发活动: 操作: 生成不同的key ...

  3. uniapp中正确使用echart

    uniapp中不能直接使用百度echart,要么就只能嵌入html,然后在html中进入echart进行使用,这样非常不方便, 下面介绍这个插件,对百度echart进行局部小改造,使他能在uniapp ...

  4. kubernets之高级调度

    一 节点的污点以及pod的容忍度以及节点的亲缘性对比 1.1 首先需要介绍的是节点的污点以及pod的污点容忍度 污点是节点的属性,容忍度是pod的属性,只有当一个pod的容忍度包含节点的污点,pod才 ...

  5. Istio(一):服务网格和 Istio 概述

    目录 一.模块概览 二.微服务架构 三.服务网格概述 3.1 服务网格概述 3.2 为什么需要服务网格? 四.istio简介 4.1 Istio 简介 4.2 流量管理 4.3 可观察性 4.4 安全 ...

  6. GROUP BY clause and contains nonaggregated 报错处理

    1055 - Expression #16 of SELECT list is not in GROUP BY clause and contains nonaggregated column 报错处 ...

  7. Vue——生命周期

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. Android 13 - Media框架(29)- MediaCodec(四)

    关注公众号免费阅读全文,进入音视频开发技术分享群! 上一节我们了解了如何通过 onInputBufferAvailable 和 getInputBuffer 获取到 input buffer inde ...

  9. Android 13 - Media框架(23)- ACodecBufferChannel

    关注公众号免费阅读全文,进入音视频开发技术分享群! 这一节我们将了解 ACodecBufferChannel 上一节我们了解到input buffer 和 output buffer 是如何分配的了, ...

  10. 开源云原生平台对比 KubeSphere vs Rainbond

    最近因为工作需要,需要找一个功能完善的云原生应用平台,经过自己筛选和朋友推荐,剩下 KubeSphere和Rainbond ,这两个产品都是基于 Kubernetes 之上构建的云原生应用平台,功能都 ...