花一天寫了個JPEG解碼器,來整理一下JPEG格式的原理
昨天花了一天的時間試著寫了一下JPEG解碼器,雖然遇到了一些麻煩,不過最後還是成功地解出了影象的資料。總共400行程式碼左右。
(解碼的核心也就這50行左右,因為只是驗證一下以前瞭解的資訊,所以看起來還是有點亂,而且沒有做各種錯誤處理,所以不要太在意啦┑( ̄Д  ̄)┍)
下面是JPEG的編碼過程的整理(因為編碼和解碼是完全對稱的所以就只說編碼,解碼可以自行腦補)(仔細看的話都能在上面那段程式碼中找到對應哦):
(圖片自制)
RGB轉YCbCr
:因為人眼對亮度比較敏感,而對於色度不那麼敏感,所以,我們就先將RGB的資料轉換到YCbCr色彩空間,便於下面的處理。
降取樣
:轉到YCbCr色彩空間後,就可以將 Cb 和 Cr 這兩個通道進行降取樣,這裡一般是將 2*2 個畫素變為 1*1 個畫素,雖然解析度下降到了四分之一,但對於人眼來說差別是不大的。(這一步是有損的)
分塊
:顧名思義,將影象分為若干個 8*8 的小塊,方便下面的處理。
DCT
:這一步的目的和RGB轉YCbCr有一些相似之處,都是將人眼較為敏感和不敏感的部分進行分離,然後就可以對減少人眼不敏感的部分的資訊量。在這一步中,DCT可以將影象的低頻(人眼敏感)和高頻(人眼不敏感)部分進行分離。這樣得到的結果是每個 8*8 小塊得到 8*8 的係數矩陣。
量化
:將DCT後得到的每個係數都除以量化矩陣中對應的值,然後進行取整。通常來說頻率較高的部分對應的量化引數比較大,這樣一來就能夠在較好地保留影象的低頻部分並去除一些高頻部分。這一步下來得到的矩陣中高頻部分幾乎全部變為0,這也為進一步的操作提供了便利。值得注意的是,JPEG中壓縮率的調整是在這一步中,量化引數越大,壓縮後的大小就會越小,但資訊的損失也就越多,圖片的失真也會更嚴重。(這一步是有損的)
Huffman編碼
:準確地說是Huffman編碼和RLE,將上一步得到的矩陣進行進一步地壓縮(這一步是無損的)。量化後得到的矩陣左上角的那個數比其他數來得大得多,所以我們將它單獨拿出來進行編碼,稱之為直流分量(DC),將剩下的稱之為交流係數(AC)。這一步會將矩陣按照 zigzag 的順序攤成一維,如下圖所示:
這樣做的好處是矩陣的高頻部分(右下角)會被安排在後面,因為它們基本上全是0,所以在編碼中有一個特殊的標記表示這之後的係數全是0,從而減少壓縮後的大小。
(話說回來,Huffman解碼這一步應該是解碼中最麻煩的一部分……位的順序搞了好久)
上面這些步驟完成之後,再加上一些必要的其他資訊(量化矩陣和Huffman的資訊,這兩個是直接沒有壓縮就儲存在檔案中的),就得到了最終的JPEG資料。
暫時先整理這麼多,以後有時間再認真寫一下解碼器,爭取某一天能夠達到 libjpeg 的水平吧 :) (以後應該會包含在 Medicat 中←某個妄圖把各種影象/音訊格式都自己實現一遍的輪子)
參考:
https://www。
w3。org/Graphics/JPEG/it
u-t81。pdf
https://
en。wikipedia。org/wiki/J
PEG