MoAR アプリを開いて最初にでてくる作品 "Mo(AR)^2" の冒頭の演出、壁面の QR コードが壁から立体化して飛び出てくるというエフェクトをおかだくんが作ってくれていてそこそこいい感じにはできていたものの、もうちょっと違和感なく実現できるんじゃないか?と思っていろいろ試してみた話。
やりたいこと
壁面の QR コードが立体化して飛び出てくるということは、もともと壁面に描かれていた QR コードをなんとかして消す必要がある。いわゆる Diminished Reality ってやつ。
作戦
消すといってもカメラ映像を加工するしかないので、上から QR コードがない状態を描くことになる。
ひとつはおかだくんの記事にもあった inpainting ってやつで、複雑なアルゴリズムで消したい領域を埋める画像をその場で生成するやつ。
もうひとつは単純に QR コードがない状態のテクスチャを用意しておいてそれを上からがっつりのっけてしまう方法。
おかだくんバージョン
事前に用意しておいた壁テクスチャをはっつける作戦。
実際のカメラ映像から取得した壁面の色を取得して色調整してからのっけてるのでほぼほぼ色はあってるけど、まだちょっとのっけてる感があるなーという感じ。
Histogram Matching
あらかじめ用意しておいた画像とカメラ映像の色味を合わせるならば Histogram Matching では?と思ってやってみました。
macOS / iOS の Accelerate Framework に含まれる vImage には Histogram を操作するメソッドがいろいろ用意されており Histogram Matching のサンプルコードもあるのでめちゃ簡単に実装できます。
シンプルな画像でテスト
カメラ映像から取得した壁画像から vImageHistogramCalculation_ARGB8888
メソッドでヒストグラムを計算。あらかじめ用意しておいた壁画像に vImageHistogramSpecification_ARGB8888
でそのヒストグラムを適用すると、あら不思議、いい感じにカメラ画像と同じようなカラーのテクスチャができあがります。
同じ壁画像に別の夕方っぽいカメラ映像のヒストグラムを適用しても同じように変換されてとてもよい感じ。あとはこれを AR 上で貼り付ければ壁の QR コードが消えそう〜。
リアルなカメラ画像でテスト
ヒストグラムが近くなるようにロゴと QR コードを避けた上部のコンクリ部分を切り抜いて、そのエリアを使ってヒストグラムマッチングしてみたけど…
全然ダメ。グリーンぽいのはデバッグ表示が影響してるので無視できるとしても、黒の電線がヒストグラムにめっちゃ影響して最終画像も黒が出てしまっている。
ヒストグラムをいじる
体験位置の都合上、カメラ映像に電線が入ってしまうのは避けられない。避けられないならいっそのこと電線含めていろいろ映ってしまってる状態のヒストグラムをいじってコンクリ部分だけのヒストグラムを抽出できればよいのでは?と思って実験。
これは Photoshop で実際の壁面の画像をひらいてヒストグラムを表示したもの。大きく3つの山があって、ロゴと QR コードの白と黒が両端にあって、真ん中のがコンクリートのグレー部分。なのでこの真ん中の山だけを残したヒストグラムが作れればいけそう…
この問題はクラスタリングなので K-Means かな?ってことで Python で適当にやってみる。
kmeans1d つかって3つにクラスタリングするといい感じに真ん中の山だけ抽出できました。
いじったヒストグラムでヒストグラムマッチング
カメラ画像のヒストグラムを計算して、コンクリ部分だけを K-Means で抽出して、それを壁テクスチャにヒストグラムマッチングで適用することで、ロゴと QR コードが描かれてるテクスチャからコンクリ部分のだけの色味を合わせたテクスチャができました。
あとは合成のエッジが目立たないようにちょっとだけアルファマスクをかけて元の位置に合成すれば完成〜。
めっちゃ自然にロゴ&QRコードが消えてるんじゃなかろうか。雨でまだらに濡れた状態でも言われないと気づかれないレベルでダミーテクスチャが生成できてる。
でも…
めっちゃいい感じにできたやん!って思ってじゃあ夜はどうかな?ってやってみると…
全くダメ… カメラ画像の切り抜きから計算したヒストグラムが想定していた3つの山にきれいにわかれてなくてコンクリ部分のヒストグラムを抽出するってのがうまくっていない。
と、このあたりで、MoAR も公開してしまって燃え尽きてしまってアプリに組み込むまでたどり着けず… (今後なんかのタイミングでもっかいやってみるかもやらんかも😆