1 前言
JPEG是joint Photographic Experts Group(聯合圖像專家組)的縮寫,檔案後辍名為”.jpg”或”.jpeg”。
jpg圖檔可以說是最常見的圖檔格式了,基本上你的自拍照,要麼是png的,要麼就是jpeg的了。(有關jpeg和png的差別,請參考我的另一博文【jpeg 與 png 圖檔格式的差別】)
但它是一種有損壓縮。支援多種壓縮級别,壓縮比率通常在10:1到40:1之間,壓縮比越大,品質就越低;相反地,壓縮比越小,品質就越好。
那麼,JPEG是如何壓縮的呢?靠的就是傳說中的DCT(離散餘弦變換)。
下圖是JPEG壓縮/解壓縮的流程圖。我想你最大的疑問估計就是DCT了。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHLwEEVNJza61kMNpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLyMTN4MzNyEjMyIjMwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
2 JPEG壓縮流程
2.1 以8x8的圖象塊為基本機關進行編碼
如下圖所示。比如一個160x160大小的原始圖像,就可以分成20x20個8x8圖像塊。
每個圖像塊共64個像素。像素可以用RGB或YUV表示,需要3個byte。是以嚴格來說,上圖3個箭頭代表的資料,指的是RGB/YUV的某一個值,比如Y。
2.2 将RGB轉換為亮度-色調-飽和度系統(YUV),并重新采樣
YUV是什麼?它也是一種很不錯的圖像資料表示方法,特别是在視訊領域。
Y:指顔色的明視度、亮度、灰階值;
U:指色調;
V:指飽和度。
YUV是一個統稱,其實有很多具體格式,比如YUV420, YUV444, YUV422。
YUV的某些格式,和RGB比起來,其資料量要少很多。
比如YUV420,每個像素需要一個Y,每4個像素需要一個U/V,是以一個8*8圖像塊,資料量隻要8x8x3/2 = 96byte。而RGB需要8x8x3 = 192byte。少了一半的資料量。現在很多視訊都是YUV420作為色域。
當然啦,在本次轉換,用的是YUV444, 也就是每個像素都有YUV的值。
YUV與RGB可以互相轉換。
Y=0.299R+0.587G+0.114B
U=0.148R-0.289G+0.473B
V=0.615R-0.515G-0.1B
2.3 FDCT與IDCT
一個是正變換,一個是逆變換。反正都可以稱為離散餘弦變換。
根據8*8的二維DCT定義
其中:0<= u, v < 8
a(v) = a(u)
是輸入8x8像素的坐标。
是輸出的8x8變換結果的坐标。
不要把上式看的有多難,也不要被“離散餘弦變換”這個詞給吓到,其實他沒什麼(如果你非要去追究,那就打開“信号與系統”的書複習一下吧,我攔不住你哈),上式其實就是一個運算公式而已。
輸入就是8x8的資料矩陣,經過計算,輸出還是一個8x8的資料矩陣。
其實上式可以簡化為:
并且A和A轉置矩陣都是已知的。是以,說白了,就是個矩陣運算。對程式來說,很簡單。
稱G(0,0),也就是輸出8x8矩陣的(0,0)坐标的值,為直流系數,其他為交流系數。
之是以稱它為直流系數,是因為當u, v = 0時,cos()結果都為0,是以最後結果就是輸入矩陣的8x8的每個數值的和,再乘于a(u) x a(v) x 1/4 = 1/8。
當然了,輸入資料其實是有3個的,也就是YUV,是以對每個8x8的原始圖像資料,需要做3次DCT。
2.4 量化與反量化
定義:将DCT變換後的臨時結果,除以各自量化步長并四舍五入後取整,得到量化系數。
為什麼可以量化?!
因為經過DCT後,資料就不同了,左上方都是大數值,右下方都是小數值。比如左上方都是幾十幾百的,右下方附近,都是個位數,那麼,大數值和小數值就可以分别量化。
在術語裡,左上方稱為低頻資料,右下方稱為高頻資料。
你要是不了解,可以這麼想,既然G(0,0)都是直流分量了,那頻率不就是0?不就是所謂的低頻?^^
還是不了解?好吧,那你也可以這麼想:
比如cos(ax),a是常數,x是變量。那麼,根據頻率f = a/2π,a越大,函數的頻率越高。
看看DCT公式:
u,v 越大,則越在右下方對吧。當計算某個G(u, v)時,x, y是變量,u, v相當于常數,當u/v越大,則頻率越高!
這就是為啥右下方稱為高頻資料了!
好了,别走偏了,還繼續說量化。
JPEG系統分别規定了亮度分量和色度分量的量化表,色度分量相應的量化步長比亮度分量大。
對量化系數的處理群組織
思想:JPEG采用定長和變長相結合的編碼方法。
直流系數:通常相鄰8*8圖象塊的DC分量很接近,是以JPEG對量化後的直流分量采用無失真DPCM編碼。通常JPEG要儲存所需比特數和實際內插補點。
交流系數:經過量化後,AC分量出現較多的0。JPEG采用對0系數的行程長度編碼。而對非0值,則要儲存所需數和實際值。
ZIG-ZAG排序:為使連續的0個數增多,采用Z形編碼。
你要是不了解,看看下面的例子,就知道為啥ZIG-ZAG可以俘獲更多的0了!
3 應用舉例
3.1 編碼
某個圖象的一個8*8方塊,的亮度值。
由于一個位元組是0~255,為了減小絕對值波動,先把數值移位一下,變成-128~127。
接着,根據DCT變換公式,各種計算,獲得臨時結果。
根據亮度量化表量化後得到的量化系數矩陣
獲得量化結果:
可見,新的資料,很小,很多是0。正如上文所說,這麼多0,完全可以用遊程編碼,大大縮小資料量。
3.2 解碼
先遊程編碼恢複為
然後,根據量化表,恢複
再根據反離散餘弦變換的公式:
結果為:
再右移127,恢複原始。
和原始圖像的資料相比,基本是一樣的,或者近似的!
4 其他
必須再強調的是,JPEG壓縮是有損失的,從上面的例子就看出來,輸出結果并不是完全等于輸入。
此外,JPEG壓縮比例是可以控制的,隻不過圖像品質會變差。比如
壓縮率:10
壓縮率:50
JPEG壓縮比例,就是通過控制量化的多少來控制。比如,上面的量化矩陣Q,如果我把矩陣的每個數都double一下,那是不是會出現更多的0?!說不定都隻有G(0, 0)非0,其他都是0,如果這樣,那編碼時就可以更省空間啦,N個0隻要一個遊程編碼搞定,資料量超小。但也意味着,恢複時,會帶來更多的誤差,圖像品質也會變差了。
參考:
https://en.wikipedia.org/wiki/JPEG#Discrete_cosine_transform