星期四, 1月 01, 2009

JPEG 壓縮簡介

/************************************************************************

JPEG 壓縮簡介
-------------

1. 色彩模型

JPEG 的圖片使用的是 YCrCb 顏色模型, 而不是計算機上最常用的 RGB. 關於色
彩模型, 這裡不多闡述. 只是說明, YCrCb 模型更適合圖形壓縮. 因為人眼對圖片上
的亮度 Y 的變化遠比色度 C 的變化敏感. 我們完全可以每個點保存一個 8bit 的亮
度值, 每 2x2 個點保存一個 Cr Cb 值, 而圖像在肉眼中的感覺不會起太大的變化.
所以, 原來用 RGB 模型, 4 個點需要 4x3=12 字節. 而現在僅需要 4+2=6 字節; 平
均每個點佔 12bit. 當然 JPEG 格式裡允許每個點的 C 值都記錄下來; 不過 MPEG 裡
都是按 12bit 一個點來存放的, 我們簡寫為 YUV12.

[R G B] -> [Y Cb Cr] 轉換
-------------------------

(R,G,B 都是 8bit unsigned)
(以下為矩陣表示)
| Y | | 0.299 0.587 0.114 | | R | | 0 |
| Cb | = |-0.1687 -0.3313 0.5 | * | G | + |128|
| Cr | | 0.5 -0.4187 -0.0813| | B | |128|

Y = 0.299 *R + 0.587 *G + 0.114 *B (亮度)
Cb = - 0.1687*R - 0.3313*G + 0.5 *B + 128
Cr = 0.5 *R - 0.4187*G - 0.0813*B + 128

[Y,Cb,Cr] -> [R,G,B] 轉換
-------------------------
R = Y + 1.402 *(Cr-128)
G = Y - 0.34414*(Cb-128) - 0.71414*(Cr-128)
B = Y + 1.772 *(Cb-128)

一般, C 值 (包括 Cb Cr) 應該是一個有號數, 但這裡被處理過了, 方法
是加上了 128. JPEG 裡的數據都是unsigned 8bit 的.

2. DCT (離散餘弦變換)
JPEG 裡, 要對數據壓縮, 先要做一次 DCT 變換. DCT 變換的原理, 涉及到數學
知識, 這裡我們不必深究. 反正和傅立葉轉換(學過高等數學的都知道)差不多. 經過
這個變換, 就把圖片裡點和點間的規律呈現出來了, 更方便壓縮. JPEG 裡是對每 8x8
個點為一個單位處理的. 所以如果原始圖片的長寬不是 8 的倍數, 都需要先補成 8
的倍數, 好一塊塊的處理. 另外, 記得剛才我說的 Cr Cb 都是 2x2 記錄一次嗎? 所
以大多數情況, 是要補成 16x16 的整數塊.按從左到右, 從上到下的次序排列 .
JPEG 裡是對 Y Cr Cb 分別做 DCT 變換的. 這裡進行 DCT 變換
的 Y, Cr, Cb 值的範圍都是 -128~127. (Y 被減去 128)

JPEG 編碼時使用的是 Forward DCT (FDCT), 解碼時使用的是 Inverse DCT (IDCT)
下面給出公式:

FDCT:
7 7 2*x+1 2*y+1
F(u,v) = alpha(u)*alpha(v)* sum sum f(x,y) * cos (------- *u*PI)* cos (------ *v*PI)
x=0 y=0 16 16

u,v = 0,1,...,7

{ 1/sqrt(8) (u==0)
alpha(u) = {
{ 1/2 (u!=0)


IDCT:
7 7 2*x+1 2*y+1
f(x,y) = sum sum alpha(u)*alpha(v)*F(u,v)*cos (------- *u*PI)* cos (------ *v*PI)
u=0 v=0 16 16

x,y=0,1...7

這個步驟很花時間, 另外有種 AA&N 優化算法, 大家可以去 Intel自己找一下.
在 Intel 主頁上可以找到 AA&N IDCT 的 MMX 優化代碼. ( Intel 主頁上的代碼,
輸入數據為 12.4 的定點數, 輸入矩陣需要轉置 90 度)

3. 重排列 DCT 結果
DCT 將一個 8x8 的數組變換成另一個 8x8 的數組. 但是記憶體裡所有數據都是線
性存放的, 如果我們一行行的存放這 64 個數字, 每行的結尾的點和下行開始的點就
沒有什麼關係, 所以 JPEG 規定按如下次序整理 64 個數字.

0, 1, 5, 6,14,15,27,28,
2, 4, 7,13,16,26,29,42,
3, 8,12,17,25,30,41,43,
9,11,18,24,31,40,44,53,
10,19,23,32,39,45,52,54,
20,22,33,38,46,51,55,60,
21,34,37,47,50,56,59,61,
35,36,48,49,57,58,62,63

這樣數列裡的相鄰點在圖片上也是相鄰的了.

4. 量化
對於前面得到的 64 個空間頻率振幅值, 我們將對它們作幅度分層量化操作.方
法就是分別除以量化表裡對應值並四捨五入.

for (i = 0 ; i<=63; i++ ) vector[i] = (int) (vector[i] / quantization_table[i] + 0.5) 下面有張 JPEG 標準量化表. (按上面同樣的彎曲次序排列) 16 11 10 16 24 40 51 61 12 12 14 19 26 58 60 55 14 13 16 24 40 57 69 56 14 17 22 29 51 87 80 62 18 22 37 56 68 109 103 77 24 35 55 64 81 104 113 92 49 64 78 87 103 121 120 101 72 92 95 98 112 100 103 99 這張表依據心理視覺閥製作, 對 8bit 的亮度和色度的圖像的處理效果不錯. 當然我們可以使用任意的量化表. 量化表是定義在 jpeg 的 DQT 標記後. 一般 為 Y 值定義一個, 為 C 值定義一個. 量化表是控制 JPEG 壓縮比的關鍵. 這個步驟除掉了一些高頻量, 損失了很高 細節. 但事實上人眼對高空間頻率遠沒有低頻敏感.所以處理後的視覺損失很小. 另一個重要原因是所有的圖片的點與點之間會有一個色彩過渡的過程. 大量的圖像 資訊被包含在低空間頻率中. 經過量化處理後, 在高空間頻率段, 將出現大量連續 的零. 注意, 量化後的資料有可能超過 2 byte 有符號整數的處理範圍. 5. 0. RLE 編碼 現在我們向量中有許多連續的 0. 我們可以使用 RLE 來壓縮掉這些 0. 這裏我們 將跳過第一個向量 (後面將解釋為什麼) 因為它的編碼比較特別. 假設有一組向量 (64 個的後 63 個) 是 57,45,0,0,0,0,23,0,-30,-16,0,0,1,0,0,0,0,0,0,0,..,0 經過 RLE 壓縮後就是 (0,57);(0,45);(4,23);(1,-30);(0,-16);(2,1); EOB EOB 是一個結束標記, 表示後面都是 0 了. 實際上, 我們用 (0,0) 表示 EOB 但是, 如果這組數位不以 0 結束, 那麼就不需要 EOB. 由於後面 huffman 編碼的要求, 每組數位前一個表示 0 的數量的必須是 4 bit, 就是說, 只能是 0~15, 所以我們實際這樣編碼: (0,57) ; (15,0) (2,3) ; (4,2) ; (15,0) (15,0) (1,895) , (0,0) 注意 (15,0) 表示了 16 個連續的 0. 6. huffman 編碼 為了提高儲存效率, JPEG 裏並不直接保存數值, 而是將數值按位數分成 16 組: 數值 組 實際保存值 0 0 - -1,1 1 0,1 -3,-2,2,3 2 00,01,10,11 -7,-6,-5,-4,4,5,6,7 3 000,001,010,011,100,101,110,111 -15,..,-8,8,..,15 4 0000,..,0111,1000,..,1111 -31,..,-16,16,..,31 5 00000,..,01111,10000,..,11111 -63,..,-32,32,..,63 6 . -127,..,-64,64,..,127 7 . -255,..,-128,128,..,255 8 . -511,..,-256,256,..,511 9 . -1023,..,-512,512,..,1023 10 . -2047,..,-1024,1024,..,2047 11 . -4095,..,-2048,2048,..,4095 12 . -8191,..,-4096,4096,..,8191 13 . -16383,..,-8192,8192,..,16383 14 . -32767,..,-16384,16384,..,32767 15 . 還是來看前面的例子: (0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-8) ; (2,1) ; (0,0) 只處理每對數右邊的那個: 57 是第 6 組的, 實際保存值為 111001 , 所以被編碼為 (6,111001) 45 , 同樣的操作, 編碼為 (6,101101) 23 -> (5,10111)
-30 -> (5,00001)
-8 -> (4,0111)
1 -> (1,1)

前面的那串數字就變成了:
(0,6), 111001 ; (0,6), 101101 ; (4,5), 10111; (1,5), 00001; (0,4) , 0111 ;
(2,1), 1 ; (0,0)

括號裡的數值正好合成一個字節. 後面被編碼的數字表示範圍是 -32767..32767.
合成的字節裡, 高 4 位是前續 0 的個數, 低 4 位描述了後面數字的位數.

繼續剛才的例子, 如果 (0,6) 的 huffman 編碼為 111000
69 = (4,5) --- 1111111110011001 ( 注: 69=4*16+5 )
21 = (1,5) --- 11111110110
4 = (0,4) --- 1011
33 = (2,1) --- 11011
0 = EOB = (0,0) --- 1010

那麼最後對於前面的例子表示的 63 個係數 (記得我們將第一個跳過了嗎?) 按位流
寫入 JPG 文件中就是這樣的:
111000 111001 111000 101101 1111111110011001 10111 11111110110 00001
1011 0111 11011 1 1010

DC 的編碼
---------
記得剛才我們跳過了每組 64 個數據的第一個吧, DC 就是指的這個數字 (後面 63
個簡稱 AC) 代入前面的 FDCT 公式可以得到
c(0,0) 7 7
DC = F(0,0) = --------- * sum sum f(x,y) * cos 0 * cos 0 其中 c(0,0) = 1/2
4 x=0 y=0

1 7 7
= --- * sum sum f(x,y)
8 x=0 y=0

即一塊圖像樣本的平均值. 就是說, 它包含了原始 8x8 圖像塊裡的很多能量. (通常
會得到一個很大的數值)

JPEG 的作者指出連續塊的 DC 率之間有很緊密的聯繫, 因此他們決定對 8x8 塊的
DC 值的差別進行編碼. (Y, Cb, Cr 分別有自己的 DC)

Diff = DC(i) - DC(i-1)

所以這一塊的 DC(i) 就是: DC(i) = DC(i-1) + Diff

JPG 從 0 開始對 DC 編碼, 所以 DC(0)=0. 然後再將當前 Diff 值加在上一個值上得
到當前值.

下面再來看看上面那個例子: (記住我們保存的 DC 是和上一塊 DC 的差值 Diff)

例如上面例子中, Diff 是 -511, 就編碼成

(9, 000000000)

如果 9 的 Huffman 編碼是 1111110 (在 JPG 文件中, 一般有兩個 Huffman 表, 一
個是 DC 用, 一個是 AC 用) 那麼在 JPG 文件中, DC 的 2 進製表示為

1111110 000000000

它將放在 63 個 AC 的前面, 上面上個例子的最終 BIT 流如下:

1111110 000000000 111000 111001 111000 101101 1111111110011001 10111
11111110110 00001 1011 0111 11011 1 1010

下面簡單敘述一下針對一個數據單元的圖片 Y 的解碼
-----------------------------------------------

在整個圖片解碼的開始, 你需要先初始化 DC 值為 0.

1) 先解碼 DC:
a) 取得一個 Huffman 碼 (使用 Huffman DC 表)
b) Huffman解碼, 看看後面的數據位數 N
c) 取得 N 位, 計算 Diff 值
d) DC + = Diff
e) 寫入 DC 值: "vector[0]=DC"

2) 解碼 63 個 AC:

------- 循環處理每個 AC 直到 EOB 或者處理到 64 個 AC

a) 取得一個 Huffman 碼 (使用 Huffman AC 表)
b) Huffman 解碼, 得到 (前面 0 數量, 組號)
[記住: 如果是(0,0) 就是 EOB 了]

c) 取得 N 位(組號) 計算 AC
d) 寫入相應數量的 0
e) 接下來寫入 AC
-----------------

下一步的解碼
------------
上一步我們得到了 64 個向量. 下面我們還需要做一些解碼工作:

1) 反量化 64 個向量 : "for (i=0;i<=63;i++) vector[i]*=quant[i]" (注意防止溢出) 2) 重排列 64 個向量到 8x8 的塊中 3) 對 8x8 的塊作 IDCT 對 8x8 塊的 (Y,Cb,Cr) 重復上面的操作 [Huffman 解碼, 步驟 1), 2), 3)] 4) 將所有的 8bit 數加上 128 5) 轉換 YCbCr 到 RGB JPG 文件(Byte 級)裏怎樣組織圖片資訊 ----------------------------------- 注意 JPEG/JFIF 文件格式使用 Motorola 格式, 而不是 Intel 格式, 就是說, 如果 是一個字的話, 高位元組在前, 低位元組在後. JPG 文件是由一個個段 (segments) 構成的. 每個段長度 <=65535. 每個段從一個標 記字開始. 標記字都是 0xff 打頭的, 以非 0 位元組和 0xFF 結束. 例如 'FFDA' , 'FFC4', 'FFC0'. 每個標記有它特定意義, 這是由第2位元組指明的. 例如, SOS (S- tart Of Scan = 'FFDA') 指明了你應該開始解碼. 另一個標記 DQT (Define Quan- tization Table = 0xFFDB) 就是說它後面有 64 位元組的 quantization 表在處理JP- EG文件時, 如果你碰到一個 0xFF, 而它後面的位元組不是 0, 並且這個位元組沒有意 義. 那麼你遇到的 0xFF 位元組必須被忽略. (一些 JPG 裏, 常常用 0xFF 做某些填充 用途) 如果你在做 huffman 編碼時碰巧產生了一個 0xFF, 那麼就用 0xFF ,0x00 代替. 就是說在 jpeg 圖形解碼時碰到 FF00 就把它當作 FF 處理. 另外在 huffman 編碼區域結束時, 碰到幾個 bit 沒有用的時候, 應該用 1 去填充. 然後後面跟 FF. 下面是幾個重要的標記 -------------------- SOI = Start Of Image = 'FFD8' 這個標記只在文件開始出現一次 EOI = End Of Image = 'FFD9' JPG 文件都以 FFD9 結束 RSTi = FFDi ( i = 0..7) [ RST0 = FFD0, RST7=FFD7] = 重定標記 通常穿插在資料流程裏, 我想是擔心 JPG 解碼出問題吧(應該配合 DRI 使用). RST 將 Huffman 的解碼資料流程重定. DC 也重新從 0 開始計 (SOS --- RST0 --- RST1 -- RST2 --... ...-- RST6 --- RST7 -- RST0 --...) ---- 標記 ---- 下面是必須處理的標記 SOF0 = Start Of Frame 0 = FFC0 SOS = Start Of Scan = FFDA APP0 = it's the marker used to identify a JPG file which uses the JFIF specification = FFE0 COM = Comment = FFFE DNL = Define Number of Lines = FFDC DRI = Define Restart Interval = FFDD DQT = Define Quantization Table = FFDB DHT = Define Huffman Table = FFC4 JPG 文件中 Haffman 表的儲存 --------------------------- JPEG 裏定義了一張表來描述 Haffman 樹. 定義在 DHT 標記後面. 注意: Haffman 代碼的長度限制在 16bit 內. 一般一個 JPG 文件裏會有 2 類 Haffman 表: 一個用於 DC 一個用於 AC (實際有 4 個表, 亮度的 DC,AC 兩個, 色度的 DC,AC 兩個) 這張表是這樣保存的: 1) 16 位元組: 第 i 位元組表示了 i 位元長的 Huffman 代碼的個數 (i= 1 到 16) 2) 這表的長度 (位元組數) = 這 16 個數位之和 現在你可以想象這張表怎麼存放的吧? 對應位元組就是對應 Haffman 代碼等價數位. 我 不多解釋, 這需要你先瞭解 Haffman 演算法. 這裏只舉一個例子: Haffman 表的表頭是 0,2,3,1,1,1,0,1,0,0,0,0,0,0,0,0 就是說長度為 1 的代碼沒有 長度為 2 的代碼為 00 01 長度為 3 的代碼是 100 101 110 長度為 4 的代碼是 1110 長度為 5 的代碼是 11110 長度為 6 的代碼是 111110 長度為 7 的代碼沒有 (如果有一個的話應該是 1111110) 長度為 8 的代碼是 11111100 ..... 後面都沒有了. 如果表下面的資料是 45 57 29 17 23 25 34 28 就是說 45 = 00 57 = 01 29 = 100 17 = 101 23 = 110 等等... 如果你懂 Haffman 編碼, 這些不難理解 採樣係數 -------- 下面講解的都是真彩 JPG 的解碼, 灰度 JPG 的解碼很簡單, 因為圖形中只有亮度信 息. 而彩色圖形由 (Y, Cr, Cb) 構成, 前面提到過, Y 通常是每點採樣一次, 而 Cr, Cb 一般是 2x2 點採樣一次, 當然也有的 JPG 是逐點採樣, 或者每兩點採樣 (橫向 兩點, 縱向一點) 採樣係數均被定義成對比最高採樣係數的相對值. 一般情況 (即: Y 逐點採樣, Cr Cb 每 2x2 點一次) 下: Y 有最高的採樣率, 橫向采 樣係數HY=2 縱向採樣係數 VY=2; Cb 的橫向採樣係數 HCb=1, 縱向採樣係數 VCb=1; 同樣 HCr=1, VCr=1 在 Jpeg 裏, 8x8 個原始資料, 經過 RLC, Huffman 編碼後的一串資料流程稱為一個 Data Unit (DU) JPG 裏按 DU 為單位的編碼次序如下: 1) for (counter_y=1;counter_y<=VY;counter_y++) for (counter_x=1;counter_x<=HY;counter_x++) { 對 Y 的 Data Unit 編碼 } 2) for (counter_y=1;counter_y<=VCb ;counter_y++) for (counter_x=1;counter_x<=HCb;counter_x++) { 對 Cb 的 Data Unit 編碼 } 3) for (counter_y=1;counter_y<=VCr;counter_y++) for (counter_x=1;counter_x<=HCr;counter_x++) { 對 Cr 的 Data Unit 編碼 } 按我上面的例子: (HY=2, VY=2 ; HCb=VCb =1, HCr,VCr=1) 就是這樣一個次序 YDU,YDU,YDU,YDU,CbDU,CrDU 這些就描述了一塊 16x16 的圖形. 16x16 = (Hmax*8 x Vmax*8) 這裏 Hmax=HY=2 Vmax=VY=2 一個 (Hmax*8,Vmax*8) 的塊被稱作 MCU (Minimun Coded Unix) 前面例子中一個 MCU = YDU,YDU,YDU,YDU,CbDU,CrDU 如果 HY =1, VY=1 HCb=1, VCb=1 HCr=1, VCr=1 這樣 (Hmax=1,Vmax=1), MCU 只有 8x8 大, MCU = YDU,CbDU,CrDU 對於灰度 JPG, MCU 只有一個 DU (MCU = YDU) JPG 文件裏, 圖像的每個組成部分的採樣係數定義在 SOF0 (FFC0) 標記後 簡單說一下 JPG 文件的解碼 ------------------------- 解碼程式先從 JPG 文件中讀出採樣係數, 這樣就知道了 MCU 的大小, 算出整個圖像 有幾個 MCU. 解碼程式再迴圈逐個對 MCU 解碼, 一直到檢查到 EOI 標記. 對於每個 MCU, 按正規的次序解出每個 DU, 然後組合, 轉換成 (R,G,B) 就 OK 了 附:JPEG 文件格式 ~~~~~~~~~~~~~~~~ - 文件頭 (2 bytes): $ff, $d8 (SOI) (JPEG 文件標識) - 任意數量的段 , 見後面 - 文件結束 (2 bytes): $ff, $d9 (EOI) 段的格式: ~~~~~~~~~ - header (4 bytes): $ff 段標識 n 段的類型 (1 byte) sh, sl 該段長度, 包括這兩個位元組, 但是不包括前面的 $ff 和 n. 注意: 長度不是 intel 次序, 而是 Motorola 的, 高位元組在前, 低位元組在後! - 該段的內容, 最多 65533 位元組 注意: - 有一些無參數的段 (下面那些前面注明星號的) 這些段沒有長度描述 (而且沒有內容), 只有 $ff 和類型位元組. - 段之間無論有多少 $ff 都是合法的, 必須被忽略掉. 段的類型: ~~~~~~~~~ *TEM = $01 可以忽略掉 SOF0 = $c0 幀開始 (baseline JPEG), 細節附後 SOF1 = $c1 dito SOF2 = $c2 通常不支援 SOF3 = $c3 通常不支援 SOF5 = $c5 通常不支援 SOF6 = $c6 通常不支援 SOF7 = $c7 通常不支援 SOF9 = $c9 arithmetic 編碼(Huffman 的一種擴展演算法), 通常不支援 SOF10 = $ca 通常不支援 SOF11 = $cb 通常不支援 SOF13 = $cd 通常不支援 SOF14 = $ce 通常不支援 SOF14 = $ce 通常不支援 SOF15 = $cf 通常不支援 DHT = $c4 定義 Huffman Table, 細節附後 JPG = $c8 未定義/保留 (引起解碼錯誤) DAC = $cc 定義 Arithmetic Table, 通常不支援 *RST0 = $d0 RSTn 用於 resync, 通常被忽略 *RST1 = $d1 *RST2 = $d2 *RST3 = $d3 *RST4 = $d4 *RST5 = $d5 *RST6 = $d6 *RST7 = $d7 SOI = $d8 圖片開始 EOI = $d9 圖片結束 SOS = $da 掃描行開始, 細節附後 DQT = $db 定義 Quantization Table, 細節附後 DNL = $dc 通常不支援, 忽略 DRI = $dd 定義重新開始間隔, 細節附後 DHP = $de 忽略 (跳過) EXP = $df 忽略 (跳過) APP0 = $e0 JFIF APP0 segment marker (細節略) APP15 = $ef 忽略 JPG0 = $f0 忽略 (跳過) JPG13 = $fd 忽略 (跳過) COM = $fe 注釋, 細節附後 其他的段類型都保留必須跳過 SOF0: Start Of Frame 0: ~~~~~~~~~~~~~~~~~~~~~~~ - $ff, $c0 (SOF0) - 長度 (高位元組, 低位元組), 8+components*3 - 資料精度 (1 byte) 每個樣本位元數, 通常是 8 (大多數軟體不支援 12 和 16) - 圖片高度 (高位元組, 低位元組), 如果不支援 DNL 就必須 >0
- 圖片寬度 (高字節, 低字節), 如果不支持 DNL 就必須 >0
- components 數量(1 byte), 灰度圖是 1, YCbCr/YIQ 彩色圖是 3, CMYK 彩色圖
是 4
- 每個 component: 3 bytes
- component id (1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q)
- 採樣係數 (bit 0-3 vert., 4-7 hor.)
- quantization table 號

DRI: Define Restart Interval:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

- $ff, $dd (DRI)
- 長度 (高字節, 低字節), 必須是 4
- MCU 塊的單元中的重新開始間隔 (高字節, 低字節),
意思是說, 每 n 個 MCU 塊就有一個 RSTn 標記.
第一個標記是 RST0, 然後是 RST1 等, RST7 後再從 RST0 重複

DQT: Define Quantization Table:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

- $ff, $db (DQT)
- 長度 (高字節, 低字節)
- QT 信息 (1 byte):
bit 0..3: QT 號(0..3, 否則錯誤)
bit 4..7: QT 精度, 0 = 8 bit, 否則 16 bit
- n 字節的 QT, n = 64*(精度+1)

備註:
- 一個單獨的 DQT 段可以包含多個 QT, 每個都有自己的信息字節
- 當精度=1 (16 bit), 每個字都是高位在前低位在後

DAC: Define Arithmetic Table:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
法律原因, 現在的軟件不支持 arithmetic 編碼.
不能生產使用 arithmetic 編碼的 JPEG 文件

DHT: Define Huffman Table:
~~~~~~~~~~~~~~~~~~~~~~~~~~

- $ff, $c4 (DHT)
- 長度 (高字節, 低字節)
- HT 信息 (1 byte):
bit 0..3: HT 號 (0..3, 否則錯誤)
bit 4 : HT 類型, 0 = DC table, 1 = AC table
bit 5..7: 必須是 0
- 16 bytes: 長度是 1..16 代碼的符號數. 這 16 個數的和應該 = 1 , <=4 (否則是錯的) 通常是 3
- 每個組件: 2 bytes
- component id (1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q), 見 SOF0
- 使用的 Huffman 表:
- bit 0..3: AC table (0..3)
- bit 4..7: DC table (0..3)
- 忽略 3 bytes (???)

備註:
- 圖片數據 (一個個掃瞄行) 緊接著 SOS 段.



作者Blog:http://blog.csdn.net/ghj1976/



Posted by: jily 發表於 November 24, 2004 10:33 AM
JPEG顏色轉換實現文件
出處 http://isee.126.com

yuvtorgb.cpp - ISee圖像瀏覽器 JPEG顏色轉換實現文件


********************************************************************/

沒有留言: