自适应算术编码与完全统计模型算术编码
算术编码(Arithmetic Coding)
算术编码是图像压缩的主要算法之一。 是一种无损数据压缩方法,也是一种熵编码的方法。和其它熵编码方法不同的地方在于,其他的熵编码方法通常是把输入的消息分割为符号,然后对每个符号进行编码,而算术编码是直接把整个输入的消息编码为一个数,一个满足(0.0 ≤ n < 1.0)的小数n。[^1]
算术编码是将一个符号序列表示成0和1之间的一个间隔(interval),并用该间隔内的一个浮点小数表示,再将该小数转换成为二进制数,符号序列越长,对应的间隔越小,表示这一间隔的二进制位数就越多。
固定模式AC
题目:设信源可能输出的符号是26个字母,且每个字母出现的概率为:a, b, c, d, e, f 均为0.1,其它是等概的,试编写程序可以对任意字母序列(如presentation)进行固定模式的算术编码,并进行相应的译码。
自适应算术编码
操作方法
自适应算术编码即每输入一个字符就实时调整一次字符出现概率,按照此概率进行算术编码,循环。
步骤:
想象一个袋子里装着一些小球,每种字符相当于一个不同颜色的小球,最初,每种小球被摸中的概率都相等:
1.从输入流中每读取一个字符 ,就对该符号进行算术编码;
2.向袋中投入代表该种字符的小球,小球总数增加1,重新计算频率;
3.循环下去,每读一个字符就更新一次频率,进行算术编码。
问题和解答
1.wireeeee和wireless计算出来的编码长度哪个更短?为什么?
答:wireeeee更短。输入的字符串排列越有个性,编码越短。
2. 讲讲decord函数是怎么实现的。
答:先将编码出来的字符串转换为十进制数,然后概率初始化,再搜索该数所在区间,计算出新的区间,将temp转换成字母,译出字母再存入数组,循环就能实现译码。
3.为什么分数组序号=0和!=0的情况?
答:用io输入输出流的getline()获取的数组首位元素不能用于正则表达式,a[0]=‘ ’,必须分开讨论;也有其他解决办法,使用其他获取数组元素的方式。
算法流程图
代码
题目要求:设信源可能输出的符号是26个字母,且每个字母出现的概率未知,试编写程序可以对任意字母序列(如presentation)进行自适应模式的算术编码,并进行相应的译码。(采用 8个字符一组,用空格或者回车作为间隔。即输入的字符串超过8位时,以8个为一组进行编码,相邻两组之间的记忆性取消。)
/****************** 自适应算术编码 **********************/
#include<cmath>
#include<string>
#include<iostream>
#include<iomanip>
using namespace std;
double proc[] = {
1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,
1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,
1.0,1.0,1.0,1.0,1.0,1.0 };
double proc_sum = 26;
double probability[] = {
1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0,1.0/26.0 };
double areaBegin, areaEnd;
int cord[1000];
double cordLength;
char str[1000], newstr[1000];
int strLength = 0; //字符串总长度
int num = 0; //计数
int rowLength = 0; //每行长度
double result;
bool readdat()
{
cout<<"*********** 自适应模式 ***********\n";
cout<<"请输入字符串(a--z): \n";
//%s格式用来输入一个字符串,通过空格和换行来识别一个字符串的结束。也就是说使用%s格式输入并保存到字符数组中的字符串是不含空格的。
//scanf("%s", str);
// cin.getline(str, 1000, '\n');
cin.getline(str, 1000);
while (str[strLength] != '\0')
strLength++;
cout << "字符总长度:"<<strLength << endl;
for (int i = 0; i < strLength; i++) // 输入是否合法
if ((str[i] > 'z' || str[i] < 'a')&& str[i] != ' ') return 1;
return 0;
}
void encord()
{
cout<<" 编 码 :"<< endl;
double w = 0.0, len;
areaBegin = 0.0, areaEnd = 1.0;
//测试
//cout << "rowLength: "<<rowLength << endl<<"num: "<<num<<endl;
double proc[] = {
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }; // 概率初始化
double proc_sum = 26;
double probability[] = {
1.0 / 26.0,1.0 / 26.0,1.0 / 26.0,1.0 / 26.0,1.0 / 26.0,
1.0 / 26.0,1.0 / 26.0,1.0 / 26.0,1.0 / 26.0,1.0 / 26.0,
1.0 / 26.0,1.0 / 26.0,1.0 / 26.0,1.0 / 26.0,1.0 / 26.0,
1.0 / 26.0,1.0 /