前回 「Vol4:実写合成ツールとしての Nuke 活用法」 は、2D トラッキングを利用して、実写プレートからバレ物を消し込む方法を紹介した。今回も引き続き実写素材を用いた CleanUp を取り上げるが、前回と異なり、3Dトラッキング(CameraTracker)とカメラプロジェクション(Project3D)を使った方法を紹介しよう。
はじめに:実写素材から隠れた部分を作り出す原理
今回は、下の動画から手前を横切っている人物を NUKE で消し込む(CleanUp)ことにする。
被写体に対して、カメラがトラック移動などで横に動いた場合、静止したオブジェクトの位置が手前にあるか奥にあるかで、画角内の移動量が変わってくる。遠景の山はほとんど動かないのに、手前の演者さんがカメラの動きで大きく画面上を動く......ということを想像してもらうと分かりやすいだろう。
しかし、今回の作例のように、パン(カメラを左右に振り撮る)やティルト(カメラを上下に振り撮る)を使い、カメラを回転させて撮影した映像では、実写プレートに映り込んでいる、静止したオブジェクト同士の位置関係が変わらず、球体に画をマッピングしてカメラを動かした時と同様の見え方となる。
例えば、自分の目の前に人垣ができている場合、自分の頭(目)の位置を変えず、首の振りだけで人垣の向こうを見るのは不可能で、背伸びや半歩横にずれたりと、頭(=カメラ)の位置を変えなければ、奥は見えない。つまり、首を振っている(=カメラを移動せずに回転している)限りは、視界に写っている手前のオブジェクトと奥にあるオブジェクトの位置関係に変化はないわけだ。
繰り返しになるが、カメラを回転して撮影した実写プレートは、球体にマッピングして、その球体を中心からカメラで撮影しているのと変わらない。実際には、回転の軸の位置等で違いはでるのだが、マクロ撮影でもない限り、無視できる範囲のものだろう。

球体にカメラプロジェクションするとこのような感じになる。パンやティルトというカメラの動きはこれで表現できる


360 フレーム目<左>にいる人物が、380 フレーム目<右>では同じ場所に居なくなっていることが確認できる
上の画像では、まずカメラの正確な動きを知るために [CameraTracker] ノードを用いて 3Dトラッキング。プリミティブなジオメトリである [Sphere] ノードを呼び出し、そこに検出したカメラから、対応するフレームの撮影プレートを [Project3D] ノードを使い投影している。実際に 360 フレーム目(人が映り込んでいる)と、380フレーム目(人が見切れている)とをオーバーラップさせてみると......

2つの画像を重ねてみると、背景のパース感がほぼ合っていることが判る。この理屈を使えば、人物で隠れている部分の画を作り出すことが可能だ
上手い具合に、重なっているのが確認できた。また試しに、元の実写プレート( Sphere に投影していないもの)を、後ろに写っている塔を基準に合わせてみると......

何も調整していない動画プレートの360フレーム目(上)と380フレーム目(下)。一見、合いそうに見えるのだが......

塔を基準に合わせてみると、2つの画像の背景パースが異なるため、ダブってしまった
このように、上手く合わない。もう少し分かりやすい例として、この撮影プレートの一番最初、つまりパンの始めのフレームと、パンの終わりのフレームを見比べてみよう。

赤で引いた線は平行ではなく、パースに違いがあることが判った
よく見ると建物のパースが違っているのが確認できる。これでは上手く合わないのも当然だ。
くどくなるが、今回、紹介する手法では、あるフレームの画角から、そのフレームの画を球体に投影して、別のアングルから再度撮影というもの。従い、最初に説明したようにパンやティルトといった回転系のカメラの動きであれば、パースが違えど画角内でのオブジェクトの位置関係に変化がなく、また、そのパースも球体の中から撮影することで解消される。

パンの始めの画を球体に投影し、330フレーム目のカメラ画角から再度撮影したもの(上)と、パンの最後の画を球面に投影し、330フレーム目のカメラ画角から再度撮影したもの(下)

一番下の差分を見ると判るが、建物、地面のパースがほぼ合っていて、黒くなっているのが確認できる
長々と説明してきたが、このような手法を用いることで手前を横切る人で隠れてしまっている部分の画を構築することが可能だ。
STEP 1:撮影プレートからカメラの動きを取得〜3D トラッキング
3D トラッキングというのは、撮影された映像から、それを撮影したカメラの動きを解析するというものである。NUKE の場合は、NUKEX という上位版でのみ使用可能であり、[CameraTracker] というノードに実装されている。一般的なスタンドアロンの 3D トラッキングソフトに比べても遜色ない、高機能さが魅力だ。ここからは、この [CameraTracker] ノードの使い方を解説しよう。

NUKEX に実装されている [CameraTracker] ノードは、半自動でトラッキングを行なってくれる。細かな調整も効くので、スタンドアロンの 3D トラッキングソフトと比べても見劣りしない。作業を Nuke 内で完結できるというのも大きなメリットだ
3D トラッキングは、今やかなりの部分をオートで処理してくれ、数年前に比べて精度もそれなりに高い。もちろん、ショットによっては色々と付加的情報を与え、さらにその情報を整理しないと上手くいかない場合もあるが、今回の作例のような、カメラ前を横切る人物を消すぐらいであれば、オートで処理しても高確率で良好な結果を得ることができる。
手順としては、feature track と呼ばれる画面内でコントラストのある特徴点を検出。これは 2D トラックであり、画面内からたくさんの feature を拾い上げ、feature の移動量、さらには feature 同士の相対的な移動量などを元に、静態したシーンにおいてのカメラの動きを解析(Camera solver)する。もちろん、先に述べたように撮影シーン内でのオブジェクトの大きさや、オブジェクト同士の配置距離、カメラのレンズの種類等、付加的情報があればそれを入力し、Camera solver の精度をさらに上げることが可能だ。
まずレンズの歪(ひずみ)の補正を行う。[CameraTracker] ノードで直接操作も可能だが、今回は [LensDistortion] ノードを用いた。撮影に使用した同じカメラ、同じレンズでグリッドを撮影し [LensDistortion] ノードに接続。線が細いグリッドだったので、プロパティから [GridAnalysis→Thin Line] を選び、その下の [Analysis Grid] をクリックしてレンズの歪みを補正する。

実写プレートの撮影と同じカメラ、レンズで撮ったグリッド。今回は 英 The Pixel Farm 社 で提供されているものを使った


別途撮影したグリッドを Nuke 内に読み、その [Read] ノードに [LensDistortion] ノードを繋ぐ。今回は動画ではなく、一枚画のグリッドを用いたが、動画から解析する手法もある。歪を補正しないと、Feature の解析が正確に行えず上手くトラッキングできない場合が多い。"決まり事"として必ず行うようにするのが賢明だ
[Analysis Grid] の結果は、[LensDistortion] タブ内にある「Radial Distortion 1」と「Radial Distortion 2」の数値で返される。


解析の結果として、ざっくりではあるが歪んでいたグリッドがほぼ真っ直ぐになったことが確認できる
このように、別途撮影したグリッド素材を用いて、いったん歪み補正値を得た [LensDistortion] ノードを使い、実際にクリーンアップを行う動画の歪み補正するわけだ。グリッドに繋がっている LensDistortion ノードを外して、それを実際の動画プレートに繋いでも良いし、新たに LensDistortion ノードを作成してから、先ほど取得した各数値を持ってきても良い。

動画プレートから歪みを除去し、トラッキングしやすい素材を作成できた。LensDistortion ノードを [d] ホットキーを使って ON/OFF してみると、実際にどれくらい変化があるかよく判る
基本的に 3D トラッキングは、静態したシーンを分析することはできるのだが、動態のオブジェクトを分析することは出来ない。厳密には、カメラの動きが判れば、そこからカメラの動きを引き算して、その動態のオブジェクトを割り出すことは可能である。ともかく静態シーンのカメラの動きを分析するには、動態のオブジェクトは邪魔になってしまう。作例では、手前を横切る人物がトラッキングの邪魔になるため、人物のマスクを切ることにした。
厳密なマスクは必要ではないので、ざっくりと [Roto] ノードを使い、マスクを作成。前回 紹介したように [Tracker] ノードを用いて、簡単に人物の移動の動きを検出し、それをマスクに適応すれば効率良くマスクが切れる。今回はフレーム数も少なかったので、適当なところにキーフレームを打ちながら、多少大きめのマスクを作成した。

こんな感じでざっくりとマスクを切っていく。撮影したカメラによってはコントラストのあるエッジ部分などにノイズの入りやすいものもあるので、多少大きめに切ってトラッキングのエラーを避ける
マスクを切り終えたら、ようやくトラッキングだ。[Roto] ノードの下に [CameraTracker] ノードを繋ぎ、そのプロパティで CameraTracekr タブの [Mask] を 「Source Alpha」 に設定。この状態で、先ほど作成したマスクで発生したアルファ(rgba.A)のある部分を避けてトラッキングが行われる。
ここまで準備ができれば、同じく CameraTracker タブの 「Track Features] をクリックして、Featureの検出を行う。




トラッキングしたくない領域のマスクを作成し、それを CameraTracker ノードで指定することで、トラッキングのエラーを極力少なくする
トラッキング処理が完了すると、動画プレート上にあるオブジェクトの同一ポイントが自動的に検出され、プレート上でのその軌跡がオレンジの小さな十字(=Feature)とラインで表現される。
同一の Feature の検出期間が長ければ、それだけ信頼度が高い可能性があるので、精度を上げるために [Refine] タブにある 「Min Length」 の値を高くし、その値以下の Feature を 「Delete Rejected」 ボタンで削除する。


オレンジ色で表示されているのが Feature だ。赤くなっているものは、 Refine タブで「Min Length」 を25としたため、Feature の検出期間が 25 フレームに満たなかったモノを示している。あまりにも短いモノは同一オブジェクトの同一ポイントとして信頼度に欠け、エラーの原因になるので 「Delete Rejected」 をクリックして、これらの赤い Feature を削除しよう
この他にも、[Tracking] タブにある 「Number of Features」 を大きくすれば、検出される Feature は多くなり、カメラの動きを検出する際の情報を増やすことができる。
さらに、カメラの情報を与えて精度を上げることも可能だ。[Solver] タブにある 「Camera」 でレンズの焦点距離(ミリ数)やフィルム面(素子面)のサイズ、もしくはカメラの動きの種類を指定することができる。


Feature が増えて、カメラの動きを検出する手がかりが多くなるのは良いのだが、反面、エラーになる可能性もあるため、前述の「Min Length」などで信頼度を上げて、Feature 全体を精査する必要もある。カメラの情報を与えて精度を高めるのも有効だ
ここまで終わった後は、[CameraTracker] タブにある 「Solve Camera」 ボタンでカメラの動きの分析を開始しよう。と言っても、実際の作業としては、ボタンを押すだけだ。2次元である動画プレートから検出された Feature が、3次元空間上の座標を特定し、カメラの動きが分析される。

実際には、信頼度の高い順に「緑→オレンジ→赤」 で3次元座標を与えられた Feature が確認できる。さらに 「Create Scene」 をクリックすれば、分析されて動きの付いたカメラと Feature に、3次元空間で座標が与えられたポイントクラウドが生成される。これにて、3D トラッキングは完了だ。


思うように結果が得られない場合は、プレートのレンズ歪みや余計な Feature によるエラーなどがトラッキングの邪魔になっている場合があるので、その辺りの設定を見直してみると良いだろう。


あくまでも筆者の経験測だが、上手くカメラトラッキングできる場合は、Solve Camera の処理はそれほど時間がかからない。時間がかかる場合は、設定にエラーが含まれている可能性を疑ってみることをお勧めする
STEP 2:空舞台の作成〜カメラプロジェクション+Expression
ここまでくれば、あともう一息。最初の説明でも述べたように、横切る人物で隠れた部分を別のフレームから補っていく。そのためにはまず、別フレームの画から現在のフレームの画に合ったパースを得るため、カメラプロジェクションを用いる。
CameraTracker でトラッキングしたものと同じノード(歪み補正をかけたモノ)を用いて、それに [Project3D] ノードを繋ぐ。また、[Project3D] ノードは [Camera] ノードをコネクトするパイプを持っているので、そこに、CameraTracker から生成されたカメラを複製し繋ぐ。さらにプリミティブのジオメトリノードである Sphere ノードにマッピング画像として繋ごう。

詳しくは後述するが、カメラを複製した理由は、現在のフレームとは異なるフレームから投影するためである
ここで Expression を利用して、映っている人物が、自身の幅を横切る時間(フレーム)の分だけ、ずらして投影することにする。実は CameraTracker ノードによって生成された Camera は、「link output」 にチェックが入っていれば、既に Expression が付いている。



CameraTracker によって生成された Camera ノードには、解析結果から算出された値による Expression が既に張られている。NodeGraph 上に表示される緑色のコネクトと矢印は Expression でリンクが張られていることを意味する
例えば、今回の Camera ノードの translate には
CameraTracker4.camTranslate
という記述が付いている。ここに"(300)"という記述を追加して
CameraTracker4.camTranslate(300)
とすると、このカメラの位置は300フレームの位置で静止し続ける。
さらに、"(frame)"を追加し
CameraTracker4.camTranslate(frame)
とすると、frame は現在フレームを意味し、"(frame)"を追加してないのと同じ結果になる。そして、さらに......
CameraTracker4.camTranslate(frame + 20)
とすると、現在のフレームの20フレーム先と同じ位置になる。要するに、アニメーションを20フレーム後ろにシフトさせたのと同じになるわけだ。
ここで、20フレーム先の画を、そのカメラアングルから Sphere に投影し、現在のフレームのカメラアングルから見る(撮影する)と、最初に説明したように、現在のフレームで人物によって隠れてしまった背景を得ることができる。
その理屈をノードで表現すると、まず、20フレーム先の画を前にずらすことになる。実際には、[Project3D] ノードとその親ノードとの間に [TimeOffset] ノードを繋ぎ、その TimeOffset ノードのプロパティにある 「time offset(frames)」 の値に ー20(=イン点を前に20ずらす)を入力。次に、この TimeOffset ノードの「time offset(frames)」値を Camera ノードに関連付ける。
動画プレートのイン点を "ー20" するということは、Camera ノードからすると 20 フレーム先(+20)の動きになるので......
CameraTracker4.camTranslate(frame - TimeOffset3.time_offset)
となる。

現在のフレームからずらした分だけ、ずれたアングルから投影できるよう、Expression を利用してノードを組む。こうしておけば、TimeOffest ノードの数値さえ手直しすれば、自動的に投影アングルを調整してくれる
ちなみに Expression での表記方法が分からない場合は、適当なノードのプロパティに、表記の知りたいプロパティから [Ctrl] キーを押しながらドラッグ&ドロップすると Expression を貼ることができるので便利だ(下)。また、その上で子のノードのプロパティの Expression 表記を見れば、表記方法が確認できる仕様となっている。

あとは、この Sphere ノードを撮影するため [ScanlineRender] ノードを作成。[obj/scn] にこの Sphere ノードを繋ぎ、[cam] に CameraTracker から生成された Camera ノードを繋ぐ。[Difference] ノード(Merge)で元の動画プレートとの差分を取って確認してみてもよい。


元の画のパースと合っているかを確認するため Difference ノード(Merge)で合わせてみると、ほぼ合っていることが確認できた。この後は、色合いと微調整を行なっていく
差分を確認してみたところ、少しズレがあることが判った。
トラッキングの精度も疑わしいが、今回の場合はカメラ側で生じた ローリングシャッター現象 による歪みのせいだろう。
この歪みを取り除く(緩和する)プラグイン(上にリンクさせた「RollingShutter」など)もあるが、今回は取り除くというより、[GridWrap] ノードを使って、元の動画プレートに合わせることにする。
ローリングシャッターの歪みは、CMOS センサが上から下に記録するより、画面の動きが早い場合に生じる。要するに、一番上と一番下に記録された画のタイミングが、微妙にずれているからで生じるのだ。速いパンでは、画面の下へ行くに従い、画の流れと同じ方向に画が歪み、平行四辺形のように変形する。詳しい説明は割愛するが、GridWrap ノードを用いて根気よく合わせていこう。



GridWrap ノードを使い、根気よくローリングシャッターの歪みを合わせていく
また、人物がフレームインする時は、空舞台はそれよりも前のフレームで作成するが(イン点を前にずらす)、人物がフレームアウトする時は、空舞台をそれよりも後の画(イン点を後ろにずらす)で作成しなければ、上手い具合に人物の居ない画を作り出すことができない。
したがい、画面を中央で左右に2つに分け、向かって左側(フレームイン側)と右側(フレームアウト側)で画を繋ぎ合わせた。最終的に、[Grade] ノード等で色を調整し、確認しながら元の動画プレートの上から人物部分をマスクして乗せる。

上手と下手で「ずらす」フレーム数を変更して常に人物の背後の画を作り出せるように調整した
人物を乗せるためのマスクの境界は色が馴染まないので、最後は根気よく Grade ノードで色を合わせていく。


色合わせの際は、合わせている Merge ノード(over)のマスクをいったんオフにして、[operation]を 「over」 から 「divide」(割り算)へと変更。境界領域でピッカーを使い色を広めに拾い、Viewer 下部の 「2D image information] で確認する。割り算なので 1 であれば同じ色ということだ。なので、極力 1 に近づくよう Grade ノードの 「gain」 をキーフレームに打ちながら調整する
最後は急ぎ足での解説になってしまったが、要するに 「根気よく丁寧にやる」 だけだ。
クリーンアップを済ませた完成形
コラム: Trapcode Particular for Nuke
ここからはオマケになるが、Trapcode Particular for Nuke というプラグインを紹介したい。「Nuke はノードベースで便利そうだけど、After Effects での Trapcode のプラグインのようなモノがないからなぁ」と言う人には、このプラグインがまさにうってつけだ。
もともと、After Effects のプラグインであった Trapcode Particular は、スウェーデンの Trapcode 社 が開発した 2D 上に 3D 的なパーティクル効果を生み出すプラグインである。最終出力としては 2D だが、シーン内に置かれたカメラやコリジョンオブジェクトを参照し、それを演算処理して最終的な画像に出力してくれる。
実際のシーンに 3D のパーティクル粒子が生成されるわけでないが、カメラの画角やアニメーションに精密に対応し、さらに、対象となるコリジョンオブジェクトには、ちゃんとその作用を反映した形でパーティクルの動きをシミュレーションしてくれるのだ。要するに、2D 画像だけど、内部的には 3D 処理されたパーティクルを扱えるプラグインと言ったところだろうか。
ここで紹介する Trapcode Particular for Nuke は、インストールするとNodes ペーン(ツールバー)に新たなアイコンが加わるので、ここから Particular にアクセスする。[Particular v2] ノードと [Particular 3D Gizmo] という2種類のノードが確認できるが、前者の Particular v2 ノードがプラグインの本体だ。

Trapcode Particular for Nuke をインストールすると、新たに Particular v2 と Particular 3D Gizmo という2つのノードが追加される
実際に、After Effects のそれとパラメータを比較してみたが、結果はほぼ一緒。AE 版で作成した Particular から手動で Trapcode Particular for Nuke に各数値を移植してみても、AE 版とほぼ同じ結果を得ることができた。

作成されるノードには様々なパイプがあり、事細かに制御することが可能だ

AE 版と同様に豊富なパラメータが付属されており、ほぼ同じ機能を有している

Particular 3D Gizmo には Setup というタブがあり、操作中の NUKE シーン内のカメラをなどを取得をすることなどが可能だ

実際に After Effetcs から手作業でパラメータを移植してみたところ、ほぼ同じ結果を得られた
今回は試せなかったが、パラメータが AE 版とほぼ同じなので、今まで After Effects で作成してきたアセットなどを、JavaScripts を用いてテキストファイルに出力し、NUKE 側の Python で読み込み移植することもできると思う。もちろんスクリプトを用いずとも、今回のように手動での移植が可能だ。
TEXT_テラオカマサヒロ(Galaxy of Terror)
株式会社ギャラクシーオブテラーにてヴィジュアル・エフェクツ・ディレクターとして活躍中。実写合成からフルCGまで、幅広いVFX制作に携わっている。
個人サイト「tiraokan. 」
Trapcode Particular for Nuke 2.1.2
価格:65,520円(ノードロック)
OS:Mac OS X 10.5.8以降&10.6(Intel Macのみ)、Windows XP SP2、Linux CentOS(32/64bit)※NUKE 6.1に対応
問:フラッシュバックジャパン