VisualSFMのカメラ情報をblenderで読み込む

VisualSFMで復元したカメラ情報のblenderへの読み込みは既に他の方々が色々試してコードも公開してくれています。
本記事は、とある公開されているコードを自分用に少し改変したので、そのまとめです。

# やりたいこと

VisualSFM（とPMVSあるいはCMPMVS）で復元した3DデータをBlender上で撮影視点と重なるようにレンダリングしたい。下図のようなイメージ。

![flow.jpg](https://qiita-image-store.s3.amazonaws.com/0/122887/860a3b08-f789-c35a-96aa-5218a860c1ef.jpeg)


# 実行環境

- windows 8.1（64ビット）
- VisualSFM v0.5.26
- blender 2.7.6b

※試していませんが、ソフトのバージョンはもっと古くても大丈夫だと思います。


# VisualSFMとは

被写体を写した複数枚の画像から、それぞれの撮影視点間の位置や向き、焦点距離を推定したり、撮影シーンの3次元情報を復元してくれるソフトです。但し、動的なシーンへの適用は難しいと思います。
以下のページで公開されています。
http://ccwu.me/vsfm/

# VisualSFMからBlenderへのカメラ情報のインポート

## ソースコード

解説記事は以下のページです。
Importing Bundler Scenes to Blender (G'raffics)
http://koelzk.crispy-cow.de/article/9/importing-bundler-scenes-to-blender

今回ベースとしたのは以下のコードです。
https://github.com/soniquev8/VSFMBundle_to_Blender/blob/master/import%20vsfm.py


これをもとに改変したコードは以下です。
https://github.com/kibekibe/VSFMBundle_to_Blender/blob/multi_cameras/import%20vsfm.py

### 変更点

- Blender上のビュートラック操作を考慮した座標変換を削除
   - 理由は、VisualSFMやCMPMVSで出力したPLYファイルと座標系を揃えたいから。
   - Blenderでは、XY平面を地面と見なして、それに合わせたトラックボール操作ができるようになっていると思います（間違ってたらご指摘ください）。
   - 一方でVisualSFMが推定するシーンの座標系は、XY平面が地面とは限りません。
   - そこで、オリジナルのソースは、Blenderでトラックボール操作しやすくなるように、VisualSFMが推定したカメラ位置を座標変換していると思います。
   - そうすると、VisualSFMで復元した3Dモデルも同じように座標変換してあげないといけないのですが、面倒だったので、今回改変したソースでは、いっそのこと、この座標変換をしないことにしました。

- 1台のカメラを時間方向に視点を変える代わりに、撮影枚数と同じ台数のカメラを生成。
  - blenderへの読み込み後に、手動でカメラ位置をまとめて動かしたいため（それしか方法を知らないだけで、もっと良い方法があるかもしれません）。

## インポート方法

まず上記スクリプトをアドオンとして登録します。
登録はBlender上で行います。

Blenderを起動します。
メニューの「ファイル」から「ユーザー設定...」を選択します。
するとBlenderユーザー設定というタイトルのウィンドウ（正式にはユーザー・プリファレンスのウィンドウ？）が表示されます。

![usersetting.jpg](https://qiita-image-store.s3.amazonaws.com/0/122887/fb9ba3bf-52de-aac3-be1d-1bad48b1edb4.jpeg)


次にアドオンパネルを表示します。
そして、ダイアログの下部にある「ファイルからインストール」ボタンを押して、上記のスクリプト（import vsfm.py）を選択します。

![addon_regist_RedCircle.jpg](https://qiita-image-store.s3.amazonaws.com/0/122887/b54f0db0-4722-eabf-0993-2d9664b6973d.jpeg)



すると、「Import-Export: import VSFM camera」というアドオンがあるはずですので、右側のチェックボックスにチェックを入れます。

![addon_active_redcircle.jpg](https://qiita-image-store.s3.amazonaws.com/0/122887/d03b7455-d8dc-688b-95c9-8708f2b9ae4a.jpeg)



チェックを入れたら、このウィンドウは閉じて、メニューの「ファイル」→「インポート」を見てみます。
「VSFM CamerasFile(txt)」という項目があればアドオン登録は完了です。
あとは、この項目を選択して、cameras_v2.txtを選択すればカメラのインポートができます。
cameras_v2.txtはVisualSFM上でPMVSを実行すると生成されるフォルダにあります（以下の図参照）。

![import_camera_v2.jpg](https://qiita-image-store.s3.amazonaws.com/0/122887/2c4a3fc7-f44a-d23a-d2a1-c48cabd6732d.jpeg)


読み込みが完了すると、VisualSFMで推定したカメラ情報に基づいて各撮影視点のカメラがシーンに生成されます。
以下の図では、復元された3Dモデルも既にインポートしています。ちなみに3DモデルはCMPMVSを使って復元しました。（CMPMVSは→http://ptak.felk.cvut.cz/sfmservice/websfm.pl?menu=cmpmvs）

![blender_after_import.jpg](https://qiita-image-store.s3.amazonaws.com/0/122887/96d80e79-0d1a-5bb5-9e83-9642c6955bff.jpeg)


これで、あとは、お好みのカメラを選択してレンダリングすれば、撮影画像に重畳することができます。↓こんなカンジ。左から順に、撮影画像、Blenderでレンダリングした画像、左2枚を重ね合わせた画像。

![result_3.jpg](https://qiita-image-store.s3.amazonaws.com/0/122887/3bacefce-b5dc-ba3c-0b52-807c2e170b27.jpeg)



以下参考文献

【VisualSFM】
Structure from Motion
[1] Changchang Wu, "Towards Linear-time Incremental Structure From Motion", 3DV 2013
[2] Changchang Wu, "VisualSFM: A Visual Structure from Motion System", http://ccwu.me/vsfm/, 2011
	   
Bundle Adjustment
[3] Changchang Wu, Sameer Agarwal, Brian Curless, and Steven M. Seitz, "Multicore Bundle Adjustment", CVPR 2011	 

Feature Detection
[4] Changchang Wu, "SiftGPU: A GPU implementation of Scale Invaraint Feature Transform (SIFT)", http://cs.unc.edu/~ccwu/siftgpu, 2007

【CMPMVS】
[5] M. Jancosek, T. Pajdla. Multi-View Reconstruction Preserving Weakly-Supported Surfaces, CVPR 2011 - IEEE Conference on Computer Vision and Pattern Recognition 2011