最近要研究多媒体了,包括摄像头,jpeg,G2D等。好吧,那就从jpeg开始吧。以前哥也做过一点jpeg相关的工作,不过只记得开头文件头是0xFF,0xD8,末尾是0xFF,0xD9。
这几天晚上看了一下jpeg编码的原理,因个人水平,也只能是大概了解吧,为了理解那DCT变换,哥还专门去翻了一下大学的高数和线性代数课本。记得以前这两门都考90多分的,唉,看来都还给老师了。
那就先介绍一下jpeg的背景和编码原理。
JPEG(Joint Photographic Experts Group)是联合图像专家小组的英文缩写。它由国际电话与电报咨询委员会CCITT(The International Telegraph and Telephone Consultative Committee)与国际标准化组织ISO于1986年联合成立的一个小组,负责制定静态数字图像的编码标准。
小组一直致力于标准化工作,开发研制出连续色调、多级灰度、静止图像的数字图像压缩编码方法,即JPEG算法。JPEG算法被确定为国际通用标准,其适用范围广泛,除用于静态图像编码外,还推广到电视图像序列的帧内图像压缩。而用JPEG算法压缩出来的静态图片文件称为JPEG文件,扩展名通常为*.jpg、*.jpe,*.jpeg。
一.JPEG编码器和解码器的基本系统结构。
JPEG文件使用的数据存储方式有多种。最常用的格式称为JPEG文件交换格式(JPEG File Interchange Format,JFIF)。而JPEG文件大体上可以分成两个部分:标记码(Tag)和压缩数据。标记码由两个字节构成,其前一个字节是固定值0xFF,后一个字节则根据不同意义有不同数值。在每个标记码之前还可以添加数目不限的无意义的0xFF填充,也就说连续的多个0xFF可以被理解为一个0xFF,并表示一个标记码的开始。而在一个完整的两字节的标记码后,就是该标记码对应的压缩数据流,记录了关于文件的诸种信息。
常用的标记有SOI、APP0、DQT、SOF0、DHT、DRI、SOS、EOI。注意,SOI等都是标记的名称。在文件中,标记码是以标记代码形式出现。例如SOI的标记代码为0xFFD8,即在JPEG文件中的如果出现数据0xFFD8,则表示此处为一个SOI标记。
1、JPEG编解码基本过程
编码
2、JPEG解码过程
或者完整一点如下图:
二 ,JPEG编码过程。
2.1 RGB格式转换为YUV格式
RGB介绍:
在记录计算机图像时,最常见的是采用RGB(红、绿,蓝)颜色分量来保存颜色信息,例如非压缩的24位的BMP图像就采用RGB空间来保存图像。一个像素24位,每8位保存一种颜色强度(0-255),例如红色保存为 0xFF0000。
YUV介绍:
YUV是被欧洲电视系统所采用的一种颜色编码方法,我国广播电视也普遍采用这类方法。其中“Y”表示明亮度(Luminance或Luma),也就是灰阶值;而“U”和“V”表示的则是色度(Chrominance或Chroma)。彩色电视采用YUV空间正是为了用亮度信号Y解决彩色电视机与黑白电视机的兼容问题,使黑白电视机也能接收彩色电视信号。
YUV与RGB相互转换的公式如下(RGB取值均为0-255):
Y = 0.299R + 0.587G + 0.114B
U = -0.147R - 0.289G + 0.436B
V = 0.615R - 0.515G - 0.100B
R = Y + 1.14V
G = Y - 0.39U - 0.58V
B = Y + 2.03U
2.2 将图像8*8分块
将原始图像转换为YUV格式后,对图像按一定的采样格式进行采样,常见的格式有4:4:4,4:2:2和4:2:0。
取样完成后,将图像按8*8(pixel)划分成MCU。
2.3 离散余弦变换(DCT)
离散余弦变换DCT(Discrete Cosine Transform)是数码率压缩需要常用的一个变换编码方法。任何连续的实对称函数的付立叶变换中只含余弦项,因此余弦变换与付立叶变换一样有明确的物理意义。DCT是先将整体图像分成N*N像素块,然后对N*N像素块逐一进行DCT变换。由于大多数图像的高频分量较小,相应于图像高频分量的系数经常为零,加上人眼对高频成分的失真不太敏感,所以可用更粗的量化。
因此,传送变换系数的数码率要大大小于传送图像像素所用的数码率。到达接收端后通过反离散余弦变换回到样值,虽然会有一定的失真,但人眼是可以接受的。二维正反离散余弦变换的算式,其中最上面一条是DCT的,第2条是反DCT的,大家不用管也行:
离散余弦变换DCT (Discrete Cosine Transform)是数码率压缩需要常用的一个变换编码方法。任何连续的实对称函数的付立叶变换中只含余弦项,因此余弦变换与付立叶变换一样有明确的物 理意义。DCT是先将整体图像分成N*N像素块,然后对N*N像素块逐一进行DCT变换。由于大多数图像的高频分量较小,相应于图像高频分量的系数经常为 零,加上人眼对高频成分的失真不太敏感,所以可用更粗的量化。因此,传送变换系数的数码率要大大小于传送图像像素所用的数码率。到达接收端后通过反离散余 弦变换回到样值,虽然会有一定的失真,但人眼是可以接受的。
其中N是像块的水平、垂直像素数,一般取N=8。N大于8时效率增加不多而复杂性大为增加。8*8的二维数据块经DCT后变成8*8个变换系数,这些系数都有明确的物理意义。譬如当U=0,V=0时F(0,0)是原64个样值的平均,相当于直流分量,随着U,V值增加,相应系数分别代表逐步增加的水平空间频率和垂直空间频率分量的大小。当我们先只考虑水平方向上一行数据(8个像素)的情况时,如图所示:
可见图像信号被分解成为直流成分;以及从低频到高频的各种余弦成分;而DCT系数只是表示了该种成分所占原图像信号的份额大小;显然,恢复图像信息可以表示为这样一个矩阵形式:F(n)=C(n)*E(n)
式中E(n)是一个基底 ,C(n)是DCT系数,F(n)则是图像信号。
如果再考虑垂直方向上的变化,那么,就需要一个二维的基底,即该基底不仅要反映水平方向频率的变化;而且要反映垂直空间频率的变化;对应于8*8的像素块;其空间基底如图2所示:它是由64个像素值所组成的图像,通常也称之为基本图像。把它们称为基本图像是因为在离散余弦变换的反变换式中,任何像块都可以表示成64个系数的不同大小的组合。既然基本图像相当于变换域中的单一的系数,那么任何像元也可以看成由64个不同幅度的基本图像的组合。这与任何信号可以分解成基波和不同幅度的谐波的组合具有相同的物理意义。
说到这个DCT,哥要说一下傅里叶级数。反正DCT跟傅里叶有相似的地方。大家可以认为差不多就行了。
客观世界中的信号都可以看作是周期运动,描述简谐振动的函数:
y=Asin(wt+∮)
周期是2PI/w
我们可以把比较复杂的周期运动看成是许多不同频率的简谐振动的叠加。如下式:
∞
f(t)=A0+ ∑An*sin(nwt+∮)
n=1
其中常数项A0称为f(t)的直流分量,其它的An*sin(nwt+∮)都叫做n次谐波,可以看出n越大,频率就越大啦。
可以把上面几句的原理应用到DCT了。DCT的原理也差不多。
到这里,我们也不用太去深入DCT是怎么把原来的图像转换成左上角的就是低频的,右下角就是高频的,反正我们懂得由这个公式会得出这样的结果就行了。你要研究的话就去算咯。
记住,DCT转换出来的是系数表,而不是原来的图像数据。
2.5 Z字形编码(zigzag scan)
按Z字形把量化后的数据读出,例:
2.6 使用行程长度编码(RLE)对交流系数(AC)进行编码
所谓游程长度编码是指一个码可以同时表示码的值和前面有几个零。这样就发挥了Z字型读出的优点,因为Z字型读出,出现连零的机会比较多,特别到最后,如果都是零,在读到最后一个数后,只要给出“块结束”(EOB)码,就可以结束输出,因此节省了很多码率。
例:图中按Z字形抽取和游程编码得到码值为
(0,1,0)(1,2,0)(0,5,0)(0,4,0)(4,8,1)EOB
这样一个4*4的矩阵用很少的数值就能表示!
2.7 熵编码
常用的熵编码有变长编码,即哈夫曼编码。
哈夫曼的编码方法:对出现概率大的符号分配短字长的二进制码,对出现概率小的符号分配长字长的二进制码,得到符号平均码长最短的码。
哈夫曼编码的步骤:(1). 把信源符号按概率大小顺序排列, 并设法按逆次序分配码字的长度。 (2). 在分配码字长度时,首先将出现概率最小的两个符号的概率相加合成一个概率 (3). 把这个合成概率看成是一个新组合符号地概率,重复上述做法直到最后只剩下两个符号概率为止。 (4). 完成以上概率顺序排列后,再反过来逐步向前进行编码,每一次有二个分支各赋予一个二进制码,可以对概率大的赋为零,概率小的赋为1。
关于AC/DC系数的编码
1.AC系数的Huffman编码
经过Z扫描和游程编码后的非零AC系数被表述为符号A和符号B。符号A由(Runlength,Size)构成,符号B(Amplitude)。
Runlength为非零AC系数前连续为0的AC系数;
Size则是表示编码Amplitude所需要的比特位数;
Amplitude为AC系数的幅值。
实际操作时,JPEG用一个8位的值RS来表示符号A,RS=RRRRSSSS,对于一个非零的AC系数,高四位用来表示Runlength,低四位用来表示Size。(00000000)用来表示EOB。
对符号B进行变字长整数(VLI)编码,将符号B的VLI码放在A后从而形成对A,B编码的最终结果。
2.DC系数的Huffman编码
对于DC系数,与非零的AC系数类似,它将相邻两块DC系数的差值(DIFF)描述如下的符号对:符号A为(Size),符号B为(Amplitude)。
Size表示为编码Amplitude所需要的位数;
Amplitude表示DC系数的幅值。
在JPEG标准中,对符号A根据相应的Huffman表进行变字长编码,对符号B进行变字长整数编码,而后将符号B 的VLI码放在符号A的Huffman码后,从而完成了对DIFF的编码。
在JPEG标准中没有定义缺省的Huffman表,用户可以根据实际应用自由选择,可以预先定义一个通用的Huffman表,也可以针对一幅特定的图像,在压缩编码前通过搜集其统计特性来计算Huffman表。
三,JPEG解码的主要过程。
3.1 读入文件的相关信息
按照JPEG文件数据存储方式,把要解码的文件的相关信息一一读出,为接下来的解码工作做好准备。参考方法是,设计一系列的结构体对应各个标记,并存储标记内表示的信息。其中图像长宽、多个量化表和哈夫曼表、水平/垂直采样因子等多项信息比较重要。以下给出读取过程中的几个问题。
1. 读取文件的大体结构
JFIF格式的JPEG文件(*.jpg)的一般顺序为:
SOI(0xFFD8),APP0(0xFFE0),[APPn(0xFFEn)]可选,
DQT(0xFFDB),SOF0(0xFFC0),DHT(0xFFC4),SOS(0xFFDA),
压缩数据,EOI(0xFFD9)。
2. 读取哈夫曼表数据;
3. 建立哈夫曼树。
在准备好所有的图片信息后,就可以对图片数据进行解码了。
关于AC,DC系数的解码
1. AC系数的解码
通过查询Huffman数据解出RS,从中的到Runlength和Size的值。因为符号B是通过VLI表来编码的,所以通过查询Size的值可以得到Amplitude。这样就可以解出符号A和符号B的值了。
2. DC系数的解码
同理,先查询Huffman表解出Size的,通过Size解出DIFF,将其与上一个8*8块的DC系数数值相加,最终得到该块的DC系数。
3.2 MCU中颜色分量(Y,U,V)的解码
图像数据流是有MCU组成,而MCU是用数据单元和颜色分量构成。图像数据流是以位(bit)为单位存储信息的。并且内部的数据都是在编码时通过正向离散余弦变换(FDCT)进行时空域向频率域变换而得到的结果,所以对于每个颜色分量单元都应该由两部分组成:1个直流分量和63个交流分量。
颜色分量单元内部综合运用了RLE行程编码和哈夫曼编码来压缩数据。每个像素的数据流由两部分构成:编码和数值,并且两者基本以互相隔开方式出现(除非该编码的权值为零)。解码的过程其实就是哈夫曼树的查找过程。
3.3 直流系数的差分编码
把所有的颜色分量单元按颜色分量(Y、Cr、Cb)分类。每一种颜色分量内,相邻的两个颜色分量单元的直流变量是以差分来编码的。也就是说,通过之前解码出来的直流变量数值只是当前颜色分量单元的实际直流变量减去前一个颜色分量单元的实际直流变量。也就是说,当前直流变量要通过前一个颜色分量单元的实际(非解码)直流分量来校正:
DCn=DCn-1+Diff
其中Diff为差分校正变量,也就是直接解码出来的直流系数。但如果当前颜色分量单元是第一个单元,则解码出来的直流数值就是真正的直流变量。
3个颜色分量的直流变量是分开进行差分编码的。也就是说,为1张图片解码时应设置3个独立的直流校正变量。
3.4 反量化
反量化的过程比较简单。只需要对8*8的颜色分量单元的64个值逐一乘以对应的量化表内位置相同的值则可。图像内全部的颜色分量单元都要进行反量化。
3.5 反Zig-zag编码
3.6 反离散余弦变换
3.7 YCrCb向RGB转换
要在屏幕上显示图像,就必须以RGB模式表示图像的颜色。所以,解码时需要把YCrCb模式向RGB模式转换。
另外,由于离散余弦变化要求定义域的对称,所以在编码时把RGB的数值范围从[0,255]统一减去128偏移成[-128,127]。因此解码时必须为每个分量加上128。具体公式如下:
R= Y +1.402*Cb +128;
G=Y-0.34414*Cr -0.71414*Cb +128;
B= Y +1.772*Cb +128;
还有一个问题,通过变换得出的R、G、B值可能超出了其定义域,所以要作出检查。如果大于255,则截断为255;如果小于0,则截断为0。
至此,每个MCU的解码已经完成。
这里,也引用一下第二个人的博客,加深一下理解:
JPEG是联合图象专家组(Joint Picture Expert Group)的英文缩写,是国际标准化组织(ISO)和CCITT联合制定的静态图象的压缩编码标准。和相同图象质量的其它常用文件格式(如GIF,TIFF,PCX)相比,JPEG是目前静态图象中压缩比最高的。我们给出具体的数据来对比一下。例图采用Windows95目录下的Clouds.bmp,原图大小为640*480,256色。用工具SEA(version1.3)将其分别转成24位色BMP、24位色JPEG、GIF(只能转成256色)压缩格式、24位色TIFF压缩格式、24位色TGA压缩格式。得到的文件大小(以字节为单位)分别为:921,654,17,707,177,152,923,044,768,136。可见JPEG比其它几种压缩比要高得多,而图象质量都差不多(JPEG处理的颜色只有真彩和灰度图)。
正是由于JPEG的高压缩比,使得它广泛地应用于多媒体和网络程序中,例如HTML语法中选用的图象格式之一就是JPEG(另一种是GIF)。这是显然的,因为网络的带宽非常宝贵,选用一种高压缩比的文件格式是十分必要的。
JPEG有几种模式,其中最常用的是基于DCT变换的顺序型模式,又称为基线系统(Baseline),以下将针对这种格式进行讨论。
1. JPEG的压缩原理
JPEG的压缩原理其实上面介绍的那些原理的综合,博采众家之长,这也正是JPEG有高压缩比的原因。其编码器的流程为:
图9.3 JPEG编码器流程
解码器基本上为上述过程的逆过程:
图9.4 解码器流程
8×8的图象经过DCT变换后,其低频分量都集中在左上角,高频分量分布在右下角(DCT变换实际上是空间域的低通滤波器)。由于该低频分量包含了图象的主要信息(如亮度),而高频与之相比,就不那么重要了,所以我们可以忽略高频分量,从而达到压缩的目的。如何将高频分量去掉,这就要用到量化,它是产生信息损失的根源。这里的量化操作,就是将某一个值除以量化表中对应的值。由于量化表左上角的值较小,右上角的值较大,这样就起到了保持低频分量,抑制高频分量的目的。JPEG使用的颜色是YUV格式。我们提到过,Y分量代表了亮度信息,UV分量代表了色差信息。相比而言,Y分量更重要一些。我们可以对Y采用细量化,对UV采用粗量化,可进一步提高压缩比。所以上面所说的量化表通常有两张,一张是针对Y的;一张是针对UV的。
上面讲了,经过DCT变换后,低频分量集中在左上角,其中F(0,0)(即第一行第一列元素)代表了直流(DC)系数,即8×8子块的平均值,要对它单独编码。由于两个相邻的8×8子块的DC系数相差很小,所以对它们采用差分编码DPCM,可以提高压缩比,也就是说对相邻的子块DC系数的差值进行编码。8×8的其它63个元素是交流(AC)系数,采用行程编码。这里出现一个问题:这63个系数应该按照怎么样的顺序排列?为了保证低频分量先出现,高频分量后出现,以增加行程中连续“0”的个数,这63个元素采用了“之”字型(Zig-Zag)的排列方法,如图9.5所示。
图9.5 Zig-Zag
这63个AC系数行程编码的码字用两个字节表示,如图9.6所示。
图9.6 行程编码
上面,我们得到了DC码字和 AC行程码字。为了进一步提高压缩比,需要对其再进行熵编码,这里选用Huffman编码,分成两步:
(1)熵编码的中间格式表示
对于AC系数,有两个符号。符号1为行程和尺寸,即上面的(RunLength,Size)。(0,0)和(15,0)是两个比较特殊的情况。(0,0)表示块结束标志(EOB),(15,0)表示ZRL,当行程长度超过15时,用增加ZRL的个数来解决,所以最多有三个ZRL(3×16+15=63)。符号2为幅度值(Amplitude)。
对于DC系数,也有两个符号。符号1为尺寸(Size);符号2为幅度值(Amplitude)。
(2)熵编码
对于AC系数,符号1和符号2分别进行编码。零行程长度超过15个时,有一个符号(15,0),块结束时只有一个符号(0,0)。
对符号1进行Hufffman编码(亮度,色差的Huffman码表不同)。对符号2进行变长整数VLI编码。举例来说:Size=6时,Amplitude的范围是-63~-32,以及32~63,对绝对值相同,符号相反的码字之间为反码关系。所以AC系数为32的码字为100000,33的码字为100001,-32的码字为011111,-33的码字为011110。符号2的码字紧接于符号1的码字之后。
对于DC系数,Y和UV的Huffman码表也不同。
掉了这么半天的书包,你可能已经晕了,呵呵。举个例子来说明上述过程就容易明白了。
下面为8×8的亮度(Y)图象子块经过量化后的系数。
15 0 -1 0 0 0 0 0
-2 -1 0 0 0 0 0 0
-1 -1 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
可见量化后只有左上角的几个点(低频分量)不为零,这样采用行程编码就很有效。
第一步,熵编码的中间格式表示:先看DC系数。假设前一个8×8子块DC系数的量化值为12,则本块DC系数与它的差为3,根据下表
Size Amplitude
0 0
1 –1,1
2 –3,-2,2,3
3 –7~-4,4~7
4 –15~-8,8~15
5 –31~-16,16~31
6 –63~-32,32~63
7 –127~-64,64~127
8 –255~-128,128~255
9 –511~-256,256~511
10 –1023~512,512~1023
11 –2047~-1024,1024~2047
查表得Size=2,Amplitude=3,所以DC中间格式为(2)(3)。
下面对AC系数编码。经过Zig-Zag扫描后,遇到的第一个非零系数为-2,其中遇到零的个数为1(即RunLength),根据下面这张AC系数表:
Size Amplitude
1 –1,1
2 –3,-2,2,3
3 –7~-4,4~7
4 –15~-8,8~15
5 –31~-16,16~31
6 –63~-32,32~63
7 –127~-64,64~127
8 –255~-128,128~255
9 –511~-256,256~511
10 –1023~512,512~1023
查表得Size=2。所以RunLength=1,Size=2,Amplitude=3,所以AC中间格式为(1,2)(-2)。
其余的点类似,可以求得这个8×8子块熵编码的中间格式为
(DC)(2)(3),(1,2)(-2),(0,1)(-1),(0,1)(-1),(0,1)(-1),(2,1)(-1),(EOB)(0,0)
第二步,熵编码:
对于(2)(3):2查DC亮度Huffman表得到11,3经过VLI编码为011;
对于(1,2)(-2):(1,2)查AC亮度Huffman表得到11011,-2是2的反码,为01;
对于(0,1)(-1):(0,1)查AC亮度Huffman表得到00,-1是1的反码,为0;
……
最后,这一8×8子块亮度信息压缩后的数据流为11011, 1101101, 000, 000, 000, 111000,1010。总共31比特,其压缩比是64×8/31=16.5,大约每个象素用半个比特。
可以想见,压缩比和图象质量是呈反比的,以下是压缩效率与图象质量之间的大致关系,可以根据你的需要,选择合适的压缩比。
表9.1 压缩比与图象质量的关系
压缩效率(单位:bits/pixel) | 图象质量 |
0.25~0.50 | 中~好,可满足某些应用 |
0.50~0.75 | 好~很好,满足多数应用 |
0.75~1.5 | 极好,满足大多数应用 |
1.5~2.0 | 与原始图象几乎一样 |
以上我们介绍了JPEG压缩的原理,其中DC系数使用了预测编码DPCM,AC系数使用了变换编码DCT,二者都使用了熵编码Huffman,可见几乎所有传统的压缩方法在这里都用到了。这几种方法的结合正是产生JPEG高压缩比的原因。顺便说一下,该标准是JPEG小组从很多种不同中方案中比较测试得到的,并非空穴来风。
上面介绍了JPEG压缩的基本原理,下面介绍一下JPEG的文件格式。
2. JPEG的文件格式
JPEG文件大体上可以分成以下两个部分:标记码(Tag)加压缩数据。先介绍标记码部分。
标记码部分给出了JPEG图象的所有信息(有点类似于BMP中的头信息,但要复杂的多),如图象的宽、高、Huffman表、量化表等等。标记码有很多,但绝大多数的JPEG文件只包含几种。标记码的结构为:
SOI
DQT
DRI
SOF0
DHT
SOS
…
EOI
标记码由两个字节组成,高字节为0XFF,每个标记码之前可以填上个数不限的填充字节0XFF。
下面介绍一些常用的标记码的结构及其含义。
(1)SOI(Start of Image)
标记结构 字节数
0XFF 1
0XD8 1
可作为JPEG格式的判据(JFIF还需要APP0的配合)
(2)APP0(Application)
标记结构 字节数 意义
0XFF 1
0XE0 1
Lp 2 APP0标记码长度,不包括前两个字节0XFF,0XE0
Identifier 5 JFIF识别码 0X4A,0X46,0X49,0X46,0X00
Version 2 JFIF版本号 可为0X0101或者0X0102
Units 1 单位,等于零时表示未指定,为1表示英寸,为2表示
厘米
Xdensity 2 水平分辨率
Ydensity 2 垂直分辨率
Xthumbnail 1 水平点数
Ythumbnail 1 垂直点数
RGB0 3 RGB的值
RGB1 3 RGB的值
…
RGBn 3 RGB的值,n=Xthumbnail*Ythumbnail
APP0是JPEG保留给Application所使用的标记码,而JFIF将文件的相关信息定义在此标记中。
(3)DQT(Define Quantization Table)
标记结构 字节数 意义
0XFF 1
0XDB 1
Lq 2 DQT标记码长度,不包括前两个字节0XFF,0XDB
(Pq,Tq) 1 高四位Pq为量化表的数据精确度,Pq=0时,Q0~Qn的
值为8位,Pq=1时,Qt的值为16位,Tq表示量化表的
编号,为0~3。在基本系统中,Pq=0,Tq=0~1,也就是
说最多有两个量化表。
Q0 1或2 量化表的值,Pq=0时;为一个字节,Pq=1时,为两个
字节
Q1 1或2 量化表的值,Pq=0时;为一个字节,Pq=1时,为两个
字节
…
Qn 1或2 量化表的值,Pq=0时,为一个字节;Pq=1时,为两个
字节。n的值为0~63,表示量化表中64个值(之字形排
列)
(4)DRI(Define Restart Interval)
此标记需要用到最小编码单元(MCU,Minimum Coding Unit)的概念。前面提到,Y分量数据重要,UV分量的数据相对不重要,所以可以只取UV的一部分,以增加压缩比。目前支持JPEG格式的软件通常提供两种取样方式YUV411和YUV422,其含义是YUV三个分量的数据取样比例。举例来说,如果Y取四个数据单元,即水平取样因子Hy乘以垂直取样因子Vy的值为4,而U和V各取一个数据单元,即Hu×Vu=1,Hv×Vv=1。那么这种部分取样就称为YUV411。如图9.7所示:
图9.7 YUV411的示意图 |
图9.8 YUV111的排列顺序 |
易知YUV411有50%的压缩比(原来有12个数据单元,现在有6个数据单元),YUV422有33%的压缩比(原来有12个数据单元,现在有8个数据单元)。
那么你可能会想,YUV911,YUV1611压缩比不是更高嘛?但是要考虑到图象质量的因素。所以JPEG标准规定了最小编码单元MCU,要求Hy×Vy+Hu×Vu+Hv×Vv≤10。
MCU中块的排列方式与H,V的值有密切关系,如图9.8、图9.9、图9.10所示。
图9.9 YUV211的排列顺序
图9.10 YUV411的排列顺序
标记结构 字节数 意义
0XFF 1
0XDD 1
Lr 2 DRI标记码长度,不包括前两个字节0XFF,0XDD
Ri 2 重入间隔的MCU个数,Ri必须是一MCU行中MCU
个数的整数,最后一个零头不一定刚好是Ri个MCU。
每个重入间隔各自独立编码。
(5)SOF(Start of Frame) 在基本系统中,只处理SOF0
标记结构 字节数 意义
0XFF 1
0XC0 1
Lf 2 SOF标记码长度,不包括前两个字节0XFF,0XC0
P 1 基本系统中,为0X08
Y 2 图象高度
X 2 图象宽度
Nf 1 Frame中的成分个数,一般为1或3,1代表灰度图,3
代表真彩图
C1 1 成分编号1
(H1,V1) 1 第一个水平和垂直采样因子
Tq1 1 该量化表编号
C2 1 成分编号2
(H2,V2) 1 第二个水平和垂直采样因子
Tq2 1 该量化表编号
…
Cn 1 成分编号n
(Hn,Vn) 1 第n个水平和垂直采样因子
Tqn 1 该量化表编号
(6)DHT(Define Huffman Table)
标记结构 字节数 意义
0XFF 1
0XC4 1
Lh 2 DHT标记码长度,不包括前两个字节0XFF,0XC4
(Tc,Th) 1
L1 1
L2 1
…
L16 1
V1 1
V2 1
…
Vt 1
Tc为高4位,Th为低4位。在基本系统中,Tc为0或1,为0时,指DC所用的Huffman表,为1时,指AC所用的Huffman表。Th表示Huffman表的编号,在基本系统中,其值为0或1。所以,在基本系统中,最多有4个Huffman表,如下所示:
Tc Th Huffman表编号(2×Tc+Th)
0 0
1 1
0 2
1 1 3
Ln表示每个n比特的Huffman码字的个数,n=1~16
Vt表示每个Huffman码字所对应的值,也就是我们前面所讲的符号1,对DC来说该值为(Size),对AC来说该值为(RunLength,Size)。
t=L1+L2+…L16
(7)SOS(Start of Scan)
标记结构 字节数 意义
0XFF 1
0XDA 1
Ls 2 DHT标记码长度,不包括前两个字节0XFF,0XDA
Ns 1
Cs1 1
(Td1,Ta1) 1
Cs2 1
(Td2,Ta2) 1
…
CsNs 1
(TdNs,TaNs) 1
Ss 1
Se 1
(Ah,Al) 1
Ns为Scan中成分的个数,在基本系统中,Ns=Nf(Frame中成分个数)。CSNs为在Scan中成分的编号。TdNs为高4位,TaNs为低4位,分别表示DC和AC编码表的编号。在基本系统中Ss=0,Se=63,Ah=0,Al=0。
(8)EOI(End of Image) 结束标志
标记结构 字节数 意义
0XFF 1
0XD9 1
原文博客:JPEG编解码过程详解JPEG编码原理
http://liucsoft.blog.163.com/blog/static/162294322008429565625/