前回の内容で示したように、ピンボケ、手ブレの画像はある画像との畳み込みで表されています。これは一つのフィルターと考えることができるでしょう。まずはフィルターと考えた際に画像の畳み込みをどのように定式化するかを考えます。
画像は成分(8bitの場合、0から255までの値)が二次元にわたって並んでいる大規模な行列と考えられるのは想像に難くないと思います。
たとえば以下のような画像を考えます。いつもと同じ画像です。
画像は成分(8bitの場合、0から255までの値)が二次元にわたって並んでいる大規模な行列と考えられるのは想像に難くないと思います。
たとえば以下のような画像を考えます。いつもと同じ画像です。
これのある部分を拡大してじっくりと見てみます。
このようになりました。見てわかる通りこれはデジタルで画素値がたくさんならんでいる行列と考えることができると思います。
画像を行列で表現(例)
ここで、画像はサイズが大きくなりすぎるので、 3 x 3 のピクセルの値を持つ部分を考えてみましょう。行列は以下のように1次元のベクトルにして考えることができます。
行列は数字を一列に並べたものです。512×512の画像の場合は、262144個の数字の列になります。画像の再構成処理では、行列の数字に対して順番に演算を行います。
行列は数字を一列に並べたものです。512×512の画像の場合は、262144個の数字の列になります。画像の再構成処理では、行列の数字に対して順番に演算を行います。
画像からベクトルへ
ここからあるフィルターによるたたみこみ演算により、画像Y[n]ができたとします。これも同じように以下のようにベクトルにすることができます。
画像からベクトルへ
ここの章での問題は、あるフィルターがかかった画像(ここでのd)が得られた状態で、sをどのように復元するかです。dもsもサイズは9なので、フィルターをHという 9 x 9の行列でかけるとすると、上のようなフィルターによる画素値の変化は
と表現できることがわかります。このような行列演算をイメージングアプローチと言います。
さて、簡単のため、Hは以下のような 3 x 3のガウシアンフィルターとしましょう。
さて、簡単のため、Hは以下のような 3 x 3のガウシアンフィルターとしましょう。
ガウシアンフィルターは以下のような式で与えられます。
今回の場合は 3 x 3 で考えているので、以下のようなフィルタを用いることにします。
これを使うと次のようなたたみこみ演算の図が得られると思います。
画像については画像の外側は0であると仮定しましょう。これについては画像処理におけるフーリエ変換(3/4)〜畳み込み〜ごご覧ください。
すると、成分は以下のように計算されることがわかります。畳み込みはフィルタHを
また画像が繰り返されている場合も同じように以下のように計算されます。
これによって行列を設定することができます。画像の外側が0であるとしたとき、
なんだかすごく仰々しくなりましたね。大変ですが、上の行列計算をしてみると畳み込みの式になっていることが確認できると思います。
このフィルターを理解するために、たたみこみ演算をOpenCVで実装してみましょう。
このフィルターを理解するために、たたみこみ演算をOpenCVで実装してみましょう。
それではOpenCVを使っていきます。まず、必要なパッケージを以下のようにインポートしてください。
ここで、#coding〜は日本語でコメントアウト(プログラムファイルにメモ)するのに必要なので、入れといてください。
3 x 3 のピクセルの画像を作ります。このために、numpyのlist構造を用いて、以下のように定義します。
3 x 3 のピクセルの画像を作ります。このために、numpyのlist構造を用いて、以下のように定義します。
出力するときは以下のように記録します。0~255の8bitで画像の白黒を表現するよ、っていう意味でuint8が入っています。
すべてのコードをまとめると以下のようになります。
実行すると、以下のような画像が出力されます。
サンプル画像
この画像の画素値を並べ直し、縦ベクトルに変換して、フィルター(H(n))をかけてみましょう。まず画像(image)を縦ベクトルsへ変換します。
ここからガウシアンフィルタの行列(H)を設計します。上の行列は何らかの規則を有している(ハンケル行列のよう)のですが、上手に設計する方法が見当たらないので、地道にセットしました。
これで、フィルターHが設計できました!やっと[math]d=Hs[/math]が計算できます。
以下のコマンドによって、これらを計算し、それの画像を表示します。
以下のコマンドによって、これらを計算し、それの画像を表示します。
コントラストが平滑化されているのが分かります。
画像の外側の影響によりなんとなく想像したのと違うかもしれません。
さて、長くなりましたが、右の画像が平滑化によって得られた得られたとします。ここから左の画像を復元できるかどうかというのが再構成の話です。今回の例は簡単で、Hという行列がかけられただけなので、[math]H^{-1}[/math]を両辺にかければ元の画像が得られるはずです。
numpyを用いると逆行列はすぐ計算することができます。
画像の外側の影響によりなんとなく想像したのと違うかもしれません。
さて、長くなりましたが、右の画像が平滑化によって得られた得られたとします。ここから左の画像を復元できるかどうかというのが再構成の話です。今回の例は簡単で、Hという行列がかけられただけなので、[math]H^{-1}[/math]を両辺にかければ元の画像が得られるはずです。
numpyを用いると逆行列はすぐ計算することができます。
このコードを実行し、結果を出力すると
平滑化処理をする前の元の画素値が得られました。当たり前といえば当たり前です、行列をかけて、それの逆行列をかけただけですからね。逆の演算処理をすれば元の画像に戻るのは当然です。
ここで平滑化処理された画像にノイズをのせてみます。この写真でみた状態ではほとんど変化はありません。
ここで平滑化処理された画像にノイズをのせてみます。この写真でみた状態ではほとんど変化はありません。
同じように、 H^(-1) をかけてみます。するとどうでしょう。今度は全く元に戻らないことがわかりますね。
実は、元に戻らない原因は、畳み込みフィルターの行列Hにあります。これについて、次の章で説明していきます。
長くなりましたので、一旦ここで休憩したいと思います。
長くなりましたので、一旦ここで休憩したいと思います。