Edited at
OpenCVDay 16

OpenCV-3.1のsfmモジュール[前編] Visual Studioでビルドする

More than 1 year has passed since last update.

 

これは、OpenCV Advent Calendar 2016 16日目の記事です。関連記事は目次にまとめられています。



1. はじめに

皆さんご存知のように,OpenCV-3.1で(contribに)sfmモジュールが入りました.皆さん使っていますか?もちろん僕は毎日バリバリ使って…ません.ビルドしてサンプルを試しただけで,実用として使ったことは一度もありません.しかし,そこにコードがある限り,完全体を目指してビルドするのは人の性というものでしょう.

ということで,sfmモジュール入りのOpenCVビルドとサンプル実行について,実際に試した人しか知らない落とし穴を前編・後編に分けて紹介します.

本日はVisualStudio 2015でsfmモジュールをビルドします.以下では64bitでReleaseビルドをしています.

cygwinでビルドしたい人は,こちらを参照してください.

Linuxでビルドしたい人は,以下で必要な依存ライブラリは全てapt-getできたはずなので,依存ライブラリのインストール後に3章のOpenCVのビルド設定を参考にしてください.

その他の環境(macOSとかAndroidとか)については全く知らないのでごめんなさい.

なお,軽く検索しただけで,藤本さんがlibmv(←opencv_sfmへ移植される前の元コード)をビルドしていたり,それを参考にしてopencv_sfmをlibmvへ上書きしてビルドしている方などが見受けられますが,ここではOpenCVの素材本来の味を生かした本来のビルドシステムの中でビルドします.

また,以下では各種ライブラリについてgithubでのmasterコードは使わず,バージョンナンバーがある(=リリースされた)コードを使っていますが,コードのバージョンを固定して紹介しただけの理由ですので,masterでも基本的に同様の手順でいけるとは思います.

それと,以下の説明ではcmakeでいろいろな変数設定をしますが,Windowsのcmakeでは,何か変数を設定してからConfigureすると新しい変数が出てきたりするので,必要に応じてConfigureを織り交ぜながら試してみてください.


2. 前準備

まず,opencv_sfmのビルドに必要な具材を順番にビルドしていきます.


2.1 Eigen

eigen の本稿執筆時の最新版は3.3.0です.

最初に3.3.0を使って作業した際には,最後のOpenCVのビルドの際に意味不明なエラーが出て,二晩ハマってから挫折しました.本稿を書き終えた後で念のため確認したら,今度はすんなりビルドが通りました.なので,3.3.0でも良いかもしれませんが,3.2.10を使った方が安全だと思います.

いずれにせよEigenのセットアップは普通にcmake,ビルド,インストールでOKなはずです.


2.2 Glog

glogの本稿執筆時の最新版は0.3.4です.

配布物にgoogle-glog.slnが含まれているので,それを使います.VisualStudioで開けばわかりますが,これは32bitビルド用なので,構成マネージャで64bitビルドのプロジェクトに変換します.

また,配布されているコードをそのままVisualStudio2015でビルドするとエラーが出ます.こちらに書かれているように,port.ccの中のsnprintf()をコメントアウトすればビルドが通ります.

ここではlibglog_staticではなくlibglogをビルドしました.


2.3 Gflags

gflagsの本稿執筆時の最新版は2.2.0です.

 BUILD_SHARED_LIBS

にチェックを入れてから,普通にcmakeしてビルドしました.


2.4 SuiteSpase,Metis

Windows対応SuiteSpase + Metisの本稿執筆時の最新版は1.3.1です.

デフォルトのままでcmakeは通りますが,ビルドするとエラーが出ます.この原因はmetis/GKlib/gk_arch.hの61行目からの

 61 #ifdef __MSC__

62 /* MSC does not have rint() function */
63 #define rint(x) ((int)((x)+0.5))
64
65 /* MSC does not have INFINITY defined */
66 #ifndef INFINITY
67 #define INFINITY FLT_MAX
68 #endif
69 #endif

の部分です.VisualStudio 2015では"does not have"ではないので,削除してしまっても構いませんが,私は

 61 #if defined __MSC__ && _MSC_VER < 1900

62 /* MSC does not have rint() function */
63 #define rint(x) ((int)((x)+0.5))
64
65 /* MSC does not have INFINITY defined */
66 #ifndef INFINITY
67 #define INFINITY FLT_MAX
68 #endif
69 #endif

のように修正しました.


2.5 Ceres-Solver

Ceres-Solverの本稿執筆時の最新版は1.11.0です.1.12.0のrc版もあるようですが,とりあえず1.11.0を使うことにします.

cmakeするとエラーが出ますが,ここから設定を始めていきます.

 EIGEN_INCLUDE_DIR

を設定してConfigureすると,いくつか新たな変数が出てきます.

 gflags_DIR

 GLOG_INCLUDE_DIR

 GLOG_LIBRARY

を設定します.なお,GLOG_INCLUDE_DIRは"glog-0.3.4/src/"ではなく"glog-0.3.4/src/windows/"なので注意しましょう.続いて,

 CXSPARSE

 LAPACK

にチェックを入れて,

 CXSPARSE_INCLUDE_DIR

 CXSPARSE_LIBRARY

 BLAS_blas_LIBRARY

 LAPACK_lapack_LIBRARY

にsuitesparse-metis-for-windowsに含まれているライブラリを指定します.ライブラリの設定にミスると,Configureした後でチェックが外されてしまうので要注意です.ここまでできたら,

 SUITESPARSE

にチェックを入れてConfigureします.また大量に変数が増えますが,

 METIS_LIBRARY

 UFCONFIG_INCLUDE_DIR

 AMD_INCLUDE_DIR

 AMD_LIBRARY

 CAMD_INCLUDE_DIR

 CAMD_LIBRARY

 CCOLAMD_INCLUDE_DIR

 CCOLAMD_LIBRARY

 CHOLMOD_INCLUDE_DIR

 CHOLMOD_LIBRARY

 COLAMD_INCLUDE_DIR

 COLAMD_LIBRARY

 SUITESPARSE_CONFIG_INCLUDE_DIR

 SUITESPARSE_CONFIG_LIBRARY

 SUITESPARSEQR_INCLUDE_DIR

 SUITESPARSEQR_LIBRARY

を全てsuitesparse-metis-for-windowsに含まれているライブラリで指定します.

ここまでできれば,あとはGenerateしてビルドできるはずです.


2.6 VTK

VTKはvizモジュールには必須(というよりは,vizモジュールが実質的にVTKのwrapper機能である,というべきかもしれない)ですが,当然,sfmにVTKが必要ということはありません.しかし,OpenCVに含まれる「sfmのサンプルコード」のビルドにはvizモジュールが必須なので,今回はVTKも必須です.

VTKのweb siteをチェックすると,どうも本稿を執筆する直前の11/25にVTK-7.1.0がリリースされたようです.ここはヒトバシラーとして,さっそくVTK-7.1.0をcmake,ビルド,インストールして使いましょう.

もちろんVTK-7.0.0や,VTK-6.3.0でも構いません.どれもデフォルト設定のままで普通にビルドが通るはずです.

なお,こちらのページでは「現状、7.0.0ではOpenCVのビルドが上手くいかない」と書かれていますが,後述のようにOpenCV側のちょっとした修正で対応できます.


3. OpenCVのビルド

本丸のOpenCVですが,とりあえずopencv-3.1.0opencv_contrib-3.1.0をダウンロード,展開してから,以降の作業に進みましょう.


3.1 vizモジュール設定

まずcmakeでopencv-3.1.0を読み込んでからConfigureすると,毎度おなじみの,設定変数がいろいろ表示された状態になります.そこでOPENCV_EXTRA_MODULES_PATHにopencv_contrib-3.1.0/modules/を設定しましょう.

image

再度Configureすると,contribのモジュールがビルド対象に追加されます.しかし,vizもsfmも”Unavailable”となります.依存ライブラリを設定していないので当然ですね.

image

では,VTKのパスを設定しましょう.ビルド後にインストールまでやった場合は,以下のように,VTK_DIRに"<インストール先>/lib/cmake/vtk-7.1/"を指定します.あるいはビルドしたフォルダを指定しても良かったような記憶も薄っすらとあります.

image

さて,この状態でConfigureをすると,エラーになります.

image

おそらく,「VTK-7だとビルドがうまくいかない」という風説はこれを指しているかと思います.

エラーは「vtkRenderingOpenGLがあらへんで」と言ってますが,たしかに存在しません.VTK-7からvtkRenderingOpenGL2という新モジュールへ移行したのが原因です.VTKのビルド時にOpenGL2ではなくOpenGLを使うように設定することも可能ですが,そういう後ろ向きの解決方法ではなく,ちゃんとOpenGL2を使うようにしましょう.

この問題を解決するためには opencv-3.1.0/cmake/OpenCVDetectVTK.cmake を修正します.冒頭部分で


修正前

# VTK 6.x components

find_package(VTK QUIET COMPONENTS vtkRenderingOpenGL vtkInteractionStyle vtkRenderingLOD vtkIOPLY vtkFiltersTexture vtkRenderingFreeType vtkIOExport NO_MODULE)

となっていますが,私は


修正後

# VTK 6.x/7.x components

find_package(VTK QUIET COMPONENTS vtkInteractionStyle NO_MODULE)
if("${VTK_RENDERING_BACKEND}" STREQUAL "OpenGL2")
find_package(VTK QUIET COMPONENTS vtkRenderingOpenGL2 vtkInteractionStyle vtkRenderingLOD vtkIOGeometry vtkIOPLY vtkFiltersTexture vtkRenderingFreeType vtkIOExport NO_MODULE)
else()
find_package(VTK QUIET COMPONENTS vtkRenderingOpenGL vtkInteractionStyle vtkRenderingLOD vtkIOGeometry vtkIOPLY vtkFiltersTexture vtkRenderingFreeType vtkIOExport NO_MODULE)
endif()

のように修正しました.

元はvtkRenderingOpenGLなどの有無でVTKの有無を判定していましたが,修正後は「まずはvtk-6,7に共通なモジュールでVTK自体の存在を確認」→「存在した場合には,OpenGLかOpenGL2かを確認」→「場合分けをして,必要な全モジュールの有無をチェック」という処理になっています.

どうもVTK-7.0と7.1で微妙にライブラリの仕様が変わったようで,7.0で動いていた設定では7.1はダメだったのですが,とにかく上記の修正をすれば6.3も7.0も7.1もいけるはずです.

さて,この修正をしてからVTK_DIRを設定してConfigureすれば,VTKも認識され,めでたくvizモジュールがビルド対象に入ります.

image


3.2 sfmモジュール設定

次に,sfmに必要なライブラリを設定していきます.

 EIGEN_INCLUDE_PATH

 WITH_EIGEN

 GLOG_Libs

 Ceres_DIR

の設定が必要です.これらを設定してConfigureすると,

image

このようにライブラリが検出されます.これでsfmがビルド対象に入るわけです.sfmがenableされているかどうかを見てみましょう.

image

ん?あ,あれっ?

"Module opencv_sfm disabled" …だと?!(゚д゚lll)ガーン

 

 

…この謎に対応しようと右往左往してネタを引っ張ろうかとも思いましたが,結論から言うと,いくらcmake上で設定をいじっても,ここでopencv_sfmをenableすることは絶対にできません.なぜかというと,opencv_contrib-3.1.0/modules/sfm/CMakeLists.txtに原因があるからです.16行目以降を確認すると

 16 if(NOT DEFINED SFM_DEPS_OK)

17
18 set(_fname "${CMAKE_CURRENT_BINARY_DIR}/test_sfm_deps.cpp")
19 file(WRITE "${_fname}" "#include <glog/logging.h>\n#include <gflags/gflags.h>\nint main() { (void)(0); return 0; }\n")
20 try_compile(SFM_DEPS_OK "${CMAKE_CURRENT_BINARY_DIR}" "${_fname}"
21 CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${GLOG_INCLUDE_DIRS};${GFLAGS_INCLUDE_DIRS}"
22 LINK_LIBRARIES ${GLOG_LIBRARIES} ${GFLAGS_LIBRARIES}
23 OUTPUT_VARIABLE OUTPUT
24 )
25 file(REMOVE "${_fname}")
26 message(STATUS "Checking SFM deps... ${SFM_DEPS_OK}")
27 endif()
28

というコードになっています.この16行目の"NOT DEFINED"という条件分岐が曲者で,要は,一回でもConfigureしてしまうとSFM_DEPS_OKにはTRUEかFALSEが設定されてしまっているため,その後は何度cmakeを走らせても二度と変更されません.

そして,Windows環境では最初に一度ConfigureしないとGUIに変数が表示されないので,結果的に必ずdisableされるわけです.最初これを見たときには殺意を(ry

気を取り直して,16行目を

 16 if(NOT DEFINED SFM_DEPS_OK OR NOT SFM_DEPS_OK)

のように修正します.

ということで,この落とし穴が本日のネタでした.この修正後もうまくいかない場合は,さらに新たな変数として

GFLAGS_INCLUDE_DIRS

GFLAGS_LIBRARIES

を"Add Entry"ボタンから追加して,それぞれ,"<gflagsインストール先>/include/"と,"<gflagsインストール先>/lib/gflags.lib"を設定してみてください.

その他の修正点を以下に列挙します.

opencv_contrib-3.1.0/modules/sfm/CMakeLists.txt


修正前

 59 if(Ceres_FOUND)

60 add_definitions("-DCERES_FOUND=1")
61 list(APPEND LIBMV_LIGHT_LIBS simple_pipeline)
62 else()


修正後

 59 if(Ceres_FOUND)

60 add_definitions("-DCERES_FOUND=1")
61 list(APPEND LIBMV_LIGHT_LIBS simple_pipeline)
62 list(APPEND LIBMV_LIGHT_INCLUDES ${CERES_INCLUDE_DIRS})
63 else()


修正前

130 if(Ceres_FOUND)

131 ocv_add_samples(opencv_viz)
132 endif ()


修正後

131 if(Ceres_FOUND AND BUILD_opencv_viz)

132 ocv_add_module(viz)
133 ocv_add_samples(opencv_sfm)
134 endif ()

opencv_contrib-3.1.0/modules/sfm/src/libmv_light/libmv/multiview/CMakeLists.txt


修正前

 20 TARGET_LINK_LIBRARIES(multiview glog numeric)



修正後

 20 TARGET_LINK_LIBRARIES(multiview ${GLOG_LIBRARIES} numeric)



3.3 ビルド

私の今回の環境ではBUILD_opencv_hdfとBUILD_opencv_bioinspiredにも自動でチェックが入っていたのですが,この2つがビルド時にエラーになりました.(以前にビルドした際はbioinspiredはビルドできていたはずなので,何かライブラリのバージョン依存の問題などかもしれません.)どちらも今回の目的とは関係ないので,ここではチェックを外してビルドしました.


4. まとめ

ということで,今日はopencv_sfmをVisualStudio 2015を使ってビルドしました.明らかにVisualStudioは想定されていない雰囲気ですが,それでも,それなりに手間をかけることでビルドできるということを紹介しました.


明日は,OpenCVに付属のサンプルコードを使ってSfMの動作確認をします.