min2=i;
m2=tree(2,i);
end
end
下面先介绍下tree,树在matlab中的构造,在matlab中用tree(MN,s1,s2,s3……)这个系统函数来构造二叉树。
声明一个tree(6,x)结构的树型结点,一个结点包括有6个变量存储单元。
其中tree(1,x)记录该结点的编号;tree(2,x)记录该结点的概率值;tree(3,x)记录该结点的父结点编号;tree(4,x)记录该结点是左结点还是右结点(其中左结点为“0”,右结点为“1”);tree(5,x)记录该结点是否为根结点标志(该结点为根结点记为“1”,否则决为“0”)。
tree(6,x)记录该结点的字符,x的个数为pro中字符的个数,其余值人为赋零。
由截断Huffman编码要求
(2),我们需要对字符进行一个定长码的顺序编码,所以需要编写函数SequenceTree=Sequence(pro)来得到一棵顺序编码的二叉树,其中pro为截断Huffman编码要求中剩余的字符组成的新pro概率分布矩阵(按概率值先大后小的顺序排序)
n0=size(pro,2);
n1=ceil(log2(n0));
n=2^n1;
tree=ones(6,2*n-1);
tree(1,:
)=1:
(2*n-1);
tree(5,(n+1):
end)=0;
tree(2,1:
n)=pro(1,:
);
tree(6,1:
n)=pro(2,:
);
tree(6,n+1:
end)=0;
如上为在进行顺序编码前构造的基本树
fori=1:
2:
(2*n-3);
location=(i+1)/2+n;
tree(2,location)=tree(2,i)+tree(2,i+1);
tree(5,location)=1;
tree(3,i)=location;tree(3,i+1)=location;
tree(4,i)=0;tree(4,i+1)=1;
tree(5,i)=0;
tree(5,i+1)=0;
end
SequenceTree=tree;
通过以上步骤可以返回得到一棵顺序编码完成的二叉树SequenceTree。
由截断Huffman编码要求
(1),需要对M个符号进行Huffman编码,因此编写其编码部分,主要代码如下
fori=(n+1):
(2*n-1);
[mi1,mi2]=getmin(tree);
tree(2,i)=tree(2,mi1)+tree(2,mi2);
tree(5,i)=1;
tree(3,mi1)=i;tree(3,mi2)=i;
tree(4,mi1)=1;tree(4,mi2)=0;
tree(5,mi1)=0;
tree(5,mi2)=0;
end
T_HuffmanTree=tree;
通过以上两步,得到了两棵二叉树T_HuffmanTree和T_SequenceTree
接下来进行对image的编码部分
依次获取image中的每个字符,然后历遍T_HuffmanTree和T_SequenceTree(如果满足进入条件)可以得到最后的T_HuffmanCode
主要代码如下:
m=find(T_SequenceTree(6,1:
n2)==k);
while(T_SequenceTree(5,m
(1))~=1)%判断是否已历遍到根节点
Code(CodeNumber)=T_SequenceTree(4,m
(1));
CodeNumber=CodeNumber+1;
m=T_SequenceTree(3,m);%指向父节点
end
k=-1;%指向标示位
如上为逆历遍T_SequenceTree的过程。
m=find(T_HuffmanTree(6,1:
n)==k);
while(T_HuffmanTree(5,m)~=1)%判断是否已历遍到根节点Code(CodeNumber)=T_HuffmanTree(4,m);
CodeNumber=CodeNumber+1;
m=T_HuffmanTree(3,m);%指向父节点
end
如上为逆历遍T_HuffmanTree的过程。
forz=LastPoint:
SumCode;%将n个符号的编码组合到一起
T_HuffmanCode(z)=Code(CodeNumber);
CodeNumber=CodeNumber-1;
end
如上为历遍之后再将暂时储存在Code(CodeNumber)中的数据传至T_HuffmanCode中输出。
循环完毕后即得到编码完成的T_HuffmanCode。
根据题目要求我们还需计算图象熵,平均码长和冗余度
求熵部分如下
Entropy=0;
forj=1:
n1;
Entropy=Entropy-pro(1,j)*log2(pro(1,j));
End
计算平均码长前需要先得到每个字符的码长,因此需要先编写得到每个字符码长的数组(代码略,详见第四部分:
编程代码),接着由下得到平均码长
AverageCodeLength=sum(CodeLength.*pro(1,:
))
再根据冗余度的计算公式可得
Redundancy=AverageCodeLength/Entropy-1;
Ⅱ解码部分
解码部分需要的元素有T_HuffmanTree、T_SequenceTree、T_HuffmanCode以及原始图像的宽高Information.high,Information.wide。
解码时是依次取遍T_HuffmanCode中的每个值,从T_HuffmanCode中最高的父节点开始,历遍T_HuffmanTree和T_SequenceTree(当历遍T_HuffmanTree得到根节点为标示符-1时进入)
如下先为T_SequenceTree的扫描部分
temp2=find(T_SequenceTree(3,:
)==temp1);
if(T_SequenceTree(4,temp2
(1))==i)
temp1=temp2
(1);
else
temp1=temp2
(2);
end
start1=start1+1;
if(step==N)
flag=1;
else
step=step+1;
end
if(temp1<=nn1)%跳出扫面
break;
end
接下为T_HuffmanTree的扫描部分
temp2=find(T_HuffmanTree(3,:
)==temp1);
if(T_HuffmanTree(4,temp2
(1))==i)
temp1=temp2
(1);
else
temp1=temp2
(2);
end
start1=start1+1;
if(step==N)
flag=1;
else
step=step+1;
end
if(temp1==n2)%扫描标记T_SequenceTree
flag_s=1;
temp1=nn;
elseif(temp1<=n1)%跳出扫描
break;
end
由以上两部分扫描就能得到一个返回值,再将返回值赋予数组image中
if(flag_s==0)%选择输出值位置
iimage(j)=T_HuffmanTree(6,temp1);
else
iimage(j)=T_SequenceTree(6,temp1);
end
当然最后需要根据原图像宽高将一维的iimage数组转换成二维的数组
image=reshape(iimage,Information.high,Information.wide);
由此截断Huffman解码部分完成,得到返回值image。
4、编程代码
Ⅰ截断Huffman编码
function[T_HuffmanTree,T_SequenceTree,T_HuffmanCode,T_Information,T_Result]=TruncationHuffman(image)
[m,n]=size(image);
T_Information.high=m;
T_Information.wide=n;
length=m*n;
image=reshape(image,1,length);
pro=getpro(image);
pro=getsequence(pro);
n1=size(pro,2);
temp=sum(pro(1,ceil(n1/2)+1:
end));
pro1(:
1:
ceil(n1/2)+1)=pro(:
1:
ceil(n1/2)+1);
pro1(1,ceil(n1/2)+1)=temp;
pro1(2,ceil(n1/2)+1)=-1;
pro1=getsequence(pro1);
n=size(pro1,2);
%///////////////Huffman编码////////////
tree=ones(6,2*n-1);
tree(1,:
)=1:
(2*n-1);
tree(5,(n+1):
end)=0;
tree(2,1:
n)=pro1(1,:
);
tree(6,1:
n)=pro1(2,:
);
tree(6,n+1:
end)=0;
fori=(n+1):
(2*n-1);
[mi1,mi2]=getmin(tree);
tree(2,i)=tree(2,mi1)+tree(2,mi2);
tree(5,i)=1;
tree(3,mi1)=i;tree(3,mi2)=i;
tree(4,mi1)=1;tree(4,mi2)=0;
tree(5,mi1)=0;
tree(5,mi2)=0;
end
T_HuffmanTree=tree;
%///////////////顺序编码/////////////
pro2=pro(:
ceil(n1/2)+1:
end);
[T_SequenceTree]=Sequence(pro2);
%///////////////编码部分/////////////
T_HuffmanCode=1;
Code=[];
SumCode=0;
LastPoint=1;
n2=size(T_SequenceTree,2);
intz;
fork=image;%循环完成n个符号的编码
flag_loc=0;
loc=find(pro(2,:
)==k);
if(loc>ceil(n1/2))
flag_loc=1;
end
CodeNumber=1;
if(flag_loc==1)
m=find(T_SequenceTree(6,1:
n2)==k);
while(T_SequenceTree(5,m
(1))~=1)%判断是否已历遍到根节点
Code(CodeNumber)=T_SequenceTree(4,m
(1));
CodeNumber=CodeNumber+1;
m=T_SequenceTree(3,m);%指向父节点
end
k=-1;
end
m=find(T_HuffmanTree(6,1:
n)==k);
while(T_HuffmanTree(5,m)~=1)%判断是否已历遍到根节点
Code(CodeNumber)=T_HuffmanTree(4,m);
CodeNumber=CodeNumber+1;
m=T_HuffmanTree(3,m);%指向父节点
end
CodeNumber=CodeNumber-1;
SumCode=SumCode+CodeNumber;%累加计算编码长度
forz=LastPoint:
SumCode;%将n个符号的编码组合到一起
T_HuffmanCode(z)=Code(CodeNumber);
CodeNumber=CodeNumber-1;
end
LastPoint=SumCode+1;
end
%///////////////求熵/////////////
Entropy=0;
forj=1:
n1;
Entropy=Entropy-pro(1,j)*log2(pro(1,j));
end
%///////////////计算单位码长/////////////
CodeLength=zeros(1,n1+1);
nn1=size(pro2,2);
nn=ceil(log2(nn1));
loc=find(pro1(2,:
)==-1);
fork=1:
n;%循环完成n个符号的编码
m=k;
if(m==loc)
CodeLength(1,k)=CodeLength(1,k)+nn;
end
while(T_HuffmanTree(5,m)~=1)%判断是否已历遍到根节点
m=T_HuffmanTree(3,m);%指向父节点
CodeLength(1,k)=CodeLength(1,k)+1;
end
end
temp=CodeLength(loc);
CodeLength(loc)=[];
CodeLength(ceil(n1/2)+1:
end)=temp;
T_Result.CodeLength=CodeLength;
T_Result.SumCode=SumCode;
T_Result.Entropy=Entropy;
T_Result.AverageCodeLength=sum(CodeLength.*pro(1,:
));
T_Result.Redundancy=T_Result.AverageCodeLength/T_Result.Entropy-1
Ⅱ截断Huffman解码
functionimage=unTruncationHuffman(T_HuffmanTree,T_SequenceTree,T_HuffmanCode,Information)
n=size(T_HuffmanTree,2);%T_HuffmanTree的长度
n1=(n+1)/2;%pro1的长度
nn=size(T_SequenceTree,2);%T_SequenceTree的长度
nn1=(nn+1)/2;%pro2的长度
n2=find(T_HuffmanTree(6,:
)==-1);%T_HuffmanTree中T_SequenceTree起始位标示位置
flag=0;%变长码扫描结束起始位
flag_s=0;%T_SequenceTree扫描起始位
start=1;%T_HuffmanCode扫描起始位
start1=0;%每个变长码长度
step=1;%扫描过的T_HuffmanCode长度
j=0;%输出字符的位置
N=size(T_HuffmanCode,2);%总码长
while(flag==0)
start=start+start1;
temp1=n;
start1=0;
flag_s=0;
fori=T_HuffmanCode(1,start:
N)
if(flag_s==1)%扫描进入T_SequenceTree
temp2=find(T_SequenceTree(3,:
)==temp1);
if(T_SequenceTree(4,temp2
(1))==i)
temp1=temp2
(1);
else
temp1=temp2
(2);
end
start1=start1+1;
if(step==N)
flag=1;
else
step=step+1;
end
if(temp1<=nn1)%扫描跳出
break;
end
else%扫描进入T_HuffmanTree
temp2=find(T_HuffmanTree(3,:
)==temp1);
if(T_HuffmanTree(4,temp2
(1))==i)
temp1=temp2
(1);
else
temp1=temp2
(2);
end
start1=start1+1;
if(step==N)
flag=1;
else
step=step+1;
end
if(temp1==n2)%标记扫描T_SequenceTree
flag_s=1;
temp1=nn;
elseif(temp1<=n1)%跳出扫描
break;
end
end
end
j=j+1;
if(flag_s==0)%选择输出值位置
iimage(j)=T_HuffmanTree(6,temp1);
else
iimage(j)=T_SequenceTree(6,temp1);
end
end
image=reshape(iimage,Information.high,Information.wide);
Ⅲ其他子程序代码
pro=getpro(image)%得到概率分布矩阵
[min1,min2]=getmin(tree)%得到最小两个概率值
pro=getsequence(proo)%按大小顺序重新排列概率分布矩阵
[SequenceTree]=Sequence(pro)%顺序编码函数
这四个子程序由于篇幅原因不在此处完整贴出,详见附文
5、程序运行结果及对比分析
在CommandWindow中输入
>>[T_HuffmanTree,T_SequenceTree,T_HuffmanCode,T_Information,T_Result]=TruncationHuffman(image)
(其中image为题目要求先前输入的矩阵)
在T_Information中包含image的宽与高
在T_Result中包含的数据有字符码长、总码长、图像的熵、平均码长、冗余度
得到如下图(一次截图不完全,分开截图):
图1.1Truncation