だいぶ前になりますが、いつものページにAviUtlのプラグインとして「JPEG3点セット」なるものをアップしました。
 動画のワンシーンをワンクリックで保存できるのが欲しかったので作りました。

 AviUtl プラグイン フィルタ by うえぽん

 さて、せっかくなのでJPEGの仕組みについて簡単に解説してみようと思います。あくまでも「概要」なので、詳しくはどこか他のサイトを見るか本を読むなどしてください。動画圧縮の基礎にもなっているので、エンコの腕を上げたい人は覚えておくと良いかもしれません。


 まずは圧縮の工程を大雑把に分けると次の三段階に分かれます。

 (1) RGBをYCbCrへ変換。色差を間引く
 (2) 離散コサイン変換。量子化で間引く
 (3) ハフマン圧縮

 ポイントは扱いやすい形に変換し、それから情報を間引くということです。

(1) RGBをYCbCrへ変換。色差を間引く
 RGBとYCbCrの変換は可逆です(※あくまでも計算精度が十分ならです)。その後に色差をダウンサンプリングすることで情報量を減らします。

 YCbCrのYは輝度でCbとCrは色差です。RGB(範囲0.0〜1.0)から輝度Y(範囲0.0〜1.0)を求める計算式はこんな感じです。
 Y = 0.299*R + 0.587*G + 0.114*B
 そして色差CbとCrはそれぞれはBとRの輝度との差分となります。
 Cb = (B - Y) * 0.564
 Cr = (R - Y) * 0.713
 この係数 0.564 と 0.713 は CbとCrの範囲を -0.5から0.5 にするためのものです。

 次にダウンサンプリングですが、簡単に言うと色差の解像度を下げます。人間の目は輝度の変化には敏感だが色差には鈍感という性質を利用しています。下の画はYUV420の場合のイメージです。情報量が1/2に減っているのが分かるかと思います。

RGBからYUV420の想像図


 JPEGではYUV420以外にもYUV444やYUV422などのダウンサンプリングができます。広く使われているのはYUV420のようです。

 さてこのダウンサンプリングには欠点があります。例えば下のように背景が黒で赤い文字の画像があったとします。

ダウンサンプリング前


 これをYUV420とYUV444のjpegに変換したのが下です。(左:YUV420、右:YUV444)

YUV420のjpegYUV444のjpeg


 jpeg変換時の圧縮品質はどちらも80%です。左の画像は色がかなり変わってます。圧縮品質をいくら上げても改善しません。劣化が気になる場合はYUV444やYUV422で保存すると良いです。


(2) 離散コサイン変換。量子化で間引く
 離散コサイン変換(DCT)はそれだけでは可逆です(※これも計算精度が十分ならばです)。圧縮はそのあとの量子化で行います。

 離散コサイン変換を乱暴に説明すると、どんな離散データでも正弦波の重ね合わせで表現できるよ、というものです。jpegでは8x8ピクセルを一つのブロックとして離散コサイン変換しますが、変換によって下の画像のような64種類の波に分解されます。左上の方が低周波成分で、右下の方が高周波成分です。

wikipediaのDCT画像


 さてここからが量子化の話。それぞれの波の高さを記録(量子化)するわけですが、人間の目で違いが分かりにくい周波数成分は精度を下げて記録することで情報量を削減します。量子化テーブルというのはその精度の一覧表です。例えば、jpegの仕様書に書かれている量子化テーブルの推奨値はこうなってます。
[輝度]
 16, 11, 10, 16, 24, 40, 51, 61,
 12, 12, 14, 19, 26, 58, 60, 55,
 14, 13, 16, 24, 40, 57, 69, 56,
 14, 17, 22, 29, 51, 87, 80, 62,
 18, 22, 37, 56, 68,109,103, 77,
 24, 35, 55, 64, 81,104,113, 92,
 49, 64, 78, 87,103,121,120,101,
 72, 92, 95, 98,112,100,103, 99

[色差]
 17, 18, 24, 47, 99, 99, 99, 99,
 18, 21, 26, 66, 99, 99, 99, 99,
 24, 26, 56, 99, 99, 99, 99, 99,
 47, 66, 99, 99, 99, 99, 99, 99,
 99, 99, 99, 99, 99, 99, 99, 99,
 99, 99, 99, 99, 99, 99, 99, 99,
 99, 99, 99, 99, 99, 99, 99, 99,
 99, 99, 99, 99, 99, 99, 99, 99

 この各数値は、ものさしで言えば目盛りの細かさです。圧縮率を上げるなら各数値を大きくし、高品質にしたいなら各数値を小さくします。

量子化の精度について


 推奨値では左上(低周波成分)の方が小さく、右下(高周波成分)の方が大きくなってます。これは低周波成分は全体像を作るのに重要な場合が多く、高周波成分は劣化しても分かりにくいためです。
 そこで簡単な実験をしてみます。量子化テーブルを全部255にし、一番左上の数値だけ16にした場合と、一番右下の数値だけ16にした場合を比べて見ます。

 [一番左上のみ16(他255)]
 一番左上のみ16(他255)

 [一番右下のみ16(他255)]
 一番右下のみ16(他255)

 両者ともモザイクのような画質ですが、前者(左上のみ16にした画像)の方が全体像が分かりますね。
 ちなみに元画像はこちら(セガサターンソフト『エアーズアドベンチャー』より)。

 [元画像]
 元画像(エアーズアドベンチャー)

 ところでjpegの量子化テーブルは圧縮時にカスタマイズできます。しかし多くのソフトでは推奨値を圧縮品質のパラメータで大小させているのがほとんどです。試しに適当なソフトで圧縮品質50%で保存し、JPEGsnoopなどのソフトで量子化テーブルを覗くとそのままの値が出てくると思います。


(3)ハフマン圧縮
 圧縮よりも先に展開から考えれば理解しやすいかと思います。
 例えばa, b, c, d、4種類の文字を出力するとして、下の二分木を見てください。

二分木


 展開はrootからスタートします。1ビット読み込みこんで、0なら右の枝へ、1なら左の枝へというように進んでいきます。末端に到達したらそこの文字を出力します。そして再びrootへ戻り繰り返します。これが展開です。
 a, b, c, dそれぞれの出力に必要なビット長が違いますね。これがポイントです。よく使う文字ほど短いビット長を割り振ることで圧縮するというわけです。
 jpeg保存のオプションに「ハフマンテーブル最適化」というのがありますが、この二分木の最適化を行うというものです。この最適化は難しいことではないのですが、安い機器でも素早く圧縮できるように高速化(簡略化)していた名残です。