JPEG(Joint Photographic Experts Group)是聯合映像專家小組的英文縮寫。它由國際電話與電報諮詢委員會CCITT(The International Telegraph and Telephone Consultative Committee)與國際標準組織ISO於1986年聯合成立的一個小組,負責制定靜態數位影像的編碼通訊協定。
小組一直致力於標準化工作,開發研製出連續色調、多級灰階、靜止映像的數位影像壓縮編碼方法,即JPEG演算法。JPEG演算法被確定為國際通用標準,其適用範圍廣泛,除用於靜態映像編碼外,還推廣到電視映像序列的幀內映像壓縮。而用JPEG演算法壓縮出來的靜態圖片檔案稱為JPEG檔案,副檔名通常為*.jpg、*.jpe*.jpeg。
一.JPEG編碼器和解碼器的基本系統結構。
1.1 JPEG檔案格式簡介
JPEG檔案使用的資料存放區方式有多種。最常用的格式稱為JPEG檔案交換格式(JPEG File Interchange Format,JFIF)。而JPEG檔案大體上可以分成兩個部分:標記碼(Tag)和壓縮資料。標記碼由兩個位元組構成,其前一個位元組是固定值0xFF,後一個位元組則根據不同意義有不同數值。在每個標記碼之前還可以添加數目不限的無意義的0xFF填充,也就說連續的多個0xFF可以被理解為一個0xFF,並表示一個標記碼的開始。而在一個完整的兩位元組的標記碼後,就是該標記碼對應的壓縮資料流,記錄了關於檔案的諸種資訊。
常用的標記有SOI、APP0、DQT、SOF0、DHT、DRI、SOS、EOI。注意,SOI等都是標記的名稱。在檔案中,標記碼是以標記代碼形式出現。例如SOI的標記代碼為0xFFD8,即在JPEG檔案中的如果出現資料0xFFD8,則表示此處為一個SOI標記。
1.2 JPEG編解碼基本過程
JPEG基本系統結構
二 ,JPEG編碼過程。
2.1 RGB格式轉換為YUV格式
RGB介紹:
在記錄電腦映像時,最常見的是採用RGB(紅、綠,藍)顏色分量來儲存顏色資訊,例如非壓縮的24位的BMP映像就採用RGB空間來儲存映像。一個像素24位,每8位儲存一種顏色強度(0-255),例如紅色儲存為 0xFF0000。
YUV介紹:
YUV是被歐洲電視系統所採用的一種顏色編碼方法,我國廣播電視也普遍採用這類方法。其中“Y”表示明亮度(Luminance或Luma),也就是灰階值;而“U”和“V”表示的則是色度(Chrominance或Chroma)。彩色電視採用YUV空間正是為了用亮度訊號Y解決彩色電視機與黑白電視機的相容問題,使黑白電視機也能接收彩色電視訊號。
YUV與RGB相互轉換的公式如下(RGB取值均為0-255):
Y = 0.299R + 0.587G + 0.114B
U = -0.147R - 0.289G + 0.436B
V = 0.615R - 0.515G - 0.100B
R = Y + 1.14V
G = Y - 0.39U - 0.58V
B = Y + 2.03U
2.2 將映像8*8分塊
將原始映像轉換為YUV格式後,對映像按一定的採樣格式進行採樣,常見的格式有4:4:4,4:2:2和4:2:0。
取樣完成後,將映像按8*8(pixel)劃分成MCU。
2.3 離散餘弦變換(DCT)
離散餘弦變換DCT(Discrete Cosine Transform)是數位率壓縮需要常用的一個變換編碼方法。任何連續的實對稱函數的付立葉變換中只含餘弦項,因此餘弦變換與付立葉變換一樣有明確的物理意義。DCT是先將整體映像分成N*N像素塊,然後對N*N像素塊逐一進行DCT變換。由於大多數映像的高頻分量較小,相應於映像高頻分量的係數經常為零,加上人眼對高頻成分的失真不太敏感,所以可用更粗的量化。
因此,傳送變換係數的數位率要大大小於傳送映像像素所用的數位率。到達接收端後通過反離散餘弦變換回到樣值,雖然會有一定的失真,但人眼是可以接受的。二維正反離散餘弦變換的算式:
其中N是像塊的水平、垂直像素數,一般取N=8。N大於8時效率增加不多而複雜性大為增加。8*8的二維資料區塊經DCT後變成8*8個變換係數,這些係數都有明確的物理意義。譬如當U=0,V=0時F(0,0)是原64個樣值的平均,相當於直流分量,隨著U,V值增加,相應係數分別代表逐步增加的水平空間頻率和垂直空間頻率分量的大小。當我們先只考慮水平方向上一行資料(8個像素)的情況時,:
可見映像訊號被分解成為直流成分;以及從低頻到高頻的各種餘弦成分;而DCT係數只是表示了該種成分所佔原映像訊號的份額大小;顯然,恢複映像資訊可以表示為這樣一個矩陣形式:F(n)=C(n)*E(n)
式中E(n)是一個基底 ,C(n)是DCT係數,F(n)則是映像訊號。
如果再考慮垂直方向上的變化,那麼,就需要一個二維的基底,即該基底不僅要反映水平方向頻率的變化;而且要反映垂直空間頻率的變化;對應於8*8的像素塊;其空間基底2所示:它是由64個像素值所組成的映像,通常也稱之為基本映像。把它們稱為基本映像是因為在離散餘弦變換的反變換式中,任何像塊都可以表示成64個係數的不同大小的組合。既然基本映像相當於變換域中的單一的係數,那麼任何像元也可以看成由64個不同幅度的基本映像的組合。這與任何訊號可以分解成基波和不同幅度的諧波的組合具有相同的物理意義。
2.4 量化(quantization)
量化過程是一個將訊號的幅度離散化的過程,離散訊號經過量化後變為數字訊號。
由於HVS對低頻訊號更為敏感,所以對訊號的低頻部分採用相對短的量化步長,對訊號的高頻部分採用相對長的量化步長。這樣可以在一定程度上,得到相對清晰的映像和更高的壓縮率。
2.5 Z字形編碼(zigzag scan)
按Z字形把量化後的資料讀出,例:
2.6 使用行程長度編碼(RLE)對交流係數(AC)進行編碼
所謂遊程長度編碼是指一個碼可以同時表示碼的值和前面有幾個零。這樣就發揮了Z字型讀出的優點,因為Z字型讀出,出現連零的機會比較多,特別到最後,如果都是零,在讀到最後一個數後,只要給出“塊結束”(EOB)碼,就可以結束輸出,因此節省了很多碼率。
例:圖中按Z字形抽取和遊程編碼得到碼值為
(0,1,0)(1,2,0)(0,5,0)(0,4,0)(4,8,1)EOB
這樣一個4*4的矩陣用很少的數值就能表示!
2.7 熵編碼
常用的熵編碼有變長編碼,即哈夫曼編碼。
哈夫曼的編碼方法:對出現機率大的符號分配短字長的二進位碼,對出現機率小的符號分配長字長的二進位碼,得到符號平均碼長最短的碼。
哈夫曼編碼的步驟:(1). 把信源符號按機率大小順序排列, 並設法按逆次序分配碼字的長度。 (2). 在分配碼字長度時,首先將出現機率最小的兩個符號的機率相加合成一個機率 (3). 把這個合成機率看成是一個新組合符號地機率,重複上述做法直到最後只剩下兩個符號機率為止。 (4). 完成以上機率順序排列後,再反過來逐步向前進行編碼,每一次有二個分支各賦予一個二進位碼,可以對機率大的賦為零,機率小的賦為1。
關於AC/DC係數的編碼
1.AC係數的Huffman編碼
經過Z掃描和遊程編碼後的非零AC係數被表述為符號A和符號B。符號A由(Runlength,Size)構成,符號B(Amplitude)。
Runlength為非零AC係數前連續為0的AC係數;
Size則是表示編碼Amplitude所需要的位元位元;
Amplitude為AC係數的幅值。
實際操作時,JPEG用一個8位的值RS來表示符號A,RS=RRRRSSSS,對於一個非零的AC係數,高四位用來表示Runlength,低四位用來表示Size。(00000000)用來表示EOB。
對符號B進行變字長整數(VLI)編碼,將符號B的VLI碼放在A後從而形成對A,B編碼的最終結果。
2.DC係數的Huffman編碼
對於DC係數,與非零的AC係數類似,它將相鄰兩塊DC係數的差值(DIFF)描述如下的符號對:符號A為(Size),符號B為(Amplitude)。
Size表示為編碼Amplitude所需要的位元;
Amplitude表示DC係數的幅值。
在JPEG標準中,對符號A根據相應的Huffman表進行變字長編碼,對符號B進行變字長整數編碼,而後將符號B 的VLI碼放在符號A的Huffman碼後,從而完成了對DIFF的編碼。
在JPEG標準中沒有定義預設的Huffman表,使用者可以根據實際應用自由選擇,可以預先定義一個通用的Huffman表,也可以針對一幅特定的映像,在壓縮編碼前通過搜集其統計特性來計算Huffman表。
三,JPEG解碼的主要過程。
3.1 讀入檔案的相關資訊
按照JPEG檔案資料存放區方式,把要解碼的檔案的相關資訊一一讀出,為接下來的解碼工作做好準備。參考方法是,設計一系列的結構體對應各個標記,並儲存標記內表示的資訊。其中映像長寬、多個量化表和哈夫曼表、水平/垂直採樣因子等多項資訊比較重要。以下給出讀取過程中的幾個問題。
1. 讀取檔案的大體結構
JFIF格式的JPEG檔案(*.jpg)的一般順序為:
SOI(0xFFD8),APP0(0xFFE0),[APPn(0xFFEn)]可選,
DQT(0xFFDB),SOF0(0xFFC0),DHT(0xFFC4),SOS(0xFFDA),
壓縮資料,EOI(0xFFD9)。
2. 讀取哈夫曼表資料;
3. 建立哈夫曼樹。
在準備好所有的圖片資訊後,就可以對圖片資料進行解碼了。
關於AC,DC係數的解碼
1. AC係數的解碼
通過查詢Huffman資料解出RS,從中的到Runlength和Size的值。因為符號B是通過VLI表來編碼的,所以通過查詢Size的值可以得到Amplitude。這樣就可以解出符號A和符號B的值了。
2. DC係數的解碼
同理,先查詢Huffman表解出Size的,通過Size解出DIFF,將其與上一個8*8塊的DC係數數值相加,最終得到該塊的DC係數。
3.2 MCU中顏色分量(Y,U,V)的解碼
映像資料流是有MCU組成,而MCU是用資料單元和顏色分量構成。映像資料流是以位(bit)為單位儲存資訊的。並且內部的資料都是在編碼時通過正向離散餘弦變換(FDCT)進行時空域向頻率域變換而得到的結果,所以對於每個顏色分量單元都應該由兩部分組成:1個直流分量和63個交流分量。
顏色分量單元內部綜合運用了RLE行程編碼和哈夫曼編碼來壓縮資料。每個像素的資料流由兩部分構成:編碼和數值,並且兩者基本以互相隔開方式出現(除非該編碼的權值為零)。解碼的過程其實就是哈夫曼樹的尋找過程。
3.3 直流係數的差分編碼
把所有的顏色分量單元按顏色分量(Y、Cr、Cb)分類。每一種顏色分量內,相鄰的兩個顏色分量單元的直流變數是以差分來編碼的。也就是說,通過之前解碼出來的直流變數數值只是使用中色彩分量單元的實際直流變數減去前一個顏色分量單元的實際直流變數。也就是說,當前直流變數要通過前一個顏色分量單元的實際(非解碼)直流分量來校正:
DCn=DCn-1+Diff
其中Diff為差分校正變數,也就是直接解碼出來的直流係數。但如果使用中色彩分量單元是第一個單元,則解碼出來的直流數值就是真正的直流變數。
3個顏色分量的直流變數是分開進行差分編碼的。也就是說,為1張圖片解碼時應設定3個獨立的直流校正變數。
3.4 反量化
反量化的過程比較簡單。只需要對8*8的顏色分量單元的64個值逐一乘以對應的量化表內位置相同的值則可。映像內全部的顏色分量單元都要進行反量化。
3.5 反Zig-zag編碼
3.6 反離散餘弦變換
之前提到,檔案中的資料是在編碼時通過正向離散餘弦變換(FDCT)進行時空域向頻率域變換而得到的結果,所以現在解碼就必須將其反向離散餘弦變換(IDCT),就是把顏色分量單元矩陣中的頻率域數值向時空域轉換。並且,原來的頻率域的矩陣大小為8*8,則經過反向離散餘弦變換後,時空域的矩陣仍然是8*8。
3.7 YCrCb向RGB轉換
要在螢幕上顯示映像,就必須以RGB模式表示映像的顏色。所以,解碼時需要把YCrCb模式向RGB模式轉換。
另外,由於離散餘弦變化要求定義域的對稱,所以在編碼時把RGB的數值範圍從[0,255]統一減去128位移成[-128,127]。因此解碼時必須為每個分量加上128。具體公式如下:
R= Y +1.402*Cb +128;
G=Y-0.34414*Cr -0.71414*Cb +128;
B= Y +1.772*Cb +128;
還有一個問題,通過變換得出的R、G、B值可能超出了其定義域,所以要作出檢查。如果大於255,則截斷為255;如果小於0,則截斷為0。
至此,每個MCU的解碼已經完成。