轉載請注明出處:(http://www.jianshu.com/p/934269064bfb)
本篇文章翻譯自谷歌出的優化視頻里面的光頭佬(Colt McAnlis),原文地址需翻墻, 以下正文:
JPG格式是1992年出現的最早進的圖片緊縮技術之1。爾后,它就成為互聯網圖片的主力。這固然和JPG背后的技術有關,JPG的工作原理異常復雜,它需要深入理解人眼是如何調劑對色采和圖象邊沿的感知。
在研究這些東西前(你也1樣,如果你在瀏覽此文),我想把JPG的編碼原理分解成幾部份,這樣我們就能夠更好的理解怎樣制作更小的JPG文件。
JPG的緊縮方案被分成幾個步驟,下圖很好的把它們展現出來,我們接下來會對每一個步驟作詳細介紹。
有損數據緊縮的1個關鍵原則是:人類的感知能力沒有計算機的精確。科學證明,人的眼睛只能辨別1000萬種不同的色彩。但是,還有很多東西會影響人眼對色采的感知,明顯的突出色采錯覺,又或你應當還記得去年這件衣服把互聯網都炸開了。這里的重點是人眼可以很好的控制它所感知的色彩。
量化是有損緊縮種的1種情勢,不過JPG使用的是1種不同的方式:色彩模型。1個色采空間是1個特定的色彩組織,它的色彩模型代表了這些色彩表示的數學公式。(例如3色彩RGB,或CMYK)
這個進程的強大的地方是,你可以把1個色彩模型轉換成另外1個,這意味著你可以將1個給定色彩的數學表達式轉成1組完全不同的值。
例如,下面這類的色彩,它可以用RGB和CMYK兩張不同的色彩模型指替,它們對人眼來講是1樣的色彩,但卻可以被表示成不同的數值集。
將JPG從RGB色彩模型轉換成Y,Cb,Cr色彩模型,包括亮度(Y)、色度藍(CB)和色度紅(CR)。這樣做的緣由,是心理視覺實驗(又名:大腦處理如何處理眼睛看到的信息)表明,人眼對亮度比色度更敏感,這意味著我們會疏忽掉較大的色度變化,而不影響我們對圖片的感知。因此,我們可以在人眼發覺前對CbCr通道用力的緊縮。
YCbCr色彩空間其中1個有趣的細節是,Cb/Cr通道有比較少的顆粒度細節,也就是說它們包括的信息沒有Y通道的多。所以JPG的算法就把Cb和Cr通道的大小縮減到原來的1/4(注意,在具體的處理上會有些細微的差別,但我這里就不展開了…),這類做法就叫做縮減取樣。
有1件很重要的事需要說明,縮減取樣是1個有損緊縮進程(緊縮過后你沒法恢復回原來的色彩,只能得到1個近視的值),但對人類視覺皮層的可視化組件的整體影響是最小的。由于我們沒有對亮度(Y)做處理,只對CbCr通道做縮減,所以對人的視覺系統的影響較低。
從現在開始,在JPG上做的所有操作都是基于8x8像素塊。這樣做是由于我們通常認為8x8像素塊里沒有太多的差異,即便是很復雜的圖片,局部區域的像素也常常類似,這類類似性有助于以后我們對它緊縮。
在這里我們需要注意1點,我們要介紹JPG編碼的常見”神器”之1。”色采滲透”是沿著鋒利邊沿的色彩可以”滲透”到另外一邊。這是由于色度通道,它代表像素的色彩,平均到單個色彩需要4個像素1塊,而有些塊穿過了鋒利邊沿。
到現在為止,這些步驟都平淡無奇。色采空間,縮減取樣,分塊處理在圖片數據緊縮領域都是小兒科。但是現在…真實的數學要上場了。
DTC(離散余弦轉換)的關鍵是,它假定任何1個數字信號都可以被1個余弦組合函數重建。
例如,如果我們有下面這個坐標圖:
你可以看到它實際上是cos(x)+cos(2x)+cos(4x)相加的結果
也許更好的展現這個進程,是在1個平面上給定1組余弦函數來真實的解碼1張圖片。為了展現這個進程,我貼了互聯網上最驚人之1的GIF圖片:在1個平面上用余弦函數來編碼1塊8x8像素。
上面是1張正在重建的圖片(最左側那個區域)。每幀我們都使用右邊面版新的基準值,來乘1個權重值(右邊區域的文字)來產生圖片(中間區域)。
如你所見,靠著帶權重的不同余弦值相加,我們可以重構出我們的原圖。(這多屌啊~)
這個的基礎背景知識是離散余弦變換原理。核心思想是,在不同頻率上,8x8塊都可以由1組權重余弦變化的和代表。這里的重點是算出要輸入的余弦值,和它們的權重。
想要得出”使用甚么余弦值”是很容易的,經過大量的測試以后,選出1組最好的余弦值,它們是我們的基礎函數,下圖是形象化的進程。
而”它們怎樣被加權在1起”的問題也很簡單,直接套用下面的公式。
我就不介紹這些值得含義了,你可以在這個維基頁面查看它們含義。
每一個色采通道的8x8像素塊都會用上面這個公式和基礎函數生成新的1個8x8矩陣,表示在這個進程中使用的權重。下面是1張表示這個進程的圖片:
這個矩陣G,用來代表重建圖片的基礎權重(在動畫右邊上方的小10進制數)。對每一個基礎余弦值,我們都將它乘與矩陣里的權重,然后全部相加,得到我們終究的圖片。
基于這點,我們就不再操作色彩空間而直接處理G矩陣(基礎權重),以后所有的緊縮操作都直接在這個矩陣上做。
這里的問題是我們現在將字節對齊的整數轉成真實的數字。這樣會很容易膨脹我們的信息(從1byte變成1個float(4個字節))。為了解決這問題,緊縮得更極致,我們將進入量化階段。
我們不想緊縮浮點數據,它會膨脹我們的信息流,并且不高效。因此,我們要找1種方法來將權重矩陣轉換到0⑵55這范圍里。我們可以直接在矩陣里將最小/最大值(分別是⑷15.38和77.13)除以這個范圍來得到1個在0⑴的值,再將這個值乘以255得到最后的值。
例如:[34.12- ⑷15.38] / [77.13?—?⑷15.38] *255= 232
這樣做可以,但代價是精度會顯著降落。這類縮放將產生1個散布不均勻的值,其結果是會致使圖片質量的降落。
JPG用了另外1種方法。不同于使用矩陣的范圍來作為縮放值,JPG用了1個可量化的預矩陣。這類可量化矩陣不需要成為數據流的1部份,它們可成為編碼的1部份。
這個例子展現了對每張圖片使用的量化因子矩陣:
現在我們使用Q和G矩陣,來計算我們的量化DCT系數矩陣:
例如,用G矩陣的[0,0]=⑷15.37和Q[0,0]=16這兩個數字:
得到最后的矩陣是:
你看現在這個矩陣多變成多簡單,它現在包括了大量的小整數或0,這會有助于緊縮。
簡單點說,我們把這個進程分別利用在Y,CbCr通道,這樣我們需要兩個不同的矩陣,1個是Y通道,另外一個是C通道:
量化緊縮有兩種重要的方式:
1. 限制可用范圍的權重,減少數字的位數和替換它們。
2. 將大部份的權重變成同1個數字或0,提高第3步緊縮,熵編碼。
這樣的量化方式主要來源于JPEG。由于圖象的右下方常常有最大的量化因子,JPEG偏向于將這些圖象組合。量化因子矩陣可以通過改變JPEG的’質量值’直接控制。(稍后介紹)
現在我們可以回到整數世界了,將眼光轉移到對色彩塊做有損緊縮階段。當看我們的轉化數據,你應當會注意到1些有趣的現象:
從左上角到右下角,0出現的數量急速上升。但主行和主列的順序其實不理想,由于這些0都交織在1起,而不是放在1起。
相反,我們可以從左上角開始以Z字形來回穿梭直到右下角的方式遍歷全部矩陣。
我們的亮度矩陣的順序變成:
?26,?3,0,?3,?2,?6,2,?4,1,?3,1,1,5,1,2,?1,1,?1,2,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
1旦數據變成這個格式,下1步就簡單了:按順序履行RLE,然后對結果進行統計編碼(霍夫曼/算術/ANS)。
Boom.你的數據塊變成JPG編碼了。
現在你已理解JPG文件是怎樣創建的,是該重新審視圖片質量參數這個概念了,你通常會在PhotoShop導出JPG圖片時會看到。(或在其他地方)
這個參數我們稱之為q,是1個從1到100的整數。你應當把q當作1個丈量圖片質量的值:q越大表示圖片的質量越高,固然文件就越大。
這個質量值用在量化階段,用來縮放適合的量化因子。因此對每一個基準權重,量化階段現在類似于* round(Gi,k / alpha*Qi,k)。*
其中alpha符號用來當作質量參數。
當alpha或Q[x,y]越大(當alpha的值越大那末q參數的值就越小),更多信息是丟失,文件就越小。
所以,如果你想要靠更多的視覺假象來得到1張更小的圖片,那末你可以在到處圖片階段設置1個更小的質量值。
注意上圖,那張質量為1的圖片里,我們可以清晰的看到在成塊階段和量化階段的痕跡。
更重要的是質量參數大小取決于具體的圖片。由于每張圖片都是唯1的,它們都有不同的展現效果,那末Q值也是唯1的。
由于你已理解了JPG的算法工作原理,1些事情就變得清晰了:
如果你想要自己處理這么多東西,那末這個1000行不到文件可以幫你弄定這些問題。
PS:由于本文觸及到的數學算法比較多,本人水平有限,如有譯錯,請留言討論。
下一篇 復雜鏈表的復制