OpenCV 3.1 SfMモジュール (Visual Studio 2013)


OpenCV3.1にはSfM(Structure from Motion)モジュールが新たに追加されたが、CMakeしてもCeres solverを見つけてくれない。

そもそも、
> [The module is only available for Linux/GNU systems.](http://docs.opencv.org/master/db/db8/tutorial_sfm_installation.html#gsc.tab=0)

とあった。

ウソだ… Windowsでやってみた

# システム環境
- OpenCV 3.1
- Visual Studio 2013
- Windows 8.1
- CMake 3.2

# GLog

1. [GLog 0.3.3](https://code.google.com/p/google-glog/downloads/detail?name=glog-0.3.3.tar.gz)をダウンロードする。
2. 解凍したら、google-glog.slnを開き、ビルドする。
3. DebugとReleaseにそれぞれlibglog.dll, libglog.libが生成される。

## logging.ccのエラー

~~~
#include <algorithm>
~~~
を追記し、
Ln1386, 1387の

~~~
const int copy = min<int>(data_->num_chars_to_log_,
                                sizeof(fatal_message)-1);
~~~
を以下のように変更すると通った。

~~~
const int copy = std::min<int>(data_->num_chars_to_log_,
                                sizeof(fatal_message)-1);
~~~



# ~~GFlags~~
~~1. [GFlags](https://github.com/gflags/gflags)をダウンロードする。~~

~~2. CMakeを起動し、~~
~~ソース先: C:\gflags-master~~
~~ビルド先: C:\gflags-master\build~~
~~と指定し、configure, そしてgenerateする。~~

~~3. build下に生成されたgflags.slnを開き、ビルドする。~~
~~4. gflags.libが生成される。~~

# Ceres Solver
1. [Ceres Solver](https://github.com/tbennun/ceres-windows)をダウンロードする。
2. 先ほどコンパイルしたGLogのソースをceres-windows-masterにコピペする。
3. また、[latest stable release](http://ceres-solver.org/)からダウンロードしたceres-solverをceres-windows-masterにコピペする。
4. さらに、[Eigen](http://eigen.tuxfamily.org/index.php?title=Main_Page)をceres-windows-masterにコピペする。
Eigenは[PCL1.7.2](http://unanancyowen.com/?p=712)に付属しているものを使用している。
5. ceres-2012.slnを開き、ビルドする。
6. Win32\DebugとWin32\Releaseにそれぞれceres.dll, ceres.libが生成される。

# libmv

libmvはSfMライブラリであるが、OpenCV3.1では、SfMモジュールの中にlight版(libmv_light)が作成されている。その中に、Ceres Solverを用いたSimple Pipelineが追加されている。

1. [libmv](https://github.com/libmv/libmv)をダウンロードする。(Eigen3に対応)
~~[これ](https://code.google.com/p/libmv/)はCMakeできず、[これ](https://code.google.com/p/libmv/downloads/detail?name=libmv-0.1-full_Win-x86-msvc2008.exe)はEigen2に対応。~~
3. 解凍したlibmv-master\srcのlibmvとthird_partyをSfMモジュールのlibmv_light(opencv_contrib-master\modules\sfm\src\libmv_light\libmv)に合わせて変更していく。

## libmv-master\src\libmvを変更
### base
libmv_light\libmv\baseの

- vector.h
- vector_utils.h

をlibmv-master\src\libmv\baseに上書き。

### correspondence
libmv_light\libmv\correspondenceの

- bipartite_graph.h
- feature.h
- feature_matching.cc
- feature_matching.h
- matches.cc
- matches.h
- nRobustViewMatching.cc
- nRobustViewMatching.h
- nViewMatchingInterface.h

をlibmv-master\src\libmv\correspondenceに上書き。

CMakeLists.txtを以下のように変更する。

~~~
# define the source files
SET(CORRESPONDENCE_SRC matches.cc 
                       feature_matching.cc
                       nRobustViewMatching.cc)

# define the header files (make the headers appear in IDEs.)
FILE(GLOB CORRESPONDENCE_HDRS *.h)

ADD_LIBRARY(correspondence ${CORRESPONDENCE_SRC} ${CORRESPONDENCE_HDRS})

# make the name of debug libraries end in _d.
SET_TARGET_PROPERTIES(correspondence PROPERTIES DEBUG_POSTFIX "_d")

TARGET_LINK_LIBRARIES(correspondence multiview)

# installation rules for the library
LIBMV_INSTALL_LIB(correspondence)
            
# LIBMV_TEST(klt "correspondence;image;numeric")
# LIBMV_TEST(bipartite_graph "")
# LIBMV_TEST(kdtree "")
# LIBMV_TEST(feature_set "correspondence;image;numeric")
# LIBMV_TEST(matches "correspondence;image;numeric")
# LIBMV_TEST(Array_Matcher "correspondence;numeric;flann")
# LIBMV_TEST(tracker "correspondence;reconstruction;numeric;flann")
~~~

### multiview
libmv_light\libmv\multiviewの

- conditioning.cc
- conditioning.h
- euclidean_resection.cc
- euclidean_resection.h
- fundamental.cc
- fundamental.h
- fundamental_kernel.cc
- fundamental_kernel.h
- homography.cc
- homography.h
- homography_error.h
- homography_parameterization.h
- nviewtriangulation.h
- panography.cc
- panography.h
- panography_kernel.cc
- panography_kernel.h
- projection.cc
- projection.h
- random_sample.h
- resection.h
- resection_kernel.h
- robust_estimation.cc
- robust_estimation.h
- robust_fundamental.cc
- robust_fundamental.h
- robust_resection.cc
- robust_resection.h
- triangulation.cc
- triangulation.h
- two_view_kernel.h
- twoviewtriangulation.cc
- twoviewtriangulation.h

をlibmv-master\src\libmv\multiviewに上書き。

CMakeLists.txtを以下のように変更する。

~~~
# define the source files
SET(MULTIVIEW_SRC conditioning.cc
                  euclidean_resection.cc
                  fundamental.cc
                  fundamental_kernel.cc
                  homography.cc
                  panography.cc
                  panography_kernel.cc
                  projection.cc
                  robust_estimation.cc
                  robust_fundamental.cc
                  robust_resection.cc
                  triangulation.cc
                  twoviewtriangulation.cc)

# define the header files (make the headers appear in IDEs.)
FILE(GLOB MULTIVIEW_HDRS *.h)

ADD_LIBRARY(multiview ${MULTIVIEW_SRC} ${MULTIVIEW_HDRS})

TARGET_LINK_LIBRARIES(multiview numeric V3D colamd ldl)

# make the name of debug libraries end in _d.
SET_TARGET_PROPERTIES(multiview PROPERTIES DEBUG_POSTFIX "_d")

# installation rules for the library
LIBMV_INSTALL_LIB(multiview)

#IF (BUILD_TESTS)
#ADD_LIBRARY(multiview_test_data
#            test_data_sets.cc)
# make the name of debug libraries end in _d.
#SET_TARGET_PROPERTIES(multiview_test_data PROPERTIES DEBUG_POSTFIX "_d")
#ENDIF (BUILD_TESTS)

#MACRO (MULTIVIEW_TEST NAME)
 # LIBMV_TEST(${NAME} "multiview_test_data;multiview;numeric")
#ENDMACRO (MULTIVIEW_TEST)

#MULTIVIEW_TEST(projection)
#MULTIVIEW_TEST(triangulation)
#MULTIVIEW_TEST(fundamental)
#MULTIVIEW_TEST(fundamental_kernel)
#MULTIVIEW_TEST(fundamental_parameterization)
#MULTIVIEW_TEST(homography)
#MULTIVIEW_TEST(homography_error)
#MULTIVIEW_TEST(homography_kernel)
#MULTIVIEW_TEST(homography_parameterization)
#MULTIVIEW_TEST(panography)
#MULTIVIEW_TEST(focal_from_fundamental)
#MULTIVIEW_TEST(nviewtriangulation)
#MULTIVIEW_TEST(resection)
#MULTIVIEW_TEST(resection_kernel)
#MULTIVIEW_TEST(robust_homography)
#MULTIVIEW_TEST(robust_fundamental)
#MULTIVIEW_TEST(robust_estimation)
#MULTIVIEW_TEST(sixpointnview)
#MULTIVIEW_TEST(bundle)
#MULTIVIEW_TEST(autocalibration)
#MULTIVIEW_TEST(five_point)
#MULTIVIEW_TEST(five_point_kernel)
#MULTIVIEW_TEST(essential_kernel)
#MULTIVIEW_TEST(affine)
#MULTIVIEW_TEST(affine_kernel)
#MULTIVIEW_TEST(affine_parameterization)
#MULTIVIEW_TEST(robust_affine)
#MULTIVIEW_TEST(euclidean_resection)
#MULTIVIEW_TEST(euclidean_resection_kernel)
#MULTIVIEW_TEST(robust_euclidean_resection)
#MULTIVIEW_TEST(twoviewtriangulation)
#MULTIVIEW_TEST(robust_resection)
#MULTIVIEW_TEST(similarity)
#MULTIVIEW_TEST(similarity_kernel)
#MULTIVIEW_TEST(similarity_parameterization)
#MULTIVIEW_TEST(robust_similarity)
#MULTIVIEW_TEST(euclidean)
#MULTIVIEW_TEST(euclidean_kernel)
#MULTIVIEW_TEST(euclidean_parameterization)
#MULTIVIEW_TEST(robust_euclidean)
#MULTIVIEW_TEST(rotation_parameterization)

# TODO(keir): Make tests that depend on generated.cc to use generated sources.
#ADD_GENERATED_SOURCE(generated.cc generator.py)
~~~

### numeric
libmv_light\libmv\numericの

- function_derivative.h
- levenberg_marquardt.h
- numeric.cc
- numeric.h
- poly.cc
- poly.h

をlibmv-master\src\libmv\numericに上書き。

### simple_pipeline
libmv-master\src\libmv\にはsimple_pipelineが存在しないので、libmv_light\libmv\simple_pipelineをコピペ。

CMakeLists.txtを以下のように変更する。

~~~
SET(SIMPLE_PIPELINE_SRC
    bundle.cc
    camera_intrinsics.cc
    distortion_models.cc
    initialize_reconstruction.cc
    intersect.cc
    keyframe_selection.cc
    pipeline.cc
    reconstruction.cc
    reconstruction_scale.cc
    resect.cc
    tracks.cc
)

# Define the header files so that they appear in IDEs.
FILE(GLOB SIMPLE_PIPELINE_HDRS *.h)

ADD_LIBRARY(simple_pipeline STATIC ${SIMPLE_PIPELINE_SRC} ${SIMPLE_PIPELINE_HDRS})

TARGET_LINK_LIBRARIES(simple_pipeline multiview)

LIBMV_INSTALL_LIB(simple_pipeline)
~~~

## libmv-master\src\third_partyの変更
### eigen
ceres-windows-master\Eigenの

- Eigen
- unsupported

をlibmv-master\src\third_party\eigenに上書き。

### glog
ceres-windows-master\glog\src\glogの

- log_severity.h
- logging.h.in
- raw_logging.h.in
- stl_logging.h.in
- vlog_is_on.h.in

をlibmv-master\src\third_party\glog\src\glogに上書き。

## libmvのコンパイル
1. CMakeを開き、
ソース先: C:\libmv-master\src
ビルド先: C:\libmv-master\src\build
としてconfigure, そしてgenerateする。
2. build下に生成されたLIBMV.slnを起動し、correspondence, gflags, multiview, numeric,  simple_pipelineのみビルドする。

- correspondenceのプロパティから追加のインクルードディレクトリに追記する。

~~~
C:\ceres-windows-master\glog\src\windows;
$(OPENCV_DIR)\build\include;
~~~
- multiviewのプロパティから追加のインクルードディレクトリに追記する。

~~~
C:\ceres-windows-master\glog\src\windows;
~~~
- simple_pipelineのプロパティから追加のインクルードディレクトリに追記する。

~~~
C:\ceres-windows-master\glog\src\windows;
C:\ceres-windows-master\win\include;
C:\ceres-windows-master\ceres-solver\include;
~~~

ビルドに成功すれば、

~~~
correspondence_d.lib
correspondence.lib
gflags_d.lib (debugでビルドするときgflags.libなので名前を変更)
gflags.lib
multiview_d.lib
multiview.lib
numeric_d.lib
numeric.lib
simple_pipeline_d.lib (debugでビルドするときsimple_pipeline.libなので名前を変更)
simple_pipeline.lib
~~~
が生成される。

# プログラム作成
これで準備が整ったので、実際のSfMモジュールの[サンプルプログラム](http://docs.opencv.org/master/d5/dab/tutorial_sfm_trajectory_estimation.html#gsc.tab=0)を動かしてみる。

## Camera Motion Estimation
### ヘッダーファイル
C:\opencv_contrib-master\modules\sfm\srcの

- libmv_capi.h

を用いる。

libmv_capi.hに以下を追記する。

~~~
#define snprintf _snprintf
#define CERES_FOUND 1

#include <opencv2/opencv.hpp>
#include <opencv2/sfm.hpp>
#include <opencv_lib.hpp>
#include <gflags/gflags.h>
#include <glog/logging.h>
~~~


### ソースファイル
C:\opencv_contrib-master\modules\sfm\samplesの

- trajectory_reconstruccion.cpp

をmain.cppとする。

また、C:\opencv_contrib-master\modules\sfm\srcの

- conditioning.cpp
- fundamental.cpp
- numeric.cpp
- projection.cpp
- reconstruct.cpp
- robust.cpp
- simple_pipeline.cpp
- triangulation.cpp

を用いる。

main.cppに以下を追記する。

~~~
#include <opencv_lib.hpp>
~~~

main.cpp, reconstruct.cpp, simple_pipeline.cppに以下を追記する。

~~~
#define CERES_FOUND 1
~~~

## 追加のインクルードディレクトリ(Release)

~~~
C:\ceres-windows-master\Eigen;
C:\ceres-windows-master\glog\src\windows;
C:\ceres-windows-master\glog\src;
C:\ceres-windows-master\win\include;
C:\ceres-windows-master\ceres-solver\include;
C:\libmv-master\src;
C:\libmv-master\src\third_party;
$(OPENCV_DIR)\build\include;
~~~

## 追加のライブラリディレクトリ(Release)

~~~
C:\ceres-windows-master\glog\Release;
C:\ceres-windows-master\Win32\Release;
C:\libmv-master\src\build\lib;
$(OPENCV_DIR)\build\lib;
~~~

## 追加の依存ライブラリ(Release)

~~~
ceres.lib
libglog.lib
gflags.lib
correspondence.lib
multiview.lib
numeric.lib
simple_pipeline.lib
~~~

# 実行結果
プロジェクトの下に、ceres.dll, libglog.dll, opencv_contrib-master\modules\sfm\samples\data\desktop_tracks.txtをコピペする。

プロジェクトのプロパティ->デバッグ->コマンド引数に

~~~
desktop_tracks.txt 1914 640 360
~~~
を入力する。

Releaseで実行した結果を以下に示す。
![sfm1.png](https://qiita-image-store.s3.amazonaws.com/0/63863/aa284496-08a4-2845-c8da-24beec2124ca.png)
![sfm2.png](https://qiita-image-store.s3.amazonaws.com/0/63863/d233b1d0-88d0-28a2-2c8e-8d3db7bd2350.png)
![sfm3.png](https://qiita-image-store.s3.amazonaws.com/0/63863/db772c00-4f5a-f711-2873-4ae314f1e75e.png)


~~~
s: カメラ座標とワールド座標の視点切り替え
q: 終了
~~~

Debugではビルドできたが、実行したらエラーが出た。
![err.png](https://qiita-image-store.s3.amazonaws.com/0/63863/dcafff66-7fbf-6820-df87-5961aadc5845.png)

次は、Scene Reconstructionをやる。


# 関連記事
- [OpenCV 3.1がリリースされたので導入してみた(Visual Studio 2013)](http://qiita.com/SatoshiRobatoFujimoto/items/21d74912a7752b9e6ca4)