量子化行列のナゾ〜その1
〜 MPEG圧縮の仕組み 〜

はじめに
 TMPGEncの設定に「量子化行列」なんてものがあります。なんでしょう、これ。動画系掲示板で聞いてみても、過去ログを見てもよくわからない。じゃあ、検索エンジンでは、というと、これまた難解で良く分からない、という状態だと思います。ここでは、なるべく堅苦しい数式は廃して、イメージをつかむ事を優先に量子化行列を解説したいと思います。

 量子化行列を語るには、MPEG圧縮の仕組みを知らなければならないので、

 ・その1 : MPEG圧縮の仕組み
 ・その2 : 量子化行列が画質に及ぼす影響

という2部構成で行きたいと思います。

MPEG圧縮の流れ
 まずは、MPEGがどんな流れで圧縮されるのか、ですね。言葉よりも図を見たほうが速いでしょう。


Fig.1 MPEG圧縮の流れ

 わからない言葉だらけだと思いますが、この図に書いた言葉は今回の解説のキーワードになってます。覚える必要はありませんが、流れだけは把握しておいてください。

(注)今回の解説は差分圧縮を無視してますので、動き検索などは割愛しています。
   つまり、JPEG圧縮の解説をしている、と言ったほうがいいかも知れませんね。

画像圧縮の考え方
 話が前後しますが、現在の画像圧縮の考え方は、「人間の目にはあまり目立たない、細かいところを端折る」というのが一般的です。まあYUVの色差間引きみたいなものですね。感度の鈍いところを攻めて情報を間引いてしまう、というやり方ですから。で、MPEG/JPEGでは、それを実現するために画像を波形として捉え、それを周波数変換する、という手法を取っています。

画像を波形として捉える?
 さて、いきなり画像を波形として捉える、と言われてもピンと来ないでしょう(^-^;; 大体はここでイメージを掴めずに挫折してしまうのではないでしょうか。。。ですので、ここでは画像を波として捉えることを考えてみます。

 こんな白黒画像を用意してみました。


Fig.2 サンプル画像(10x10ドットの拡大画像)

 白黒なのは、単純化するために色差を0にしただけの話です。なので、この画像は輝度のみで表すことができ、知りうる情報は、座標値(x,y)、および輝度Yです。これを、輝度YをZ軸とした3次元のグラフで表現すると以下の通りになります。


Fig.3 サンプル画像の波形表示

 実は、これで波形表示は終わりなんです(汗 で、(x,y)座標を決めると一元的に輝度が求まることから、輝度はx,yの関数であり、

  輝度=f(x,y)

 と表現することも可能です。

── 実際はカラー画像がほとんどなので、色差U、Vも同様に扱うことになります ──

 というわけで、画像も波形として捉えることが可能で、算術計算させる基本的な考え方になります。

 等高線ではなく、棒グラフじゃないダメなのでは? という突っ込みは平にご容赦を。。。(^-^;;

波とフーリエ級数
 画像を波形として捉えられることは分かりました。ここで、細かいところとおおざっぱなところを分離したくなります。幸い、現在の数学にはこの目的に合致した数式変換が存在します。が、なかなかイメージが掴みにくいので、比較的考えやすい「フーリエ級数」というもので考え方を説明します。とりあえず、ある波形関数 f(t) に関するフーリエ級数の式は以下の通りです。


Fig.4 フーリエ級数

 よくわからない式ですね。なので、以下の通りに書き換えます。sin と cos をひとまとめとして、「波」(汗)とし、その係数をAとしておきます。


Fig.5 フーリエ級数もりのバージョン(汗

 簡単になりましたね(汗 ここで、「波1」は低周波成分、添え字が∞に近づくに従い高周波になっていきます。「波0」が無いのは、元の式にn=0を代入すれば分かりますが、波0=1(定数)となるためです。つまり、いちばんの低周波は、もはや波とは呼べない一定値(=A0)を示す成分となります。他の周波数のイメージは上図の通りです。ここから次のことが分かります。

 1)どんな複雑な波 f(t) であっても、単純な波の足し算で表現できる
    (=どんな波でも周波数成分に分解できる)
 2)係数Anが分かっていれば、元の波形 f(t) を復元できる

 2)がここでは重要で、MPEG圧縮のエッセンスに通じます。係数Anは、各項(各々の単純な波形)の振幅に相当し、言い換えるとどの周波数成分が強いか、を示しているものです。また、定数項A0は波形全体の平均値を示します。

DCT
 フーリエ級数でも周波数成分に分解できますが、画像データは前述の通り2次元データなのでそのままでは適用できません。また、無限大の考え方をコンピュータに適用するのは容易ではありません。そこで出てくるのがDCT(Discrete Cosine Transform、離散コサイン変換)というものです。これもフーリエ変換の一種で、複雑な波形を単純な波の和で表す、という本質に変わりはありません。なので、恐れるに足らず、です。MPEG/JPEGでは、画像の8x8ドットを一つの単位としてDCTを行い、上記フーリエ級数と同様に各周波数の振幅(=DCT係数)を求めます。いちおう、DCTの式も下に示しますか。


Fig.6 DCT

 よくわかりません(汗 まだフーリエ級数くらいなら私でもなんとか理解できるんですが、ここまで来ると何が言いたいのかさっぱりです(ぉぃ まあ、なんとなく、フーリエ級数を2次元にして、sin を cos に変換したように見えますが。。。ここらへんは数学者に任せましょう(^-^;;

 例によって、「波」と係数「A」という形で示します。


Fig.7 DCTもりのバージョン

 画像は(x,y)座標を持つ2次元のデータなので、DCTも2次元に対応したものでなくてはなりません。このときの「単純な波」は、やはり2次元の波となり、その2次元な「単純な波」の和で表すのがDCTです。ええ、フーリエ級数との違いは2次元になっただけですね。厳密には他にも違いがあるのですが、イメージ的にはこれで十分です。

 ここで得られる情報は、DCT係数Aです。前述の通り、係数Aが分かっていれば波形を復元できることから、このデータを保持すれば良いのです。偶然にも、8x8ドットのDCT係数Aは、8x8マトリクスのデータになります(本当は偶然ではなく必然だが)。通常、係数Aをマトリクス状に示す場合は、


Fig.8 DCT係数マトリクス

 このようにA(0,0)を左上に、A(7,7)を右下になるような配置で示します。この配置だと、DCTもりのバージョン式と、波のイメージ図を見比べて欲しいのですが、左上が低周波成分、右下に行くほど高周波成分を持つことが分かります。ををっ、なんか聞いたことがあるフレーズですね!

 こうして、画像を単純で、かつ周波数別の波に分解することが出来ました。ここまでは、前述のフーリエ変換の項の通り、逆DCTを行えば元の波形(=画像)を完全に復元できます。が、それだけでは意味がありません。ここからデータを端折る作業に入ります。

おまけ
 DCT後のデータはあくまでもDCT係数であって、各ドットのデータを示すものではないことに気づくと思います。この場合の「単純な2次元の波形」というのが既に「8x8ドット」のデータだからです。DCT係数はそれらの強度を示しているに過ぎないわけです。

量子化
 訳のわからない計算を経て(汗、ようやく画像の細かいところとおおざっぱなところを分けることが出来ました。ここで、量子化という手順を踏んで、データを端折ります。

 内容は簡単です。DCT係数をある数値で割り算し、小数点以下を切り捨てるだけです。DCT係数は8x8マトリクスで表せることは前述しましたが、ある数値も各々のDCT係数に対し個別の値をとることができるため、やはり8x8のマトリクスで表現できます。このある数値をマトリクス状に表現したものを量子化行列と呼びます。行列とは言っても、いわゆる行列演算ではないことに注意してください。

 切り捨てではなく、四捨五入という話もあるみたいです。ちょっと調べきれていません

 具体的には以下のような感じです。


Fig.9 量子化

 一般にDCT後の係数は、低周波成分により大きな数値が集まる傾向にあります。ここで、人間の目は感度が低く、細かい情報は察知できない、と考え、高周波成分を間引くことを考えます。量子化行列の右下、高周波成分に対応する数値を大きくすれば、割り算/切り捨てによって0になることが分かります。この0の部分が多くなればそれだけ情報を間引くことができ、結果のデータサイズを小さくすることが出来ます。これがMPEG/JPEG圧縮の基本となります。

 ここで「切り捨て」という作業が入るため、データを復元(デコード)するときは完全に元には戻りません。MPEG/JPEGの不可逆性は、この段階で生まれます。

 となると、量子化行列の数値によって、圧縮画像の出来が違って見えるのは容易に想像がつくと思います。これについては、その2で実際に確かめてみたいと思います。

量子化スケール
 じつは、量子化にはもう一つパラメータがあって、量子化スケールというものがあります。するどい人なら薄々気づいているかもしれません。量子化行列で割っただけでは圧縮率を任意に調整できないではないか、ということに!

 そこで出てくるのが量子化スケールです。具体的には、以下のような計算で量子化されます。


Fig.10 量子化スケール

 この量子化スケールを調節して、圧縮率を調整するわけです。この量子化スケールは、マクロブロック(16x16ドットのMPEG圧縮の基本単位)ごとに指定することが可能と定められており、例えば画面上の複雑な模様の部分だけ圧縮率を低く、というような芸当も可能です。なるほど、よくできていますね。

 ところで、DCT係数のA(0,0)にあたる部分、つまり量子化行列のいちばん左上のセルですが、ここはDCT後の定数項にあたり、フーリエ級数の項でも書いた、波形全体の平均値を表す成分となります。この成分を直流成分(DC成分)と呼び、量子化行列、量子化スケールに関わらず「8」で量子化するよう決められているそうです。これはたぶん、平均値、つまり8x8全体の明るさ、色味が変化してしまうと大幅な劣化に見えてしまうためだと思います。

 なお、確認していませんが、TMPGEncのCQ(固定品質)は、この量子化スケールをなるべく一定に保つエンコードモードだと考えられます。なので、CQで量子化行列を変更すると、極端にサイズが増減します(^-^;;

符号化
 量子化行列に関わる部分はこれでおしまいなんですが、どうせなら最後まで軽く解説しちゃいましょう。量子化によって間引かれたデータは、符号化という段階で更に圧縮されます。考え方ですが、例えば0000000というデータがあるなら、0が7個ということで、ルールさえ決めれば「7」だけで元のデータを表すことが可能です(乱暴な説明だな)。このように、単位コードの繰り返しを別のデータに置きかえることを符号化と呼びます。この考え方はZIPなどの通常のファイル圧縮にも用いられており、可逆圧縮です。

 で、その符号化にもちょっと工夫があって、量子化した後のマトリクスを下図のように


Fig.11 ジグザグスキャン

 順番に斜めに読んで符号化します。斜めにすることで、高周波成分が連続して0が集まることになり、より効率良く圧縮できることが分かります。これをジグザグスキャンと呼びます。


 いちおう、これで大雑把な解説は終わりです。う〜ん、わかってもらえるかちょっと自信無いなあ。。。とはいえ、自分も完璧に知っているわけでもないので、詳しい方、突っ込みお願いします(^-^;;

圧縮の弊害
 こうして得られた圧縮データは、ちょうど逆の手順を踏んで復元され、デコードする訳ですが、その際に現れる圧縮劣化はどんなモードがあるでしょうか。これについてちょっと触れます。

モスキートノイズ
 量子化の段階で高周波成分をより多く間引く、と書きました。では、そのデータを画像に復元するとどうなるでしょうか。ちょっと下の図を見てください。


Fig.12 モスキートノイズ

 わかりやすく、便宜的に1次元の波形で表します。ある元画像の波形が(a)だったとき、その中に高周波成分(b)が含まれているとし、その成分は量子化によって間引かれる、と仮定します。このとき、圧縮データから復元した画像は、元画像から(b)が間引かれたデータ、すなわち(c)=(a)−(b)となります。はい、(c)には細かいギザギザが残ってしまいますね。これをモスキートノイズと呼びます。

デコードした画像の物体の周りに、蚊の大群がまとわりついているように見えるのが命名の理由みたいです。

 ちょっと方程式風に、

    元画像=デコード画像+間引き成分
  間引き成分=元画像−デコード画像
       =ノイズ成分     (元画像とデコード画像の差がまさに圧縮ノイズだから)
 ∴間引き成分=ノイズ成分
という式が成り立ちそうです。まるで質量保存の法則みたいです。。。

 間引いた成分=ノイズ成分となるので、ノイズ無しには高圧縮できないことが分かります。ムシの良い話は無い、ってことでしょうか。。。

ブロックノイズ
 量子化のところで、「直流成分は8で固定」と書きました。では、圧縮率をどんどん高めて、交流成分(直流成分以外の波形成分)を間引いていくとどうなるでしょうか。極端な例で、仮に直流成分しか残らない時を考えてみます。このデータをデコードすると、当然直流成分しかありませんから、ひとつの8x8=64ドットは、全て等しい値をとります。すると、画像としては8x8のモザイク状に見えることになります。まあ、これは極端な例ですが、交流成分が間引かれる以上、直流成分が相対的に強調されるのは事実で、このおかげでDCT単位の境界が目視確認できる現象が起こります。これをブロックノイズ(ブロック歪み)と呼びます。

 また、「量子化スケールはマクロブロック毎に指定可能」とも書きました。これは逆に言うと、ひとつの画像の中で量子化スケールが一定である保証は無い、ということでもあり、隣接マクロブロックの量子化スケールが異なるケースがある事を示しています。これは、隣接マクロブロックの量子化行列が異なることと同値であり、その境界が目視確認できるケースもあり得ます。これもブロックノイズと呼んで良いでしょう。

(注)後者は確認してません。たぶん、このモードもあるかな、と思って。。。(^-^;;
   どうやって確認すれば良いんだか。。。って、そもそも出来るのか?!

イントラブロック、ノンイントラブロック
 ひとつ触れるのを忘れてました(^-^;; TMPGEncの量子化行列には、イントラブロックとノンイントラブロックの、2つの量子化行列がありますね。なんで2つなんでしょうか?

 MPEG圧縮の最小単位であるマクロブロックですが、それには2種類あります。ひとつは今回説明したフレーム内で圧縮するマクロブロックです。そしてもうひとつは、今回触れなかった基準フレームとの差分圧縮を行うマクロブロックがあります。で、前者をイントラブロック、後者をノンイントラブロック(非イントラブロック)と呼びます。

 言葉の定義はこうなんですけど、もう想像がつきましたね。イントラブロックに適用する量子化行列と、ノンイントラブロックに適用する量子化行列を、別々に指定できるのがMPEGの特徴です。

 が、ノンイントラブロックの量子化行列の評価は、困難だ、と言わざるを得ません。なぜかと言うと、

 1)動き検索精度でノンイントラブロックの画質が左右される
 2)P、Bピクチャと言えど、イントラブロックの存在が許される

 の2点です。1)を無視したとしても、2)の、注目すべき差分圧縮フレームにイントラブロックも含まれる可能性がある点が事を複雑にして、どの要因のおかげで画質が変化したか切り分けするのが困難なためです。でも、大筋な傾向として、Iピクチャのような全てがイントラブロックのフレームで、量子化行列の評価をし、それをノンイントラブロックにフィードバックすれば何とかなるかな、なんて考えています(^-^;;

 ここらへんを踏まえて、「その2」で量子化行列の実験をやってみたいと思います。

戻る