一、实验目的
(1)了解图像编码的目的及意义,加深对图像编码的感性认识。
(2)熟练掌握哈夫曼编码的实现与应用。
(3)掌握行程长度编码的实现与应用,尤其是BMP和PCX文件的行程长度编码*。
二、实验内容
(1)选择图像,对其进行哈夫曼编码,总结哈夫曼编码的压缩思想。
(2)选择图像,对其进行行程编码,观察将图像保存为PCX文件后,图像占用空间的变化,并总结PCX的编码特点*三、实验代码及结果、分析
三、实验原理、代码、结果、分析
(1)哈夫曼编码
- 原理:η
哈夫曼编码是一种无损编码,依据信源符号出现的概率来构造其码字,对出现概率大的字符使用较短的码字,对出现概率低的字符则使用较长的码字,从而达到压缩数据的目的,哈夫曼编码又称为最佳编码。
编码的基本步骤:
- 统计信源字符中各符号出现的概率,将各字符出现的概率由大到小的顺序排列;
- 将最小的两个概率相加,合并成新的概率,与其他概率重新按由大到小的顺序排列;
- 重新排列后将两个最小概率合并相加合并为新的概率,即重复步骤b),直到最后两个概率之和为1;
- 将每个相加的组合中,概率大的指定为0,概率小的指定为1,相等则任意指定
- 找出由每一个信源字符到达概率为1.0处的路径,顺序记录路径的每一个1和0的数字编码
- 反向写出编码,即为该信源字符的哈夫曼编码
- 代码:
HuffmanCode.m:
I=imread('lena.jpg');
Gray=rgb2gray(I);
[zipped,info]=huffencode(Gray);%调用哈夫曼编码程序进行压缩
unzipped=huffdecode(zipped,info);%调用哈夫曼解码程序进行解码
disp('平均码长');L=info.avalen
disp('压缩比');CR=info.ratio
disp('信息熵');H=info.h
disp('编码效率');CE=info.ce
subplot(131);imshow(Source);title('原始图像');
subplot(132);imshow(Gray);title('灰度图像');
subplot(133);imshow(unzipped);title('哈夫曼编码并解码重构图像');
huffencode.m与huffdecode.m实际代码展示一部分:
info.zeropad=zp;%添加的比特数
info.huffcodes=huffcodes;
info.length=length(vector);%灰度图矩阵长度
info.rows=m;
info.cols=n;
info.avalen=avawordlen;%平均码长
info.ratio=8/avawordlen;%压缩比
info.h=H;
info.ce=H/avawordlen;%编码效率
- 结果:
平均码长L = 7.4626
压缩比CR =1.0720
信息熵H =7.4384
编码效率CE =0.9968
- 分析:
1、哈夫曼编码是无失真编码,则原始矩阵与解码之后的矩阵相同
- 哈夫曼编码的效率的计算公式:
- 3、当图像灰度值分布不均匀时,哈夫曼编码效率比较高,如该题中,编码效率达到的99.7%
4、哈夫曼编码方法对图像数据进行编码时,须两次读取图像数据,第一次是为了计算每个数据出现的概率,并对各数据进行排序,第二次读取数据转换表格中的编码值代替图像数据存入图像编码文件中
(2)行程编码
- 原理:
仅存储一个像素值以及具有相同颜色的像素数目的图象数据编码方式称为行程编码,或称游程编码,常用RLE(Run-Length Encoding)表示,是一种统计编码,该编码属于无损压缩编码,对于二值图有效。在此方式下每两个字节组成一个信息单元。第一个字节给出其后面相连的象素的个数,第二个字节给出这些象素使用的颜色索引表中的索引。游程编码所能获得的压缩比有多大,主要取决于图像本身的特点。如果图像中具有相同颜色的图像块越大,图像块数目越少,获得的压缩比就越高。反之,压缩比就越小
- 代码:
clc;clear('all');close all;
Source=imread('lena.png'); %读入图像
Gray=rgb2gray(Source);
%以下程序为对原图像进行行程编码,压缩
Gray_Linear=Gray(:);
Gray_Length=length(Gray_Linear);
j=1; index(1)=1;
for z=1:1:(length(Gray_Linear)-1) %行程编码程序段
if Gray_Linear(z)==Gray_Linear(z+1);
index(j)=index(j)+1;
else
Encode(j)=Gray_Linear(z);
j=j+1;
index(j)=1;
end
end
Encode(j)=Gray_Linear(length(Gray_Linear)); %最后一个像素数据
index=uint8(index);
k=1;
for i=1:1:j
if index(i)==1
Encode_hex(k)=Encode(i); % 十六进制的次数或者灰度值
k=k+1;
else
Encode_hex(k)=192+index(i);
k=k+1;
Encode_hex(k)=Encode(i);
k=k+1;
end
end
Encode_hex=dec2hex(Encode_hex);
Encode_hex_Length=size(Encode_hex,1);%计算行程编码后的所占字节数,Encode_hex_Length
index_Lenght=length(index);
CR=Gray_Length/Encode_hex_Length; %比较压缩前与压缩后的大小
%行程编码解码
l=1;
for m=1:index_Lenght
for n=1:1:index(m)
Decode_temp(l)=Encode(m);
l=l+1;
end
end
Decode=reshape(Decode_temp,500,500); %重建二位图像数组
figure(1);
subplot(121);imshow(Gray);title('原始灰度图'); %显示原图的二值图像
subplot(122);imshow(Decode);title('解压缩恢复后的图像'); %显示解压缩恢复后的图像
disp('压缩比:');
disp(CR);
disp('原图像数据的长度:');
disp(Gray_Length);
disp('压缩后图像数据的长度');
disp(Encode_hex_Length);
disp('解压缩后的数据长度');
disp(length(Decode_temp));
- 结果:
原图像数据的长度:250000
压缩后图像数据的长度:229014
解压缩后的数据长度:250000
压缩比:1.0916
- 分析:
- reshape函数中的m*n需要重灰度变换后的Gray矩阵的维度获取
2.行程编码的实验结果可根据以下三个图来得到:
index对应Encode相应列灰度值出现的次数,Encode_hex表示编码之后的十六进制
(2,162)-----(1100_0010,1010_0010)---(C2,A2)
(1,163)-----A3
(2,164)-----(1100_0010,1010_0100)---(C2,A4)
(1,163)-----A3
(2,162)-----(1100_0010,1010_0010)---(C2,A2)
(1,154)-----9A
(1,155)-----9B
(4,156)-----(1100_0100,1001_1010)---(C4,9C)......
行程编码则用(次数十六进制,灰度值十六进制)表示:
- 当灰度值出现的次数大于1小于等于63时,前一个字节表示出现的次数,且前两位为11,后一个字节表示本来的数据;
- 当灰度值出现的次数大于63时,将这个数据出现的数据分为几部分;
- 当只出现1次时,数据大于或等于C0时,仍用两个字节表示,(C1,数据),小于C0时,直接用数据表示