一种可移植的JPEG解码库的实现
2018-02-23顾燕卿
顾燕卿
摘要 JPEG是一种图片影像领域广泛使用的压缩标准,是如今互联网和多媒体技术的基础技术。越来越多的用于网络软件、数码相机、消费型电子设备、激光扫描仪、医院影像设备等多媒体系统中。目前JPEG在嵌入式设备中的编解码多由专门的ASIC硬件实现,但此种硬件电路成本高、可拓展性差。本文提出了一种轻量级的、可移植、优化的JPEG软件解码库,不依赖任何操作系统和芯片类型,具有较高的灵活度和更广的适用性。
【关键词】JPEG解码 图像编码 DCT 变换Huffman
1 压缩标准JPEG概述
JPEG即Joint Photographic Experts Group联合图像专家组,是由国际标准化组织制定的第一套静态图像压缩的国际标准,适用于照片、传真、印刷等各方面。JPEG压缩是一种有损的压缩,充分利用了人眼的视觉生理特性,去除了人眼不易觉察的图像高频数据,在保证了图像显示效果的同时大大压缩了图像的体积。
JPEG压缩编码不受长宽比和大小限制,适用于二值、灰度、彩色等各种图像,具有连续色调、多级灰度、静态图像等特点。与其他的图像压缩格式相比,如bmp、 gif、 png、tiff等,JPEG在丰富地展现图像内容的同时还能具有极高的压缩比率。JPEG的优良品质使得它在互联网、多媒体、人机交互等许多领域获得广泛的应用。
JPEG标准定义了三种编码操作模式:基于DCT的基本顺序模式、基于DCT的渐进拓展模式、无失真模式。在实际应用中,JPEG图像使用的是基于DCT的顺序模式,软硬件解码器都支持此种模式。本文讨论和实现的是这种模式。
2 图片存储格式解析
JPEG只是一种压缩标准,并没有说明图像文件的存储格式。JFIF即JPEG FileInterchange Format,是事实上的JPEG文件格式标准,即以*jpg、*.jpeg、*.jfif后缀命名的文件。JFIF标准定义了一种格式,就如一种通用语言,用于JPEG图片在计算机系统中的存储和交换。想要对JPEG图片解码首要的就是解析JFIF格式存储的文件。JFIF交换格式将JPEG解码的必要信息按段的形式组织和存储,每个段都由一个特殊的標记值打头。表1是常用的JFIF段标记。
JFIF格式的各个段中,除了SOI、EOI,并没有严格的顺序要求,可以由用户自行组织。除了JPEG标准定义的一些内容,如分辨率、量化表、Huffman表,JFIF还允许用户自定义私有数据段,这就带来了更多的灵活性。不过需要注意的是二进制值0xFF作为保留字,代表一个标记段的开始,如果用户数据中恰巧包含0xFF,则需要在后面加上0x00,表明这是用户数据以同段标记区分开。
以下是从JFIF文件提取关键信息的一个实例,字节流样本来自IPHONE6S手机拍摄的一张JPEG原图。JFIF文件中的原始数据为ffc0 0011 0805 0002 d003 0122 0002 1101 0311 01ffc400 lf00 0001 0501 0101 0101 0100 0000 0000 0000 0001 0203 0405 0607 0809 0a0bfaffdb00 4300 0202 0202 0202 0302 0203 0503 03030506 0505 0505 0608 0606 0606 0608 0a08 08080808 080a 0a0a 0a0a 0a0a 0a0e 0c0e 0c0e 0c0e0e0e 0e0e 0f0f 0f0f 0f0f 0f0f 0f0f。分析这段数据,发现有一个FFCO标记、FFDB标记和一个FFC4标记,说明包含了SOFO、DQT、DHT三个段,即一个图像信息段、一张量化表和一张Huffman表,解析后如表2、表3、表4所示。
解析完JFIF文件中的SOFO、DQT、DHT标记后,再找到图像数据段SOS,就获得了解码JPEG所需的全部信息和数据。从JFIF交换格式提取信息是实现JPEG编解码的前提。同时,理解JFIF的格式对数据恢复、图像重建、
3 解码原理与实现细节
JPEG解码流程如图1所示。其中熵解码模块是最繁琐的部分,IDCT变换则计算量最大,而数据损失最多的一步是反量化过程。各模块涉及到的主要原理将详细分析。
3.1 熵解码
熵解码是无损变换,目的是解出每个分量的DCT量化系数,以供IDCT变换使用。主要包括如下几个方面:
3.1.1 范式Huffman编码
Huffman编码是一种前缀不定长的编码。其思想在于:统计词频,出现频率高的符号用较短的编码来表示,达到整体的比特数压缩。哈夫曼编码的效果十分显著,在各种情况下都能获得极高的压缩比率。但是其缺点在于,每种符号和对应的哈夫曼编码必须写入一张表,而这张编码表的大小是不定的,带来的额外开销也是不定的。范式Huffman编码是哈夫曼编码的一个重要变种,采用了一种巧妙的方法调整了哈夫曼树以克服上述缺点。首先,范式Huffman树每一层的叶子节点都集中在最左边;再者,对每个节点的编码采取左O右1的策略。这就带来一个好处,无论每一层有多少叶子节点表示的符号,并不需要记录每一个符号对应的编码,仅需要记录下首节点的编码。而首节点的编码可以通过每一层的符号数计算得到,这样就大大减少了码表的体积。在JPEG标准中,实际使用的范式Huffman树层次不超过16层,所以仅用16字节的空间记录叶子节点数,再在尾部按顺序填入不超过256字节的符号集。表4的Huffman编码表中,编码位长代表层数,符号数量代表每一层叶子节点数,可以容易地还原出图6的范式Huffman树。
3.1.2 行程编码与变长编码
行程编码又称游程编码,使用一种中间格式记录一串重复的数字。比如111111可以记录成(6,1),代表6个1。而JPEG中使用的行程编码略有区别,考虑到待编码数据的特性,其只记录数字0的行程。举个例子说明一下,比如待编码数据为:7,0,0,0,0,31,0,-20,-12,0,0,1,0…0。则可以写成(0,7)(4,31)(1,.20)(O,.12)(2,1)EOB。即用每组数字的第一个数来表示前面0的长度,EOB代表后面全是0。
变长编码是相对于固定的编码而言的。在计算机里,数字的表示多采用固定编码,比如数字7将被存储为00000111,占用8个比特。在变长编码中,7将被存储为( 0011,111),括号内第一个数是固定的4比特长,用来表示后面的数字位数。那么数字7采用变长编码后就能节省一个比特。另外还需要注意一点的是变长编码对于负数是用反码来表示的,比如.7将被存储为(0011,000)。
行程编码的中间格式将采用变长编码来表示。比如(4,31)将被表示成(4,0100,1111),前两个数可以合在一起使用8比特表示,最后即( 01000100,1111);比如(1,-20)将被表示成(00010101,01011)。需要说明一点的是,范式Huffman编码只对行程编码的行程长度和变长编码的前4比特进行编码,第二个数将原样存储。如图2所示。
3.1.3 解码前后数据量对比
首先范式Huffman编码的数据源是一个8比特数,编码后的结果则是频率高的数小于8位,频率低的数字大于8位,从而达到数据的压缩。那么到底压缩了多少,节约了多少空间?可以来看一下JPEG字节流解码前后的数据量比较,数据源是来自网络爬虫随机抓取的1000张JPEG图片,结果如表5。可以看出范式Huffman编码的压缩率在42%左右,节省了58%的存储空间,展示了十分优异的性能。
3.2 反量化
上一步的熵解码每解出64个数字,就得到一个8x8图像块的64个系数。这些系数是被量化过的系数,需要依靠量化表还原。反量化之前还需要反zigzag扫描,将64个连续的数字排成8x8的形式,与量化表一一对应以便后面计算。Zigzag扫描顺序如表6。
將64个数字从0-63编号,然后按序号填入图8的矩阵中排成与量化表相同的8x8的形式。然后每一个数乘以量化表中相同位置的参数,计算后得到真正的DCT系数,就完成了反量化。
反量化的计算并不复杂,只是整数之间的乘法,但是反量化却是解码过程中数据量损失最大的部分。举个例子说明,假如一个DCT系数原始值为120,量化步长为50,量化系数值则为2。那么反量化的时候,利用量化系数乘以量化步长,计算所得DCT系数却为100。可见反量化是有损的计算,并且丢失的余数不可恢复。
3.3 IDCT计算
IDCT即反向离散余弦变换,将频率域的64个DCT系数变换成色彩域的64个像素值。8x8矩阵的二维IDCT公式为:个最小单元,才能进行颜色空间转换。根据各分量采样率的不同,一个最小单元可以由1:1:1或4:1:1的YUV比例组成。JPEG中最常见的是使用4:1:1的采样比,即对4个8x8的RGB像素块编码时,Y分量每块采样一次,即全采样,U分量和V分量是每4个块采样一次,由4块共享。那么JPEG原始码流蕴含的编码顺序就是:[YO、Yl、Y2、Y3、U、V],每解出6个分量的8x8块,就需要合并成一个最小单元,转换到RGB空间,共还原32x32个像素。不断重复以上过程,最后就能完成对整幅JPEG图片的解码。
参考文献
[1]章毓晋,图像工程[M].北京:清华大学出版社,2013 (01).
[2]蒙智明.基于S3C44BOX的JPEG图像解码及LCD显示的实现[D].江南大学,2 007.