1、JPEG标准的工作原理和实现技术,朱志婷 2010.4.16,1.位图文件格式简介,位图(BMP)文件是Windows系统下最常用的独立于设备的位图文件。BMP格式是基于RGB颜色模式,且一般不压缩原始图像。BMP位图文件默认的文件扩展名是BMP或bmp。读取BMP文件中每个像素点的R、G、B值是非常重要的,它是之后整个图像压缩编码的基础。首先需要清楚地知道BMP文件的详细结构。,BMP文件大体上分成四个部分,如下图所示:,1.1位图文件头,BITMAPFILEHEADER是一个结构,定义如下: typedef struct tagBITMAPFILEHEADER WORD bfType;DW
2、ORD bfSize;WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; BITMAPFILEHEADER;该结构的长度固定,为14个字节(WORD为无符号16位整数,DWORD为无符号32位整数),各个域的说明如下: bfType:指定文件类型,必须是0x424D,即字符串“BM”,所有.bmp文件的头两个字节都是“BM”。 bfSize:文件大小,包括位图文件头的14个字节。 bfReserved1,bfReserved2:为保留字,不用考虑。 bfOffBits:从文件头到实际的位图数据的偏移字节数,即表2中前三个部分的长度之和。,1
3、.2位图信息头,BITMAPINFOHEADER也是一个结构,定义如下: typedef struct tagBITMAPINFOHEADER DWORD biSize; LONG biWidth; LONG biHeight;WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; BITMAPINFOHEADER;,该结构长度固定为40个字节
4、(LONG为32位整数),各个域的说明如下: biSize:指定这个结构的长度,为40。 biWidth:指定图像的宽度,单位是像素。 biHeight:指定图像的高度,单位是像素。 biPlanes:必须是1,不用考虑。 biBitCount:指定表示颜色时要用到的位数。常用的位数值有:1(黑白两色图),4(16色图),8(256色图),24(真彩色图)。 biCompression:指定位图是否压缩。一般为BI_RGB,表示不压缩。 biSizeImage:指定实际的位图数据占用的字节数。 biXPelsPerMeter:指定目标设备的水平分辨率,单位是每米的像素个数。 biYPelsPe
5、rMeter:指定目标设备的垂直分辨率,单位是每米的像素个数。 biClrUsed:指定本图像实际用到的颜色数,如果该值为零,则用到的颜色数为2的biBitCount次方。 biClrImportant:重要的颜色数,如果该值为零,则认为所有的颜色都重要。,1.3调色板,调色板是对那些需要调色板的位图文件而言的。有些位图,如真彩色图,是不需要调色板的,BITMAPINFOHEADER之后直接是位图数据。调色板实际上是一个数组,共有biClrUsed个元素,若biClrUsed为零,则有2 的biBitCount次方个元素。数组中每个元素的类型是一个RGBQUAD结构,占4个字节,其定义如下:
6、typedef struct tagRGBQUADBYTE rgbBlue; /该颜色的蓝色分量BYTE rgbGreen; /该颜色的绿色分量BYTE rgbRed; /该颜色的红色分量BYTE rgbReserved; /保留值 RGBQUAD;,1.4 实际的图像数据,对于用到调色板的位图,图像数据是该像素颜色在调色板中的索引值,对于真彩色图,图像数据是实际的B,G,R值。256色图,一个字节恰好可以表示1个像素。真彩色图:三个字节表示一个像素。,1.5 BMP文件读取和显示的过程可以概括为以下几步:,在BMP文件的相应位置读出文件的有关信息,如文件类型(bfType)、图像的宽度(bi
7、Width)、图像的高度(biHeight)、表示颜色时要用到的位数(biBitCount)。Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充。所以要根据biWidth和biBitCount计算补齐的字节数。计算补齐的字节数externWidth的代码为:externWidth = biWidth * (biBitCount / 8) % 4;if (externWidth != 0) externWidth = 4 - externWidth;,若是8位图,需要先读取调色板的数据,再根据像素点颜色在调色板中的索引值获得每个像素点的R、G、B值;若是
8、24位图,直接读取每个像素点的值即可。根据每个像素点的值显示图片。需要注意一点,BMP文件的数据是从下到上、从左到右的。从文件中最先读到的是图像最下面一行的左边第一个像素,然后是左边第二个像素接下来是倒数第二行左边第一个像素,然后是左边第二个像素依次类推,最后得到的是最上面一行的最右边的一个像素。,2. 静态图像压缩标准JPEG,2.1 JPEG简介 JPEG(Joint Photographic Experts Group)是联合图像专家小组的英文缩写,这个专家组开发的算法称为JPEG算法,并且成为国际上的彩色、灰度、静止图像的第一个国际标准,因此又称为JPEG标准。 JPEG是一个适用范围
9、很广的静态图像数据压缩标准,不仅适用于静止图像的压缩,也常常被用于电视图像序列的帧内图像压缩编码。目前JPEG专家组开发了两种基本的压缩算法: 一种是采用以离散余弦变换DCT为基础的有损压缩算法;另一种是采用以预测技术为基础的无损压缩算法。 使用有损压缩算法时,在压缩比为25:1的情况下,压缩后还原得到的图像和原始图像相比较,非图像专家难以找到它们之间的区别,因此得到了广泛的应用。例如在V-CD和DVD-Video电视图像压缩技术中,就使用JPEG的有损压缩算法来取消空间方向上的冗余数据。,基于DCT的JPEG压缩算法是有损压缩,它利用了人的视角系统的特性,使用量化和无损压缩编码相结合来去掉视
10、角的冗余信息和数据本身的冗余信息。JPEG算法框图如图1所示,压缩编码大致分成三个步骤: (1)使用正向离散余弦变换(Forward Discrete Cosine Transform,FDCT)把空间域表示的图变换成频率域表示的图。 (2)使用加权函数对DCT系数进行量化,这个加权函数对于人的视觉系统是最佳的。 (3)使用哈夫曼可变字长编码器对量化系数进行编码。,译码或者叫做解压缩的过程与压缩编码过程正好相反。,2.2 JPEG压缩的基本原理,基于DCT编码的JPEG压缩算法可由如下的几个步骤实现:颜色模式转换及采样;正向离散余弦变换(FDCT);量化(Quantization);编码:(1
11、)Z字形编码(Zigzag Scan);(2)使用差分脉冲编码调制(DPCM)对直流系数(DC)进行编码;(3)使用行程长度编码(RLE)对交流系数(AC)进行编码;(4)熵编码;,2.2.1颜色模式转换及采样,JPEG 的图片使用的是 YCrCb 颜色模型, 而不是计算机上最常用的 RGB. YCrCb 模型更适合图形压缩. 因为人眼对图片上的亮度 Y 的变化远比色度 C 的变化敏感. 从RGB转换成YCrCb:Y0.299R+0.587G+0.114BCr(0.500R-0.4187G-0.0813B)+128 Cb(-0.1687R-0.3313G+0.500B)+128 常用的采样格式
12、有4:1:1和1:1:1 1:1:1采样就是保留所有的YCrCb值,相当于每个像素点用1个Y样本、1个Cr样本、1个Cb样本表示。而4:1:1采样是指对于一个22像素的数据块,取4个亮度Y样本、1个红色差Cr样本、1个蓝色差Cb样本 。,2.2.2正向离散余弦变换(FDCT),(1)DCT要求输入数据是一个88的矩阵,且每个矩阵元素具有8bit精度,分为从128到127,故DCT变换前,每个像素值的分量先要减去128。(2)把一幅图像划分成一系列的图像块,每个图像块包含88个像素。若图像的高或宽不是8的整数倍,必须扩展其下边或右边到8的整数倍。如果原始图像有640480个像素,则图片将包含80
13、列60行的方块。如果图像是彩色的,那么每个像素可以用24比特、相当于三个8位比特的组合来表示。因此,可以用三个8行8列的二维数组表示这个88的像素方块。每一个数组表示其中一个八位比特组合的像素值。离散余弦变换作用于每个数组。,DCT变换是做什么的 ?,简单的说,是用一个8行8列的二维数组产生另一个同样包含8行8列二维数组的函数,也就是说,把一个数组通过一个变换,变成另一个数组。 如图下图所示,对每个图像块做离散余弦变换。通过DCT变换可以把能量集中在矩阵左上角少数几个系数上。,f(i,j)经DCT变换之后得到F(i,j),其中F(0,0)是直流系数,称为DC系数,其他为交流系数,称为AC系数。
14、,图2 离散余弦变换,(3)用f表示像素值的数组,f(i ,j)表示i行j列的值,则离散余弦变换后定义一个新的数组F (u ,v),表示u行v列的值。,DCT变换使用公式(1)计算:,(1),它的逆变换使用公式(2)计算:,(2),上面两式中,C(u), C(v) = ,当u, v =0; C(u), C(v) = 1,其他。,图3显示了对源图像的88的图像样本的原始数组应用离散余弦变换的结果。在对源数组f进行变换之前首先对源图像中的每个样本数据减去128。然后再按公式(1)分别计算出结果数组F中每个数组元素的值。比如说,计算F(0,0)的值过程如下:,235.6,(因为cos(0)=1),这
15、样再继续计算出数组中其余元素的值,得到数组F。,图3 离散余弦变换的数组,f(i,j)经DCT变换之后得到F(i,j),其中F(0,0)是直流系数,称为DC系数,其他为交流系数,称为AC系数。,(4)在计算二维的DCT变换时,也可使用下面的计算式(3)、(4)进行简化,把二维的DCT变换变成一维的DCT变换,如图4所示为二维DCT变换方法。,(3),(4),图4 两维DCT变换方法,2.2.3量化 为了达到压缩数据的目的,DCT系数需做量化。量化是对经过FDCT变换后的频率系数进行量化,这是一个多到一映射的过程。量化的目的是减小非0系数的幅度以及增加0值系数的数目,在一定的主观保真的前提下,丢
16、掉那些对视觉效果影响不大的信息,量化是图像质量下降的最主要原因。,对于有损压缩算法,JPEG算法使用如图5所示的均匀量化器进行量化,量化步距是量化表的元素,它由系数所在的位置和每种颜色分量的色调值来确定。因为人眼对亮度信号比对色差信号更敏感,因此使用了两种量化表:如表1所示的色度量化值(针对Cr,Cb)和表2所示的亮度量化值(针对Y)。 此外,由于人眼对低频分量的图像比对高频分量的图像更敏感,因此图中左上角的量化步距要比右下角的量化步距小。表1和表2中的数值对CCIR 601标准(国际无线电咨询委员会CCIRInternational Radio Consultative Committee在
17、20世纪80年代初制定的彩色电视图像数字化标准)电视图像已经是最佳的。如果不使用这两种表,你也可以用自己的量化表替换它们。,注意:JPEG文件中量化表中的64个值是按z字形顺序排列的,表1 色度量化值,表2 亮度量化值,图5 均匀量化器,对于上面的例子,我们用表2的量化表对其进行量化,得到数组Q(i,j)。量化的公式为:Q(i,j)=Integer(F(i,j)/U(i,j) 其中:U(i,j)为量化数组中对应的数组元素。也就是用数组F中的各元素分别除以量化数组Q中的相应元素,如图6所示。,图6 用量化表量化的数组,以上是编码时对图像块的正向离散余弦变换和量化过程,解码的时候要进行逆量化和逆向
18、离散余弦变换,图6说明了解码的过程,并且在逆向离散余弦变换之后对重构图像中的每个样本数据加了128,最后得到重构图像样本:,图6 JPEG压缩编码举例,2.2.4编码阶段,(1)Z字形编排。对于量化后的二维数组,我们还要对其进行线性化,然后再进行压缩加以传输。为保证低频分量先出现,高频分量后出现,以增加行程中连续“0”的个数,63个AC系数采用z字形排列。,(2)直流系数的编码。88图像块经过DCT变换之后得到的DC直流系数有两个特点,一是系数的数值比较大,二是相邻88图像块的DC系数值变化不大。根据这个特点,JPEG算法使用了差分脉冲调制编码(DPCM)技术,对相邻图像块之间量化DC系数的差
19、值进行编码 。 Delta = Dc(0,0)k-Dc(0,0)k1 (5),图7 量化DCT系数编排,(3)熵编码,为了进一步达到压缩数据的目的,需对量化后的DC系数,和行程编码后的AC系数进行基于统计特性的熵编码。JPEG建议两种熵编码方法:哈夫曼(Huffman)编码和自适应二进制算术编码。熵编码可分成两步进行,首先把DC和AC系数转换成一个中间格式的符号序列,第二步是给这些符号赋以变长码字。a 熵编码的中间符号表示 DC系数:符号1 符号2(尺寸)(幅值)“尺寸”表示DC差值的幅值编码所需的比特数,由于计算机中将负数存为反码或补码的形式,当幅值DIFF为负数时,DIFF的有效位数为(-
20、DIFF)的有效位数。 AC系数:符号1 符号2(行程,尺寸)(幅值)“行程”表示“Z”形扫描时所遇到前后两个非零AC系数之间连续0 的个数;“尺寸”是后一个非零AC系数的幅值表示所需要的比特数。,“行程”用一个字节的高4 位表示。当两个非零AC系数之间连续零的个数超过15时,用增加扩展符号“(15,0)”的个数来扩充, “(15,0)” 表示16个零。当一串连续为零的系数包含最后的AC系数 。这时以标记(0,0)表示后面的系数全为零,此块(Block)的数据结束,(0,0)一般称为EOB(End of block)。b 可变长度熵编码熵编码的下一步工作就是将中间符号编码,对DC系数和AC系数
21、中的符号1采用huffman表中的可变长度码(Variable-length Code,VLC)进行编码。符号2用变长整数(Variable-Length Integer,VLI)表示。,亮度DC系数表,亮度AC系数表(部分),2.2.5组成位数据流,JPEG编码的最后一个步骤是把各种标记代码和编码后的图像数据组成一帧一帧的数据,这样做的目的是为了便于传输、存储和译码器进行译码,这样组织的数据通常称为JPEG位数据流 。,继续前面的例子说明编码过程:,假设前一Block的DC系数为12,将系数转为中间符号的序列为: (2)(3)(1,2)(-2)(0,1)(-1)(0,1)(-1)(0,1)(
22、-1)(2,1)(-1)(0,0) 进行熵编码: 对于(2)(3):2查DC亮度Huffman表得到011,3经过VLI编码为11; 对于(1,2)(-2):(1,2)查AC亮度Huffman表得到11011,-2是2的反码,为01; 对于(0,1)(-1):(0,1)查AC亮度Huffman表得到00,-1是1 的反码,为0; 依次类推,可以得到这个8*8的子块经压缩后最后的数据流为01111,1101101,000,000,000,111000,1010 (31位),Z字形扫描后得1*64的数组: 15,0,-2,-1,-1,-1,0,0,-1,55个0,量化后得到Q数组:,2.2.6生成
23、JPEG文件,JPEG编码的最后一个步骤是把各种标记代码和编码后的图像数据写入文件。标记码由两个字节构成,其前一个字节是固定值0xFF,每个标记之前还可添加数目不限的0xFF填充字节。标记码部分给出了JPEG图像的所有信息,如图像的宽、高、哈夫曼表、量化表等,标记码有很多,但绝大多数的JPEG文件只包含以下几种。 SOI 0xD8 图像开始,可作为JPEG格式的判据 APP0 0xE0 JFIF应用数据块 APPn 0xE1 0xEF 其它的应用数据块(n,115) DQT 0xDB 量化表 SOF0 0xC0 帧开始 DHT 0xC4 哈夫曼表 SOS 0xDA 扫描线开始 EOI 0xD9
24、 图像结束,2.2.7哈夫曼编码在图像压缩中的实现,哈夫曼表一般是事先确定的,(也可以在线实时调整)。下面以JPEG中的一个哈夫曼表(表3)为例,来说明如何实现哈夫曼编码,解码。 表3 JPEG标准中推荐的亮度信息哈夫曼表 码值 码字的长度 码字 0 2 00 1 3 010 2 3 011 3 3 100 4 3 101 5 3 110 6 4 1110 7 5 11110 8 6 111110 9 7 1111110 10 8 11111110 11 9 111111110,在JPEG文件格式中,哈夫曼表以哈夫曼码字中位数相同的个数和所有的哈夫曼码值的形式存储,实际上是存储了一个哈夫曼树。
25、下面以亮度DC系数表(表3)为例说明哈夫曼表构造的整个过程。 由表3可以得到两个数组:,bits17 = 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 ;huffval = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ;这两个数组和表3是对应的。bits数组中的元素除bits0外,bits1,bits2,bits3,bits16代表哈夫曼代码中长度为1,2,316的个数。huffval中的各个元素是按照哈夫曼代码长度递增的顺序相对应的哈夫曼值(Huffman value),也即被代表的信息,如果几个元素对应的哈
26、夫曼代码长度相同,顺序可以交换。从这两个数组出发,看看是如何实现编码的。,为了生成哈夫曼表,要建立huffsize,huffcode 两个整数型数组,此处它们的元素个数只要大于12即可。,第一步:得到huffsizehuffsize是用于记录12个哈夫曼码字的有效位的位数(单位是Bit),即生成表3的第二列(码字的长度),这主要是因为编码后输出码字时一定要知道码字的长度。 第二步得到huffcode它的各个元素是与huffsize各元素相对应的哈夫曼码字,即表的第三列(码字)。生成huffcode的过程;第一个码字必定为0。如果第一个码字位数为1, 则码字为0;如果第一个码字位数为2, 则码字
27、为00;如此类推。相邻的相同长度的哈夫曼码字彼此间差1。长度为si+1的代码中数值最小的代码,是长度为si的代码中数值最大的代码加1后并左移一位,这就能保证没有任何一个代码是另外一个代码的前缀,也就是说11,110这样的两个代码是不允许的。否则,解码时就会出现问题。 huffval, huffsize,huffcode 就构成了哈夫曼表 哈夫曼编码的过程就是一个查表过程。,参考资料:,钟玉琢,王琪,贺玉文.基于对象的多媒体数据压缩编码国际标准MPEG-4及其校验模型.北京:科学出版社,2000张益贞,刘滔.Visual C+实现MPEG/JPEG编解码技术.北京:人民邮电出版社,2002吴嘉慧.JPEG图像解码方案.现代计算机.2007,总第二五五期:49-53,