JPEGを読む(9) AC係数のデコード(DCT、量子化)
AC係数のデコード
8×8のDCT係数のうち先頭を除く63個をAC係数と呼ぶ。(3)で後回しにしたAC係数の部分を見る。
JPEGを読む(3) ハフマン符号の復号準備 - yunomuのブログ
この中のDecode_ZZ(K)
の部分はDCと同じで、RECEIVE
してEXTEND
している。DCと異なるのはDECODE
で取得したハフマン符号値の扱いになる。
RS = DECODE SSSS = RS modulo 16 RRRR = SRL RS 4 R = RRRR
とあるように、DECODE
でハフマン符号を読み取り、取得した値を上位と下位の4ビットずつに分けている。SSSS = 0
の時は一旦無視して、上位4ビットの表す数R
だけZZ
のインデックスK
をスキップしている。そしてDecode_ZZ(K)
でSSSS
の示す値をZZ(K)
に格納する。R
は4ビットしかなく15までの値しか表現できないため、ZZ
の中で0が15以上連続する場合はSSSS = 0
とする。
つまりAC係数は0についてのみのランレングス符号化されている。おそらくほとんどの値が0なんだろう。
DCTとZZと量子化の関係
ちょっと一旦わかったことまとめ。
DCT(離散コサイン変換)
ここでちょっとDCTの話。定義はここで紹介されているのがわかりやすい。
離散コサイン変換 - MATLAB & Simulink - MathWorks 日本
要するに、8×8の値を8×8=64種類の正弦波の和として表現し、それぞれの重みを8×8のDCT係数に変換するということ。8×8行列の値を8×8行列に変換しても情報量は変わっていない気がするけど、画像の場合は8×8の中でそれほど複雑に値が変化しないので、DCT係数のほとんどが0になる。この0が続く部分をランレングス符号で圧縮することができるので、画像の圧縮にはよくDCTが使われるらしい。この段階では情報の欠落は発生していない。
DCTの定義を見ると、DC成分は周波数0を表していて、他の値のベースになるので確かに必ず値が入っていそうではある。かつ隣の8×8ブロックとの連続性もありそうなので、DCだけを差分符号化するのは理に適っている。コンポーネントのH, Vの値で近隣の8×8ブロックをグループ化していたのも、差分の絶対値を小さくする効果がありそう。絶対値が小さいと値を表現するビット数が少なくなる。ビット長が短い方に偏るので、ビット長を表現するハフマン符号の圧縮効果も高くなる。
ところでもしかしてDCとかACって直流と交流ってこと?
Zig-zag sequence
8×8=64個のDCT係数はFigure A.6のジグザグ順序で配列ZZ
に格納する。
これもどうしてかと思っていたんだけど、DCTの周波数が少なく単純なデータから順に並べることで0が連続する部分を増やし、ランレングス符号の圧縮効果を高めるためなんだろう。
量子化
最初の方で飛ばしちゃったけど、JPEGファイルの最初の方に量子化表(DQT)という64個の値がある。
Figure A.5の符号化/復号化の流れを見ると、これは単純に符号化時にDCT係数を量子化表の値で割り、復号化の時に掛けている。
これにより、DCT係数ぞれぞれの絶対値が小さくなる。
ただしRoundがかかっているので、情報の欠落がそれなりに発生する。元の成分値が105で量子化係数が50だった場合、符号化後は2、復号後は100になり、元の値と5だけずれてしまう。つまり量子化表が品質とファイルサイズの関係を決定付けているのだろう。
手元のJPEGファイルをいくつか見たところ、おおむね高周波数の量子化係数が大きくなる傾向があった。量子化係数50の場合は50未満は0になるので、複雑な変化は多少つぶしてしまってもいいということだろう。ジグザグ順序との関連もあるし、0が多いとランレングス符号の効果も高くなる。
一方で[1, 1, 1, ..., 1]
となっているものもあった。最高品質にするとそうなるんだろう。