Structure From Motion (SfM)を試す 〜 OpenCV3.3.1 +  SfMモジュール編 (Ubuntu 16.04) 〜

今回は、Structure From Motion (SfM) について
OpenCV(3.3.1) + SfMモジュールを使い、サンプルを実行してみました。

# Structure From Motion (SfM) とは
Structure From Motion は、複数の画像から三次元形状を復元する手法になります。
https://en.wikipedia.org/wiki/Structure_from_motion

# 実行環境
・Ubuntu 16.04 LTS
・OpenCV 3.3.1

# 導入手順

## SfMモジュール導入
参考）
https://docs.opencv.org/3.3.1/db/db8/tutorial_sfm_installation.html

#### 要求されるパッケージをインストール
```
sudo apt-get install libeigen3-dev libgflags-dev libgoogle-glog-dev
```

#### 無ければ Cmake もインストール
```
sudo apt-get install cmake
```



#### Ceres Solver ビルド＆インストール
```
git clone https://ceres-solver.googlesource.com/ceres-solver
cd ceres-solver
mkdir build && cd build
cmake ..
make -j4
make test
sudo make install
```

## OpenCV(3.3.1) + contrib 導入

参考）
https://docs.opencv.org/3.3.1/d7/d9f/tutorial_linux_install.html

#### 要求されるパッケージをインストール
```
sudo apt-get install build-essential
sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev
```

#### チュートリアルに載っていないが必要なパッケージ(Viz)をインストール
```
sudo apt-get -y install libvtk5-dev
```

#### Git Repository から最新ソースコードを取得
```
cd ~/<my_working_directory>
git clone https://github.com/opencv/opencv.git
git clone https://github.com/opencv/opencv_contrib.git
```

#### OpenCV(3.3.1) + contrib ビルド＆インストール
```
cd ./opencv
mkdir build
cd build

# cmake [<some optional parameters>] <path to the OpenCV source directory>
# オプション：　OPENCV_EXTRA_MODULES_PATH=<path to opencv_contrib modules directory>
cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local ..　<path to the OpenCV source directory>
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D OPENCV_EXTRA_MODULES_PATH=<path to opencv_contrib modules directory> ..

# make
# ジョブ数：8 (任意)
make -j8

# make install
sudo make install
```

## サンプルコード実行
参考）
https://docs.opencv.org/3.3.1/d5/dab/tutorial_sfm_trajectory_estimation.html#gsc.tab=0
https://qiita.com/ChaoticActivity/items/178d23508b92a09e59ea
https://iwaki2009.blogspot.jp/2016/01/ubuntu-1404_7.html

#### trajectory_reconstruccion.cpp をコンパイル
```
cd <path to opencv_contrib directory>/modules/sfm/samples/
g++ -o trajectory_reconstruccion trajectory_reconstruccion.cpp `pkg-config --libs opencv` -I/usr/local/include -I/usr/include/eigen3 -DCERES_FOUND=1
```

> ※エラー対応メモ
> ・エラーケース１
> /usr/local/include/opencv2/sfm/numeric.hpp:41:22: fatal error: Eigen/Core: No such file or directory
> compilation terminated.
> → -I/usr/include/eigen3 オプション追加
>
> ・エラーケース２
> trajectory_reconstruccion.cpp: In function ‘int main(int, char**)’:
> trajectory_reconstruccion.cpp:148:77: error: ‘reconstruct’ was not declared in this scope
>    reconstruct(points2d, Rs_est, ts_est, K, points3d_estimated, is_projective);
> → -DCERES_FOUND=1 オプション追加

#### Viz のパスを通す
- ライブラリのパスの確認する

```
ldd trajectory_reconstruccion
```
not found となっており、パスが通っていない・・

```
	linux-vdso.so.1 =>  (0x0000~)
	libopencv_sfm.so.3.3 => /usr/local/lib/libopencv_sfm.so.3.3 (0x0000~))
	libopencv_viz.so.3.3 => not found
    ...
```

- libopencv_viz のパスを通す

```
# ファイル生成
cd /etc/ld.so.conf.d
touch opencv_viz.conf
```
ファイル生成後、opencv_viz.conf に /usr/local/lib を記載し保存し、
ldconf.cache を更新（※高速化のためキャッシュから読み出されるため）

```
# ldconf.cache 更新
ldconfig
```

パスを確認

```
ldconfig -p | grep opencv_viz
```
パスが通っている事が確認出来ました。

```
	libopencv_viz.so.3.3 (libc6,x86-64) => /usr/local/lib/libopencv_viz.so.3.3
	libopencv_viz.so (libc6,x86-64) => /usr/local/lib/libopencv_viz.so
```

### trajectory_reconstruccion 実行
```
./trajectory_reconstruccion ./data/desktop_tracks.txt 1914 640 360
```

実行すると Viz が起動します。

![S1.png](https://qiita-image-store.s3.amazonaws.com/0/134550/94c1a2fa-dbaa-ccde-1c05-6876f279d9c8.png)

マウスで角度を変える事が出来る他、以下のキーが使えます。

|キー|内容|
|:-----------------|:------------------|
|s|カメラ視点にスイッチ|
|q|終了|


### scene_reconstruction 実行

サクラダファミリアを撮影した４枚の画像から三次元情報を復元します。
※画像は[こちら](https://github.com/opencv/opencv_contrib/tree/master/modules/sfm/samples/data/images)になります。


- コンパイル

```
g++ -o scene_reconstruction scene_reconstruction.cpp `pkg-config --libs opencv` -I/usr/local/include -I/usr/include/eigen3 -DCERES_FOUND=1
```

- 実行

```
./scene_reconstruction ./data/images/dataset_files.txt 350 240 360
```

Vizが起動し、サクラダファミリアの点群が表示されます。
下部の線の黄色い点はカメラでの撮影位置になっています。

![S2.png](https://qiita-image-store.s3.amazonaws.com/0/134550/c9f4280a-b0dc-6aff-2021-0dd8ee0842c4.png)

|キー|内容|
|:-----------------|:------------------|
|q|終了|

以上、Structure From Motion (SfM) として OpenCV(3.3.1) + SfMモジュールを試しました。