图像压缩一度曾属于个人计算机(PC)范畴,现在正普遍用于嵌入式环境。这种趋势很大程度上是由于新的DSP处理能力提高和多媒体功能增强的结果。从而,这成为嵌入式产品设计工程师为提高图像压缩效率更好地理解图像算法的优势。本文介绍了JPEG(baseline)压缩标准,它是现在采用的所有图像压缩算法中最流行的算法。当这里没没有明确指出时,JPEG解码(解压缩)过程与其编码(压缩)过程正好相反。
JPEG标准虽然有许多规定的版本,其中 JPEG(baseline)压缩标准(这里简称JPEG压缩)包括一组最基本的要求。JPEG属于有损压缩算法,所以原图像不能精确地重构(虽然也有“无损JPEG”压缩标准)。JPEG利用人的视觉系统特性,去掉或减少那些对眼睛不敏感的数据。JPEG适合用于灰度级和彩色图像,特别是照片,但是它并不适合双色图像。图1示出了JPEG压缩过程,将在下文做比较详细介绍。
预处理
颜色空间
输入的未压缩图像可按照多种格式中的一种保存。一种流行的24 bit的RGB格式,即每个红、绿和蓝像素对应8 bit。但是,考虑到对一幅给定的图像有R、G和B三个独立的子通道,通常在这3个子通道之间存在明显的视觉相关性。因此,为了获得更加压缩比,通常将RGB格式解相关得到分立的亮度(Y)和色差(Cb、Cr)分量。变换公式如下:
Y=0.299(R-G) + G + 0.114(B-G)
Cb=0.564(B-Y)
Cr=0.713(R-Y)
空间滤波
因为人眼对亮度信号比对色差信号更敏感,所以通过对色差(Cb,Cr)分量滤波(子采样)能够降低图像带宽。一个没经过滤波的图像,子像素的排列为{Y,Cb,Cr,Y,Cb,Cr,Y…}的称为4:4:4格式,因为对于每4个连续采样点取4个Cb,,4个Cr和4个亮度Y样本。这相当于,每个像素都由一个完整{Y,Cb,Cr}组成。换一种表达方式就是,对一幅720×480像素的图像,4:4:4格式意味着这3个分量样本中每个分量图像都是720×480字节(byte)。
如果通过对色差分量滤波我们可把水平带宽降至原来的一半,我们可得到4:2:2格式{Cb,Y,Cr,Y,Cb,Y,Cr,Y,…}。这里,每个像素由一个字节的Y和一个字节的Cb或Cr组成。因此,对于一幅720×480的图像,4:2:2格式意味着Y分量图像为720×480字节,Cb和Cr分量图像每个都是360×480字节。
为了进一步降低图像带宽,可以再在竖直方向对色差分量滤波。这就得到了4:2:0格式,意味着对于一幅720×480图像,其Y分量图像为720×480字节,Cb和Cr分量图像每个都是360×240字节。
不论选择何种格式,图像都会被单独存入Y,Cb和Cr缓冲区,因为JPEG算法按照相同的方式在每个分量上单独地执行。如果色差分量被滤波,那么这就相当于在减小尺寸的图像上运行JPEG算法。
JPEG算法在8×8字节的数据块上的操作如图1示出。因此,在每个图像缓冲区中,数据被从左到右、从上到下地划分成8×8个象素块。这些象素块不重叠,如果图像的行和列象素数不是8的倍数,那么就要根据需要通过重复图像的最后一行或列来填充。
DCT变换
JPEG算法中的DCT变换利用这样的一个事实:人眼对低频分量的图像比对高频分量的图像更敏感。8×8 DCT变换把空间域表示的图像变换成频率域表示的图像。虽然其它频率变换也会有效,但选择DCT变换的原因是其解相关特性,图像独立性,压缩图像能量的有效性和正交性(这使DCT反变换非常简单)。此外,二维(2D)DCT变换的可分特性允许在8列向量上计算一维(1D)DCT,接着在得到的8×8矩阵的8行向量上计算1D DCT。该8×8 DCT可按照下式表示:
Ymn=1/4 KmKnXij cos((2i+1)mπ/16) cos((2j+1)nπ/16)
其中:
Ymn =8×8输出块的第m行第n列的输出DCT系数
Xij =8×8输入块的第i行第j列的输入空间图像坐标
Km = ,当 m=0时; 或 1 ,当m为其余值时
Kn = ,当n=0时;或1,当n取其余值时
为了统一地处理不同的图像分量,DCT编码器通常要求所有像素的期望平均值为0。因此,在完成DCT变换之前,需要从每个像素(一般从1~255范围内)减去128将其范围变换为-127~127。这种偏移对于像素块的交流(AC)系数特性没有影响。
观察DCT变换很有启发性。参见图2中示出的DCT基函数。在一个8×8像素块上完成DCT变换,我们实际上做的事情是将输入8×8像素块与64个DCT基函数相关并且将表征相关性程度的相关系数记录在输出DCT矩阵中。
例如,输出DCT矩阵在(2,1)的系数对应于在(2,1)的基函数与整个8×8输入像素块之间的相关系数。高频分量对应的相关系数位于DCT数据块的右下角,并且我们的目的正要使这些系数变为零——在8×8 DCT数据块中零系数越多,获得的压缩比就越大。在下面介绍的量化步骤中,我们将讨论如何减小矩阵中非零系数的幅度和增加零系数的数目。
量化
在8×8像素块上完成DCT变换之后,为了在压缩比方面获得大的提高需要量化过程。量化过程指的是用一组预定的容许值之一代表实际系数值的过程,以便可用较少的位数对全部数据编码(因为该容许值是所有可能的值中的一小部分)。
请记住人眼对低频分量的图像比对高频分量的图像更敏感。因此,高频分量的图像中的细小错误不容易被发现,所以完全去掉一些高频分量通常在视觉上可以接受。JPEG算法中的量化过程正是利用这一特性来降低对给定8×8像素块编码所需要的DCT信息量。
在JPEG处理中,量化是不可逆的关键步骤。虽然完成一个DCT反变换由于舍入误差将不能精确地恢复原始输入的8×8输入矩阵,但是其结果通常视觉上完全能接受。然而,由于量化后原来未量化的系数的精密度会永久地丢失,所以量化仅用在有损压缩算法中,例如,我们在这里讨论的JPEG(BASELINE)压缩算法。
当量化表建立好之后量化过程就很简单,但是量化表本身也可能非常复杂,对8×8 DCT变换输出数据块的每个元素通常具有一个单独的量化系数。因为这个输出矩阵对应于其输入像素块与64个DCT基函数关系的密切程度,并且可以用实验方法测定每个DCT频率对人眼的重要性,并且由此做相应的量化处理。换句话说,频率朝着图2示出的基函数的右下角方向的变化趋势有助于在它们的整个量化表中出现大的频率值,因为这将有助于使DCT输出块中较高频率分量系数变成零。量化的实际过程是在对于给定的行和列,DCT输出系数与量化系数的简单元素相除。
“质量比例系数”可适用于量化矩阵以平衡图像质量和压缩图像尺寸。对于在JPEG标准中提到的示例表格,典型的质量值范围为从0.5(高恢复图像质量)到5(高压缩比)。
量化后的二维系数要重新编排,并转换为一维系数,为了增加连续的“0”系数的个数,就是“0”的游程长度,JPEG编码中采用的Z字形编排方法。
Z字形编码
接下来,我们准备按照一种有效的编码方式对量化后的二维系数要重新编排。正如我们从DCT输出中看到的,随着水平方向和垂直方向频率值的增加,其量化系数变为零的机会越来越大。为了利用这一特性,我们可将这些二维系数按照从DC系数开始到最高阶空间频率系数的顺序重新编排为一维系数,如图3所示。通过使用Z字形编码方法实现这种编排,即在8×8像素块中沿着空间频率增加的方向呈“Z”字形来回移动的过程。在图3的左边,我们可看到对DCT量化后输出的矩阵系数。使用图3中部示出的Z字形编排模式,我们能产生一个如图3右边示出的一维系数。
每个量化后的DCT输出矩阵都经过Z字形编码过程。从DCT二维系数生成的64×1一维数组中的第一个元素代表DC系数,其余的63个系数代表AC系数。这两类系数完全不同足以将它们分开,并且可采用不同的编码方法以获得最佳压缩效率。
必须对所有的DC系数(每个DCT输出块中有一个)分组放在一起。因此,对DC系数组和每个AC系数组分别编码。
DC系数编码
DC系数代表每个8×8像素块的亮度(数值比较大)。因此,在相邻像素块之间存在很大相关性(DC系数值变化不大)。虽然仅靠其自身不能公正地预测任何给定输入数组的DC系数,实际的图像通常在局部区域变化不大。因此,我们可以用以前的DC系数预测当前的DC系数。我们通过使用差分预测技术〔差分脉冲编码调制(DPCM)〕对相邻图像块之间的DC系数的差值进行编码,能增加对数值很小的系数进行编码的可能性,从而降低压缩图像中的位数。
为了获得编码值,我们简单地从当前的像素块中的DC系数减去以前处理过的8×8像素块的DC系数。这个差值被称为“DPCM差值(Δ)”。该差值一旦计算出来,与一个表比较以确定它属于的符号组(根据其幅度),然后使用熵编码方法(例如,霍夫曼编码)进行适当的编码。
AC系数编码(游程编码)
由于经过量化步骤后有许多AC系数值变为零,所以对这些系数要采用游程编码(RLE)。游程编码的概念根据一种简单的原理。在实际图像序列中,相同值的像素总可以用单个字节表示,但是把相同的数值一遍又一遍地发送没有意义。例如,我们看到量化后的DCT输出数据块产生许多系数为零的字节。Z字形编排有助于在每个序列末尾产生系数为零的数组。
我们首先在给定“行程”长度中简单地对零的个数编码,而不是对每个零单独编码。然后通常使用霍夫曼可变字长编码器(VLC)提供游程编码信息。
熵编码
对上面介绍的JPEG系数序列做进一步压缩称作熵编码。在这一阶段,对量化后的DCT系数完成最终的无损压缩以提高总压缩比。
熵编码是一种使用一系列位编码代表一组可能出现的符号的压缩技术。图4示出了一种明显的2 bit编码序列对应4种可能出现的符号(A,B,C和D)。
在这个例子中,我们能用两位信息惟一地描述每个符号。因为每个符号都可用2 位信息表示,我们称这种编码为“定长码”。定长码最常用于每个符号以相同的概率出现的系统中。
实际上,大多数符号并非以相同的概率出现。在这种情况下,我们可利用这样的事实来减少用于压缩数据所用的平均位数。每个符号所采用的编码的长度可以根据该符号出现的概率改变。通过对出现频度比较高的符号分配比较短位数的代码,而对出现频度较低的符号分配比较长位数的代码,我们很容易改进对压缩数据编码所用的平均位数。
霍夫曼编码
霍夫曼(Huffman)编码是一种可变长度编码技术,它用于压缩具有已知概率分布的一连串符号。霍夫曼编码具有这样一个编码树结构,首先找出该序列中具有最小出现概率的两个符号。将这两个符号的独立概率之和作为新的符号的概率。这个过程继续进行,使每个节点都由两个最小概率的符号组成,直到所有符号都用这样的编码树结构表示。
当编码树构建成之后,首先对每个树支分别赋予二进制数字0或1,可以在编码树结构中可赋予编码序列。接着,从树根开始沿着树枝方向依次连接一直到定义相关符号(这里指A, B, C和D中的某一个)的那个树支末梢,同时按照上述顺序依次读取对每一树支赋予的代码(0或1)组合起来构成该符号的代码。这种方法得出的独特代码保证每个符号的数据长度都是最佳的(见译者附图)。
虽然这种编码可具有不同的长度,但是如果从最高有效位(MSB)开始读取编码,每个编码都能毫无疑义地解码。JPEG标准提供许多霍夫曼编码表格来描述输入量化后的数据不同的编码方式——例如,已经介绍的根据亮度或色差信息编码。
图5中使用和图4相同的例子,但是具有不同权重的符号概率。位编码栏示出了修改的编码序列。正如我们看到的,最可能出现的符号采用一位编码,而最不可能出现的符号是使用3位编码。
使用这个表格,我们能确定对每个符号编码的平均位长度。
(0.5×1 位) + (0.3×2 位) + (0.1×3 位) + (0.1×3 位) = 1.7 位/符号
在这个例子中,变长编码方法产生平均1.7 位/符号,它比图4中产生的定长编码产生的2 位/符号提高了效率。
JPEG标准使用的另一种熵编码方法是算术编码。虽然这种算法由于使用适应性技术更容易达到熵速率而提供比霍夫曼编码更好的压缩性能,但是要求的附加处理还不能证明对压缩效率有任何小的改进。此外,算术编码还存在专利限制问题。
JPEG文件交换格式(JFIF)
将编码数据写入JPEG文件交换格式(JFIF),顾名思义JFIF是一种简化的格式允许JPEG压缩图像在多个平台和应用间共享。JFIF包括嵌入图像和编码系数,并采用适合的标题信息构建。尤其是,除了编码数据之外,JFIF文件必须保存所有编码和量化的表格,这是保证JPEG解码器正确工作必须的。
译者附图
参考文献
1. Symes, Peter. Video Compression Demystified. McGraw-Hill: New York, 2001.
2. Bhaskaran, Vasudev and Konstantinides, Konstantinos. Image and Video Compression Standards. 2nd edition. Kluwer Academic Publishers: Boston, 1997.