算术编码(xdu多媒体实验一)

  • 前言
  • 详细原理
  • 源代码

前言

算术编码(多媒体实验一)
sklearn主成分分析pca用python实现(多媒体实验二)
BOW图像检索corel数据集(多媒体实验三)
手写数字识别(多媒体实验五)

不要问我为什么没第四个 ,因为LSH和idestence实验我也不会,是从网上搬的,所以不发了。
所有实验代码:Vsingeryh/Media_xdu


关于本文的一些联想:
我曾读到大刘(可能是)的一本短片科幻小说集,其中有一个故事说的与算术编码有关,但当时我并不清楚其原理,非常震惊。类似居然有人提问过:如果有个飞船,在某处画个点,就能解码出一套百科全书,真的可能么?。
故事讲述的是一个外星人来到地球,然后获取了地球的所有知识,包括地球的历史,科技,自然风光等等记录。然后他们带回去的时候只是在飞船上刻了一个记号,这个记号的精度非常之高,其中承载的信息就是整个地球知识的信息熵。等到他们回去只需要测量这个记号到船头的距离就可以解码出所有的知识。
我希望看完本文你可以懂其中的道理,以及对信息论的进一步深思。虽然是个美好的科幻小说,但宇宙的时空是不连续的,精度在也不可能超过普朗克尺度,也就是说宏观的精度是有极限的,所以这篇小说只是一个美妙的幻想罢了。

本文解决的问题:

详细原理参考算数编码原理解析。实验原理并不难,但网上大部分代码未解决两个问题。本文主要旨在实现以下两方面。

  1. 不能自行计算出字符串概率。这个很好解决,但不清楚为何很多博客代码仍需手动输入各个字符概率。
  2. 不能求出左右区间内最小的二进制编码对应十进制小数。此问题需要对二进制编码了解才能算出,本文可以求出算数编码的最短二进制编码。

详细原理

请务必看完算数编码原理解析或了解原理后再读以下内容。
用例子简单介绍一下:

  1. 假设输入字符串为ARBCRARBCRARBCR,那么A,B,CA,B,CA,B,C出现概率为0.20.20.2,RRR出现概率为0.40.40.4。
  2. 在[0,1][0,1][0,1]内 划分字符概率区间。此处按照字典序来排序即A[0,0.2]A[0,0.2]A[0,0.2],B[0.2,0.4]B[0.2,0.4]B[0.2,0.4],C[0.4,0.6]C[0.4,0.6]C[0.4,0.6],R[0.6,1]R[0.6,1]R[0.6,1]。
  3. 划分概率实际上和哈夫曼编码不允许前缀码相同的意思一样,只不过算术更加精细,更接近信息熵的本质。
    假设deltadeltadelta为区间大小,初始左边界low=0.0low=0.0low=0.0,右边界high=1.0high=1.0high=1.0,那么delta=1.0delta=1.0delta=1.0。字符charcharchar的区间为[L,R][L,R][L,R]。
  4. 我们想要对第一个A[0,0.2]A[0,0.2]A[0,0.2]进行编码,更新左边界low=low+delta∗Llow=low+delta*Llow=low+delta∗L,那么low=0+1.0∗0=0low=0+1.0*0=0low=0+1.0∗0=0。同理右边界high=0+1.0∗0.2=0.2high=0+1.0*0.2=0.2high=0+1.0∗0.2=0.2。
    再看第二个字符R[0.6,1]R[0.6,1]R[0.6,1],此时左边界更新为low=0+0.2∗0.6=0.12low=0+0.2*0.6=0.12low=0+0.2∗0.6=0.12,右边界high=0+0.2∗1=0.2high=0+0.2*1=0.2high=0+0.2∗1=0.2。
    依次类推,最终得到区间[0.14432,0.1456][0.14432,0.1456][0.14432,0.1456]。其中抽取任意一个值就可以利用字符概率表得到原字符串。

原理部分并不难,主要是左右边界的迭代,公式为:
low=low+(high−low)∗Llow=low+(high−low)∗Llow=low+(high−low)∗L
high=low+(high−low)∗Hhigh=low+(high−low)∗Hhigh=low+(high−low)∗H

代码实现如下:

double low = 0.0;double high = 1.0;for (auto it = str.begin(); it != str.end(); it++) {double delta = high - low;high = low + delta * mp[*it].high;low = low + delta * mp[*it].low;}

然后解决我们上述所说的两个问题。
其一:怎么输入字符串后统计概率呢?
很简单,当输入字符串时,我们用一个数组记录每个数字出现的次数,由于输入的是ASCII码,我们只需建立一个大小256的数组记录次数。然后调用string.lenth()string.lenth()string.lenth()函数获得长度或者提前输入字符串长度nnn,最后用次数除以长度即可得到出现频率,频率区间按照字典序叠加即可,即字典序上一个的字母的右边界变为字典序下一个字母的左边界。最后我们将其字符及左右区间和区间长度放入map里方便查询。

const int N = 256;
int len;//长度
string str;
int char_num[N];//统计字符
struct node {//字符及概率区间char c;double l, r;
}ch[N];
struct spcode {double low=0.0, high=1.0, delta;//区间左右端及大小spcode() = default;spcode(double a, double b) :low(a), high(b), delta(b-a) {}
};
map<char, spcode> mp;
void create() {memset(char_num, 0, sizeof(char_num));printf("输入字符串个数n\n");cin >> len;printf("输入字符串:\n");cin >> str;for (auto i = 0; i < str.length(); i++)//统计概率char_num[str[i]]++;double last = 0.0;//字典序上一个字母频率的右边界for (int i = 0; i <N; i++) {if (char_num[i]) {//该字符出现过ch[i].c = i;ch[i].l = last;ch[i].r = last + double(char_num[i]) / len;last = ch[i].r;}}for (auto i = 0; i < str.length(); i++) {if (char_num[str[i]]) {mp.insert(make_pair(str[i], spcode(ch[str[i]].l,ch[str[i]].r)));}}
}

我们调用map查看其字符及左右区间和区间长度:

for (auto it = mp.begin(); it != mp.end(); it++) {cout << it->first <<  " (";cout << it->second.low << " ";cout << it->second.high << ") ";cout << it->second.delta << "\n";}

效果如下:

其二:在获取最终的左右区间[low,high][low,high][low,high]之后,怎样从中抽取出一个小数可以使其转化后的二进制编码最短?
最核心的思路显然是,当某个二进制小数在某一位后全为0,那么就可以舍弃掉,也就是确定最需要的1在哪一位。有两种思路。

  1. 十进制转二进制来考虑。既然左右边界确定了,那么对应的左右边界转为二进制,当第一次出现不一样的0,1时,说明此处最短。举个例子,左右边界转为二进制分别为0.1010011,0.101111001,第四位开始不一样,那么取0.1011即为最短的二进制表示。
  2. 二进制转十进制考虑,二进制的每一位分别对应十进制0.5,0.25,0.1250.5,0.25,0.1250.5,0.25,0.125……我们初始化ans=0.0ans=0.0ans=0.0,然后需要考虑ans加上每一位对应十进制后是否在区间内,当第一次满足在区间内时即为最短。

本文实现的是第二种方法:如果需要该位即为1,不需要为0。

 string anstr = "";double ans = 0.0;int cnt = 1;while (ans < low) {ans += pow(0.5, cnt);anstr += '1';if (ans >= high) {ans -= pow(0.5, cnt);anstr[cnt-1] = '0';}cnt++;}db = ans;return anstr;

源代码

演示效果如图所示:

源码如下:

#include <iostream>
#include <map>
#include <string>
#include <cstring>
#include<math.h>
using namespace std;
const int N = 256;
int len;//长度
string str;
int char_num[N];//统计字符
struct node {//字符及概率区间char c;double l, r;
}ch[N];
struct spcode {double low=0.0, high=1.0, delta;//区间左右端及大小spcode() = default;spcode(double a, double b) :low(a), high(b), delta(b-a) {}
};
map<char, spcode> mp;
void create() {memset(char_num, 0, sizeof(char_num));printf("输入字符串个数n\n");cin >> len;printf("输入字符串:\n");cin >> str;for (auto i = 0; i < str.length(); i++)//统计概率char_num[str[i]]++;double last = 0.0;for (int i = 0; i <N; i++) {if (char_num[i]) {ch[i].c = i;ch[i].l = last;ch[i].r = last + double(char_num[i]) / len;last = ch[i].r;}}for (auto i = 0; i < str.length(); i++) {if (char_num[str[i]]) {mp.insert(make_pair(str[i], spcode(ch[str[i]].l,ch[str[i]].r)));}}
}
string encode(double &db,string str){double low = 0.0;double high = 1.0;for (auto it = str.begin(); it != str.end(); it++) {double delta = high - low;high = low + delta * mp[*it].high;low = low + delta * mp[*it].low;}//寻找最短二进制string anstr = "";double ans = 0.0;int cnt = 1;while (ans < low) {ans += pow(0.5, cnt);anstr += '1';if (ans >= high) {ans -= pow(0.5, cnt);anstr[cnt-1] = '0';}cnt++;}db = ans;return anstr;
}
string decode(double value) {double low, high;                   //编码区间double prelow = 0.0, prehigh = 1.0;//记录前一次string ans = "";int cur = 0;while (true) {low = prelow;high = prehigh;for (auto it = mp.begin(); it != mp.end(); it++) {double delta = high - low;high = low + delta * it->second.high;low = low + delta * it->second.low;if (value>=low && value<high) {prelow = low;prehigh = high;ans += (it->first);cur++;break;}else{low = prelow;high = prehigh;}}if (cur == len)break;}return ans;
}
int main() {spcode sp;create();cout << "\n";/*test mapfor (auto it = mp.begin(); it != mp.end(); it++) {cout << it->first <<  " (";cout << it->second.low << " ";cout << it->second.high << ") ";cout << it->second.delta << "\n";}*/double db;string anstr = encode(db, str);cout << "转化为小数的最短十进制表示为:\n" << db << endl;cout << "\n";cout << "最短二进制码为:\n" << anstr << endl;cout << "\n";string destr=decode(db);cout <<"解码后的字符串为: \n"<< destr << endl;return 0;
}

算术编码(多媒体实验一)相关推荐

  1. 算术编码 matlab程序,实验二算术编码及MATLAB实现.doc

    实验二算术编码及MATLAB实现 武夷学院实验报告 课程名称: 多媒体通信技术 项目名称: 算术编码及MATLAB实现 姓名: _专业:__通信工程___ 班级: 学号:____同组成员_无_ 实验准 ...

  2. 信息论与编码实验报告——MATLAB实现算术编码

    一.实验内容 试用MATLAB编制算术编码算法实现程序. 二.实验过程 2.1 算术编码实现原理 算术编码的算法思想如下: (1)对一组信源符号按照符号的概率从大到小排序,将[0,1)设为当前分析区间 ...

  3. 算术编码(matlab)上课实验

    clear all format long symbol='abcd'; pr=[0.1 0.4 0.2 0.3]; seqin='aabccddcd'; codeword=arenc(symbol, ...

  4. 计算机组成原理实验报告 算术逻辑单元ALU实验(源代码全)

    算术逻辑单元ALU实验 一. 实验目的 二. 实验设备 三. 实验任务 四. 实验步骤 五.结果记录及分析 一. 实验目的 1.理解算术逻辑单元ALU的工作原理. 2.掌握算术逻辑单元ALU的设计方法 ...

  5. 算术编码算法的程序实现

    实验目的     本实验通过编程实现简单的算术编码解码过程,加深对视频编码中熵编码原理及过程的理解,锻炼理论与实践相联系的能力. 实验任务 理解算术编码的有关原理,尤其是自适应二元算术编码的原理及编码 ...

  6. 基于Python的算术编码的设计与实现

    基于Python的算数编码实验 一.实验目的 给出算术编码实现的详细原理. 编制编解码程序 设计并实现自适应算术编码(选做) 二.实验环境 硬件环境:windows 10; VScode 编程语言:p ...

  7. 多媒体实验 Visual Studio 图像显示与处理 对图像进行二值化、求边缘、增强等处理

    具体代码,图像处理结果,报告,请访问: 多媒体实验VisualStudio图像显示与处理对图像进行二值化.求边缘.增强等处理.zip-讲义文档类资源-CSDN文库 一.实验目的 1.掌握BMP文件格式 ...

  8. 计算机组成原理实验报告西华大学,计算机组成原理实验报告算术逻辑运算单元实验...

    <计算机组成原理实验报告算术逻辑运算单元实验>由会员分享,可在线阅读,更多相关<计算机组成原理实验报告算术逻辑运算单元实验(6页珍藏版)>请在人人文库网上搜索. 1.西华大学数 ...

  9. [转]算术编码+统计模型=数据压缩 - 第二部分:统计模型

    转自:http://deercrane.spaces.live.com/blog/cns!8BEF692B75EB8095!189.entry 算术编码 + 统计模型 = 数据压缩 - 第二部分:统计 ...

最新文章

  1. ResNet被全面超越了,是Transformer干的:依图科技开源“可大可小”T2T-ViT,轻量版优于MobileNet...
  2. css margin-top设置html元素之间的距离
  3. 录播软件开始麦克风应该打开还是关闭
  4. Ocelot中使用Butterfly实践
  5. 95-36-032-ChannelHandler-SimpleChannelInboundHandler
  6. Spring框架----Spring的bean的生命周期
  7. 计算机网络—数据链路层的流量控制与可靠传输机制(思维导图)
  8. 学习强化学习无法避开的两个词:Model-Based与Model-Free
  9. linux ssh反向代理
  10. 有道智云 php,调用有道智云API,自动翻译WORDPRESS标题为英文
  11. 电脑知识:如何将旧的Windows笔记本电脑切换到Linux
  12. 艾永亮:优衣库,究竟是怎么卖衣服的?
  13. 基于ARM处理器的U-BOOT详细移植总结
  14. C语言的goto语句,scanf的注意点以及好玩的指令
  15. VN Studio环境的搭建
  16. 资深EMC工程师总结:EMC整改流程及常见问题
  17. Python中如何保留n位有效数字
  18. 服务器被攻击了多久恢复?服务器被攻击了怎么处理?
  19. 忘记计算机网络域名密码,自己家里wifi密码忘记了怎么办?
  20. springmvc 使用InternalResourceViewResolver解析URL文件

热门文章

  1. 荣耀逆增长:双品牌下的蓝色急行军
  2. WTM+LayUI实现组件一对多的联动
  3. 最好的cpm广告联盟哪里有
  4. 一个 Angular 程序员两年多的远程办公经验分享
  5. 夕阳西下,行业内卷,土木转行Python的几个方向?
  6. ib网卡命令_一种IB网卡连通配置方法、装置、终端及存储介质与流程
  7. Android 6.0 仿支付宝主页UI实战案例
  8. UML图中的关系符号解释
  9. golang对接企业微信群机器人-在线客服系统新消息提醒方式之一【唯一客服】
  10. 说说我的2015(做了一年多的程序媛)