赫夫曼编码
设计原理
赫夫曼(Huffman)编码是1952年提出的,是一种比较经典的信息无损熵编
码,该编码依据变长最佳编码定理,应用Huffman算法而产生。Huffman编码是一
种基于统计的无损编码。
设信源X的信源空间为:
PX
:]
[
x
N
(
(
)
xPxPxPXP
xxX
21
(
:
)
:)
(
2
1
)
(
xP
N
)
3
其中,
N
i
1
(
ixP
1)
,现用二进制对信源X中的每一个符号 ix (i=1,2,…N)进行
编码。
根据变长最佳编码定理,Huffman编码步骤如下:
(1)将信源符号xi按其出现的概率,由大到小顺序排列。
(2)将两个最小的概率的信源符号进行组合相加,并重复这一步骤,始终
将较大的概率分支放在上部,直到只剩下一个信源符号且概率达到1.0为
止;
(3)对每对组合的上边一个指定为1,下边一个指定为0(或相反:对上边
一个指定为0,下边一个指定为1);
(4)画出由每个信源符号到概率1.0处的路径,记下沿路径的1和0;
(5)对于每个信源符号都写出1、0序列,则从右到左就得到非等长的
Huffman码。
Huffman编码的特点是:
(1)Huffman编码构造程序是明确的,但编出的码不是唯一的,其原因之一是两
个概率分配码字“0”和“1”是任意选择的(大概率为“0”,小概率为“1”,
或者反之)。第二原因是在排序过程中两个概率相等,谁前谁后也是随机的。这
样编出的码字就不是唯一的。
(2)Huffman编码结果,码字不等长,平均码字最短,效率最高,但码字长短不
一,实时硬件实现很复杂(特别是译码),而且在抗误码能力方面也比较差。
(3)Huffman编码的信源概率是2的负幂时,效率达100%,但是对等概率分布的
信源,产生定长码,效率最低,因此编码效率与信源符号概率分布相关,故Huffman
编码依赖于信源统计特性,编码前必须有信源这方面的先验知识,这往往限制了
哈夫曼编码的应用。
(4)Huffman编码只能用近似的整数位来表示单个符号,而不是理想的小数,这
也是Huffman编码无法达到最理想的压缩效果的原因。
设计程序
clear
%调用Huffman
load woman;
%X=imread('girl.bmp','bmp');
data=uint8(X);
[zipped,info]=huffencode(data);
编码程序进行压缩
unzipped=huffdecode(zipped,info,data);
%调用Huffman编码程序进行解码
%显示原始图像和经编码后的图像,显示压缩比,并计算均方根误差得erms=0,
表示是Huffman是无失真编码
subplot(121);imshow(data);
subplot(122);imshow(unzipped);
%erms=compare(data(:),unzipped(:))
cr=info.ratio
whos data unzipped zipped
%huffencode函数对输入矩阵vector进行Huffman编码,返回%编码后的向量
(压缩后数据)及相关信息
function [zipped,info]=huffencode(vector)
%输入和输出都是unit8格式
%info返回解码需要的机构信息
%info.pad是添加的比特数
%info.huffcodes是Huffman码字
%info.rows是原始图像行数
%info.cols是原始图像行数
%info.length是原始图像数据长度
%info.maxcodelen是最长码长
if ~isa(vector,'uint8')
end
[m,n]=size(vector);
vector=vector(:)';
f=frequency(vector);
symbols=find(f~=0);
f=f(symbols);
[f,sortindex]=sort(f);
%将符号按照出现的概率大小排序
symbols=symbols(sortindex);
len=length(symbols);
symbols_index=num2cell(1:len);
codeword_tmp=cell(len,1);
while length(f)>1
error('input argument must be a uint8 vector');
%计算各符号出现的概率
%读入图像数据
index1=symbols_index{1};
index2=symbols_index{2};
%生产Huffman树,得到码字编码表
codeword_tmp(index1)=addnode(codeword_tmp(index1),uint8(0)
);
codeword_tmp(index2)=addnode(codeword_tmp(index2),uint8(1)
);
symbols_index(3:end)];
f=[sum(f(1:2)) f(3:end)];
symbols_index=[{[index1,index2]}
[f,sortindex]=sort(f);
symbols_index=symbols_index(sortindex);
len=len+length(codeword{double(vector(index))+1});
end
codeword=cell(256,1);
codeword(symbols)=codeword_tmp;
len=0;
for index=1:length(vector) %得到整个图像所有比特数
end
string=repmat(uint8(0),1,len);
pointer=1;
for index=1:length(vector) %对输入图像进行编码
code=codeword{double(vector(index))+1};
len=length(code);
string(pointer+(0:len-1))=code;
pointer=pointer+len;
string=[string uint8(zeros(1,pad))];
end
len=length(string);
pad=8-mod(len,8);
%非8整数倍时,最后补pad个0
if pad>0
end
codeword=codeword(symbols);
codelen=zeros(size(codeword));
weights=2.^(0:23);
maxcodelen=0;
for index=1:length(codeword)
len=length(codeword{index});
if len>maxcodelen
maxcodelen=len;
end
if len>0
code=sum(weights(codeword{index}==1));
code=bitset(code,len+1);
codeword{index}=code;
codelen(index)=len;
end
end
codeword=[codeword{:}];
%计算压缩后的向量
cols=length(string)/8;
string=reshape(string,8,cols);
weights=2.^(0:7);
zipped=uint8(weights*double(string));
%码表存储到一个稀疏矩阵
huffcodes=sparse(1,1);
huffcodes(codeword(index),1)=symbols(index);
error('input argument must be a uint8 vector');
for index=1:nnz(codeword)
end
%填写解码时所需的结构信息
info.pad=pad;
info.huffcodes=huffcodes;
info.ratio=cols./length(vector);
info.length=length(vector);
info.maxcodelen=maxcodelen;
info.rows=m;
info.cols=n;
%huffdecode函数对输入矩阵vector进行Huffman编码,
%返回解压后的图像数据
function vector=huffdecode(zipped,info,image)
if~isa(zipped,'uint8')
end
%产生0,1序列,每位占一个字节
len=length(zipped);
string=repmat(uint8(0),1,len.*8);
bitindex=1:8;
for index=1:len
string(bitindex+8.*(index-1))=uint8(bitget(zipped(index),
bitindex));
end
string=logical(string(:)');
len=length(string);
%开始解码
weights=2.^(0:51);
vector=repmat(uint8(0),1,info.length);
vectorindex=1;
codeindex=1;
code=0;
for index=1:len
code=bitset(code,codeindex,string(index));
codeindex=codeindex+1;
byte=decode(bitset(code,codeindex),info);
if byte>0
vector(vectorindex)=byte-1;
codeindex=1;
code=0;
vectorindex=vectorindex+1;
end
end
%vector=reshape(vector,info.rows,info.cols);
%函数addnode添加节点
function codeword_new=addnode(codeword_old,item)
codeword_new=cell(size(codeword_old));
for index=1:length(codeword_old)
codeword_new{index}=[item codeword_old{index}];
error('input argument must be a uint8 vector');
end
%函数frequency计算各符号出现的概率
function f=frequency(vector)
if~isa(vector,'uint8')
end
f=repmat(0,1,256);
len=length(vector);
for index=0:255
end
f=f./len;
%函数decode返回码字对应的符号
function byte=decode(code,info)
byte=info.huffcodes(code);
f(index+1)=sum(vector==uint8(index));
(1)对图像 woman 进行编码
cr = 0.6291
Name
data
unzipped
zipped
(2) 对图像 cameraman.tif 进行编码
Size
256x256
1x65537
1x41226
Attributes
Bytes Class
65536 uint8
65537 uint8
41226 uint8
cr = 0.8806
Name
data
unzipped
zipped
Size
256x256
1x65537
1x57712
Attributes
Bytes Class
65536 uint8
65537 uint8
57712 uint8
cr =0.8708
Name
Attributes
data
unzipped
zipped
心得体会
Size
409x541x3
1x663808
1x578031
Bytes Class
663807 uint8
663808 uint8
578031 uint8
通过本次课程设计我进一步体会到了数字图像处理的神秘,我们用霍夫曼编
码实现了对图像的压缩,本以为把程序输入了就可以正确运行,但是发现书上的
程序在matlab中有很多的错误,因此用了很长的时间进行修改,最后终于顺利
运行了,这个过程让我明白了不能完全依赖课本,一定要有自己的思考和分析才
能攻克难题,而且遇到困难后应该学会互助和自信,希望以后还能得到同样的收
获和锻炼。