昨天花了一天的時間試著寫了一下JPEG解碼器,雖然遇到了一些麻煩,不過最後還是成功地解出了影象的資料。總共400行程式碼左右。

花一天寫了個JPEG解碼器,來整理一下JPEG格式的原理

(解碼的核心也就這50行左右,因為只是驗證一下以前瞭解的資訊,所以看起來還是有點亂,而且沒有做各種錯誤處理,所以不要太在意啦┑( ̄Д  ̄)┍)

下面是JPEG的編碼過程的整理(因為編碼和解碼是完全對稱的所以就只說編碼,解碼可以自行腦補)(仔細看的話都能在上面那段程式碼中找到對應哦):

花一天寫了個JPEG解碼器,來整理一下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 的順序攤成一維,如下圖所示:

\left[ \begin{matrix} DC & AC_{1} & AC_{5} & AC_{6} & AC_{14} & AC_{15} & AC_{27} & AC_{28} & \\ AC_{2} & AC_{4} & AC_{7} & AC_{13} & AC_{16} & AC_{26} & AC_{29} & AC_{42} & \\ AC_{3} & AC_{8} & AC_{12} & AC_{17} & AC_{25} & AC_{30} & AC_{41} & AC_{43} & \\ AC_{9} & AC_{11} & AC_{18} & AC_{24} & AC_{31} & AC_{40} & AC_{44} & AC_{53} & \\ AC_{10} & AC_{19} & AC_{23} & AC_{32} & AC_{39} & AC_{45} & AC_{52} & AC_{54} & \\ AC_{20} & AC_{22} & AC_{33} & AC_{38} & AC_{46} & AC_{51} & AC_{55} & AC_{60} & \\ AC_{21} & AC_{34} & AC_{37} & AC_{47} & AC_{50} & AC_{56} & AC_{59} & AC_{61} & \\ AC_{35} & AC_{36} & AC_{48} & AC_{49} & AC_{57} & AC_{58} & AC_{62} & AC_{63} & \\ \end{matrix} \right] \rightarrow \left[ DC \right] \left[ AC_{1}, AC2, AC3, ... \right]

這樣做的好處是矩陣的高頻部分(右下角)會被安排在後面,因為它們基本上全是0,所以在編碼中有一個特殊的標記表示這之後的係數全是0,從而減少壓縮後的大小。

(話說回來,Huffman解碼這一步應該是解碼中最麻煩的一部分……位的順序搞了好久)

上面這些步驟完成之後,再加上一些必要的其他資訊(量化矩陣和Huffman的資訊,這兩個是直接沒有壓縮就儲存在檔案中的),就得到了最終的JPEG資料。

暫時先整理這麼多,以後有時間再認真寫一下解碼器,爭取某一天能夠達到 libjpeg 的水平吧 :) (以後應該會包含在 Medicat 中←某個妄圖把各種影象/音訊格式都自己實現一遍的輪子)

參考:

https://www。

w3。org/Graphics/JPEG/it

u-t81。pdf

https://

en。wikipedia。org/wiki/J

PEG