简介
微处理机中的存放顺序有正序(big endian)和逆序(little endian)之分。正序存放就是高字节存放在前低字节在后,而逆序存放就是低字节在前高字节在后。例如,十六进制数为A02B,正序存放就是A02B, 逆序存放就是2BA0。摩托罗拉(Motorola)公司的微处理器使用正序存放,而英特尔(Intel)公司的微处理器使用逆序。JPEG文件中的字节 是按照正序排列的。
JPEG委员会在制定JPEG标准时,定义了许多标记(marker)用来区分和识别图像数据及其相关信息,但笔者没有找到JPEG委员会对JPEG文件交换格式的明确定义。直到1998年12月从分析网上具体的JPG图像来看,使用比较广泛的还是JPEG文件交换格式(JPEG File Interchange Format,JFIF)版本号为1.02。这是1992年9月由在C-Cube Microsystems公司工作的Eric Hamilton提出的。此外还有TIFF JPEG等格式,但由于这种格式比较复杂,因此大多数应用程序都支持JFIF文件交换格式。
JPEG文件使用的颜色空间是CCIR 601推荐标准进行的彩色空间(参看第7章)。在这个彩色空间中,每个分量、每个像素的电平规定为255级,用8位代码表示。从RGB转换成YCbCr空间时,使用下面的精确的转换关系:
Y = 256 * E'y
Cb = 256 * [E'Cb] + 128
Cr = 256 * [E'Cr] + 128
其中亮度电平E'y和色差电平E'Cb和E'Cb分别是CCIR 601定义的参数。由于E'y的范围是0~1,E'Cb和E'Cb的范围是-0.5~+0.5,因此Y, Cb和Cr的最大值必须要箝到255。于是RGB和YCbCr之间的转换关系需要按照下面的方法计算。
(1) 从RGB转换成YCbCr
YCbCr(256级)分量可直接从用8位表示的RGB分量计算得到:
Y = 0.299 R + 0.587 G + 0.114 B
Cb = - 0.1687R - 0.3313G + 0.5 B + 128
Cr = 0.5 R - 0.4187G - 0.0813 B + 128
需要注意的是不是所有图像文件格式都按照R0,G0,B0,…… Rn,Gn,Bn的次序存储样本数据,因此在RGB文件转换成JFIF文件时需要首先验证RGB的次序。
(2) 从YCbCr转换成RGB
RGB分量可直接从YCbCr(256级)分量计算得到:
R = Y + 1.402 (Cr-128)
G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128)
B = Y + 1.772 (Cb-128)
在JFIF文件格式中,图像样本的存放顺序是从左到右和从上到下。这就是说JFIF文件中的第一个图像样本是图像左上角的样本。
JPEG文件的存储方式
JPEG文件的格式是分为一个一个的段来存储的(但并不是全部都是段),段的多少和长度并不是一定的。只要包含了足够的信息,该JPEG文件就能够被打开,呈现给人们。JPEG文件的每个段都一定包含两部分一个是段的标识,它由两个字节构成:第一个字节是十六进制0xFF,第二个字节对于不同的段,这个值是不同的。紧接着的两个字节存放的是这个段的长度(除了前面的两个字节0xFF和0xXX,X表示不确定。他们是不算到段的长度中的)。注意:这个长度的表示方法是按照高位在前,低位在后的,与Intel的表示方法不同。比方说一个段的长度是0x12AB,那么它会按照0x12,0xAB的顺序存储。但是如果按照Intel的方式:高位在后,低位在前的方式会存储成0xAB,0x12,而这样的存储方法对于JPEG是不对的。这样的话如果一个程序不认识JPEG文件某个段,它就可以读取后两个字节,得到这个段的长度,并跳过忽略它。
本人曾经编写过一个读取JPEG文件信息的程序,该程序能够读取JPEG文件中包含的段的信息并显示出来。下面是一个JPEG图片的信息片断:
SOI
APP0 Length: 0x10
DQT
DQT [0]:
8 6 5 8 12 20 26 31
6 6 7 10 13 29 30 28
7 7 8 12 20 29 35 60
7 9 11 15 26 44 50 31
9 11 19 28 34 56 52 0
12 18 28 32 61 52 0 46
25 32 39 57 52 0 60 0
36 46 39 49 253 50 0 50
Length: 0x43
DQT
DQT [1]:
9 9 12 24 50 50 50 50
9 11 13 33 50 50 50 50
12 13 28 50 50 50 50 50
24 33 50 50 50 50 50 50
50 50 50 50 50 50 50 0
50 50 50 50 50 50 0 50
50 50 50 50 50 0 50 0
50 50 50 50 253 50 0 50
Length: 0x43
SOF0
Image Height: 173
Image Width: 401
Number of Frame(s): 3
****************
Content ID: 1
H Factor: 2
V Factor: 2
QT ID: 0
****************
Content ID: 2
H Factor: 1
V Factor: 1
QT ID: 1
****************
Content ID: 3
H Factor: 1
V Factor: 1
QT ID: 1
Length: 0x11
DHT
Type: DC TABLE
ID: 0
Length: 0x1f
DHT
Type: AC TABLE
ID: 0
Length: 0xb5
DHT
Type: DC TABLE
ID: 1
Length: 0x1f
DHT
Type: AC TABLE
ID: 1
Length: 0xb5
SOS Length: 0xc <-Will Not Process This Seg.
FATAL ERROR: File Structure Does NOT Support.
你首先会想到为什么最后会出现一个错误的信息呢?这是因为,在SOS(Start Of Scan)段的后面,就是编码后的一行一行的图像信息。不再是段的结构了。在开始的SOI(Start Of Image)不是一个段,它是文件的开始,它的值也是类似于0xFF,0xXX的结构,但是后面没有段的长度。在文件的最后,有一个EOI(End Of Image)的标识,它的结构和SOI是类似的。它标志着文件的结束。
在这中间,包含了APP0段,DQT段,SOF0段,DHT段,SOS段。有的段的个数是不唯一的,比方说DQT段。
文件格式
JFIF文件格式直接使用JPEG标准为应用程序定义的许多标记,因此 JFIF格式成了事实上JPEG文件交换格式标准。JPEG的每个标记都是由2个字节组成,其前一个字节是固定值0xFF。每个标记之前还可以添加数目不限的0xFF填充字节(fill byte)。下面是其中的8个标记:
-
- SOI 0xD8 图像开始
- APP0 0xE0 JFIF应用数据块
- APPn 0xE1 - 0xEF 其他的应用数据块(n, 1~15)
- DQT 0xDB 量化表
- SOF0 0xC0 帧开始
- DHT 0xC4 霍夫曼(Huffman)表
- SOS 0xDA 扫描线开始
- EOI 0xD9 图像结束
为使读者对JPEG定义的标记一目了然,现将JPEG的标记码列于表1,并保留英文解释。
表1 JPEG定义的标记
Symbol (符号) | Code Assignment (标记代码) | Description (说明) |
Start Of Frame markers, non-hierarchical Huffman coding | ||
SOF0 | 0xFFC0 | Baseline DCT |
SOF1 | 0xFFC1 | Extended sequential DCT |
SOF2 | 0xFFC2 | Progressive DCT |
SOF3 | 0xFFC3 | Spatial (sequential) lossless |
Start Of Frame markers, hierarchical Huffman coding | ||
SOF5 | 0xFFC5 | Differential sequential DCT |
SOF6 | 0xFFC6 | Differential progressive DCT |
SOF7 | 0xFFC7 | Differential spatial lossless |
Start Of Frame markers, non-hierarchical arithmetic coding | ||
JPG | 0xFFC8 | Reserved for JPEG extensions |
SOF9 | 0xFFC9 | Extended sequential DCT |
SOF10 | 0xFFCA | Progressive DCT |
SOF11 | 0xFFCB | Spatial (sequential) Lossless |
Start Of Frame markers, hierarchical arithmetic coding | ||
SOF13 | 0xFFCD | Differential sequential DCT |
SOF14 | 0xFFCE | Differential progressive DCT |
SOF15 | 0xFFCF | Differential spatial Lossless |
Huffman table specification | ||
DHT | 0xFFC4 | Define Huffman table(s) |
arithmetic coding conditioning specification | ||
DAC | 0xFFCC | Define arithmetic conditioning table |
Restart interval termination | ||
RSTm | 0xFFD0~0xFFD7 | Restart with modulo 8 counter m |
Other marker | ||
SOI | 0xFFD8 | Start of image |
EOI | 0xFFD9 | End of image |
SOS | 0xFFDA | Start of scan |
DQT | 0xFFDB | Define quantization table(s) |
DNL | 0xFFDC | Define number of lines |
DRI | 0xFFDD | Define restart interval |
DHP | 0xFFDE | Define hierarchical progression |
EXP | 0xFFDF | Expand reference image(s) |
APPn | 0xFFE0~0xFFEF | Reserved for application use |
JPGn | 0xFFF0~0xFFFD | Reserved for JPEG extension |
COM | 0xFFFE | Comment |
Reserved markers | ||
TEM | 0xFF01 | For temporary use in arithmetic coding |
RES | 0xFF02~0xFFBF | Reserved |
JPEG文件由下面的8个部分组成:
(1) 图像开始SOI(Start of Image)标记
(2) APP0标记(Marker)
① APP0长度(length)
② 标识符(identifier)
③ 版本号(version)
④ X和Y的密度单位(units=0:无单位;units=1:点数/英寸;units=2:点数/厘米)
⑤ X方向像素密度(X density)
⑥ Y方向像素密度(Y density)
⑦ 缩略图水平像素数目(thumbnail horizontal pixels)
⑧ 缩略图垂直像素数目(thumbnail vertical pixels)
⑨ 缩略图RGB位图(thumbnail RGB bitmap)
(3) APPn标记(Markers),其中n=1~15(任选)
① APPn长度(length)
② 由于详细信息(application specific information)
(4) 一个或者多个量化表DQT(difine quantization table)
① 量化表长度(quantization table length)
② 量化表数目(quantization table number)
③ 量化表(quantization table)
(5) 帧图像开始SOF0(Start of Frame)
① 帧开始长度(start of frame length)
② 精度(precision),每个颜色分量每个像素的位数(bits per pixel per color component)
③ 图像高度(image height)
④ 图像宽度(image width)
⑤ 颜色分量数(number of color components)
⑥ 对每个颜色分量(for each component)
1.ID
2.垂直方向的样本因子(vertical sample factor)
3.水平方向的样本因子(horizontal sample factor)
4.量化表号(quantization table#)
(6) 一个或者多个霍夫曼表DHT(Difine Huffman Table)
① 霍夫曼表的长度(Huffman table length)
② 类型、AC或者DC(Type, AC or DC)
③ 索引(Index)
④ 位表(bits table)
⑤ 值表(value table)
(7) 扫描开始SOS(Start of Scan)
① 扫描开始长度(start of scan length)
② 颜色分量数(number of color components)
③ 每个颜色分量
1.ID
2.交流系数表号(AC table #)
3.直流系数表号(DC table #)
④ 压缩图像数据(compressed image data)
(8) 图像结束EOI(End of Image)
表6-06表示了APP0域的详细结构。有兴趣的读者可通过UltraEdit或者PC TOOLS等工具软件打开一个JPG图像文件,对APP0的结构进行分析和验证。
表6-06 JFIF格式中APP0域的详细结构
偏移 | 长度 | 内容 | 块的名称 | 说明 |
0 | 2 byte | 0xFFD8 | (Start of Image,SOI) | 图像开始 |
2 | 2 byte | 0xFFE0 | APP0(JFIF application segment) | JFIF应用数据块 |
4 | 2 bytes | length of APP0 block | APP0块的长度 | |
6 | 5 bytes | "JFIF"+"0" | 识别APP0标记 | |
11 | 1 byte | <Major version> | 主要版本号(如版本1.02中的1) | |
12 | 1 byte | <Minor version> | 次要版本号(如版本1.02中的02) | |
13 | 1 byte | <Units for the X | X和Y的密度单位 units=0:无单位 units=1:点数/英寸 units=2:点数/厘米 | |
14 | 2 bytes | <Xdensity> | 水平方向像素密度 | |
16 | 2 bytes | <Ydensity> | 垂直方向像素密度 | |
18 | 1 byte | <Xthumbnail> | 缩略图水平像素数目 | |
19 | 1 byte | <Ythumbnail> | 缩略图垂直像素数目 | |
3n | < Thumbnail RGB bitmap> | 缩略RGB位图(n为缩略图的像素数) | ||
Optional JFIF extension APP0 marker segment(s) | 任选的JFIF扩展APP0标记段 | |||
…… | …… | |||
2 byte | 0xFFD9 | (EOI) end-of-file | 图像文件结束标记 |
JPEG文件的段的介绍
1)APP0段
APP0段中主要存储的是图片的识别信息(字符串”JFIF/0”)、一些分辨率的信息以及缩略图的信息。在我的实际测试中,发现并不是所有的JPEG文件都有APP0段的,有的仅是有APP2之类的其他段,但是每个文件中肯定是包含APPX的段(X可以取得的值可以查阅相关文档)。我个人估计,这些APPX的段的信息应该是大同小异。这个的验证还有待本人进一步的学习,目前只能说到这里。
2)DQT段
DQT段的内容是量化表的信息。众所周知,一个颜色可以分为RGB(红、绿、兰)三个分量,这三色光组成了我们可以见到的所有色彩。但是,在JPEG文件中,RGB色彩格式需要先转化为YUV的格式。Y分量代表了亮度信息,UV分量代表了色差信息。相比之下,人眼对于Y分量更为敏感。量化表的作用就是对于一些不需要的量进行去除,这也是JPEG有损压缩损失数据的关键。上面的输出可以看到两个量化表,一个给Y分量,另一个给UV分量。其实,他们也可以共用一个量化表。一个量化的结果如下所示(摘自《JPEG压缩编码标准》):
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
我们可以看到,量化后出现了大量的0,这种结果很有利于我们进行下一步的数据压缩的。至于为什么是8x8的大小,待会你就知道了。
3) SOF0段
SOF0段的内容是图像的大小信息,每个像素的位数信息,以及YUV每个分量分别得的采样信息(这部分如果读者想要进一步学习,请参考相应书籍和文档)。JPEG文件图像的编码是一个方块一个方块进行的,每块的大小为8x8大小(如果图像不是整数个方块的大小那么就对图像补齐为整数个大小)。简略地说采样信息,就是如何按组记录YUV的信息,即若干个Y方块,若干个U方块,若干个V方块经过量化的数据再次经过编码后组成一组记录,保存在SOS段结束后。
4) DHT段
DHT段的内容是一个重头戏,如果没有它,JPEG压缩效率就不会那么高了。它内部定义的是一个Huffman表,不同的DHT段定义不同的Huffman表,有的是直流量的表,有的是交流量的表。什么是直流量,什么是交流量呢?待会我再作介绍。最多的Huffman表示几个呢?YUV各一个,直流交流各一个,因为YUV每个分量都有直流和交流,所以最多时,Huffman表有3x2个,也就是可以有6个DHT段。该文件中有4个DHT表,您可以大概猜出来是哪几个表么?Y的直流和交流各一个Huffman表,UV和起来直流和交流各一个Huffman表。这样说应该比较合理吧。
好了,现在我们应该弄明白什么是交流量,什么是直流量了。还举上面那个有许多个0的8x8的表的例子说,所谓交流量,是经过量化后的块内部除了左上角15那个值的其余值。实际上,块与块之间左上角那个值是用直流Huffman表来单独编码的。不与块内部一同编码。虽然不同的编码,但是要注意的事,不同的编码方式并不意味着它们是不在一起的,具体的存储编码后的数据的时候,还是按照若干个Y方块,若干个U方块,若干个V方块经过量化的数据再次经过编码后组成一组记录来存储的。
5)SOS段
SOS段的内容是关于YUV每个分量的直流和交流各使用那个Huffman表来编码的。
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>