次にサブサンプリングしたYCbCrデータに離散コサイン変換(DCT)を施して、YCbCrスペクトルに変換します。 このDCTはピクセル座標−YCbCrデータ関数を三角関数を複数合成した合成関数(フーリエ級数)によって表し、それをその合成係数(フーリエ係数)関数すなわち周波数スペクトルに変換する手法で、数学的にはフーリエ変換と呼ばれる手法の一種です。
まずピクセルの位置座標を(x、y)とし、ピクセルの輝度をzとして、輝度変化をグラフ化しますと、それは3次元のグラフz=f(x,y)になります。 3次元のグラフは描きにくいので、z=f(x,y)をy=yj面で切った断面図を描きますと左図のようになります。
ピクセル座標−輝度関数z=f(x,y)は有限離散関数(値が飛び飛びで、かつそれが有限個の関数)ですから、(n×m)個のフーリエ級数(コサイン級数)で完全に表すことができます。
f(x,y)= | 1 —— 4 | [ | n-1 Σ i=0 | m-1 Σ j=0 | c(i)・c(j)・f(i,j)・cos{ | (2x+1)iπ ————— 2n | }・cos{ | (2x+1)iπ ————— 2m | }] |
f(i,j)= | 1 —— 4 | c(i)・c(j)・[ | n-1 Σ x=0 | m-1 Σ y=0 | f(x,y)・cos{ | (2x+1)iπ ————— 2n | }・cos{ | (2x+1)iπ ————— 2m | }] |
ただし k=0の時 c(k)=c(0)= | 1 —— √2 | k≠0の時 c(k)=1 |
フーリエ級数は輝度の変化を複数のコサイン波に分解したもので、そのコサイン波の振幅を表すf(i,j)をフーリエ係数といいます。 フーリエ係数f(i,j)の番号を表す(i,j)は周波数に関係した値で、(i,j)をx、y軸とし、フーリエ係数f(i,j)をz軸としたグラフを「フーリエ係数(または周波数)スペクトル」といいます。 この場合のフーリエ係数スペクトルは、元の関数f(i,j)が有限離散関数ですから、連続スペクトルではなく離散的な線スペクトルになります。
フーリエ係数スペクトルを見れば、フーリエ級数の中に、ある周波数のコサイン波がどの程度含まれているかがわかりますから、それによって元のピクセル座標−輝度関数z=f(x,y)を復元することができます。
つまりf(x,y)とf(i,j)は同じ情報を別の形式で表現したものになり、お互いに変換可能な関係にあります。
このように、f(x,y)をf(i,j)に変換することを「離散コサイン変換(Discrete Cosine Transform、DCT)」といいます。
一般に、ある関数をフーリエ級数で表すことを「フーリエ展開」、フーリエ係数スペクトルに変換することを「フーリエ変換」といいますが、離散コサイン変換はフーリエ変換の一種です。
昔、理科の実験などでやったことがあると思いますが、光をプリズムに通しますと、波長の違う単色光スペクトル(いわゆる虹です)に分解します。 これは波長による屈折率の違いを利用した、フーリエ展開あるいはフーリエ変換に相当します。 また、波長の違うたくさんの純音(波形がサインカーブ状の音)を組み合わせることによって、色々な波形(音色)の音を合成するアナログ・シンセサイザーは、フーリエ変換を逆向きに応用したものです。(これを「フーリエ逆変換」といいます)
DCTによってYCbCrスペクトルに変換されたデータは、元のYCbCrデータと同じ個数、同じビット数で、同じ情報量を持っていますから、この段階では圧縮は行われません。
YCbCrデータをYCbCrスペクトルに変換するのは、次の段階の量子化とハフマン符号化法による圧縮を効果的に行うためです。
量子化とはアナログデータをデジタルデータに変換するA/D変換のことで、JPEG圧縮の場合は、原理的には実数であるYCbCrスペクトルすなわちフーリエ係数をある精度で整数化することを意味します。 JPEG圧縮の量子化は「1次の量子化」という方法で行われます。 これはフーリエ係数を量子化因数という値で割り、結果を四捨五入して整数化するという単純な方法です。
例えば量子化因数を4としますと、フーリエ係数は1/4の値になり、結果として値を保存するためのビット数が2ビット減ることになります。 この場合、元のYCbCrデータのビット数が各々8ビットだったとしますと、量子化されたYCbCrスペクトルデータのビット数は各々6ビットとなり、データの精度も量も75%になります。 この過程で2番目の圧縮が行われ、それは元の情報の精度を厳密には復元できない非可逆的な圧縮となります。 この量子化の精度のことを量子化パラメターといい、普通は75%程度の値が用いられることが多いようです。 JPEG圧縮を展開する場合は量子化因数をかけて元の値を復元しますが、下位ビットは0となり精度は落ちたままです。
実際には、全てのYCbCrスペクトルに対して同じ量子化因数を用いるわけではなく、スペクトルの最初の低周波成分については小さな量子化因数を用いて精度をあまり落とさず、スペクトルの最後の高周波成分については大きな量子化因数を用いて精度を大きく落とし、平均として指定された量子化パラメターの値になるようにしています。 なぜかと言いますと、スペクトルの最初の低周波成分は画像の大きな構造、例えば全体の構図や人物の配置といったものを反映しているため、この成分の精度を落としますと画像の劣化が目立ってしまうからです。 それに対してスペクトルの最後の高周波成分は細かい構造、例えば人物の髪の毛や服の模様といったものを反映しているため、この成分の精度を落としても画像の劣化は目立ちません。
このようにして、量子化されたYCbCrスペクトルデータからYCbCrデータを復元した場合、復元された輝度関数f(x,y)は元の関数に比べて高周波成分、つまり細かい変化をする周期成分が減り、全体としてなだらかな変化をするものになります。 このため、元々輪郭のはっきりしないなだらかな変化をする写真画像の場合は画質の劣化が目立たず、輪郭のはっきりした急激な変化をする漫画調の画像の場合は、画質の劣化が目立つことになります。 輪郭線が周囲ににじんだ感じになるJPEG特有の劣化は、輝度関数がシャープな台形状になっているところを、なだらかなサインカーブ状の曲線で近似していることに起因します。
また元の画像がなだらかな変化をするものは、高周波成分のフーリエ係数が小さいため、精度を落とすとほとんど0となり、低周波成分だけになってしまいます。 つまりデータとしては0の部分が多く、ところどころに0以外の値があるという状態になり、このことは次の段階の改良版ハフマン符号化法による圧縮において大きなポイントとなります。
最後に、量子化されたYCbCrスペクトルデータを改良型ハフマン符号化法という可逆的圧縮法で圧縮します。 ハフマン法は古典的なデータ圧縮法のひとつで、一定のビット数でコードを表す通常の固定長コードではなく、コードごとにビット長が異なる可変長コード(Variable Length Code、VLC)を用い、頻繁に出てくるコードは短いビット数で表し、あまり出てこないコードは長いビット数で表すことにより、全体としてデータを圧縮する手法です。
0000 | 0001 | … | 11111111110 | 11111111111 |
↑ ↑ コード長 コード |
例えば最初の3ビットでコード長(実際にはコード長−1)を表し、次にその長さの実際のコードを続けることにします。 そうしますと、左表のように4ビット(コード長3ビット+コード1ビット)から11ビット(コード長3ビット+コード8ビット)までのコードで、通常の8ビットの固定長コードと同じ数のコードを表すことができます。
このデータ圧縮法は、データを保存する前にあらかじめデータ中の各コードの出現頻度を集計しておく必要があるため、圧縮に多少時間がかかることと、可変長コードと固定長コードの対応表を保存する必要があるため、オーバーヘッドが少し増えるという欠点があります。 しかし量子化されたYCbCrスペクトルデータのように、多くの値が0で、ところどころに0以外の値があるというデータをこの方法で圧縮しますと、非常に高率に圧縮することができます。
輪郭がはっきりせず、しかも同じ色の部分が少ない写真のような画像は、RGBデータにせよYCbCrデータにせよ、同じ値のデータが少ないので、可逆的圧縮法では原理的にあまり圧縮できません。 しかし、そのようなデータを離散コサイン変換によってスペクトルデータに変換しますと同じ値(0)が多くなり、可逆的圧縮法によって効率的に圧縮することができるようになります。 これが、JPEG圧縮法においてわざわざ面倒な離散コサイン変換を行う理由のひとつです。
逆に輪郭がはっきりしていて、しかも同じ色の部分が多い漫画調の画像の輝度データを離散コサイン変換によってスペクトルデータに変換しますと、同じ値が少ないデータとなり、可逆的圧縮法の圧縮率がかえって悪くなってしまいます。
以上のことから、JPEG圧縮法が写真画像に最適な(と言うよりも、写真画像用に開発された)圧縮法である理由が納得できると思います。