一、JPEG 壓縮簡介
1. 色彩模型
JPEG 的圖片使用的是 YCrCb 顏色模型, 而不是計算機(jī)上最常用的 RGB. 關(guān)于色彩模型, 這里不多闡述. 只是說明, YCrCb 模型更適合圖形壓縮. 因?yàn)槿搜蹖D片上的亮度 Y 的變化遠(yuǎn)比色度 C 的變化敏感. 我們完全可以每個點(diǎn)保存一個 8bit 的亮度值, 每 2x2 個點(diǎn)保存一個 Cr Cb 值, 而圖象在肉眼中的感覺不會起太大的變化. 所以, 原來用 RGB 模型, 4 個點(diǎn)需要 4x3=12 字節(jié). 而現(xiàn)在僅需要 4+2=6 字節(jié); 平均每個點(diǎn)占 12bit. 當(dāng)然 JPEG 格式里允許每個點(diǎn)的 C 值都記錄下來; 不過 MPEG 里都是按 12bit 一個點(diǎn)來存放的, 我們簡寫為 YUV12.
[R G B] -> [Y Cb Cr] 轉(zhuǎn)換 -------------------------
(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] 轉(zhuǎn)換 -------------------------
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) 應(yīng)該是一個有符號的數(shù)字, 但這里被處理過了, 方法 是加上了 128. JPEG 里的數(shù)據(jù)都是無符號 8bit 的.
2. DCT (離散余弦變換)
JPEG 里, 要對數(shù)據(jù)壓縮, 先要做一次 DCT 變換. DCT 變換的原理, 涉及到數(shù)學(xué)知識, 這里我們不必深究. 反正和傅立葉變換(學(xué)過高數(shù)的都知道) 是差不多了. 經(jīng)過這個變換, 就把圖片里點(diǎn)和點(diǎn)間的規(guī)律呈現(xiàn)出來了, 更方便壓縮.JPEG 里是對每 8x8 個點(diǎn)為一個單位處理的. 所以如果原始圖片的長寬不是 8 的倍數(shù), 都需要先補(bǔ)成 8 的倍數(shù), 好一塊塊的處理. 另外, 記得剛才我說的 Cr Cb 都是 2x2 記錄一次嗎? 所以大多數(shù)情況, 是要補(bǔ)成 16x16 的整數(shù)塊.按從左到右, 從上到下的次序排列 (和我們寫字的次序一樣). JPEG 里是對 Y Cr Cb 分別做 DCT 變換的. 這里進(jìn)行 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 優(yōu)化算法, 大家可以去 inet 自己找一下. 在Intel 主頁上可以找到 AA&N IDCT 的 MMX 優(yōu)化代碼. ( Intel 主頁上的代碼, 輸入數(shù)據(jù)為12.4 的定點(diǎn)數(shù), 輸入矩陣需要轉(zhuǎn)置 90 度)
3. 重排列 DCT 結(jié)果
DCT 將一個 8x8 的數(shù)組變換成另一個 8x8 的數(shù)組. 但是內(nèi)存里所有數(shù)據(jù)都是線形存放的, 如果我們一行行的存放這 64 個數(shù)字, 每行的結(jié)尾的點(diǎn)和下行開始的點(diǎn)就 沒有什么關(guān)系, 所以 JPEG 規(guī)定按如下次序整理 64 個數(shù)字.
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
這樣數(shù)列里的相鄰點(diǎn)在圖片上也是相鄰的了.
4. 量化
對于前面得到的 64 個空間頻率振幅值, 我們將對它們作幅度分層量化操作.方法就是分別除以量化表里對應(yīng)值并四舍五入.
for (i = 0 ; i<=63; i++ ) vector[i] = (int) (vector[i] / quantization_table[i] + 0.5)
下面有張 JPEG 標(biāo)準(zhǔn)量化表. (按上面同樣的彎曲次序排列)
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
這張表依據(jù)心理視覺閥制作, 對 8bit 的亮度和色度的圖象的處理效果不錯.當(dāng)然我們可以使用任意的量化表. 量化表是定義在 jpeg 的 DQT 標(biāo)記后. 一般為 Y 值定義一個, 為 C 值定義一個.
量化表是控制 JPEG 壓縮比的關(guān)鍵. 這個步驟除掉了一些高頻量, 損失了很高細(xì)節(jié). 但事實(shí)上人眼對高空間頻率遠(yuǎn)沒有低頻敏感.所以處理后的視覺損失很小.另一個重要原因是所有的圖片的點(diǎn)與點(diǎn)之間會有一個色彩過渡的過程. 大量的圖象信息被包含在低空間頻率中. 經(jīng)過量化處理后, 在高空間頻率段, 將出現(xiàn)大量連續(xù)的零.
注意, 量化后的數(shù)據(jù)有可能超過 2 byte 有符號整數(shù)的處理范圍.
5. 0 RLE 編碼
現(xiàn)在我們矢量中有許多連續(xù)的 0. 我們可以使用 RLE 來壓縮掉這些 0. 這里我們將跳過第一個矢量 (后面將解釋為什么) 因?yàn)樗木幋a比較特別. 假設(shè)有一組矢量(64 個的后 63 個) 是 57,45,0,0,0,0,23,0,-30,-16,0,0,1,0,0,0, 0 , 0 ,0 , 0,..,0 經(jīng)過 RLE 壓縮后就是 (0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-16) ; (2,1) ; EOB EOB 是一個結(jié)束標(biāo)記, 表示后面都是 0 了. 實(shí)際上, 我們用 (0,0) 表示 EOB, 但是, 如果這組數(shù)字不以 0 結(jié)束, 那么就不需要 EOB. 另外需要注意的是, 由于后面 huffman 編碼的要求, 每組數(shù)字前一個表示 0 的 數(shù)量的必須是 4 bit, 就是說, 只能是 0~15, 所以, 如果有這么一組數(shù)字: 57, 十八個0, 3, 0, 0, 0, 0, 2, 三十三個0, 895, EOB 我們實(shí)際這樣編碼: (0,57) ; (15,0) (2,3) ; (4,2) ; (15,0) (15,0) (1,895) , (0,0) 注意 (15,0) 表示了 16 個連續(xù)的 0.
6. 范式 Huffman 編碼
為了提高儲存效率, JPEG 里并不直接保存數(shù)值, 而是將數(shù)值按位數(shù)分成 16 組:
數(shù)值 組 實(shí)際保存值 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)
只處理每對數(shù)右邊的那個: 57 是第 6 組的, 實(shí)際保存值為 111001 , 所以被編碼為 (6,111001) 45 , 同樣的操作, 編碼為 (6,101101) 23 -> (5,10111) -30 -> (5,00001) -8 -> (4,0111) 1 -> (1,1)
前面的那串?dāng)?shù)字就變成了: (0,6), 111001 ; (0,6), 101101 ; (4,5), 10111; (1,5), 00001; (0,4) , 0111 ; (2,1), 1 ; (0,0)
括號里的數(shù)值正好合成一個字節(jié). 后面被編碼的數(shù)字表示范圍是 -32767..32767.合成的字節(jié)里, 高 4 位是前續(xù) 0 的個數(shù), 低 4 位描述了后面數(shù)字的位數(shù).
繼續(xù)剛才的例子, 如果 06 的 huffman 編碼為 111000 ( 06 對應(yīng) 111000 為查表所得. jpeg 文件里保存了壓縮時所產(chǎn)生的 huffman 表, 將 0~255 這 256 個 8 bits 定長數(shù)字, 對應(yīng)成 1~16 bits 的不定長數(shù)值. 出現(xiàn)頻率高的數(shù)字小于 8bits, 頻率低的大于8bits,從而使整個的數(shù)據(jù)長度降低, jpeg 實(shí)際使用的是范式 Huffman 編碼(Canonical Huffman Code)關(guān)于范式 huffman 編碼的詳細(xì)介紹, 請查閱相關(guān)資料 )
69 = (4,5) --- 1111111110011001 ( 注: 69=4*16+5=0x45 ) 21 = (1,5) --- 11111110110 4 = (0,4) --- 1011 33 = (2,1) --- 11011 0 = EOB = (0,0) --- 1010
那么最后對于前面的例子表示的 63 個系數(shù) (記得我們將第一個跳過了嗎?) 按位流 寫入 JPG 文件中就是這樣的: 111000 111001 111000 101101 1111111110011001 10111 11111110110 00001 1011 0111 11011 1 1010
7. DC 的編碼
記得剛才我們跳過了每組 64 個數(shù)據(jù)的第一個吧, DC 就是指的這個數(shù)字 (后面 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 圖象塊里的很多能量. (通常會得到一個很大的數(shù)值)
JPEG 的作者指出連續(xù)塊的 DC 率之間有很緊密的聯(lián)系, 因此他們決定對 8x8 塊的DC 值的差別進(jìn)行編碼. (Y, Cb, Cr 分別有自己的 DC)
Diff = DC(i) - DC(i-1)
所以這一塊的 DC(i) 就是: DC(i) = DC(i-1) + Diff
JPG 從 0 開始對 DC 編碼, 所以 DC(0)=0. 然后再將當(dāng)前 Diff 值加在上一個值上得到當(dāng)前值.
下面再來看看上面那個例子: (記住我們保存的 DC 是和上一塊 DC 的差值 Diff)
例如上面例子中, Diff 是 -511, 就編碼成
(9, 000000000)
如果 9 的 Huffman 編碼是 1111110 (在 JPG 文件中, 一般有兩個 Huffman 表, 一個是 DC 用, 一個是 AC 用) 那么在 JPG 文件中, DC 的 2 進(jìn)制表示為
1111110 000000000
它將放在 63 個 AC 的前面, 上面上個例子的最終 BIT 流如下:
1111110 000000000 111000 111001 111000 101101 1111111110011001 10111 11111110110 00001 1011 0111 11011 1 1010
出處:云風(fēng)工作室
責(zé)任編輯:moby
上一頁 JPEG 簡易文檔 V2.14 [1] 下一頁 JPEG 簡易文檔 V2.14 [3]
◎進(jìn)入論壇網(wǎng)絡(luò)編程版塊參加討論
|