多媒体数据处理实验1:算术编码

article/2025/9/16 2:43:43

1. 算法描述

功能:

  给定概率字典以及待编码字符串,求出该字符串算术编码的结果(最短二进制串),并能根据算数编码结果进行解码,得到原字符串。

2.算法流程:

算术编码流程:

  (1) 首先,初始化概率区间上下界分别为1和0。读入第一个字符,并根据该字符的概率区间更新当前区间,具体方法为:
u p p e r _ b o u n d = l o w e r _ b o u n d + i n t e r v a l L e n g t h ∗ p r o b D i c t [ c h r ] [ 1 ] l o w e r _ b o u n d = l o w e r _ b o u n d + i n t e r v a l L e n g t h ∗ p r o b D i c t [ c h r ] [ 0 ] upper\_bound = lower\_bound + intervalLength * probDict[chr][1]\\ lower\_bound = lower\_bound + intervalLength * probDict[chr][0] upper_bound=lower_bound+intervalLengthprobDict[chr][1]lower_bound=lower_bound+intervalLengthprobDict[chr][0]
其中 i n t e r v a l L e n g t h intervalLength intervalLength表示当前区间长度, p r o b D i c t [ c h r ] [ 1 ] , p r o b D i c t [ c h r ] [ 0 ] probDict[chr][1], probDict[chr][0] probDict[chr][1],probDict[chr][0]分别表示当前字符的概率区间上下界。

  (2) 然后,继续读入下一字符并不断更新当前概率区间,直到最后一个字符处理完毕后退出循环,得到最终的概率区间。

  (3) 根据最终概率区间求出该区间内的最短二进制串,方法如下:从第一个二进制位开始,若当前位置1得到的数大于区间上界,则将该位置0;若当前位置1得到的数恰好在区间内(即恰好大于下界),则该位置1不变,然后直接出循环,无需生成后续的位数;若当前位置1得到的数小于下界,则该位置1。如此可保证求出的二进制串必为该区间内的最短二进制串。

算术解码流程:

  (1) 将编码得到的二进制串转为十进制小数,记作 e n c o d e d D e c encodedDec encodedDec

  (2) 先看 e n c o d e d D e c encodedDec encodedDec落在哪个字符的概率区间内,若它落在字符 c c c的概率区间内,则解码出的第一个字符即为 c c c

  (3) 接下来,继续对当前区间进行划分,得到概率字典中各字符的新概率区间,再看现在 e n c o d e d D e c encodedDec encodedDec落在哪个字符对应的区间内,则第二个解码出的字符就是该字符。

  (4) 重复步骤(3)直到循环次数达到字符串长度,完成解码过程。

求区间内的最短二进制串流程:

  从小数点后第一位开始往后:若该位置1得到的数大于区间上界,则将该位置0;若当前位置1得到的数恰好在区间内(即恰好大于下界),则该位置1不变,然后直接出循环,无需生成后续的位数;若当前位置1得到的数小于下界,则该位置1。

3. 核心代码

# 算术编码函数:输入为字符串和概率字典,返回最终区间的上下界
def arithEncode(string, probDict):lower_bound = Decimal('0.0')upper_bound = Decimal('1.0')for chr in string:intervalLength = upper_bound - lower_bound  # 区间长度# 不断更新区间上下界,注意必须先更新上界,否则会导致上界更新错误(因为上界的计算用的是上一次的下界)upper_bound = lower_bound + intervalLength * probDict[chr][1]lower_bound = lower_bound + intervalLength * probDict[chr][0]print(lower_bound, upper_bound)# 返回最终区间的上下界return lower_bound, upper_bound# 求出最终区间内的最短二进制串
def dec2Bin(lower_bound, upper_bound):binStr = ''# 初始化01串转为的二进制数为0.0temp = Decimal(0.0)  i = 1  # 初始化幂为1while(1):bit = 1# 若当前位 置1 得到的数大于区间上界,则将该位 置0,temp不变if((temp + Decimal(1 / (2 ** i) * bit)) > upper_bound):bit = 0binStr += '0'# 若当前位 置1 得到的数恰好在区间内(即恰好大于下界),则该位 置1 不变,然后直接出循环,无需生成后续的位数else:if((temp + Decimal(1 / (2 ** i) * bit)) > lower_bound):binStr += '1'break# 若当前位 置1 得到的数小于下界,则该位 置1 else:binStr += '1'# 更新temptemp += Decimal(1 / (2 ** i) * bit)# 阶数自增1,下一轮循环时用i += 1return binStr# 二进制串转十进制小数(乘二取整)
def bin2Dec(bin):dec = Decimal(0.0)for i in range(len(bin)):if(bin[i] == '1'):dec += Decimal(1 / (2 ** (i + 1)))# 这里返回的数据类型一定要是Decimalreturn dec# 算术解码函数:输入为已编码二进制串、概率字典、字符串长度,返回解码后的字母串
def arithDecode(encodedBin, probDict, strLength):decodedStr = ''# probDict_copy存放原始的概率字典probDict_copy = deepcopy(probDict)# 二进制串转十进制小数encodedDec = bin2Dec(encodedBin)# 因为要解码出strLength个字符,所以共循环strLength次for _ in range(strLength):# 如果编码数字落在某个字符的概率区间内,则在结果中加入该字符for chr, interval in probDict.items():if((encodedDec >= interval[0]) & (encodedDec < interval[1])):decodedStr += chr# 继续对当前区间划分,看编码数字落在哪个字符对应的区间内# 更新字典中各字符的概率区间temp_lower_bound = interval[0]    # 记录当前区间下界和区间长度intervalLength = interval[1] - interval[0]for chr in probDict.keys():probDict[chr][0] = temp_lower_bound + intervalLength * probDict_copy[chr][0]probDict[chr][1] = temp_lower_bound + intervalLength * probDict_copy[chr][1]breakreturn decodedStr

4. 实验结果

[外链图片转存中...(img-uSu7JNve-1659445339484)]

  结果分析:用户输入待编码各字符、各字符的概率以及需要编码的字符串,程序会先构造出概率字典,然后输出算数编码的最终结果,即最短二进制串和对应的十进制浮点数。在编码成功后,程序对编码得到的二进制串解码,最终的解码结果与原字符串一致,说明解码准确率为100%。从程序运行的结果可以看到,本实验成功实现了对给定概率字典的字符串的无损算术编码及解码。

5. 分析与总结

 1. 通过本次实验,我掌握了算术编码及解码的基本算法思想,并通过编程实现了算数编码及解码的过程,提高了自己的动手实践能力,对于Python语言中的float、Decimal等数据类型的概念和用途有了更深的理解。

  2. 题目要求我们求出在最终概率区间内的最短二进制串作为算术编码结果,但我一开始没有想到最短二进制串的求法,于是我在草稿纸上从小数位第一位开始逐位向后推算,看每一位上1和上0后得到的十进制数在不在概率区间内,最后推出了求最短二进制串的算法。其实我们在碰到看起来不会解决的问题时,不妨先静下心来拿出纸笔演算几步,说不定就能得出解法,而不是对着电脑在大脑里思考,这样做效率是很低下的。

  3. 在写算术编码函数的时候,按照算法流程,我们需要反复更新概率区间的上下界,在这个过程中我们是利用上一次的概率区间下界以及当前字符的概率区间上下界去更新的。我一开始在写这个函数的时候,没注意到必须要先更新upper_bound再更新lower_bound,而是先更新了lower_bound。这么做会导致新的区间上界是用新的区间下界更新的,而不是用上一次的下界更新的,后来我调试的时候发现了这一错误并且改正了。

  4. 关于数据类型的收获:Python中的float类型无法在任意指定的小数位上保持精确,因此在实验过程中所有的数值均转化为了Decimal类型,以保证精确计算(Decimal的精度默认是28位)。在对于运行效率要求不是很高而对于精度要求很高时,可以使用Decimal保精度,若对于运行效率的要求较高而不怎么在意精度,则使用float类型也无妨。

源码:多媒体数据处理实验1:算术编码


http://chatgpt.dhexx.cn/article/Io1mXTtP.shtml

相关文章

数字图像算术编码python_算术编码简介

上一篇讲了LZW编码&#xff0c;本篇讨论另一种不同的编码算法&#xff0c;算数编码。和哈夫曼编码一样&#xff0c;算数编码是熵编码的一种&#xff0c;是基于数据中字符出现的概率&#xff0c;给不同字符以不同的编码。本文也会对这两种编码方式的相似和不同点进行比较。 编码…

算术编码

文章首发于我的个人博客 前言 这篇博客主要总结大二下课程《信息论》实验的内容。主要包含固定模式的算数编码以及自适应模式的算术编码。我将首先介绍这两种算术编码的基本思想和实现思路&#xff0c;然后给出具体的python代码并对代码中的一些关键点进行解释说明。 固定模…

算术编码原理及其python实现

目录 1. 原理部分&#xff1a;2. 香农界理论分析&#xff1a;3. 代码实现&#xff1a;4.实验结果 1. 原理部分&#xff1a; 原理部分参考什么是算术编码 一个从信源序列到不可压缩二元序列的一个可逆映射&#xff0c;假设序列 { X 1 … X n } \{X_{1} \ldots X_{n}\} {X1​…X…

基本算术编码

1.基本思想 算术编码&#xff0c;就是用一个数编码一串字符串。它的思想是这样的:对一个需要编码的字符串&#xff0c;给出一个初始区间[0, 1),这个区间被分成n份&#xff0c;n是这串字符串中不同字符的个数&#xff0c;每一份占区间长度的比例与相应字符出现次数占整个字符串…

算术编码的基本概念

二、算术编码的基本概念 算术编码属于熵编码的一种重要的类型&#xff0c;其作用同变长编码等熵编码方法类似&#xff0c;用于压缩输入数据中的统计冗余&#xff0c;并且使用算术编码的压缩同样是无损压缩。 在本系列第1篇中讨论了典型的变长编码方法——哈夫曼编码。包括哈夫…

Otsu大津算法公式推导及python实现

目录 前言 一、类间平方差是什么&#xff1f; 二、公式推导及实现 1.求类间平方差 2.opencv-python编程实现 2.1 引入图像并灰度化 2.2 查看灰度值的分布情况 2.3 求全局平均阈值 2.4 求最大类间方差 3.算法的验证 总结 前言 OTSU&#xff08;大津算法&#xff09;是…

OTSU算法原理

OTSU算法原理及实现&#xff1a; 最大类间方差是由日本学者大津(Nobuyuki Otsu)于1979年提出&#xff0c;是一种自适应的阈值确定方法。算法假设图像像素能够根据阈值&#xff0c;被分成背景[background]和目标[objects]两部分。然后&#xff0c;计算该最佳阈值来区分这两类像素…

大津阈值分割算法(OTSU处理图像)

1.算法原理简述 对于图像I(x,y)&#xff0c;前景(即目标)和背景的分割阈值记作T&#xff0c;属于前景的像素点数占整幅图像的比例记为ω0&#xff0c;其平均灰度μ0&#xff1b;背景像素点数占整幅图像的比例为ω1&#xff0c;其平均灰度为μ1。图像的总平均灰度记为μ&#xf…

[图像处理]14.分割算法比较 OTSU算法+自适应阈值算法+分水岭

参考文献&#xff1a; OTSU阈值分割孔洞填充海陆分离_SwordKii的博客-CSDN博客 drawContours函数_普通网友的博客-CSDN博客_drawcontours R329-opencv阈值分割算法——自适应阈值_Third Impact的博客-CSDN博客_opencv自适应阈值分割 分水岭算法的python实现及解析_进不去的…

OTSU算法 (大津算法)理解代码

OTSU算法&#xff1a;对图像进行二值化的算法 介绍 OTSU算法是一种自适应的阈值确定的方法&#xff0c;又称大津阈值分割法&#xff0c;是最小二乘法意义下的最优分割。 它是按图像的灰度特性&#xff0c;将图像分成背景和前景两部分。因方差是灰度分布均匀性的一种度量,背景…

Pr-快速上手-基本操作-教程

视频链接: Pr教程 视频设计到的知识点: 视频的剪辑bgm的管理添加字幕及弹幕的添加鬼畜视频的制作发布教程

Pr常用操作技巧

操作技巧持续更新中 1.premiere如何裁剪视频尺寸 视频尺寸怎么修改 1.将premiere左下角的视频素材直接向右拖动到编辑区中 2.鼠标左键单击视频,然后选择上方的【效果】 3.这时,页面左侧将弹出效果的菜单栏,依次选择效果→视频效果→变换→裁剪 4.鼠标左键按住【裁剪】不放,直接…

Premiere: 基本操作

1、首先进入编辑模式&#xff0c;使得视频能加效果 2、这时候能找到视频的效果添加&#xff0c;这里有视频的水平翻转&#xff0c;高斯模糊等&#xff0c;需要什么效果直接&#xff0c;把该效果抓到视频上就可以。

PR的入门基础教程

提示&#xff1a;这里只记述作者学习PR入门基础教程视频后的总结 文章目录 常用视频概念第1天学习总结第2天学习总结第3天学习总结 常用视频概念 第1天学习总结 第2天学习总结 第3天学习总结

Adobe Premiere Pro快速入门教程

简介&#xff1a; 适用于纯新手零基础&#xff0c;看完本教程即可完成常用视频编辑技巧。 采用Adobe Premiere Pro 2020版本 windows10操作系统 一、制作 照片音频字幕的视频 目标&#xff1a;把三张图片和一个音乐做成带字幕的视频。&#xff08;素材请自行准备&#xff0…

使用pr的8大技巧

许多小伙伴是通过pr这个软件进行素材剪辑的&#xff0c;当我们面对许多素材需要剪辑的时候&#xff0c;往往被这些素材弄得头昏脑涨&#xff0c;剪辑拼接的费时费力&#xff0c;最后出来的成品效果也不太好&#xff0c;下面就告诉大家一些pr使用的技巧&#xff0c;来提升我们的…

Premiere 零基础快速上手教程

关注并星标“高级农民工” 回复“视频”可获取视频剪辑软件和教程 在前几天的文章中&#xff0c;我分享了几款主流视频剪辑软件&#xff1a; 最主流的视频剪辑软件 简单来说就是&#xff0c;手机端用「剪映」这一款 app 就够&#xff0c;当你熟练到发现手机剪视频不方便&#x…

pr基础学习笔记

pr基础学习笔记&#xff08;正题&#xff09; 推荐几个小技巧 1.快速插入 2.快速移动小片段 2. 另&#xff1a;移动Ctrl是多轨移动移动CtrlAlt是单轨移动3.如何去除两个片段之间的空档&#xff1f; 4.两种选择工具的比较 附&#xff1a; pr快捷键 应用程序 选择工具…

pr基础入门

一、快速认识 PR 主界面并导入素材 修改 名称、位置&#xff0c;其他不用变&#xff0c;点击确定 进入界面如下&#xff1a; 认识、添加必要 窗口 导入素材方法 1.直接将文件拖入pr中 2.导入媒体以开始&#xff0c;部分右键创建 素材箱 进入素材箱&#xff0c;右键选择导入&a…

PR(基础剪辑)

一.剪辑步骤&#xff1a; 1.先粗剪后精剪&#xff1a; 粗剪&#xff1a; 精剪&#xff1a; 二. 常用键&#xff1a; 1. i&#xff1a;设置素材的起点 o&#xff1a;设置素材的终点 &#xff08;在预览素材时&#xff09; 2.快速浏览素材&#xff1a; l&#xff1a;按一次常速…