しばらく放置してしまいました。新年一つ目の内容は画像の拡大・縮小にしました。



画像を拡大・縮小させる場合は、回転させる場合と同様に考えます。
つまり、outputの画像の座標から必要なinputの画像の座標を求めて画素値を取得します。

コードは以下のように考えました。
Scaleが取得した拡大率になります。
for (int i = 0; i < bitmap.Width; i++)
{
    for (int j = 0; j < bitmap.Height; j++)
    {
        double x = i / Scale;
        double y = j / Scale;

        if (chk[flag](x, y, bmp))
        {
            Color bmpCol = func[flag](x, y, bmp);
            bitmap.SetPixel(i, j, bmpCol);
        }
    }
}


前回同様処理の肝の部分だけ書きました。
delegateを用いてfunc内で使用する補間用のメソッドを切り替えています。 詳細なコードは、
画像を回転させる際の画素を補間するコード
で記載した補間方法を使用しています。

拡大(1.3倍)

【ニアレストネイバー】
Near13.png


【バイリニア】
bilinear13.png


【バイキュービック】
bicubic13.png


【Lanczos2】
Lan2_13.png


バイリニアは若干ぼやけているように見えます。
下二つの違いがあるのですかねぇ・・・

縮小(0.75倍)

【ニアレストネイバー】
Near075.png


【バイリニア】
bilinear075.png


【バイキュービック】
bicubic075.png


【Lanczos2】
Lan2_075.png


ギザギザが目立つようです・・・
縮小の場合は低域通過フィルターで高域をカットしないとダメなようです。

前回、前々回とバイリニア、バイキュービック補間を行っていましたが、
今回はLanczos(読めない)で行います。


参考にさせていただいたサイトは以下になります。理論的なところはこちらの方が詳しいです。
画像の拡大「Lanczos法」


結果

Lancoz2

Lancoz2.png


Lancoz3

Lancoz3.png


バイキュービック

Bicubic.png


どうやらうまくいっているようです。
前回のバイリニアに続き、バイキュービックを適用した結果です。

参考にさせていただいたサイトは以下です。m(_ _)mアリガタヤ
画素の補間(Nearest neighbor,Bilinear,Bicubic)



すごく簡単に言ってしまうと、
バイリニアは周囲4点から画素の値を推測していたのを、
バイキュービックは周囲16点から画素の値を推測しています。

結果

ニアレストネイバー

near.png


バイリニア

bilinear.png


バイキュービック

Bicubic.png


バイリニアでは、若干ぼけていた画像がバイキュービックでははっきり見えるようになっています。
しかし、計算する周囲の画素の数が増加したため、やはり処理が重くなっています。


どうやって高速化するかは自分のプログラム上の課題ですね(汗



詠み人知らずの備忘録 - 画像を回転させる
にて実装したプログラムは何も補間をかけずに回転させたため、ギザギザな画像となっていました。

これは変換前の座標を算出した際に、必ずしも整数値をとる座標とはならないため最も近い点の画素値を持ってきていたためと考えられます。

I(x',y')を求める際にαなどを以下のように仮定します。(図がキタナイですが・・・)
bilinear_graph.png


その時のI(x',y')は下記の式のように求めることができます。
eqn_20121109023054.png


結果

ニアレストネイバー





バイリニア補間

bilinear.png




バイリニアの方がギザギザが軽減しているためきれいに見えます。
今度はバイキュービックに挑戦してみようと思います。
以前行った、
位相限定相関(POC)で求めたピーク値を探し出せば、移動量が求められるのですが、

画像は整数の値しかとらない格子なので、サブピクセルのレベルで移動していた場合詳細は求められません。

スズメレンダラー・クマ将棋の開発日記さんの記事ではSinc関数に当てはめて求める方法が記載してあります。

ちなみに、Sinc関数とは以下のような関数です


調べてみたところ、最急降下法などで関数のフィッティングを行い厳密な値を求めていきます。



・・・ですが、

私のような凡人にはちょいと難しかったので、もっと簡単な方法を探してました。
x方向だけで考えると移動量dは、




と表すことができます。ここで、
・R(0)はピーク値(位相限定相関画像の値)
・R(-1)はピーク値の一つ前の座標の相関値
・R(1)はピーク値の一つ先の座標の相関値

です。

このパラボラフィッティングを使えば、Sinc関数よりは精度は落ちますが楽にサブピクセル精度で移動量を算出できます。


また、等角直線フィッティングもあるそうですが、
1次関数でのフィッティングであるため、パラボラフィッティングの2次関数の方が精度はよいと考えられます。


FC2カウンター
プロフィール

詠み人知らず

Author:詠み人知らず
プログラム好きな名もなき凡人がお送りしています。(得意とは言っていない
最近の興味はPython、C#、Matlab(Octave)、画像処理、AR(拡張現実)、統計などなど・・・

気分で思いついたことを書くため話題に一貫性がないかもしれません。

カレンダー
06 | 2017/07 | 08
- - - - - - 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 - - - - -
最新記事
タグクラウドとサーチ

カテゴリ
最新コメント
最新トラックバック
月別アーカイブ