JPEG圖像壓縮算法流程詳解

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

JPEGJoint Photographic Exports Group的英文縮寫,中文稱之爲聯合圖像專家小組。該小組隸屬於ISO國際標準化組織,主要負責定製靜態數字圖像的編碼方法,即所謂的JPEG算法JPEG專家組開發了兩種基本的壓縮算法、兩種熵編碼方法、四種編碼模式。如下所示:

壓縮算法:

(1)有損的離散餘弦變換DCTDiscrete Cosine Transform

(2)無損的預測壓縮技術;

熵編碼方法:

(1)Huffman編碼;

(2)算術編碼;

編碼模式:

(1)基於DCT的順序模式:編碼、解碼通過一次掃描完成;

(2)基於DCT的漸進模式:編碼、解碼需要多次掃描完成,掃描效果由粗到精,逐級遞增;

(3)無損模式:基於DPCM,保證解碼後完全精確恢復到原圖像採樣值;

(4)層次模式:圖像在多個空間分辨率中進行編碼,可以根據需要只對低分辨率數據做解碼,放棄高分辨率信息;

       在實際應用中,JPEG圖像編碼算法使用的大多是離散餘弦變換、Huffman編碼、順序編碼模式。這樣的方式,被人們稱爲JPEG的基本系統。這裏介紹的JPEG編碼算法的流程,也是針對基本系統而言。基本系統的JPEG壓縮編碼算法一共分爲11個步驟:顏色模式轉換、採樣、分塊、離散餘弦變換(DCT)、Zigzag 掃描排序、量化、DC係數的差分脈衝調製編碼、DC係數的中間格式計算AC係數的遊程長度編碼、AC係數的中間格式計算、熵編碼。下面,將一一介紹這11個步驟的詳細原理和計算過程。

(1)顏色模式轉換

        JPEG採用的是YCrCb顏色空間,而BMP採用的是RGB顏色空間,要想對BMP圖片進行壓縮,首先需要進行顏色空間的轉換。YCrCb顏色空間中,Y代表亮度,Cr,Cb則代表色度和飽和度(也有人將Cb,Cr兩者統稱爲色度),三者通常以Y,U,V來表示,即用U代表Cb,用V代表CrRGBYCrCb之間的轉換關係如下所示:

Y = 0.299R+0.587G+0.114B

Cb = -0.1687R-0.3313G+0.5B+128

Cr = 0.5R=0.418G-0.0813B+128

一般來說,C 值 (包括 Cb Cr) 應該是一個有符號的數字但這裏通過加上128,使其變爲8位的無符號整數,從而方便數據的存儲和計算。

R = Y+1.402(Cr-128)

G = Y-0.34414(Cb-128)-0.71414(Cr-128)

B = Y+1.772(Cb-128)

(2)採樣

        研究發現,人眼對亮度變換的敏感度要比對色彩變換的敏感度高出很多。因此,我們可以認爲Y分量要比Cb,Cr分量重要的多。在BMP圖片中,RGB三個分量各採用一個字節進行採樣,也就是我們常聽到的RGB888的模式;而JPEG圖片中,通常採用兩種採樣方式:YUV411YUV422,它們所代表的意義是Y,Cb,Cr三個分量的數據取樣比例一般是411或者422411含義就是:在2x2的單元中,本應分別有4Y4U4V值,用12個字節進行存儲。經過4:1:1採樣處理後,每個單元中的值分別有4個Y、1個U、1V,只要用6個字節就可以存儲了)。這樣的採樣方式,雖然損失了一定的精度但也在人眼不太察覺到的範圍內減小了數據的存儲量。當然,JPEG格式裏面也允許將每個點的U,V值都記錄下來;

(3)分塊

        由於後面的DCT變換是是對8x8的子塊進行處理的,因此,在進行DCT變換之前必須把源圖象數據進行分塊。源圖象中每點的3個分量是交替出現的,先要把這3個分量分開,存放到3張表中去。然後由左及右,由上到下依次讀取8x8的子塊,存放在長度爲64的表中,即可以進行DCT變換。注意,編碼時,程序從源數據中讀取一個8x8的數據塊後,進行DCT變換,量化,編碼,然後再讀取、處理下一個8*8數據塊。 

JPEG 編碼是以每8x8個點爲一個單位進行處理的所以如果原始圖片的長寬不是 的倍數都需要先補成8的倍數使其可以進行一塊塊的處理。將原始圖像數據分爲8*8的數據單元矩陣之後,還必須將每個數值減去128,然後一一帶入DCT變換公式,即可達到DCT變換的目的。圖像的數據值必須減去128,是因爲DCT公式所接受的數字範圍是-128127之間。

(4)離散餘弦變換

        DCTDiscrete Cosine Transform,離散餘弦變換),是碼率壓縮中常用的一種變換編碼方法。任何連續的實對稱函數的傅里葉變換中只含有餘弦項,因此,餘弦變換同傅里葉變換一樣具有明確的物理意義。DCT是先將整體圖像分成N*N的像素塊,然後針對N*N的像素塊逐一進行DCT操作。需要提醒的是,JPEG的編碼過程需要進行正向離散餘弦變換,而解碼過程則需要反向離散餘弦變換。

正向離散餘弦變換計算公式:


反向離散餘弦變換計算公式:


這裏的N是水平、垂直方向的像素數目,一般取值爲8。8*8的二維像素塊經過DCT操作之後,就得到了8*8的變換系數矩陣。這些係數,都有具體的物理含義,例如,U=0,V=0時的F(0,0)是原來的64個數據的均值,相當於直流分量,也有人稱之爲DC係數或者直流係數。隨着U,V的增加,相另外的63個係數則代表了水平空間頻率和垂直空間頻率分量(高頻分量)的大小,多半是一些接近於0的正負浮點數,我們稱之爲交流係數AC。DCT變換後的8*8的係數矩陣中,低頻分量集中在矩陣的左上角。高頻成分則集中在右下角。

這裏,我們暫時先只考慮水平方向上一行數據(8個像素)的情況時的DCT變換,從而來說明其物理意義。如下圖所示:

原始的圖像信號(最左邊的波形)經過DCT變換之後變成了8個波,其中第一個波爲直流成分,其餘7個爲交流成分。


可見圖像信號被分解爲直流成分和一些從低頻到高頻的各種餘弦成分。而DCT係數只表示了該種成分所佔原圖像信號的份額大小。顯然,恢復圖像信息可以表示爲下面的式子:

F(n) = C(n)*E(n),這裏,E(n)是一個基底,C(n)是DCT係數,F(n)則是圖像信號;如果考慮垂直方向的變化,那就需要一個二維的基底。大學裏面的信號處理,傅里葉變換等課程上也講過,任何信號都可以被分解爲基波和不同幅度的諧波的組合,而DCT變換的物理意義也正是如此。

由於大多數圖像的高頻分量比較小,相應的圖像高頻分量的DCT係數經常接近於0,再加上高頻分量中只包含了圖像的細微的細節變化信息,而人眼對這種高頻成分的失真不太敏感,所以,可以考慮將這一些高頻成分予以拋棄,從而降低需要傳輸的數據量。這樣一來,傳送DCT變換系數的所需要的編碼長度要遠遠小於傳送圖像像素的編碼長度。到達接收端之後通過反離散餘弦變換就可以得到原來的數據,雖然這麼做存在一定的失真,但人眼是可接受的,而且對這種微小的變換是不敏感的。

(5)Zigzag掃描排序

         DCT 將一個 8x8 的數組變換成另一個 8x8 的數組但是內存裏所有數據都是線形存放的如果我們一行行的存放這 64 個數字每行的結尾的點和下行開始的點就沒有什麼關係所以 JPEG 規定按如下圖中的數字順序依次保存和讀取64 DCT的係數值


這樣數列裏的相鄰點在圖片上也是相鄰的了。不難發現,這種數據的掃描、保存、讀取方式,是從8*8矩陣的左上角開始,按照英文字母Z的形狀進行掃描的,一般將其稱之爲Zigzag掃描排序。如下圖所示:


(6)量化

        圖像數據轉換爲DCT頻率係數之後,還要進行量化階段,才能進入編碼過程。量化階段需要兩個8*8量化矩陣數據,一個是專門處理亮度的頻率係數,另一個則是針對色度的頻率係數,將頻率係數除以量化矩陣的值之後取整,即完成了量化過程。當頻率係數經過量化之後,將頻率係數由浮點數轉變爲整數,這才便於執行最後的編碼。不難發現,經過量化階段之後,所有的數據只保留了整數近似值,也就再度損失了一些數據內容。JPEG算法中,由於對亮度和色度的精度要求不同,分別對亮度和色度採用不同的量化表。前者細量化,後者粗量化。
    下圖給出JPEG的亮度量化表和色度量化表,該量化表是從廣泛的實驗中得出的。當然,你也可以自定義量化表。



這兩張表依據心理視覺閥製作對 8bit 的亮度和色度的圖象的處理效果不錯。量化表是控制 JPEG 壓縮比的關鍵,這個步驟除掉了一些高頻量損失了很多細節信息。但事實上人眼對高頻信號的敏感度遠沒有低頻信號那麼敏感。所以處理後的視覺損失很小,從上面的量化表也可以看出,低頻部分採用了相對較短的量化步長,而高頻部分則採用了相對較長的量化步長,這樣做,也是爲了在一定程度上得到相對清晰的圖像和更高的壓縮率。另一個重要原因是所有的圖片的點與點之間會有一個色彩過渡的過程,而大量的圖象信息被包含在低頻率空間中,經過DCT處理後在高頻率部分, 將出現大量連續的零

(7)DC係數的差分脈衝調製編碼

        8*8的圖像塊經過DCT變換之後得到的DC係數有兩個特點:

(1)係數的數值比較大;

(2)相鄰的8*8圖像塊的DC係數值變化不大;

根據這兩個特點,DC係數一般採用差分脈衝調製編碼DPCMDifference Pulse Code Modulation),即:取同一個圖像分量中每個DC值與前一個DC值的差值來進行編碼。對差值進行編碼所需要的位數會比對原值進行編碼所需要的位數少了很多。假設某一個8*8圖像塊的DC係數值爲15,而上一個8*8圖像塊的DC係數爲12,則兩者之間的差值爲3

(8)DC係數的中間格式計算

        JPEG中爲了更進一步節約空間,並不直接保存數據的具體數值,而是將數據按照位數分爲16組,保存在表裏面。這也就是所謂的變長整數編碼VLI。即,第0組中保存的編碼位數爲0,其編碼所代表的數字爲0;第1組中保存的編碼位數爲1,編碼所代表的數字爲-1或者1......,如下面的表格所示,這裏,暫且稱其爲VLI編碼表:


前面提到的那個DC差值爲3的數據,通過查找VLI可以發現,整數3位於VLI表格的第2組,因此,可以寫成(2)(3)的形式,該形式,稱之爲DC係數的中間格式。

(9)AC係數的行程長度編碼(RLC)

        量化之後的AC係數的特點是,63個係數中含有很多值爲0的係數。因此,可以採用行程編碼RLCRun Length Coding)來更進一步降低數據的傳輸量。利用該編碼方式,可以將一個字符串中重複出現的連續字符用兩個字節來代替,其中,第一個字節代表重複的次數,第二個字節代表被重複的字符串。例如,(4,6)就代表字符串“6666”。但是,在JPEG編碼中,RLC的含義就同其原有的意義略有不同。在JPEG編碼中,假設RLC編碼之後得到了一個(M,N)的數據對,其中M是兩個非零AC係數之間連續的0的個數(即,行程長度),N是下一個非零的AC係數的值。採用這樣的方式進行表示,是因爲AC係數當中有大量的0,而採用Zigzag掃描也會使得AC係數中有很多連續的0的存在,如此一來,便非常適合於用RLC進行編碼。

例如,現有一個字符串,如下所示:

57,45,0,0,0,0,23,0,-30,-8,0,0,1,000.....

經過RLC之後,將呈現出以下的形式:

(0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-8) ; (2,1) ; (0,0)

注意,如果AC係數之間連續0的個數超過16,則用一個擴展字節(15,0)來表示16連續的0

(10)AC係數的中間格式

        根據前面提到的VLI表格,對於前面的字符串:

    (0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-8) ; (2,1) ; (0,0)

只處理每對數右邊的那個數據,對其進行VLI編碼查找上面的VLI編碼表格,可以發現,57在第6組當中,因此,可以將其寫成(0,6),57的形式,該形式,稱之爲AC係數的中間格式。

同樣的(0,45)的中間格式爲:(0,6),45

 (1,-30)的中間格式爲:(1,5),-30

(11)熵編碼

        在得到DC係數的中間格式和AC係數的中間格式之後,爲進一步壓縮圖象數據,有必要對兩者進行熵編碼。JPEG標準具體規定了兩種熵編碼方式:Huffman編碼和算術編碼。JPEG基本系統規定採用Huffman編碼(因爲不存在專利問題),但JPEG標準並沒有限制JPEG算法必須用Huffman編碼方式或者算術編碼方式。 

Huffman編碼:對出現概率大的字符分配字符長度較短的二進制編碼,對出現概率小的字符分配字符長度較長的二進制編碼,從而使得字符的平均編碼長度最短。Huffman編碼的原理請參考數據結構中的Huffman樹或者最優二叉樹。

Huffman編碼時DC係數與AC係數分別採用不同的Huffman編碼表,對於亮度和色度也採用不同的Huffman編碼表。因此,需要4Huffman編碼表才能完成熵編碼的工作。具體的Huffman編碼採用查表的方式來高效地完成。然而,在JPEG標準中沒有定義缺省的Huffman表,用戶可以根據實際應用自由選擇,也可以使用JPEG標準推薦的Huffman表。或者預先定義一個通用的Huffman表,也可以針對一副特定的圖像,在壓縮編碼前通過蒐集其統計特徵來計算Huffman表的值。

下面我們舉例來說明8*8圖像子塊經過DCT及量化之後的處理過程:

假設一個圖像塊經過量化以後得到以下的係數矩陣:

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係數爲15,假設前一個8*8的圖像塊的DC係數量化值爲12,則當前DC系統同上一個DC係數之間的差值爲3,通過查找VLI編碼表,可以得到DC係數的中間格式爲(2)(3),這裏的2代表後面的數字(3)的編碼長度爲2位;之後,通過Zigzag掃描之後,遇到第一個非0的AC係數爲-2,遇到0的個數爲1,AC係數經過RLC編碼後可表示爲(1,-2),通過查找VLI表發現,-2在第2組,因此,該AC係數的中間格式爲(1,2)-2;
    其餘的點類似,可以求得這個8*8子塊熵編碼的中間格式爲
(DC)(2)(3);AC(1,2)(-2),(0,1)(-1),(0,1)(-1),(0,1)(-1),(2,1)(-1),(EOB)(0,0)
    對於DC係數的中間格式(2)(3)而言,數字2查DC亮度Huffman表得到011,數字3通過查找VLI編碼表得到其被編碼爲11;
    對於AC係數的中間格式(1,2)(-2)而言,(1,2)查AC亮度Huffman表得到11011,-2通過查找VLI編碼表得到其被編碼爲01;

對於AC係數的中間格式(0,1)(-1)而言,(0,1)查AC亮度Huffman表得到00,數字-1通過查找VLI編碼表得到其被編碼爲0;

對於AC係數的中間格式(2,1)(1)而言,(2,1)查AC亮度Huffman表得到11100,數字-1通過查找VLI編碼表得到其被編碼爲0;

對於AC係數的中間格式(0,0)而言,查AC亮度Huffman表得到1010;
    因此,最後這個8*8子塊亮度信息壓縮後的數據流爲01111,1101101,000,000,000,111000,1010。總共31比特,其壓縮比是64*8/31=16.5,大約每個像素用半個比特。

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