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 是程序運行時的畫面。


