【Python】基于动态规划和K聚类的彩色图片压缩算法

description

引言

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

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.shapenp_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的彩色图片。分别使用不同的聚类数量和颜色数量来进行测试。

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

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

文件名原始大小(KB)压缩后的中间文件大小(KB)解压缩后的图片大小 (KB)
reconstructed_image2_n4_c279.4929.541.7
reconstructed_image2_n4_c479.4949.345.2
reconstructed_image2_n4_c879.4970.951.3
reconstructed_image2_n4_c1679.4994.359.3
reconstructed_image2_n8_c279.4948.348.7
reconstructed_image2_n8_c479.4973.352.5
reconstructed_image2_n8_c879.4910159.1
reconstructed_image2_n8_c1679.4912561.1

结束语

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/40105.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis理解【精细】【快速上手】

目录 1. 了解3V和3高 2.什么是redis 3. redis可以做什么 4. Windows安装 5. 使用redis客户端操作redis 5.1 redis基本命令 5.1.1 切换数据库 5.1.2 查看当前数据库的大小 5.1.3 查看当前数据库所有的key ​​​​​​​ 5.1.4 清空当前数据库所有key 5.1.5 清空所…

Element 的 el-table 表格实现单元格合并

html 部分 <template><div class"index-wapper"><el-table :data"tableData" :span-method"objectSpanMethod" border><el-table-column v-for"(item, index) in tableHeader" :key"index" :prop&quo…

vue中使用amis(做管理后台渲染器)

0.导入amis sdk 在github上下载 sdk.tar.gz&#xff1a;https://github.com/baidu/amis/releases 若网速不行&#xff0c;github下载不下来&#xff0c;可以这样&#xff1a; yarn add amis&#xff0c;然后在 node_modules\amis\sdk 目录里就能找到相关资源 public/index.…

Android Studio上传新项目到Gitee

一、在Gitee上创建仓库 首先需要再Gitee上创建仓库 1、在Gitee中新建仓库 2、输入仓库信息 3、生成仓库地址 创建成功会生成一个仓库地址&#xff0c;格式如下&#xff1a; https://gitee.com/test/compose_mvi_demo.git二、Android Studio 上传项目到Gitee 1、在Android …

全局优化与目标优化的异同

从porgo和optimtool的使用来解释 在多模态问题中&#xff0c;多数全局优化算法是通过设置跳跃局部最优点的比率来完成全局最优的搜索&#xff0c;这类算法需要利用到一阶梯度的局部信息&#xff0c;以至于演进方向的分叉导致了算法的执行复杂度按照搜索次数倍增。首先&#xf…

微信小程序转发朋友圈详细教程

微信小程序转发朋友圈功能&#xff0c;官方说的很官方&#xff0c;容易踩坑 官方链接戳这里 想分享朋友圈必须要分享好友 onShareTimeline() { } 想要生效必须先定义 onShareAppMessage() { } /*** 用户点击右上角分享*/onShareAppMessage() { },onShareTimeline() { } 简单…

不锈钢酸退作业区冷线氮氧分析仪采样系统优化改造

不锈钢酸退作业区冷线氮氧分析仪采样系统优化改造 一、项目提出前状况: (一)不锈钢酸退作业区酸洗线脱氮系统使用的废气监测仪器氮氧分析仪属于环保设备,数据检测的准确性直接影响环保指标,因此一旦数据检测有误,势必会引起环保事件。脱氮系统是将酸洗过程中产生的酸雾通…

一维信号全变分(TV)降噪方法(MATLAB)

信号降噪一直是领域研究的热点&#xff0c;这是一项十分有意义并且极具挑战性的工作&#xff0c;经过几十年来相关科研人员的共同努力&#xff0c;降噪技术得到了极大的发展&#xff0c;并在现实生活中也得到了广泛的应用。其中&#xff0c;许多常用的方法有&#xff1a;小波变…

深入Django(三)

Django视图&#xff08;Views&#xff09;详解 引言 在前两天的博客中&#xff0c;我们介绍了Django的基本概念和模型系统。今天&#xff0c;我们将深入探讨Django的视图&#xff08;Views&#xff09;&#xff0c;它们是处理用户请求和返回响应的地方。 什么是Django视图&a…

Golang 单引号、双引号和反引号的概念、用法以及区别

在 Golang&#xff08;Go 语言&#xff09;中&#xff0c;单引号 ()、双引号 (") 和反引号 () 用于不同类型的字符串和字符表示。以下是它们的概念、用法和区别&#xff1a; 1. 单引号 () 概念 单引号用于表示 字符&#xff08;rune 类型&#xff09;。一个字符表示一个…

免费最好用的证件照制作软件,一键换底+老照片修复+图片动漫化,吊打付费!

这款软件真的是阿星用过的&#xff0c;最好用的证件照制作软件&#xff0c;没有之一&#xff01; 我是阿星&#xff0c;今天要给大家安利一款超实用的证件照工具&#xff0c;一键换底&#xff0c;自动排版&#xff0c;免费无广告&#xff0c;让你在家就能轻松搞定证件照&#…

尚玩助手短视频看广告app开发

尚玩助手短视频看广告app的开发涉及多个关键步骤和考虑因素。以下是其主要开发流程&#xff1a; 需求分析和规划&#xff1a; 确定目标用户群体和市场定位。 收集和分析竞争对手的数据和特点&#xff0c;了解市场上已有的短视频app的优缺点。 确定尚玩助手短视频app的功能和特…

搭建知识付费系统的技术框架与实现路径

知识付费系统已经成为内容创作者和企业变现的重要工具。要成功搭建一个高效、稳定、用户体验良好的知识付费系统&#xff0c;明确技术框架和实现路径至关重要。本文将详细解析搭建知识付费系统的技术框架&#xff0c;并提供具体的实现路径和相关技术代码示例。 一、知识付费系…

C++之程序流程结构

C/C支持最基本的三种程序运行结构&#xff1a;顺序结构、选择结构、循环结构 顺序结构&#xff1a;程序按顺序执行&#xff0c;不发生跳转选择结构&#xff1a;依据条件是否满足&#xff0c;有选择的执行相应功能循环结构&#xff1a;依据条件是否满足&#xff0c;循环多次执行…

测试图片上传功能,使用postman提供的url

是不是有时候想要测试图片上传功能&#xff0c;但是没有后台url进行测试&#xff0c;这时候就可以使用postman提供的url&#xff1a; https://postman-echo.com/post接下来&#xff0c;我将教你在postman中&#xff0c;用该url测试图片上传功能。 1.发送图片上传请求 第一步…

Character.ai因内容审查流失大量用户、马斯克:Grok-3用了10万块英伟达H100芯片

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 更多资源欢迎关注 1、爆火AI惨遭阉割&#xff0c;1600万美国年轻人失恋&#xff1f;Character.ai被爆资金断裂 美国流行的社交软件Character.ai近期对模型进行大幅度内容审查&#xff0c;导致用户感到失望并开始流失。…

12. Revit API: Document、Element

12. Revit API: Document、Element 前言 还是先讲一下Document吧&#xff0c;不然Selection不好讲&#xff0c;那涉及到了挺多东西的&#xff0c;比元素&#xff08;Element&#xff09;和各类Filter&#xff0c;这些都与Document有关&#xff0c;所以先简单讲一下这个。 一、…

Chart.js四个示例

示例代码在图片后面&#xff0c;点赞加关注&#xff0c;谢谢 条形图 雷达图 折线图 圆环图 完整例子代码 具体代码在干什么看粗体加重的注释 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <me…

【linux/shell实战案例】linux中变量的使用

目录 一.linux变量声明及定义 二.linux变量使用方法 三.linux变量使用花括号${name}和双引号“$name”的区别 四.linux变量使用单引号$name和双引号“$name”的区别 五.linux变量中使用命令 一.linux变量声明及定义 #!/bin/bash namezhaodabao 等号两边不能有空格变量名…

C++精解【10】

文章目录 读写文件概述example csv读文件读取每个字段读取机器学习数据库iris constexpr函数GMP大整数codeblock环境配置数据类型函数类 EigenminCoeff 和maxCoeffArray类 读写文件 概述 fstream typedef basic_fstream<char, char_traits<char>> fstream;此类型…