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
3.
JPEG
基本系统解码器的实现
笔者曾经实现了一个
Windows
下
JPEG
基本系统的解码器,限于篇幅,这里就不给源程序了,只给出大体上的程序流程图
(
见图
9.11)
。
图9.11 JPEG
解码器的程序流程图
|
图9.12
程序运行时的画面
|
由于没有用到什么优化算法,该解码器的速度并不高,在用
VC
的性能评测工具
Profile
评测该程序时我发现最耗时的地方是反离散余弦变换
(IDCT)
那里,其实这是显然的,浮点数的指令条数要比整数的多得多,因此采用一种快速的
IDCT
算法能很大的提高性能,我这里采用是目前被认为比较好的一种快速
IDCT
算法,其主要思想是把二维
IDCT
分解成行和列两个一维
IDCT
。图
9.12
是程序运行时的画面。