课程设计费诺编码和自适应算术编码Word文件下载.docx
《课程设计费诺编码和自适应算术编码Word文件下载.docx》由会员分享,可在线阅读,更多相关《课程设计费诺编码和自适应算术编码Word文件下载.docx(22页珍藏版)》请在冰豆网上搜索。
按字符出现的概率大小
对符号进行排列
调用编码对函数进行编
码
N字符都已
编码完,
Y
输出编码结果
输入要编码的数字串
第3页
调用译码函数译码
结束
7.四元费诺编码思想与函数模块划分
四元费诺编码主要在二元费诺编码的基础上修改编码函数,即二元费诺编码每次递归分两组,四元费诺编码每次就要分为四组。
具体修改方法如下:
参数说明
第4页
递归结束条条件
递归函数
第5页
递归分组
第6页
8.程序测试与结果
9.总结
费诺编码:
由实验结果可得,在一般情况下,费诺编码不一定能使短码得到充分利用,尤其当信源符号较多,并有一些符号概率分布很接近时,分两大组的组合就会很多,可能某种分大组的结果,会出现后面小组的概率和相差较远,因而使平均码长增加。
所以,费诺码通常不是最佳码。
程序:
由于时间比较仓促,无法对程序进行美化和进一步的编写窗口化程序,界面比较传统和简陋。
第7页
是图像压缩的主要算法之一。
是一种无损数据压缩方法,也是一种熵编码的方法。
和其它熵编码方法不同的地方在于,其他的熵编码方法通常是把输入的消息分割为符号,然后对每个符号进行编码,而算术编码是直接把整个输入的消息编码为一个数,一个满足(0.0?
n<
1.0)的小数n。
2.基本要求
请设计程序用以对输入字符串实现自适应的算术编码,其中要有相应的概率调整的过程,并且设计译码函数使满足根据编码的结果,能够正确的译码。
3.算术编码原理
在给定符号集和符号概率的情况下,算术编码可以给出接近最优的编码结果。
使用算术编码的压缩算法通常先要对输入符号的概率进行估计,然后再编码。
这个估计越准,编码结果就越接近最优的结果。
例:
对一个简单的信号源进行观察,得到的统计模型如下:
60%的机会出现符号中性
20%的机会出现符号阳性
10%的机会出现符号阴性
10%的机会出现符号数据结束符.
中性对应的区间是[0,0.6)
阳性对应的区间是[0.6,0.8)
阴性对应的区间是[0.8,0.9)
数据结束符对应的区间是[0.9,1)
当所有的符号都编码完毕,最终得到的结果区间即唯一的确定了已编码的符号序列。
任何人使用该区间和使用的模型参数即可以解码重建得到该符号序列。
实际上我们并不需要传输最后的结果区间,实际上,我们只需要传输该区间中的一个小数即可。
在实用中,只要传输足够的该小数足够的位数(不论几进制),以保证以这些位数开头的所有小数都位于结果区间就可以了。
4.自适应算术编码
第8页
自适应算术编码即上述的模型还可以进行自适应的变化,即在某种上下文下出现的概率分布的估计随着每次这种上下文出现时的符号而自适应更新,从而更加符合实际的概率分布。
不管编码器使用怎样的模型,解码器也必须使用同样的模型。
编码过程的每一步,除了最后一步,都是相同的。
编码器通常需要考虑下面三种数据:
1.下一个要编码的符。
2.当前的区间(在编第一个符号之前,这个区间是[0,1),但是之后每次编码区间都会变化
3.编码其将当前的区间分成若干子区间,每个子区间的长度与当前上下文下可能出现的对应符号的概率成正比。
当前要编码的符号对应的子区间成为在下一步编码中的初始区间。
5.自适应算术编码特点
1)不必预先定义概率模型,自适应模式具有独特的优点;
2)信源符号概率接近时,建议使用算术编码,这种情况下其效率高于Huffman
编码;
3)算术编码绕过了用一个特定的代码替代一个输入符号的想法,用一个浮点
输出数值代替一个流的输入符号,较长的复杂的消息输出的数值中就需要更
多的位数。
4)算术编码实现方法复杂一些,但JPEG成员对多幅图像的测试结果表明,算
术编码比Huffman编码提高了5%左右的效率,因此在PEG扩展系统中用算术
编码取代Huffman编码。
6.自适应算法流程图
初始化概率空间和准
备数据
第9页
输入字符串
字符找到相应的概率空
间
调整字符概率序列
调整指针指向下一字符
N
字符都已编码,
区间内任选一树
转二进制并去相应的
有效位
7.自适应算术编码编程思想
算法主要基于算术编码,其中编码译码都要增加一个概率调整的式子。
编程
思想如下:
第10页
(1)对一组信源符号按照符号的概率排序,将[0,1)设为当前分析区间。
按
信源符号的概率序列在当前分析区间划分比例间隔。
(2)检索“输入消息序列”,锁定当前消息符号(初次检索的话就是第一个
消息符号)。
找到当前符号在当前分析区间的比例间隔,将此间隔作为新的
当前分析区间。
并把当前分析区间的起点(即左端点)指示的数“补加”到编
码输出数里。
当前消息符号指针后移。
(3)根据输如的字符,相应的调整信源的概率序列。
(4)按照新的信源符号的概率序列在当前分析区间划分比例间隔。
然后重
复第二步。
直到“输入消息序列”检索完毕为止。
(5)最后的编码输出数就是编码好的数据。
修改信源概率序列方法:
Cnt[i]为相应信源符号的出现次数,初始化都为1;
Sum为总共的信源符号
Proc[i]为相应信源符号的概率
areaBegin为区间起始概率
areaEnd为区间结束概率
第11页
自适应算术编码:
不必预先定义概率模型,自适应模式具有独特的优点,没有对个输入符号的信息量为整数的限制,随着编码结果的小数随位数的增加,它的精度也随之增高,从信息的角度来说,它所含的信息量也随之增加。
信源符号概率接近时编码效率比较好,其效率高于哈夫曼编码。
自己在指导书的程序基础上修改了编码译码函数,总体来说还是比较轻松简单的。
但是因为时间比较紧,没有足够的时间对程序进行可视化窗口编程和美化,所以程序基于黑白对话框比较简陋;
输入字符要手动输入,过程比较繁琐,容易出错,可以在以后增加文件操作和成熟美化等工作,使程序简单实用。
第12页
附录一:
费诺编码源程序
//Fano编括?
码?
.cpp:
定?
义?
控?
制?
?
应畖用?
程ì
序ò
的?
入?
口ú
点?
。
//
//Fano编码.cpp:
定义控制台应用程序的入口点。
//
#include"
stdafx.h"
#include<
stdio.h>
#include<
math.h>
string.h>
algorithm>
usingnamespacestd;
typedefstruct
{
chardata;
floatweight;
charcode[1000];
}fnode;
fnodef[50];
intnum;
intforwd,mid,last;
intjsq(char*s,intcnt[],charstr[])
char*p;
inti,j,k=0;
inttemp[257];
for(i=0;
i<
257;
i++)
temp[i]=0;
for(p=s;
*p!
='
\0'
;
p++)
temp[*p]++;
for(i=0,j=0;
=256;
if(temp[i]!
=0)
j++;
str[j]=i;
cnt[j]=temp[i];
}
returnj;
//shuru
voidInput(charreceive[],intcnt[],charstr[])
unsignedintlen=0;
第13页
printf("
输入要编码的字符串:
"
);
gets(receive);
len=strlen(receive);
num=jsq(receive,cnt,str);
for(inti=1;
=num;
f[i-1].data=str[i];
f[i-1].weight=float(cnt[i])/len;
//编码
voidcode(fnodef[],doubletotal,intbegin,intend)
//doublesum=0.0,tsum=0.0,temp1old=total/2;
double
sum=0.0,fsum=0.0,msum=0.0,lsum=0.0,temp1=0.0,temp2=0.0,temp3=0.0,old1=total/4,o
ld2=total/4,old3=total/4;
//intforwd,mid,last;
if(end-begin==0)
return;
else
if(end-begin==1)
strcat(f[begin].code,"
0"
strcat(f[begin+1].code,"
1"
if(end-begin==2)
strcat(f[begin+2].code,"
2"
if(end-begin==3)
strcat(f[begin+3].code,"
3"
第14页
for(inti=begin;
=end;
sum+=f[i].weight;
temp1=fabs(sum-total/4);
if(temp1<
=old1)
forwd=i;
fsum=sum;
strcat(f[i].code,"
old1=temp1;
//temp=fabs(sum)
//msum=sum-fsum;
temp2=fabs(sum-fsum-total/4);
if(temp2<
=old2)
mid=i;
msum=sum-fsum;
old2=temp2;
temp3=fabs(sum-fsum-msum-total/4);
if(temp3<
=old3)
last=i;
lsum=sum-fsum-msum;
old3=temp3;
//old3=temp3;
code(f,fsum,begin,forwd);
code(f,msum,forwd+1,mid);
第15页
code(f,lsum,mid+1,last);
code(f,sum-fsum-msum-lsum,last+1,end);
//译码
voiddecode(chars[]){
unsignedinti=0;
intj=0;
chars2[100];
s2[0]='
while(i<
strlen(s))
chartemp[2];
temp[0]=s[i];
temp[1]='
strcat(s2,temp);
for(j=0;
j<
num;
j++)//分别与各个编码比较
if(strcmp(s2,f[j].code)==0)//判断是否匹配
%c"
f[j].data);
break;
i++;
//输出结果
voidprint()
inti;
//cout<
<
符号"
f[i].code
符号%c概率%f,编码为%s\n"
f[i].data,f[i].weight,f[i].code);
//计算编码效率
doublecode_ratio(fnodef[50],charreceive[],intcnt[],charstr[])
doubleup=0.0,down=0.0,temp=0.0;
inti=1,j,len=strlen(receive);
for(i;
第16页
temp=cnt[i]/double(len);
up-=temp*(log10(temp)/log10(4.0));
for(j=0;
50;
j++)
if(f[j].data==str[i])
down+=temp*strlen(f[j].code);
return(up/down)*100;
//sort函数的参数
boolMyless(constfnodel,constfnoder)
returnl.weight>
r.weight;
}
voidmain()
chargot[1000],s[1000]={'
},receive[1000],str[1000];
//got接收输入的待解码的字符串,s接受解码的结果,receive接受输入的字符串
intcnt[1000];
//str,cnt分别统计字符中的字符和其出现的概率
Input(receive,cnt,str);
//调用输入函数
sort(f,f+num,Myless);
//调用排序函数
code(f,1.0,0,num-1);
//调用编码函数
print();
//调用输出编码函数
上述字符串的费诺编码为"
inti=0,j=0;
while(receive[i]!
)
if(f[j].data==receive[i])
%s"
f[j].code);
\n编码效率:
%f%%\n"
code_ratio(f,receive,cnt,str));
请输入四进制码开始的解码:
\n"
gets(got);
strcat(s,got);
译码结果为:
decode(s);
//调用译码函数
//system("
pause"
第17页
附录二:
自适应算术编码//自适应算术编码.cpp:
iostream>
string>
cmath>
doubleproc[]={0.10,0.10,0.10,0.1,0.1,0.1,0.1,0.1,0.1,0.1};
intcnt[]={1,1,1,1,1,1,1,1,1,1};
doublenum=10.0;
doubleresult,areaBegin,areaEnd;
intcord[1000],cordLength;
charstr[1000];
intstrLength=0;
boolreaddat(){
cout<
*********************自适应模式********************************"
endl;
请输入字符(0~9):
cin>
>
str;
while(str[strLength]!
='
){
strLength++;
for(i=0;
i<
strLength;
i++){//输入是否合法
if(str[i]>
'
9'
||str[i]<
0'
)return1;
return0;
第18页
voidencode(){
编码:
"
inti,l;
doublew=0.0,len;
areaBegin=0.0,areaEnd=1.0;
i++){
intn=str[i]-'
k;
cnt[n]++;
num++;
w=0.0;
for(k=0;
k<
n;
k++){
w+=proc[k];
//计算所在区间
len=areaEnd-areaBegin;
//计算新的区间
areaEnd=areaBegin+len*(w+proc[k]);
areaBegin+=len*w;
for(l=0;
l<
=9;
l++)//调整信源概率序列
proc[l]=cnt[l]/num;
result=areaBegin*0.01+areaEnd*0.99;
//选择适当的点
cordLength=(int(-log10(areaEnd-areaBegin)/log10(2.0)))+1;
编码位数:
cordLength<
编码结果:
doubletemp1=result;
第19页
inttemp2,j;
for(j=0;
j<
cordLength;
j++){//十进制转换成二进制
temp1*=2;
temp2=int(temp1);
temp1-=temp2;
cord[j]=temp2;
temp2;
voiddecode(){
译码:
result=0.0;
intl;
l++)
cnt[l]=1;
num=10.0;
doublewei=0.5;
i++,wei*=0.5){//二进制转换成十进制
result+=wei*cord[i];