哈夫曼编码的译码是比较简单的。按照图314所描述的过程,就可以得到表31所示的每个符号(或电平)所编成的码字。这种电平与码字之间的关系叫做码本,编码时可以用它,而译码时同样可以用它,两者是一种逆过程。因此,只要从编码序列中取出一个码字,而后再去查码本,即可获得相应的符号(或电平)。
若编码与解码的原理已明了,则具体实现起来就很灵活了,可以用硬件,也可以用软件或者软件硬件相结合,这要看具体应用环境的要求。
最后,我们注意到哈夫曼编码是建立在图像信号(也可以是音频或其他信号)的统计特性上的。有了信号的统计特性,知道了各电平出现的概率,然后便可以构成码本,编码也就很容易实现了。但是,有许多信号(包括视频信号)的统计特性并不都是先验可知的,而有些信号又要求很强的实时性,这些都限制了哈夫曼编码的使用。
再就是哈夫曼编码序列的码长是可变的,而且码与码之间没有同步信息。这就带来一个问题:若其编码序列中某一位出现错误,则会顺序错下去,使许多个码都发生错误,这又称为错误传播。在使用哈夫曼编码时应特别注意这个问题。
3.4.3算术编码
算术编码不是对单个字符编码,而是对信源的字符串进行编码。即在进行算术编码时先统计信源所有字符出现的概率和取值范围,然后以字符串为单位进行编码。其过程是按字符的顺序,把整个字符串映射到一段实数半开区间\[0,1)内的某一区段,构造出小于1且大于或等于0的数值,这个数值(实数)就是输入字符串的编码。
对字符串的编码思想是,从第一个输入字符开始,列出它的出现概率及其取值范围,以后每输入一个字符都在上一个字符的基础上来缩短这个范围,字符越多,所得到的实数区间就越小,就需要用较多的位数来表示这个区间,但与对每个字符进行编码相比,还是减少了编码数据量。总之,算术编码是用一个实数(浮点数)对一个字符串进行编码,而不是对每个字符单独编码,从而达到数据压缩的目的。现举例说明上述编码过程。
【例3.3】设输入数据为“XYYZ”,字符出现概率和设定范围如表32所示。
其中,“范围”是字符的赋值区间,这个区间是根据字符发生的概率划分的,在编码过程中是相对前面字符所得出的编码区间而言的。也就是说每输入一个字符,将前面字符所得到的编码区间作为基础,再按当前输入字母的范围去进一步缩短编码区间。
当本例第一个字符X输入后,由字符概率取值区间的定义可知其实际取值范围为\[0.2,0.4),它决定了代码最高有效位取值的范围。读入第二个字符Y后,Y的取值范围在区间的\[0.4,0.8)内。要说明的是,由于第一个字符X已将取值区间限制在\[0.2,0.4)的范围中,因此Y的实际取值是在当前范围\[0.2,0.4)之内的\[0.4,0.8)处,即字符Y输入后的编码取值范围为\[0.28,0.36),而不是在\[0,1)整个概率分布区间上。可见,读入新字符后编码区间的上、下限可由下式计算:
high=(low)+range×rangelow
low=(low)+range×rangehigh
式中,high、low分别为读入当前字符后的编码区间的上、下限值;(low)为原字符串的编码区间的下限值;range为原字符串编码区间的取值范围(差值);rangehigh、rangelow分别表示当前字符发生概率的上、下限。
重复上述编码过程,直到字符串“XY-YZ”结束。计算结果如表33所示。
当字符串“XY-YZ”全部输入后,编码区间应为\[0.29152,0.2928\],在此区间内任取一数值(实数)都可作为该字符串的编码。这样,就可以用一个浮点数表示一个字符串,达到少占存储空间压缩数据的目的。
译码过程比较简单。根据编码时所使用的字符概率分配表和压缩以后的数值代码所在的范围,可以很容易确定该字符串的第一个字符,依次进行上述计算的逆过程,除去每个字符对编码取值区间的影响,就可以得到对应的字符串,完成译码过程。
【例3.4】设英文元音字母采用固定模式符号概率分配如表34所示,设编码的数据串为eai,令high为编码间隔的高端,low为编码间隔的低端,range为编码间隔的长度,rangelow为编码字符分配的间隔低端,rangehigh为编码字符分配的间隔高端。求数据串eai的编码结果。
初始high=1,low=0,range=high-low=1,一个字符编码后新的low和high按下式计算:
low=low+range×rangelow
high=low+range×rangehigh
①在第一个字符e被编码时,e的rangelow=0.2,rangehigh=0.5,于是:
low=0+1×0.2=0.2
high=0+1×0.5=0.5
range=high-low=0.5-0.2=0.3
此时分配给e的范围为\[0.2,0.5),在接收到第一个字符e后,范围由\[0,1\]变成\[0.2,0.5)。
②第二个字符a编码时使用新生成范围\[0.2,0.5),a的rangelow=0,rangehigh=0.2,于是:low=0.2+0.3×0=0.2。
high=0.2+0.3×0.2=0.26range=0.06
范围由\[0.2,0.5)变成\[0.2,0.26)。
③对下一个字符i编码,i的rangelow=0.5,rangehigh=0.6,则:
low=0.2+0.06×0.5=0.23
high=0.2+0.06×0.6=0.236
即用\[0.23,0.236)表示数据串eai,如果解码器知道最后范围是\[0.23,0.236)这一范围,它马上可解得一个字符为e,然后依次得到唯一解a,i,最终得到eai。
算术编码的特点:
①算术编码具有自适应的能力,所以不必预先定义概率模型,该方法适用于不进行概率统计的场合。
②信源符号概率接近时,建议使用算术编码,这种情况下其效率高于Huffman编码。
③算术编码绕过了用一个特定的代码替代一个输入符号的想法,用一个浮点输出数值代替一个流的输入符号,较长的复杂消息输出的数值中就需要更多的位数。
④算术编码实现方法复杂一些,但JPEG成员对多幅图像的测试结果表明,算术编码与Huffman编码相比,效率提高了5%左右,因此在JPEG扩展系统中用算术编码取代Huffman编码。
⑤当信源概率比较接近时,建议使用算术编码,因为此时哈夫曼编码的结果趋于定长码,效率不高。根据T.Bell等人对主要的统计编码方法的比较,算术编码具有最高的压缩效率。但实现起来,算术编码比哈夫曼编码复杂,特别是使用硬件实现的时候更复杂。
3.4.4二维预测编码
前面已经介绍了预测编码,主要是针对音频及其他一维信号来叙述的。在图像信号处理中,由于图像是二维的,它不但在水平轴上有相关性,而且在垂直轴上也有相关性。例如,图像上某块面积灰度一样或颜色一样的情况很多。利用二维预测可更好地进行数据压缩。首先,观察图315所示的某部分图像示意图,以便说明二维预测的原理。
根据图315,要求得当前像素点Xij的预测值X,可有多种方法。最简单的有如下几种:
前向预测X=A
平均预测X=(A+C)/2
或X=(A+D)/2
或X=(A+B)/2
平面预测X=a1A+a2C+a3B
在这里,预测当前像素点Xij只用到本行前一像素点和前一行中与Xij相邻近的像素点。原则上讲,还可以用更多行上的更多像素点来预测当前像素点。但它们与当前像素点相距较远,相关性小,对当前像素点的预测影响会小些,所以,更高阶的二维预测器对改善预测性能贡献不大。
因此,二维平面预测的预测系数若取a1=a2=1,a3=-1,则二维平面预测的运算最为简单,只进行加减运算即可完成,无论用硬件还是用软件,实现起来都极为方便。有人取a1=a2=3/4,a3=-17/32,这可供直接使用。
3.4.5变换编码
对图像数据进行某种形式的正交变换,并对变换后的数据进行编码,从而达到压缩的目的,这就是变换编码。变换编码对单色图像、彩色图像、静止图像、运动图像等各种图像都是有效的,因此,在图像编码中应用十分广泛。
变换编码的过程是将原始图像分块,对每一块进行某种形式的正交变换。可以简单地理解为将小块图像由时间域变换到频率域,而且能够想像经变换后能量主要集中在直流分量和频率低的分量上。在误差允许的条件下,我们只采用直流和有限的低频分量来代表原始数据就能达到数据压缩的目的。在解压缩时,利用已压缩的数据并补上高频分量(为0),而后进行逆变换,通过逆变换,就可恢复原始数据。可以想到,在压缩时忽略了许多高频分量,而在解压缩时用0来代替这些高频分量,这必然减少了信源的熵,使信息量减少,从而带来一定的失真。因此,这种变换是一种有损压缩。以上就是变换编码的简单解释。正交变换的种类很多,在许多书籍上都可以看到。例如,傅里叶变换、沃尔什哈德马变换、哈尔变换、正弦变换、余弦变换、斜变换等。从理论上讲,卡亨南洛甫(KL)变换效果最好,因为它是建立在对输入图像数据求取统计特性的基础上。由于只有求出输入数据的相关矩阵及特征矢量,才能在此基础上进行KL变换,而且这种变换又没有快速算法,实现起来很复杂,因此,尽管它最佳,但却很少应用。本书中只简单介绍余弦变换,余弦变换与KL变换的性能十分接近,但其计算复杂度适中,而且有快速算法,因此,在图像数据的压缩中经常使用此变换。在后面要说明的多媒体图像压缩标准JPEG、MPEG和P×64中,均采用余弦变换。
1.离散傅里叶变换(DFT)
离散傅里叶变换是时域有限采样序列x(n)(n=0,1,…,N-1)的傅里叶变换。一个时域的非周期信号的对应频域是连续频谱密度函数。为了使频域也离散化,先要将时域的有限序列x(n)延拓成周期信号x~(n),周期T=NTs(Ts为采样周期)。对周期序列x~(n)进行傅里叶变换,就可以得到频域的离散傅里叶变换C(k)(k=0,1,…,N-1)。在时域和频域都取主域N个离散值就得到x(n)与C(k)的离散傅里叶变换对。定义:一个有限的实数或复数序列x(n),n=0,1,…,N-1,它的傅里叶变换对称为离散傅里叶变换。其关系为
C(k)=N1n=0x(n)ei2πkn/N,k=0,1,…,N-1
x(n)=1NN1k=0C(k)ei2πkn/N,n=0,1,…,N-1
其中,x(n)是时域有限采样序列,C(k)为对应的频域离散频谱。
2.离散余弦变换(DCT)
离散余弦变换实际上是一种特殊的离散傅里叶变换。由离散傅里叶变换的性质可知,一个周期性的偶函数的傅里叶级数只有余弦项而无正弦项。当一个周期序列的离散傅里叶变换也只有余弦项而没有正弦项时,就是离散余弦变换。
一个有限实数序列x(n)不会具有周期性,也不会具有偶函数性质。为了利用上述偶函数性质,可以将x(n)扩展成周期性偶函数,然后再进行傅里叶变换,就可得到离散余弦变换关系。
其他实现上面DCT和IDCT有快速算法,可以利用软件来实现。由于近年来多媒体的发展,对图像(视频)信号的实时处理提出了更高的要求,这就促使集成电路生产厂家开发了许多大规模和超大规模的集成电路,用以实现DCT和IDCT。这也为多媒体视频信号处理提供了方便。
在利用二维余弦变换进行图像数据压缩时,首先要对图像进行分块,块的大小通常为8×8或16×16像素点,而后,对图像块进行快速余弦变换(FDCT),从而得到余弦变换系数。
可以这样认为,采用8×8图像子块进行FDCT得到的DCT系数就是输入的64个时间域信号被变换成64个频率域的幅度数据。在这64个频域数据中包括:1个0频率(直流分量)分量,叫做DC系数;63个其他频率的分量,叫做AC系数。
【例3.5】随意取得8×8输入图像子块的数据如下所示:
很显然,经过余弦变换后,在频域里,幅度大的分量都集中在左上角的0频和低频处。DC系数和相对低频分量的AC系数大,而对应于高频分量的幅度都比较小。
接下来,就是对变换所得到的DC系数和AC系数进行量化处理。对经过上述变换后得到的8×8变换系数进行量化,可规定每个系数的量化间隔,那么,对8×8个变换系数,就有8×8个量化间隔。这8×8个量化间隔构成一个表,叫做量化表。
量化表是根据图像处理的要求、压缩比的大小和图像重建效果等因素来考虑的。在JPEG标准中给出了参考的量化表。为了解释所阐明的问题,摘录JPEG标准的亮度量化表如下:
从量化表中可以看到,各变换系数的量化间隔是不一样的。对低频分量,量化间隔小,量化误差也小,精度要高些。频率越高,量化间隔越大,精度越低。这是因为高频分量只影响图像的细节,对整块图像来讲,它没有低频分量重要。这就是为什么量化表中左上角量化间隔小而越靠近右下角量化间隔越大的原因。
利用量化表中的量化间隔,分别对各变换系数进行量化。量化后的变换系数称为规格化(或归一化)量化系数。对于上面所举的例子来说,可以得到如下的规格化量化系数:
从上面的规格化量化系数中,可以解释压缩过程。也就是说,从原理上讲,只要保留直流和5个低频分量的值,就可以代表原始的8×8的数据,从而达到数据压缩的目的。
在解压缩时,首先恢复规格化系数,接下来就需要利用压缩时使用的量化表求出重建的变换系数。很显然,重建的变换系数并不与原始变换系数相同,这是有损压缩的必然结果。但是,利用重建的变换系数进行快速逆余弦变换(IFDCT)可以重建原始图像。重建图像数据与原始数据仅有微小的差别,对图像的视觉效果而言,这个微小差别主要决定压缩比的大小。
以上就是在图像处理中常用的余弦变换的简单过程,现以图316所示的过程说明余弦变换的大致过程。
3.4.6LZW编码
LZW(LempelZivWelch)编码技术由三位学者提出并加以完善,故用其三人名字的第一个字母的组合LZW表示这种编码方法。
1.LZW压缩算法
LZW压缩算法是围绕着串表来组织的。该串表具有前缀特性,也就是说表中的每一个串的前缀串也必定在表内。若用符号表示,即假如串ωk是由串ω和字符k构成并且在串表中,则ω也肯定在串表中。