jpeg編碼學習筆記
各種圖片格式目的是在網絡傳輸和存儲的時候使用更少的字節,即起到壓縮的作用。在圖片格式解碼後,無論圖片的格式,圖片數據都是像素數組。
本文將嘗試通過JPEG這種圖片編碼格式的學習,瞭解圖片編碼的祕密。
JPEG簡介
一張100X100大小的普通圖片,如果未經壓縮,大概在100*100*4*8bits=0.3MB左右,這也是圖片在內存中佔用的內存大小。
通常JPEG文件相對於原始圖像,能夠得到1/8的壓縮比,如此高的壓縮率是如何做到的呢?
JPEG能夠獲得如此高的壓縮比是因爲使用了有損壓縮技術,所謂有損壓縮,就是把原始數據中不重要的部分去掉,以便可以用更小的體積保存。
JPEG編碼是基於兩個idea,第一個是基於相鄰的像素信息是相近的,即空間冗餘性,儘量少記錄重複的數據來達到壓縮的效果。第二個是基於圖像信號的頻譜特性,圖像包含各種頻率,大部分爲低頻頻譜,少部分爲高頻頻譜。可以保留包含圖像信息較多的低頻頻譜,捨去包含圖像信息較少的高頻頻譜。而達到圖片質量沒有可察覺的損傷,又能達到壓縮的效果。這也說明了JPEG是有損編碼。
JPEG的編碼過程
編碼流程如下圖:
1.色彩空間轉換
將RGB色彩空間轉換到其他色彩空間,比如YUV色彩空間。
出現YUV,主要有兩個原因,一個是爲了讓彩色信號兼容黑白電視機,另外一個原因是爲了減少傳輸的帶寬。
下圖爲老電視後面的色差接口。
YUV中,Y表示亮度,U和V表示色度,總之它是將RGB信號進行了一種處理,根據人對亮度更敏感些,增加亮度的信號,減少顏色的信號,以這樣“欺騙”人的眼睛的手段來節省空間。YUV的格式也很多,不過常見的就是422和420格式。
下圖爲420格式,每四個Y共用一組UV分量,每個YUV分量和RGB一樣都用8位來表示,YUV色彩空間就比RGB色彩空間所需的存儲空間少一半,數據就被壓縮到了一半。
2.離散餘弦變換DCT
簡單地說,DCT是傅里葉變換的一種,變換後會得到一個係數。
有關DCT的詳細介紹可以看這個視頻。
在JPEG壓縮過程中,經過顏色空間的轉換,每一個色值表示成8X8的圖像塊,下圖爲一個色彩域取樣塊,轉化爲頻率域的DCT係數塊:
圖片經過此步驟會輸出一個頻率係數矩陣,左上的係數幅度值最大,越往右下,係數的幅度值越小,頻率越高。大部分圖片信息都在頻率域矩陣左上區域,右下幾乎不含有圖片信息,甚至只含雜波。
注意:轉換後的DCT係數塊矩陣(x,y)處的值並不和轉換前的顏色空間矩陣(x,y)處的像素值直接對應。
這一步驟沒有壓縮作用,它目的是爲下一步驟找低頻和高頻區域,也就是找出留下的區域和捨去的區域。
3.量化
此步是將上步求得的DCT係數的簡化的過程,利用人眼對高頻部分不敏感的特性來捨去高頻部分。
這裏有兩張表分別對亮度和色度做量化處理。
標準亮度量化表:
標準色度量化表:
量化表是控制 JPEG 壓縮比的關鍵。
DCT係數矩陣中的不同位置的值代表了圖像數據中不同頻率的分量,這兩張表中的數據是根據人眼對不同頻率的敏感程度的差別所積累下的經驗制定的。這個步驟除掉了一些高頻量, 損失了很多細節。
但事實上人眼對高空間頻率遠沒有低頻敏感.所以處理後的視覺損失很小。
另一個重要原因是所有的圖片的點與點之間會有一個色彩過渡的過程。大量的圖象信息被包含在低空間頻率中。 經過量化處理後, 在高空間頻率段, 將出現大量連續的零。
把上面的DCT係數塊通過量化後的結果如下圖,其中第一個數-26是直流DC部分,它是一塊圖象樣本的平均值,包含了原始8x8圖像塊中的很多能量,其餘的是交流AC部分。
計算方法爲:頻率係數矩陣的數值除以對應量化表位置上的數值,並四捨五入到最近的整數。
解碼的時候,反量化步驟會乘回量化表相應值,但是四捨五入導致低頻有所損失,高頻0字段被捨棄。此步爲有損運算,會導致圖像質量變低。所以說JPEG是有損編碼。
4.zig-zag遊程編碼
量化後的數據還可以進行簡化,更大程度的去壓縮。
根據上面的zig-zag表重排數據的過程:
根據ZigZag表的規則對量化後的數據進行重排後的結果中可以看到出現連續的多個0,這樣有利於進行遊程編碼。
5.範式Huffman編碼
基本原理
huffman編碼的基本原理是根據數據中元素的使用頻率,調整元素的編碼長度,以得到更高的壓縮比。
舉個例子,比如下面這段數據
AABCBABBCDBBDDBAABDBBDABBBBDDEDBD
這段數據裏面包含了33個字符,每種字符出現的次數統計如下
字符 | A | B | C | D | E |
次數 | 6 | 15 | 2 | 9 | 1 |
如果我們用我們常見的定長編碼,因爲有5個文字,可以用3個bit表示,那麼這段文字共需要3*33 = 99個bit來保存
字符 | A | B | C | D | E |
編碼 | 001 | 010 | 011 | 100 | 101 |
如果根據字符出現的概率,使用如下的編碼
字符 | A | B | C | D | E |
編碼 | 100 | 0 | 1110 | 10 | 1111 |
那麼這段文字共需要3x6 + 1x15 + 4x2 + 2x9 + 4x1 = 63bit,壓縮比爲63%。 是較短的編碼不能夠是較長編碼的前綴,比如上面這個編碼,就是由下面的這顆二叉樹生成的。
哈弗曼編碼一般都是使用二叉樹來生成的,頻率會高的數據對應的樹節點的位置越高。這樣得到的編碼符合前綴規則,也就是較短的編碼不能夠是較長編碼的前綴。
Huffman編碼在JPEG中
假設在JPEG量化處理後的數據爲:
35,7,0,0,0,-6,-2,0,0,-9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,…,0
根據RLE編碼(遊程編碼)規則
1、用固定的4位來存儲重複的數量,所以最多重複內容可以記錄數量爲15,超過15次要進行分段處理;
2、只將0作爲重複的內容,每個數值記錄前面有多少重複的0,末尾如果都是0用EOB作爲代表;
3、此步不包含第一個數值,第一個數爲直流係數,此步只處理交流係數。
得到處理結果:
爲了提高儲存效率, JPEG 裏並不直接保存數值, 而是將數值按位數分成 16 組,JPEG提供了一張標準的碼錶用於對這些數字編碼
舉例來說,第3個單元中的“-6”這個數字,在表中的位置是長度爲3的那組,所對應的bit碼是“001”,由於這種編碼附帶長度信息,所以我們的數據變成了如下的格式。
對於括號前面的數字的編碼,分成DC編碼和AC編碼。
下表是針對直流(DC)部分即第一個數字的哈弗曼表,由於直流部分沒有前置的0,所以取值範圍在0~15之間。
對於其餘的交流(AC)部分,取值範圍在0~255,哈夫曼表如下:
完整個編碼過程如下表,最終的數據使用10個字節保存了原本長度爲64字節的數據,JPEG的壓縮算法完成。