らんらん技術日記

日々の学習メモに

Bilateral Solverをソルブする(第2回)

艦これ改が発売となりましたね!提督の一人としては是非とも購入したいところですが、PS vitaがない。これだけのために買うべきだろうか・・・?しかし高いしなぁ。

さて、Bilateral Gridの話でしたね。最近はいろいろあった(特に何もない)ので進捗が遅いですね・・・。しかし!ほぼ完璧に理解することができました!今回はその完結編です。

Birateral Gridのアルゴリズム

Bilateral Gridは①splat ②blur ③slice の3つの処理で構成されます。1次元信号を用いて説明します。 

①splat

今回のサンプル信号は(0〜255)の値をとるサンプルが500個で構成されます。Bilateral Gridの格子パラメータをσ_scale = 5、σ_range = 3とすると、作成される格子は(500/5, 255/3) = (100, 85)の二次元配列になります。

f:id:yukirunrun:20160221215149p:plain

サンプル信号をBilateral Grid上にプロットします。説明のため各サンプルを(number, value)、Bilateral Grid上の座標をB(x, y)と表記します。例えば、(0, 9)のサンプルはB(0/5, 9/3) = B(0, 3)にプロットされます。(6, 4)のサンプルは、少数点以下四捨五入でB(6/5, 4/3) = B(1, 1)です。この時、プロット先のグリッドに値とカウントを保存しておいてください。

f:id:yukirunrun:20160221221030p:plain

なぜカウントを保存するかというと、Bilatera Grid上の一つの座標に対して、複数のサンプルが対応する可能性があるからです。この時は保存する値を、その総和としてください。サンプル信号を全てプロットしたものを下図に示します。

f:id:yukirunrun:20160208003430p:plain   f:id:yukirunrun:20160221221729p:plain

図中の紫の領域は、単純に対応するサンプルがなかったことを示します。あくまで視覚に配慮したものなので、特に意味はありません。また図中の下は黒色、上は白色に着色していますが、これは保存されている値の大きさを示したものです。

 

blur

Bilateral Grid上の値を適当にぼかしてください。ガウシアンフィルタでもいいし、移動平均でもいいと思います。

f:id:yukirunrun:20160221224048p:plain

私が少し困ったのが、値の無い場所(紫)をどうやってボカすのかです。工夫のしどころだと思うのですが、

(フィルタカーネル内の値の総和)/(フィルタカーネル内のカウントの総和)

で計算することにしました。当然カウントの総和が0であれば、0除算になるので例外処理とします。

 

③slice

サンプル信号と、Bilateral Gridから出力信号を得ます。

f:id:yukirunrun:20160221225712p:plain

各サンプルの(number, value)から、Bilateral Grid上の値value_Bを参照し、出力を(number, value_B)とします。参照の方法は①splat処理と似ているのですが、一つ注意が必要です。slice処理では少数点をカットせずに使用します。例えばサンプル(6, 4)であれば、B(6/5, 4/3) = B(1.2, 1.33)です。小数点以下の計算には、B(1, 1), B(1, 2), B(2, 1), B(2, 2)の全てを参照して、線形補間します。

元のサンプル信号(ピンク色)と、slice処理後の出力信号(緑色)を下に示します。大きなエッジはそのままに、小さなエッジが抑制されていることを確認できます。

f:id:yukirunrun:20160221231552p:plain

以上がアルゴリズムの概要です!詳しい数式は元論文を参照願いします。

画像への応用

アルゴリズムを画像に適用します。画像はXとYに空間成分をもち、かつRGBのチャンネルがあることを考慮します。Bilateral Gridは3次元配列のものをR,G,Bの3つ用意しました。例にならって、レナの画像でテストします!

f:id:yukirunrun:20160221232552j:plain 入力画像

f:id:yukirunrun:20160221232624p:plain 出力画像

 こころなしかザラザラ感がとれた気がします。

3次元ブラシ

元論文によるとBilateral Gridは3次元ブラシをイメージして考案されたもののようです。3次元ブラシとは、エッジを検知して色を塗る/塗らないの判定を行う機能をもつブラシらしいです。レナの画像でいうと、レナを色塗りしている間にブラシが背景領域にはみ出しても、それを無効にするというイメージでしょうか。

アルゴリズムとしては、Bilateral Grid上の値を強制的に書き換えます。こうすると、Slice処理で参照するBilateral Grid上の座標をそのままに、取得する値が変化します。

簡易的にプログラムを組んでみました。画像は「のんのんびより」から引張てきてま

す。

入力画像がこちら。

f:id:yukirunrun:20160222000404j:plain

れんちょんのズボンの色を変更してみます。 Bilateral Gridを用いたブラシで、ズボンの上をテキトーになぞります。テスト中のスクショが下。地味にこのGUIを作るのに苦労しています・・・・。色は蛍さんのランドセルからコピーしてきました。

f:id:yukirunrun:20160222000645p:plain

そして出力画像がこちら!

f:id:yukirunrun:20160222000842p:plain

やっぱれんちょんはかわいいなぁ・・・・・。

 

∑( ̄Д ̄;)はっ!

出力画像についてですが、いい加減になぞったにしては上出来ではないでしょうか・・!(境界線が微妙?まぁ、こういうのは色を専門に扱う人達が頑張ってください)

ソースコードは今は汚いので、そのうち公開できたらというところです。以上!