JPEG解碼算法流程詳解

轉至:http://blog.csdn.net/carson2005/article/details/7875416

(1)讀入JPEG/JFIF文件的相關信息

按照JFIF文件格式,將JPEG文件相關的字段信息一一讀取出來,並進行相應的解析。例如,圖像的寬度、高度、量化表、Huffman表、水平/垂直採樣因子等。一般而言,JFIF格式文件的讀取順序依次爲:

SOI字段;

APP0字段;

APPn字段;

DQT字段;

SOFO字段;

DHT字段;

SOS字段;

壓縮數據字段;

EOI字段;

讀取JPEG文件相關信息的時候,有兩點需要特別注意:

(a)由於JPEG中以0XFF來做爲特殊標記符,因此,如果某個像素的取值爲0XFF,那麼實際在保存的時候,是以0XFF00來保存的,從而避免其跟特殊標記符0XFF之間產生混淆。所以,在讀取文件信息的時候,如果遇0XFF00,就必須去除後面的00;即,將0XFF00當做0XFF

(b)JPEG文件中,一個字(16位)的存儲是採用了Motorola格式(big-endian),而不是我們常用的Intel格式(little-endian)。因此,如果需要的話,請在處理之間進行依次高低字節的轉換。

(2) 讀取Huffman

在標記碼DHT之後,包含了一個或者多個Huffman表(通常是4個表)。對於一個Huffman表而言,它包含了以下三部分內容:

(a)ID和表類型;1個字節;僅有4個可選的取值,0X00,0X01,0X10,0X11,分別表示DC直流0號表,DC直流1號表,AC交流0號表,AC交流1號表;

(b)不同位數的碼字數量;前面提到,JPEG中的Huffman編碼表是按照編碼長度的位數以表格的形式保存的,而且,Huffman編碼表的位數只能是1--16位,因此,這裏用16個字節來分別表示1--16位的每種位長的編碼在Huffman樹中的個數。

(c)編碼內容;該字段記錄了Huffman樹中各個葉子節點的權重,上一個字段(不同位數的碼字數量)的16個數值之和,就是本字段的長度,也就是Huffman樹中葉子節點的個數。

這裏,我們不妨以下面一段Huffman表的數據爲例來說明情況(均以16進製表示):

11 00 02 02 00 05 01 06 01 00 00 00 00 00 00 00 00

00 01 11 02 21 03 31 41 12 51 61 71 81 91 22 13 32

以上數據串中第一行代表了HuffmanID、表類型、不同位數的碼字數量信息;

第一行的第一個字節0X11代表了表的ID和類型是AC交流1號表;

第一行的第2到第17字節代表了不同位數碼字的數量。即,第2個字節00表示沒有位數爲1的編碼;第3個和第4個字節的02表示位數爲2和位數爲3的編碼各有兩個;第5個字節的00表示沒有位數爲5的編碼。。。。此外,通過這些數據我們發現,此Huffman樹有0+2+2+0+5+1+6+1=17個葉子節點。

第二行爲編碼的內容,表明17個葉子節點按照從小到大的順序排列,即,權值依次爲0,1,11,2,21,3,31,41...

(3) 構建Huffman

讀取到Huffman表的數據之後,就需要構建Huffman樹了。其具體規則如下

  (a)第一個編碼的數字必定爲0;如果第一個編碼的位數爲1,就被編碼爲0;如果第一個編碼的位數爲2,就被編碼爲00;如果第一個編碼的位數爲3,就被編碼爲000。。。

  (b)從第二個編碼開始,如果它和它前面編碼具有相同的位數,則當前編碼是它前面的編碼加1;如果它的編碼位數比它前面的編碼位數大,則當前編碼時它前面的編碼加1之後再在後面添加若干個0,直到滿足編碼位數的長度爲止。

還是以上面的數據爲例:

第一行的第2個字節00表示沒有位數爲1的編碼;

第一行的第3個字節02表示位數爲2的編碼有2個;由於沒有位數爲1的編碼,因此這裏位數爲2的編碼中的第一個爲00,第二個爲00+1=01

第一行的第4個字節02表示位數爲3的編碼有2個;因此,這裏位數爲3的編碼中的第一個爲01+1=10,然後添加1個“0”,得到100;位數爲3的編碼中的第二個爲100+1=101

依次類推,可以得到如下的Huffman

序號

碼字長度

碼字

權值

1

2

00

0x00

2

2

01

0x01

3

3

100

0x11

4

3

101

0x02

5

5

11000

0x21

6

5

11001

0x03

7

5

11010

0x31

8

5

11011

0x41

9

5

11100

0x12

10

6

111010

0x51

11

7

1110110

0x61

12

7

1110111

0x71

13

7

1111000

0x81

14

7

1111001

0x91

15

7

1111010

0x22

16

7

1111011

0x13

17

8

11111000

0x32

特別提醒的是,如果中間有某個位數的編碼缺失,例如,沒有4位的編碼,則應該在3位的編碼後面加1,添加2個“00”補足5位,形成下一個5位編碼。

 

(4) DC係數的Huffman解碼

JPEG編碼階段我們講到,DC係數是以(A,B)的中間形式進行編碼的。其中的A代表了B的二進制編碼位數,B則利用VLI進行編碼。另外,8*8的圖像塊經過DCT變換之後得到的8*8的係數矩陣,經過Huffman編碼及RLE編碼之後,寫入編碼數據的時候,DC係數也是被寫在數據流最前面的。因此,解碼的時候,DC係數也是最先被讀取出來,假設,我們一次性讀入了若干個字節長度的數據。其中的第一個字節代表了DC係數的Huffman編碼,通過查找DC係數的Huffman表(亮度表或色度表),得到該Huffman編碼所在的組編號,該編號就是DC係數中間格式(A,B)中的A,也就是B的位數。例如,A=2,就代表B採用2位二進制數進行編碼。這樣一來,讀取接下來的A位二進制數,將其譯碼爲十進制,就得到了DC係數的差值。將該差值與上一個DC係數值相加,就得到了真正的當前DC係數的值。

(5) AC係數的Huffman解碼

處理完DC係數之後,接下來進行AC係數的譯碼工作,顯然,這裏依然需要讀取一個Huffman編碼,通過查找AC係數的Huffman編碼表,進行解碼,我們得到(A,B)的數據對,其中的A代表了0的個數,而B則代表了後面數據的位數。例如,(2,3)就代表了當前AC係數之前有20,下一個需要讀取的二進制數據是3位。需要提醒的是,(0,0)代表EOB,即8*8塊的編碼結束。接着,讀取B位二進制數據,進行譯碼,我們就得到了AC係數的值。如此反覆循環,直到遇到EOB,或者讀取了63AC係數,我們就完成了一個8*8塊的係數矩陣的譯碼工作。

(6) 反量化

在譯碼得到了8*8的係數矩陣之後,我們需要進行反量化工作。該步驟,就是將前一個步驟得到的8*8係數矩陣分別乘以8*8的量化矩陣即可。

(7) 反Zig-zag掃描

JPEG編碼過程中,爲了編碼方便,採用了Zig-zag掃描,因此,這裏需要進行反Zig-zag掃描,重新排列8*8的反量化係數矩陣。反Zig-zag掃描的輸入時8*8矩陣,輸出依然是8*8矩陣,只不過,數據的排列方式有所不同而已。

(8) DCT逆變換

DCT變換,將原始圖像變換到頻域,而DCT逆變換,就是要將數據從頻域變換回時域。

DCT逆變換的計算公式爲:

DCT逆變換的公式,可以改寫爲:

其中A爲矩陣:

左邊爲未轉秩的數據順序,右邊爲轉秩之後的數據順序。

(9)顏色模式轉換

BMP圖片是以RGB顏色空間進行保存的,因此,將JPEG解碼爲BMP必須進行顏色模式的轉換。另外,由於DCT要求的定義域對稱,所以,在編碼的時候將RGB的數值範圍從[0,255]統一減去128,將數值範圍轉換到[-128,127]的範圍內。因此,解碼的時候,必須爲每個顏色分量加上128。另外需要注意的是,通過解碼變換之後得到的RGB的值有可能超過255或者小於0;如果小於0,就截斷爲0,如果大於255,就截取爲255

發佈了23 篇原創文章 · 獲贊 15 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章