読者です 読者をやめる 読者になる 読者になる

プログラムdeタマゴ

nodamushiの著作物は、文章、画像、プログラムにかかわらず全てUnlicenseです

画像の縮小処理におけるエイリアスの発生とそれを抑える仕組み

【楽天ブックスならいつでも送料無料】OpenGL+GLSLによる画像処理プログラミング [ 酒井幸市 ]
OpenGL使って画像処理をしたかったので参考に買ってみた。

「OpenGLとシェーダ言語でレタッチ・ソフトの仕組みを知る!」って書いてあるけど、信号処理について全く知らない人が、よっしゃ画像処理やってみようっていって読める本ではない。重要な部分で説明が載ってなかったりする。で、パラパラめくってあぁそうだね、って言う人は、おそらくもうこれに載っている程度のことは大体知ってるだろう。




それにしても、第二章にある縮小の項目は流石に説明がなさ過ぎる気がする。縮小の際のエイリアスについて言及しながら、それ以降の説明が、こういうフィルター通したらエイリアスだいぶ消えたでしょというだけで一切無いとか放置感がすごい。4章にて解説的な雰囲気を醸し出しておきながら、縮小については一切の説明がない。確かに、肝となる部分がp95 〜 101に書いてあるのだけど、普通わからん気がする。



なので、ここで軽く説明してみることにした。


画像を縮小すると何故エイリアスの問題が発生するのかについて簡単に説明する。

ある周波数を表現するためには、その周波数の倍のサンプリングレートが必要である、という標本化定理がある。エイリアスはこの定理を破ったときに現れる。この事は頭に置いておいて欲しい。

さて、画像を実空間で縮小すると言うことは周波数空間では拡大することになる。つまり、元画像では低周波領域だった周波数が高周波数領域になると言うことである。
ここで、全体的に高周波になること自体はなんの問題もない。(高周波はエイリアスではない。)


では、いったい問題はなにか?
元の画像が、画像の持ち得る限界の周波数を含んでいた場合などを考えてみるとわかりやすい。この周波数はサンプリング間隔(=ピクセルの幅)に対応するので大きな画像だろうが、小さな画像だろうが変わらない
縮小すると周波数は拡大するので、この画像の持つ限界の周波数帯は、画像を縮小するとその限界を超えてしまう


すなわち、エイリアスの発生である。



限界を超えてしまった周波数は折り返して低周波領域に現れてくる。こうなると、邪魔な低周波と元の低周波を分離することは不可能である。



以下に例を示す。
(図1)

(図2)
図2は図1を50%に線形補間で縮小した物である。線形補間ってローパスフィルタ(どんなフィルタの形なのかは知らんけど)だから多少は折り返す高周波を除去しているはずだが、それでも多くのエイリアスが発生しているのが分かる。



そこで、「OpenGL+GLSLによる画像処理プログラミング」にサンプルとして乗っているコードでは、縮小する前にはみ出して邪魔になる高周波領域を先にローパスフィルタを通して除去してから、線形補間で縮小している。


ローパスフィルタには単に周波数空間に矩形関数をかけるだけ。これを逆フーリエ変換して実空間にすると、sinc関数の畳み込みになる。ただし、sinc関数だと無限遠までたたみ込まないといけないので、窓関数をsinc関数にかけて、ある一定の範囲だけ値を持ち、その他は全て0になるようにする。窓関数は単純に矩形関数でも良いのですが、矩形関数は分解能がよろしくないので、ハン窓関数を使う。(窓関数(Wikipedia)

(図3)
図3がその結果です。

ちなみに、元のサンプルがフィルタリングした後に線形補完法で縮小していたから、それに乗っ取ってやったけど、そもそもフィルタリングで高周波成分は取り除いたので、縮小時にさらに線形補完する必要はあんまりない。フィルタリングした後に最近傍で縮小した物。
(図4)
対して変わらないね。




ちなみに、高速にそれなりの縮小結果を得たい場合は、面積平均法(area average method)を使うというのもある。
これは矩形関数の畳み込みで、非常に単純な処理。工夫をすれば浮動小数点とか使わずに、割り算もほとんどせずに乗り切ることができたりする。
周波数空間でみれば、sinc関数をかけることになる。sinc関数は(振動しているが)減少関数なので高周波成分をある程度抑えることができる。ただし、必要な低周波領域にも影響が大きな影響が出るので元の画像に比べて線が細い感じになっていますね。
(図5)



でも、今回見たく明らかに幾何学的で、整然としすぎた不自然な画像を扱いでもしない限り、面積平均法で問題ないと思いますけど。