数字图像处理 -- 霍夫曼编码(无损压缩)练习

devtools/2025/4/2 12:05:58/

算法的设计说明

目标

  • 对彩色图像进行压缩,使用霍夫曼编码方法对图像的每个像素进行编码,从而减少其存储空间。
  • 解码时,能够恢复图像的原始像素数据,确保图像在经过压缩和解压后与原图像一致。

输入

  1. 原始图像(以RGB格式存储)
  2. 霍夫曼编码的输入是图像的像素数据(RGB元组),每个像素表示为一个 (R, G, B) 的三元组

输出

  1. 霍夫曼编码后的图像数据(以二进制字符串形式存储)
  2. 解码后的图像(还原为原始的RGB图像)

算法设计

1. 图像数据表示:
  • 首先,读取图像并将其转换为RGB数据格式。图像的每个像素由三个数字表示,分别表示红、绿、蓝颜色的强度。
  • 图像数据被展平成一个二维数组,每一行包含一个像素的 (R, G, B) 元组。
2. 霍夫曼编码过程:
2.1 统计频率:
  • 使用 collections.Counter 来计算图像中每个颜色(RGB元组)出现的频率。由于图像中可能有大量相同的像素颜色,这些颜色会有较高的频率。
2.2 构建霍夫曼树:
  • 根据频率生成霍夫曼树,具体步骤是:
    • 将每个RGB元组和其对应的频率放入最小堆(heapq)。最小堆的作用是快速取出频率最小的元素。
    • 通过不断合并最小频率的元素(叶子节点),直到堆中只剩下一个元素。每次合并时,生成一个新的内部节点,该节点的频率是合并的两个节点的频率之和。
    • 在合并过程中,为每个节点的左子树和右子树分配不同的二进制数字(‘0’ 和 ‘1’),从而为每个RGB元组分配唯一的霍夫曼编码。
2.3 生成霍夫曼编码字典:
  • 遍历霍夫曼树,基于树的结构为每个RGB元组分配霍夫曼编码。
  • 将每个RGB元组与其对应的编码保存在字典中 huffman_code 中,键是RGB元组,值是该RGB元组的霍夫曼编码。
2.4 编码图像数据:
  • 使用生成的霍夫曼编码字典,将每个像素的RGB元组转换为对应的二进制编码。通过遍历图像的每一个像素,将每个RGB元组替换为其对应的霍夫曼编码,最终形成一个长的二进制字符串(encoded_data)。
3. 霍夫曼解码过程:
3.1 反转编码字典:
  • 由于霍夫曼编码是可逆的,解码时需要通过编码字典的反向映射来恢复原始的RGB元组。
  • 通过交换字典中的键和值,创建一个反向编码字典 reverse_code,其中每个二进制编码映射回相应的RGB元组。
3.2 逐位解码:
  • 解码过程从编码字符串的开头开始,逐个读取二进制位。通过将这些位拼接成一个二进制字符串,不断与反向字典匹配,直到匹配到一个完整的RGB元组。
  • 一旦匹配成功,恢复出RGB元组并将其添加到解码后的数据中,然后继续处理剩余的编码。
3.3 重建图像数据:
  • 解码后的像素数据被存储为一个列表 decoded_data,最终通过 np.array(decoded_data) 将其转换为NumPy数组,并恢复图像的原始形状(根据图像的宽、高、颜色通道数)。
4. 文件保存与恢复:
4.1 保存编码数据**:**
  • 编码后的数据(霍夫曼编码后的二进制字符串)被保存到一个文本文件中 霍夫曼编码后的文件.txt,以便后续使用。
4.2 保存解码后的图像:
  • 解码后的图像数据(恢复的RGB图像)被保存为一个新图像文件 霍夫曼解码后的图片.bmp

复杂度分析

  1. 时间复杂度:
    • 统计频率:O(n),其中 n 是图像中像素的总数。
    • 构建霍夫曼树:O(m log m),其中 m 是图像中唯一RGB颜色的数量。最坏情况下,m 接近 n,因此复杂度大约为 O(n log n)
    • 编码:O(n),遍历每个像素并通过字典获取霍夫曼编码。
    • 解码:O(n),遍历编码数据并通过反向字典恢复像素数据。
  2. 空间复杂度:
    • 霍夫曼编码字典:O(m),其中 m 是图像中的唯一RGB颜色数。
    • 图像数据:O(n),存储图像的像素数据。

总结

  • 压缩过程: 使用霍夫曼编码通过统计图像中颜色的频率为每个颜色分配一个二进制编码,常见颜色的编码较短,不常见的颜色的编码较长,从而压缩图像的数据量。
  • 解压过程: 通过反向映射的霍夫曼编码字典,逐步将二进制编码恢复为原始的RGB颜色值,重建图像数据。

代码

import numpy as np
from collections import Counter
import heapq
import os
from PIL import Image# 加载上传的图像
image_path = "图像原图.bmp"
image = Image.open(image_path)# 将原始图像转换为RGB(以保留颜色信息)
rgb_image_data = np.array(image)# 对彩色图像进行霍夫曼编码
def huffman_encoding_rgb(data):data_flat = data.reshape(-1, data.shape[2])freq = Counter(tuple(pixel) for pixel in data_flat)# 为霍夫曼编码创建最小堆heap = [[weight, [symbol, ""]] for symbol, weight in freq.items()]heapq.heapify(heap)while len(heap) > 1:lo = heapq.heappop(heap)hi = heapq.heappop(heap)for pair in lo[1:]:pair[1] = '0' + pair[1]for pair in hi[1:]:pair[1] = '1' + pair[1]heapq.heappush(heap, [lo[0] + hi[0]] + lo[1:] + hi[1:])huffman_code = dict(sorted(heap[0][1:], key=lambda p: p[0]))encoded_data = ''.join([huffman_code[tuple(pixel)] for pixel in data_flat])return huffman_code, encoded_data# 解码霍夫曼编码后的RGB图像数据
def decode_huffman_rgb(encoded_data, huffman_code, image_shape):reverse_code = {v: k for k, v in huffman_code.items()}decoded_data = []temp_code = ''for bit in encoded_data:temp_code += bitif temp_code in reverse_code:decoded_data.append(reverse_code[temp_code])temp_code = ''return np.array(decoded_data).reshape(image_shape)# 保存编码后的数据到文件
def save_encoded_data(filename, encoded_data):with open(filename, 'w') as f:f.write(encoded_data)output_dir = os.path.join(os.path.dirname(image_path), "compressed_files")
os.makedirs(output_dir, exist_ok=True)huffman_code_rgb, encoded_data_rgb = huffman_encoding_rgb(rgb_image_data)huffman_encoded_filename = os.path.join(output_dir, "霍夫曼编码后的文件.txt")
save_encoded_data(huffman_encoded_filename, encoded_data_rgb)decoded_huffman_rgb_image_data = decode_huffman_rgb(encoded_data_rgb, huffman_code_rgb, rgb_image_data.shape)decoded_huffman_rgb_image = Image.fromarray(decoded_huffman_rgb_image_data.astype(np.uint8))huffman_decoded_rgb_image_filename = os.path.join(output_dir, "霍夫曼解码后的图片.bmp")
decoded_huffman_rgb_image.save(huffman_decoded_rgb_image_filename)# 计算压缩比、比特率、信噪比# 计算原始图像的大小(单位:比特)
original_size_bits = rgb_image_data.size * 8  # 每个像素3个通道,每个通道8位# 计算霍夫曼编码后的文件大小(单位:比特)
huffman_encoded_size_bits = len(encoded_data_rgb)# 计算压缩比
compression_ratio = original_size_bits / huffman_encoded_size_bits# 计算比特率
bit_rate = huffman_encoded_size_bits / rgb_image_data.size  # 每个像素的比特数# 计算信噪比(SNR)
# 计算均方误差(MSE)
mse = np.mean((rgb_image_data - decoded_huffman_rgb_image_data) ** 2)
# 计算信号的方差(原始图像的方差)
signal_variance = np.var(rgb_image_data)
# 计算SNR
snr = 10 * np.log10(signal_variance / mse)# 输出计算结果
print("压缩比:", compression_ratio)
print("比特率:", bit_rate)
print("信噪比 (SNR):", snr)# 返回保存文件的路径供下载
huffman_encoded_filename, huffman_decoded_rgb_image_filename

相关指标计算

表格统计
压缩比比特率 (比特/像素)信噪比 (SNR)
13.582650.588987inf
综合分析
  1. 压缩效果:
    • 压缩比为 13.58,说明压缩算法在保持图像质量的同时显著减少了文件的大小,这意味着该压缩方法压缩效率较好。
  2. 比特率:
    • 0.589 比特/像素 表示每个像素仅需不到 1 比特的存储空间,这也表明压缩方法比较高效,能够以非常小的存储空间表示每个像素。
  3. 图像质量:
    • 由于 SNR 为无限,表示该压缩方法是 无损的。无损压缩意味着图像的所有细节和信息都被完全保留,恢复后的图像与原始图像没有任何差异。

http://www.ppmy.cn/devtools/172816.html

相关文章

基于STC89C51的太阳自动跟踪系统的设计与实现—单片机控制步进电机实现太阳跟踪控制(仿真+程序+原理图+PCB+文档)

摘 要 随着我国经济的飞速发展,促使各种能源使用入不敷出,尤其是最主要的能源,煤炭石油资源不断消耗与短缺,因此人类寻找其他替代能源的脚步正在加快。而太阳能则具有无污染﹑可再生﹑储量大等优点,且分布范围广&…

SQL语言分类及命令详解(一)

目录 1. DQL(Data Query Language)数据查询语言 主要命令: SELECT 2. DDL(Data Definition Language)数据定义语言 主要命令: CREATE ALTER DROP TRUNCATE(清空表数据,保留…

PHP 包含:深入理解与最佳实践

PHP 包含:深入理解与最佳实践 引言 在PHP编程中,文件包含是一个核心功能,它允许开发者将一个文件的内容插入到另一个文件中。这一功能在模块化编程、代码重用以及提高页面加载速度等方面发挥着重要作用。本文将深入探讨PHP的包含功能,包括其工作原理、不同类型的包含方式…

【VSCode的安装与配置】

目录: 一:下载 VSCode二:安装 VSCode三:配置 VSCode 一:下载 VSCode 下载地址:https://code.visualstudio.com/download 下载完成之后,在对应的下载目录中可以看到安装程序。 二:安装…

IPv6 网络访问异常 | 时好时坏 / 部分访问正常

注:本文为 “ IPv6 间接性连接异常” 相关文章合辑。 略作重排,未去重。 如有内容异常,请看原文。 IPv6 间接性连接异常?尝试调整路由器的 MTU 设置 Nero978 2024-1-29 17:54 背景 2024 年 1 月 29 日,因寒假返家…

PyTorch中的Tensor

PyTorch中的Tensor‌ 是核心数据结构,类似于 NumPy 的多维数组,但具备 GPU 加速和自动求导等深度学习特性。 一、基本概念 ‌核心数据结构‌ Tensor 是存储和操作数据的基础单元,支持标量(0D)、向量(1D&am…

【安全运营】关于攻击面管理相关概念的梳理(二)

CYNC(持续可见性和网络控制) CYNC(Continuous Visibility and Network Control)即“持续可见性和网络控制”,是一个与网络安全和IT运营管理相关的概念。它强调的是在一个组织的数字环境中,确保对所有资产、…

Java-sort(自定义排序)

今天学到了java的匿名内部类,然后看到了通过匿名内部类的sort,感觉和c里的sort(v.begin(),v.end(),cmp) --->bool cmp() 有点像哈。 学生类: package com.itheima.demo4;public class Student {private String n…