OpenCVを使って擬似ディフュージョン・フィルタ | Nature | Photography | Music | Art

Nature | Photography | Music | Art

日々好奇心の趣くまま

サイト内の写真の使用ならびに無断転用を禁じます。

久しぶりにテクニカルネタです。

遅蒔きながらようやく流行のgithubを使い出したので、その第一弾のお披露目も兼ねています。

https://github.com/delphinus1024

以前に公開したプログラムも時間を見つけては順次ここに移していこうかと考えています。

で、今回のテーマは以前から星撮影に関してカメラを始めた頃から悩んでいた事柄についてのソリューションを試行錯誤した結果でもあります。

時折写真やっている人から星景撮影について訊かれるのが、「ソフトフィルタ(=ディフュージョンフィルタ)使わないんですか?」というもの。

確かに、星景やってる人はほとんどディフュージョンフィルタ(以下DF)はデフォルトで使っているようで。

以下が、DFありとなしの写真を比較したもので、DFを付けると星の明るい部分がいい具合に拡散・誇張されて写真が華やかになる。

なし


あり


空が澄んでいるところで使うとそれはそれはファンタジー。



このDF、私も一時期は常用していたのですが以下の理由からあまり使わないようになりました。


  • DFを使うと星以外の風景までが不必要にぼやけてしまうのでなんだか好きになれない。

  • DFで拡散することは、画像の情報量を故意に劣化させることに他ならないので抵抗がある。

  • そもそもフィルターがつけられない(つけにくい)広角レンズが多い。



とはいえ、ディフュージョンフィルタの醸し出す華やかな絵は捨てがたい。

ハーフNDならぬハーフDFのようなものがあればいいのだが、どうやらそれは高価な特注品になるらしい。

そういうこともあり、このDFの効果を後処理で付けることができないかを試行錯誤していました。
これがうまく行けば、元画像と重ねて必要な領域だけマスクを付けてDF効果を出すことができる。

まず単純に思いつくのが、拡散という言葉から連想するガウシアンフィルタをかけるという技。

しかし以下の例のように、単純にガウシアンフィルタをかけるだけだと画像が満遍なくぼやけるだけで、DFの効果とはほど遠い。





このことより、DFの効果というのは単純に再現できないような非線形な現象であることが分かり、同時におそらくソリューションは写真・画像処理の世界ではなくCGの世界にありそうだと目星をつけた。

そこで思いつくのが、レイトレーシングを応用して拡散を表現できないかということ。

ググってみるとレイトレーシングの中でも上級技(たぶん)となるBRDF(双方向反射率分布関数)という質感をコントロールする小難しい方法論があって、この中で扱う反射を屈折に置き換えればフィルタによる拡散を表現できるかもと考えた。

そこで試しにオープンソースのレイトレーシングソフトでBRDFの実装を試みたのだが、愚直すぎる方法のため労力と計算時間ばかりかかってあまり綺麗な効果が出ない。
もうすこし試行錯誤すればうまくいったのかもしれないが…この方法は一旦中断して更に別の方法を探してみる。

どうやら「拡散」というキーワードに固執していたことがだめだったんじゃないかと考え、そこで思いついたのが拡散≒グロー効果かも…ということ。

グロー効果を綺麗に作る方法で検索すると理屈を懇切丁寧に説明してくれている記事を発見。しかも日本語で >多謝。

結局は最初に試したガウシアンフィルタが鍵だった。

詳細はリンクに譲るが、σパラメータを二乗で拡大しながら(要はぼかしを増やしながら)元画像にガウシアンフィルタをかけたレイヤーを作成していって、それらを指数的にゲイン(不透明度)を減衰させながら元画像に加算していくというもの。

これだと元画像の芯を残しながら、同時に拡散の要素をやんわり加えることができる。(ただし非常に計算時間がかかるという弱点があるが。)

そこでこのアルゴリズムをOpenCVを用いて実装してみました。もちろん本物のDFと比べればいろいろ相違点があります。

また、速度の最適化には時間を費やしていないので、画像サイズとパラメータによっては計算に数十秒もしくはそれ以上かかります。

https://github.com/delphinus1024/diff_filter_emu.git

詳細な使い方はgithubのreadmeを読んでもらうとして。(githubなので英語記述にしていますが)

こんな感じにDF効果を施した画像が生成されます。いずれも元画像はFull HDのサイズ。

before



after



パラメータを簡単に説明すると


  • n: 加算するレイヤーの枚数。大きくなると拡散範囲が大きくなるが、計算時間も大きくなる。

  • g: 処理前に元画像にかけるガンマ係数。大きいほど明るい部分が強調される。処理後この逆数で逆ガンマ補正をして戻す。

  • d: ゲイン(不透明度)の減衰係数。大きいほど急激に減衰する。

  • f: ゲインの初期値を調整。0なら初期ゲインは最大(完全な不透明)大きくなると初期ゲインが下がっていく。



パラメータを調整すると効果のかかり方が変化。

n=5 g=1.3 d=1.6 f=0



n=5 g=1.3 d=3.0 f=0



ここまで行くとやりすぎだが、ガンマ値を大きくすると明るい箇所が強調されすぎてこんなことも。

n=5 g=3 d=2 f=0



この方法のよいところはローパスフィルタ後の画像を加算していくのであまりノイズが増えないこと。

また、途中の計算はすべて浮動小数点を用いているので、下手に同じアルゴリズムをPhotoshopやAfterEffectsで実現するより綺麗に仕上がると思います。

パラメータを調整すれば星景だけじゃなくて、普通の写真でもグロー効果が出ます。

before



after



後日追加


以下の作品の中で、このプログラムを隠し味に使用したカットがいくつか入っています。よろしければご覧ください。