2011-07-20

clean up プレートの作成

実写撮影素材を用いてコンプを行っていると、その撮影素材に映っているモノを消さないといけないという状況にしばし遭遇する。

塗りつぶしたりできるような場合であれば、トラッキングしてマスク作って塗りつぶして・・・ とかでできたりするのであるが、そうもいかない場合もある。

たとえば、


(※このムービーは http://www.hollywoodcamerawork.us/trackingplates.html より許可を得て使用させてもらっております)

このムービーの手前のおそらくトラッキング用に立てられたであろうマーカーを消しこむ必要があるとしよう。残念なことに、このムービーは手持ちでカメラが動いている。実は、パンやチルトのようないわゆるノーダルと呼ばれる動きであれば、このマーカーと背景の関係は変わらない。球体にマッピングされたものを、その中から「首の振り」だけの動きで撮影しているのと同じである。カメラトラッキングさえできてしまえば、割と消しこむのは容易な部類に入ると思う。
ただ、このムービーのように、ノーダルでなく、カメラが手持ちで動いていると、マーカーと背景の位置関係は絶えず変わり、地面のパースも変化していき、いろいろと厄介である。 Imagineer Systems社のmokeyなどを用いるとペコっと消えてしまう場合もあるのだけど、今回はnukeを用いて、clean upを行う手法を紹介したいと思う。

こういうclean upは3Dトラッキングを行いカメラアニメーションを取得し、cardなどのジオメトリに一枚消しこんだ画像(静止画)をプロジェクションして、それをそのトラッキングして得られるカメラから撮影(レンダリング)して、それをマーカー部分に重ねるとうまくいく場合が多い。
ただ、この撮影素材の厄介なところは地面の芝生が平面もしくは、それに近いものでないことである。
多少の起伏があるので、それをうまくマーカーのたて看板の上から重ねても、全フレームでうまくは合わない。

手法としては、たとえば、50f目 での地面の芝生部分を基準として、


同じ位置の比較的50f目から変化の少ない別フレームの画像(下記は70f目)を


パースを合わせて上から被せる。「比較的50f目から変化の少ない別フレーム」ってのは要するに、50f目の近傍になるであろう。ただし、近すぎると、その位置から、マーカーがまだ「行き過ぎていない」ってこともあり得る。
で、この「パースを合わせて」ってのは、3Dトラッキングを行いカメラアニメーションを取得し、大体、地面と思しきあたりに、地面と大体パースを合わせて回転などを掛けcardを置いて(point cloudなどから推測)、そのcardにProject3Dノードを用いて用いて投影する。投影するのだが、同じフレームを同じカメラアングルから投影し、同じフレームで撮影しても結果は同じモノを得るだけなので、今回は合成時のロトのボケ足を含めた、マーカーの移動分が大体20fだったので、20fずらした画を、20fずらしたカメラからプロジェクションして、それをscanlineRenderを介して、トラッキングしたカメラでレンダリングする。
 

 トラッキングが正確で、投影を受けるジオメトリが正しければ、理論的には20fずらしても、そのジオメトリの任意の位置における投影されるピクセルは同じピクセルが投影されるはずである。 言い換えれば、正しい位置から、正しいジオメトリに、正しい画を投影すれば、その画を別アングルからレンダリングしても、そのアングルから見た画が来てるはずということである。ただし、今回の場合、ジオメトリの形状が単一でないことや、マーカーの位置等の問題で、そこまではうまくはいかないので、割と近いフレームで変化の少ない画をそのアングルから投影するとこでそれを回避している。

上の画で20f遅らせたカメラというのは、エクスプレッションを用いて調整している。以前にも説明したが、nukeの場合アニメーションをつけるとエクスプレッションに「curve」というものがはいる。で、エクスプレッションでたとえば、

curve(100)

とすると、そのカーブの100f目の値という意味になる。また、

curve(frame)

とすると、現在のフレーム数での値を返す。要するにこれは「curve」と変わらないのだけど、たとえば、

curve(frame + 20)

とすると、現在のフレームから20フレーム先の値のを返してくれる。で、さらに、「+20」で上手くいくかどうかはわからないので、調整しやすいように、この「+20」にあたる部分を「user knob」で再定義できるものにしておく。具体的には、プロパティー上で右クリックし「Manege Usetr knob...」で「Add」>「Floating Point Slider」でUserタブに新たに数値を入力できるようにする。


今回はトラッキングして得たカメラの位置と回転のアニメーションをこれを用いて20fずらす。
位置と回転のカーブに対して、

curve( frame + [python nuke.thisNode().knob('offset').value()] )

こんなふうに、+20 に相当する部分を

[python nuke.thisNode().knob('offset').value()]

としてやる。基本的にエクスプレッションはtclスクリプトという記述方法にのっとっているが、

[python hoge~~~]

でpythonを用いることが出来る。こうすることで、「+20」部分の調整が楽になる。
同じく、「20f分遅れた画像」を処理するのはTimewarpノードだ。Timewarpノードは作成した時点で、デフォルトでそのシーンの最初と終わりにキーフレームが打たれており、すでに「curve」を持っている。なので、その「curve」を同様に調整する。





curve(frame+[python nuke.toNode('Projection_CameraA').knob('offset').value()])


 さっきは、同じノード内の別knobだったので「nuke.thisNode().knob('offset')」だったが、今回は、別ノードのアクセスするため、「nuke.toNode('Projection_CameraA').knob('offset')」としている。

オリジナルの画と比べてみると・・・


となる。重ねて「差分」を見てみる。


となり、ぴったりきている。これで、現在のフレームで 

マーカーの位置で隠れていた地面芝生の画像

を取得することができた。
あとは、これを、マーカーのマスクを作成して、元の画の上から被せる。

マーカーのマスクの作成には、6.3から搭載されたplanar trackerを用いてみる。
planer trackerは非常に簡単で楽チン!
とりあえず、rotoノードなどでマーカーの形に沿ったベジェマスクを作成。


 で、次に、そのそのベジェを選んで、右クリックで「planar track this shape」でplanar trackingを開始。今回は「fwd」で前進フレーム側へトラックさせた。



すると、自動的にトラッキングが始まり、ちゃんと見切れるまでトラッキングしてくれる。この見切れるまでってのが地味に便利だと思う。


planar trackingを行うと、自動で、PlanarTrackerノードがぶら下がる。


で、あとは、ちょっとしたズレなどを、ベジェの頂点で修正したり、ボケ足をつけたりすれば、簡単にマスクが取得できる。



プロジェクションの都合で、今回の場合は、どうしても下位置で見切れが発生したが、そういうものを調整して完成。


ちなみに、こちらがオリジナル。


 下位置の見切れは次回説明します!
しかし、画質悪いですね・・・