目录
1.介绍
JPEG是一个适用范围很广的静态图像压缩技术,既可用于灰度图像又可用于彩色图像。JPEG算法与色彩空间无关,处理的彩色图像是单独的彩色分量图像,因此它可以压缩来自不同色彩空间的数据,如RGB、YCbCr和CMYK。JPEG专家组开发了两种基本的压缩算法,一种是采用以离散余弦变换(DCT)为基础的有损压缩算法,使用有损压缩算法时,在压缩比为25:1的情况下,压缩后还原得到的图像与原始图像相比较,区别不大,因此得到了广泛的应用;另一种是以预测技术为基础的无损压缩算法。下面主要介绍以DCT为基础的JPEG编码。
2.数据压缩的前提
视觉冗余
人类视觉系统并不是对任何图像的变化都很敏感,人眼对于图像的注意是非均匀的。实际上人类视觉系统一般分辨能力约为64级灰度等级,而一般图像量化采用256灰度等级,这类冗余称为视觉冗余。例如,人的视觉对于边缘的急剧变化不敏感,且人眼对图像的亮度信息敏感,对颜色的分辨率弱等,这就可以减少色度分量的分辨率。在JPEG压缩中应对这类冗余,主要的编码方法是非线性量化、位分配。
空间冗余
在一幅图像中,规则物体和规则背景的表面物理特性具有相关性,这些相关性的光成像
结构在数字化图像中就表现为数据冗余。在JPEG压缩中应对这类冗余,主要的编码方法是DCT变换。
编码冗余
一般来说,如果编码时没有充分利用编码对象的概率特性就会产生编码冗余。在图片中,像素值一般都集中某一区间内,因此某些灰度值出现的概率必定大于其他灰度值,如果用等长码,就会产生编码冗余。在JPEG压缩中应对这类冗余,主要的编码方法是DPCM、游程编码、熵编码(霍夫曼编码)。
3.基于DCT的JPEG压缩编码流程
3.1 色相转换
如果是黑白图像,可以直接进行JPEG压缩。虽然JPEG也可以压缩RGB分量,但是在亮度/色度空间(YUV空间)的压缩效果更好。如果是彩色图片,需要将RGB彩色空间转换为YCbCr彩色空间。色相转换是无损的,它仅仅是将图像从一种色彩空间变换到另一个色彩空间而已。RGB与YCbCr之间的转换并不包含在编解码器中,而是根据应用程序在编码之前和解码之后根据需要完成。RGB->YUV变换公式如下:
Y = 0.299R + 0.587G + 0.114B
Cr = (0.500R – 0.4187G – 0.0813B) + 128
Cb = (-0.1687R – 0.3313G + 0.500B) + 128
3.2 区块切割与采样
JPEG算法是在8×8像素的数据块上的操作,块(8×8像素)是离散余弦变换操作的基本单位,高速信号处理器对这个尺寸大小的数据块有最高的处理性能。在每个图像缓冲区中,数据被从左到右、从上到下地划分成多个8×8大小的像素块。这些像素块不重叠,如果图像的行和列像素数不是8的整数倍数,那么就要根据需要通过重复图像的最后一行或列来填充。
RGB转换成YCbCr,如果不进行采样,那么一个像素在RGB色彩空间中对应有3个分量分别是R、G、B,色相转换后也对应有3个分量分别是Y、Cb、Cr,这种情况就是上图中4:4:4采样.但实际中使用4:2:0较多,也就是4个亮度点Y对应1个色差Cb和1个色差Cr。最后将Y、Cb、Cr各自组成8×8的块大小,因此一个16×16像素宏块可以分成4个8×8的Y块、1个8×8的Cb块和1个8×8的Cr块,这就是离散余弦变换操作的基本单位。
3.3 离散余弦变换
JPEG算法中的DCT变换利用这样一个事实——即人眼对低频分量的图像比对高频分量的图像更敏感。8×8像素DCT变换把空间域表示的图像变换成频率域表示的图像。简单来说,是用一个8行8列的二维数组产生另一个同样包含8行8列二维数组的函数,相当于把一个数组通过一个变换,变成另一个数组,实质是指将一组光强数据转换成频率数据。其实DCT变换也是从傅里叶变换发展而来的,傅里叶变换一个最大的问题是,它的参数都是复数,在数据的描述上相当于实数的两倍。DCT变换相当于只取了实部,减少了数据量。
二维DCT变换的公式如下。如果从这个公式展开之后,频率域F(0,0)的值相当于输入的空间域8×8像素矩阵和一个变换矩阵做內积得到,这个变换矩阵就是下面的DCT基函数。8×8的DCT就有64个基函数。
DCT变换过程如图6所示。对每个图像块做离散余弦变换,通过变换可以把能量集中在矩阵左上角少数几个系数上。若不考虑截尾误差,DCT变换过程是属于无失真的转换过程,经DCT转换后每个8×8的像素会产生一个DC(直流)系数及63个AC(交流)系数。
DCT的特点:
- 输入是8×8个像素点,输出则是8×8个系数
- 把影像由空间定义域转换为频率定义域,每个8×8块里面系数的位置越靠近左上角,它代表的频率越低,越靠近右下角,则代表的频率越高
- 大部分的影像能量会集中在低频部分,也就是转换之后的输出系数在低频部分的值比较大,而输出系数在高频部分的值很小。(可以看下面的DCT频谱图)
- 当输出系数经过量化后,高频部分的值大部分都会变为0
具体的DCT计算如下图所示。首先图片中原始灰度和亮度值用8bit表示,也就是(0,255)这个范围,更多会分布在128附近,因此首先将原始灰度值/亮度值减去128,这样会有更多值为0,有利于压缩,这时候范围变成(-128,127)。然后再做DCT变换。
具体的计算过程,例如我要算F(0,0),下面是我的计算过程,利用减去128的灰度值和对应的基函数做內积,F(0,0)对应的基函数是一个8×8单位矩阵。做完內积之后乘以系数1/8,具体可以看上面的2D DCT公式。
3.4 DCT量化过程
为了达到压缩数据的目的,需要对DCT系数做量化。量化是对经过离散余弦变换后的频率系数进行量化,这是一个“多到一”映射的过程。量化的目的是减小非0系数的幅度以及增加0值系数的数目,在一定的主观保真的前提下,丢掉那些对视觉效果影响不大的信息,量化是图像质量下降的最主要原因。
量化是在8×8像素块上完成DCT变换之后进行的,一旦非重要的分量被去除,是无法恢复的,因此量化过程是不可逆的有损压缩过程。当量化表建立好之后量化过程就很简单了,简单说就是选择“量化比例系数”,然后DCT系数除以“比例系数”得到“量化后的DCT系数”,量化后的比例系数中数值较大的被映射到非零的整数,数值较小的系数被映射到零。
量化表的特点是在量化表的左上角的数值都小,而越往右下角则数值越大。这样设计的目的是为保持低频区系数的准确度,至于高频区,由于人类肉眼对其并不敏感,故量化的数值较大。如果量化系数高,那么压缩比就大,质量不清晰,而反之,量化系数低,那么就是相对较少地抛弃图像信息,压缩比就小。因此需要在一定的主观保真的前提下,丢掉那些对视觉效果影响不大的信息。
该量化表是根据人眼对量化误差的视觉阈值来确定的。由于人眼视觉系统的频率响应随着空间频率的增加而下降,并且对于两个色度分量的下降比亮度分量快。所以,JPEG为亮度分量和色度分量分别推荐了量化表,那也就是Y分量和UV分量使用的量化表是不同的。
3.5 Z字型编码过程
量化后的二维系数要重新编排,并转换为一维系数,为了增加连续的“0”系数的个数,也就是“0”的游程长度,JPEG编码中采用“Z字形”编排方法。
DCT变换就是使一些高频分量为0,达到压缩目的。随着水平方向和垂直方向频率值增加,其量化系数为零的技术越来越大,因此将二维系数重新排列为一维系数的过程中,可以在8×8像素块中沿着空间频率增加的方向(即Z字形)进行编排。
Z字形编码过程如下图所示,对DCT量化后的矩阵系数使用图中部所示的Z字形编排模式,产生一个图右边的一维系数。从DCT二维系数生成64×1一维数组中的第一个元素代表DC系数,其余63个系数代表AC系数。这两类系数完全不同,可用不同的编码方法压缩以获得最佳压缩效率。
游程编码的结果可以用三个量(a,b,c)表示:a表示0的个数(称为游程);b表示系数值;c表示最后非0位置,如果非0系数已处于最后的位置或其后所有值均为0,则置1,不然,则置0.
3.6 DC系数及AC系数编码
对DC系数组合每个AC系数组分别编码,DC系数与AC系数编码流程如下图所示。为什么要分别编码?就是因为根据不同的数据特征使用不同压缩编码可以提高压缩率。
3.6.1 AC系数编码
由于经过量化过程后有许多AC系数值变为零,对这些系数采用游程编码(RLE)方式进行压缩,游程编码也被称为长度编码或行程编码。游程编码其实很好理解,在日常生活中经常被应用到,例如现在你有一个电话号码,15900008888,你会怎么记?那一定是159四个零四个八。但如果这个电话号码是15984265612,你就无法使用这样方式去记忆了。因此,游程编码就适合这种有连续重复的数据,而AC系数有很长的连续0,因此使用游程编码非常合适。
3.6.2 DC系数编码
DC系数代码每个8×8像素块的亮度。8×8图像块经过DCT变换之后得到的DC系数有两个特点:一个特点是系数的数值比较大,二是相邻8×8图像块的DC系数值变化不大。根据这两个特点,JPEG算法使用了差分脉冲调制编码(DPCM)技术,对相邻图像块之间量化DC系数的差值进行编码,降低图像中的空间冗余信息。举例,例如量化后的DC系数分别为15,17,17,16,16,17,19,每一位至少需要5bits去表示,因此总的就是5×6=30bits。而经过DPCM之后,每一位可能就需要2bit去表示,即使加上符号位,也会远远小于原来的比特数。
3.7 熵编码
对上面得到的系数序列做进一步压缩称作熵编码。在这一阶段,对量化后的DCT系数完成最终的无损压缩以提高总压缩比。什么是熵编码,熵其实就与概率有关,熵编码就是给出现概率较高的符号使用较短的码字,而出现概率较低的符号使用较长的码字。具体的理论知识可以去看相关大学教材,但其实我们在使用时会查表即可。
JPEG建议的熵编码方法有两种:哈夫曼编码和自适应二进制算术编码,前者使用哈夫曼编码,后者使用算术码的条件码表。因为专利问题,一般的JPEG都是使用哈夫曼编码。JPEG在具体实现哈夫曼编码时采用了查表方式,在大量实际图像测试结果的基础上生成了哈夫曼码表,编码时只需要直接查表即可。编码时,DC系数与AC系数分别使用不同的哈夫曼编码表,亮度与色度也需要不同的哈夫曼编码表,所以一共需要4个编码表。
3.7.1 DC系数编码步骤
- 将DC系数转换为二进制数表示,如果系数为负,用反码表示;
- 得到DC系数的二进制码长n;
- 找到码长对应的哈夫曼编码码字,即Category=n所对应的Code word;
- 编码等于DC系数的哈夫曼编码码字+DC系数二进制编码;
举例:下图对于DC系数亮度差值进行编码。
3.7.2 AC系数编码步骤
- 将AC系数转换游程编码结果用三个量(a,b,c)表示;(a表示0的个数(称为游程);b表示系数值;c表示最后非0位置,如果非0系数已处于最后的位置或其后均未0,则置1,不然,则置0.);
- 将系数值b转换为二进制数表示,如果系数为负,用反码表示;
- 得到系数值b的二进制码长n;
- 找到游程为a、二进制码长为n对应的哈夫曼编码码字,即Run/Size=a/n所对应的Code word;
- 编码等于AC系数的哈夫曼编码码字+AC系数二进制编码;
- 在一个块结束后加一个EOB块结束标志(Run/Size=0/0);
举例:下图对于AC系数亮度差值进行编码。
DC系数编码表
AC系数编码表
4.总结
JPEG编码流程
- RGB转YCbCr
- 将图片分割成8×8像素块
- 像素值经过DCT变换变成DCT系数
- DCT系数经过量化变成量化后DCT系数
- DCT系数分为AC系数和DC系数,分别进行编码
- 对AC系数和DC系数编码后再进行哈夫曼编码
最后经过JPEG压缩后的数据解析如图20.从下图可以看到每张JPEG格式的图片都包含2张量化表和4张哈夫曼编码表。
以上内容主要是自己看文献总结得出,其中DCT变换计算过程、熵编码的查表过程网上也基本没有完整的计算过程和哈夫曼编码表的查表过程,都是自己学习记录,所以如果有误请大家多多提出。
参考资料
[1]潘国辉.安防天下2[M].北京:清华大学出版社,2014
[2]JPEG标准,itu-t81
[3]中国大学MOOC《视频压缩原理》刘卫华