最近グラフィックボードを買って、CUDA環境を手に入れたのでかねてから興味のあったNeRFを試してみました。
そんな中で、フォトグラメトリーとの似ているところ、違うところが見えてきたので紹介したいと思います。
前置きのおまけ:環境構築と使い方
まずは公式のGitHubを見てほしいです。ほとんどのことはここに書いてあります。
よくわからない場合、日本語の資料としてInstant NGP (NeRF) のセットアップ方法や
初心者による初心者のためのInstant NGP(NeRF) 備忘録が詳しいです。
使い方もこれらのページにある通りですが、少々実体と異なるので説明すると、主に3フェーズ(+1)に分かれます。
フェーズ1 フォルダの準備をする
まず、作業用のフォルダを作ります。なんでもいいです。instant-ngpのフォルダとは関係ないところで良いです。
さらにその下にimagesフォルダを作って、学習対象の写真を置いておきます。
例えば、instant-ngpをCドライブ直下に置いて、C:\testフォルダを作業用にするには以下のような感じ。
--C:
|-instant-ngp
| |-build
| |-scripts
| :
|-test
|-images
そして、この作業用フォルダ(C:\test)をカレントにして作業します。
フェーズ2 COLMAPを使ってデータセットを作る
instant-ngpフォルダ内のscripts\colmap2nerf.pyを使うと、特定のフォルダの画像を使ってNeRF用のデータセットを作成できます。
C:\testをカレントにして実行するので、コマンドプロンプトなら以下のような感じ。
C:\test> python c:\instant-ngp\scripts\colmap2nerf.py --colmap_matcher exhaustive -–run_colmap
オプションは色々ありますが基本的にこれで良いです。
実行すると、カレントフォルダ(C:\test)にtransform.jsonというファイルができます。
この、transform.jsonと写真ファイルがデータセットです。
フェーズ3 Instant NeRFで学習する
instant-ngpフォルダ内のbuild\testbed.exeを使うと、アプリケーションが起動してNeRFの学習が始まります。
これもC:\testがカレントなら、
C:\test> C:\instant-ngp\build\testbed.exe --scene .\
で良いです。
なお、ヘッドレスモード(GUIを使わずに学習だけさせるモード)を使いたい場合、build\testbed.exeではなく、scripts\run.pyを使います。
C:\test> python c:\instant-ngp\scripts\run.py --mode nerf --scene c:\test\ --save_snapshot c:\test\base.msgpack --n_steps 100000
などとすると、10万ステップ学習して、その結果をbase.msgpackに保存してくれます。この学習結果はGUIでもLoad Snapshotから再利用できます。
フェーズ3+1 映像を出力する
GUIの画面をキャプチャして映像化しても良いですが、公式でmp4を出力する方法があります。こちらのほうが時間をかけてレンダリングできる分、出力が綺麗です。
まずGUIでカメラワークを設定してbase_cam.jsonを出力しておく必要があります(ここは省略します。頑張ってください)。
その後、
C:\test> python c:\instant-ngp\scripts\run.py --mode nerf --scene c:\test\ --load_snapshot c:\test\base.msgpack --video_camera_path c:\test\base_cam.json --video_n_seconds 15 --video_fps 24 --width 1920 --height 1080
などとすると、1920×1080で24fpsの動画が出力されます。
本編:フォトグラメトリーとの比較
フォトグラメトリーと同じところ
そもそも、NeRFは撮影位置の特定が済んでいる写真から3D空間を再現するAI技術であって、撮影位置を特定するのはデータセットの準備フェーズであり、狭い意味ではNeRFではありません。
「写真の撮り方が悪くてデータセットが上手く作れない」ことがあるのはフォトグラメトリーと共通です。
また、小物の撮影などはどちらも得意とするところで、精度良く再現できます。
NeRFがフォトグラメトリーより優れているところ
とにかく、以下の要素に強いです。
- 遠景(空や遠くのビルなど)の再現
- フォトグラメトリーは、立体感が分からない程遠くにあるものはメッシュ化できません。一方NeRFは遠くのものでもある程度描画してくれます。
- 水面・金属面の表現
- 反射する物体や半透明な物体はNeRFの得意とするところです。フォトグラメトリーではこれらの立体化は困難です。
- 草木のような細いものの再現
- フォトグラメトリーだと細すぎるものが苦手で、木の枝が消えたり階段の手すりが消えたりというのがよくありますが、NeRFはこれらも得意です。
- リアルな映像出力
- 上記3つを含む空間について、リアルな映像を出力することに長けています。
NeRFがフォトグラメトリーより劣っているところ
以下の点で劣っていると感じました。
- メッシュ(ポリゴン)の出力が弱い
- 当たり前ですが、NeRFはメッシュを出力するための仕組みではないので、これは弱いです。
- 生成物の再利用性が低い
- フォトグラメトリーなら作った3Dモデルを3Dゲームの中に配置したりVRChatのワールドにしたりできます。現状NeRFは写真や映像出力が主で、このように再利用できる形での生成物は出力し辛いです。
- 大規模データがほぼ扱えない
- データを大規模にすると、学習に時間がかかるのはもちろんのこと、GPUのメモリ(VRAM)大量に消費します。VRAMが不足するとプログラムが終了して学習不可能になってしまいます。VRAMはGPUと分けて増設できないので、GPUの性能によってNeRFで学習できるデータの規模が決まります。公式のTipsでは、50~150枚程度の写真が最適としています。
- 人の映り込みに弱い
- フォトグラメトリーもNeRFも「写真に写っているものはすべて止まっている」という前提があります。しかし実際のところ屋外で撮影していると人が映り込むことは避けられません。フォトグラメトリーの場合はメッシュ化できない物体は消えるので、写り込んだ人は居なかったことになりますが、NeRFは全ての写真を完全に再現しようとするので、空間にゴミのようなものが多々浮かぶことになります。
総観
NeRFはあくまでも3D空間を再現して写真や映像を出力するための技術であり、3Dモデルを出力する技術ではない、と感じました。
3Dモデルを出力したい場合はフォトグラメトリーを使うべきで、また小物やぬいぐるみなどのフォトグラメトリーが得意なものはフォトグラメトリーの方が良いと思います。
一方で水面や空を含む風景の再現はとても強く、フォトグラメトリーではほとんど何も生成できないような風景でもNeRFなら綺麗に描画するので、こういった表現にはとても向いているようです。
おまけ:生成物の紹介
instant-ngpで生成したものをいくつか紹介します。
instant-ngpのいくつかの作例。雑踏は苦手で空はわりと得意、小さなシーンなら結構ムリが効くかも。 pic.twitter.com/2D6q9SlvpL
— ぎんしゃり🍱 (@givemegohan) November 20, 2022
NeRF(instant-ngp)で家にあるものを再現させてみた。ガラス細工はわりといけるけど、金属光沢はハッキリ再現できるわけじゃないみたい。あと当然ながら半透明にはなっても屈折はしないし反射も難しい。 pic.twitter.com/UqzDNmlEPo
— ぎんしゃり🍱 (@givemegohan) November 21, 2022
NeRFだいぶ分かってきた。橋と堤防から撮った写真だけでこういうのができるんだ。 #instantNeRF pic.twitter.com/1PThNlbzPt
— ぎんしゃり🍱 (@givemegohan) November 22, 2022
カメラワークがくどすぎる動画ができた pic.twitter.com/Vfnt4sOF5H
— ぎんしゃり🍱 (@givemegohan) November 22, 2022
まだinstant-ngpで遊んでいます。これは御手水。 pic.twitter.com/FS5IpDDxlk
— ぎんしゃり🍱 (@givemegohan) November 23, 2022