Direct Sparse Odometry (DSO) を Win10, VS2017 でビルド
- SLAM手法の1つである Direct Sparse Odometry (DSO) をWindows上でTUMのデータセットを使って動かしたくトライ。
- ※DSOの要点まとめはこちらのエントリを参照:
環境
- Windows 10 Home x64
- Visual Studio Community 2017
- CMake 3.10.2
スタート地点
本家Gitは下記だがLinux/Mac前提。
GitHub - JakobEngel/dso: Direct Sparse Odometry
これをWindows向けに移植したforkがあったので、これを使う。
GitHub - AndreV2890/dso: Direct Sparse Odometry
しかし手元の環境ではすんなりビルドができなかった。
どうも、上記Win版DSOは下記の環境でのビルドを想定しているようである。
- Visual Studio 2015
- x86版
- Releaseモードのみ
thirdpartyの準備
まず、thirdpartyはx86を前提として準備されている。自分で全部やりなおすのが面倒だったので、同じくx86で行くことにする。
READMEによると、cmakeしたときに依存ライブラリのパスをそれぞれ設定すればOKと書いてあるが、一部はそのままではうまくいかなかった。
- READMEの通りやれば、うまくいったもの
- Eigen
- SuiteSparse
- CHOLMOD
- OpenCV
以下ではうまくいかなかったものについて記す
Boost, Pangolin, OpenCVへのlink (CMakeLists.txt)
cmakeのfind_packageではうまく見つからないので、
set (Boost_FOUND ON) set (Pangolin_FOUND ON) set (OpenCV_FOUND ON)
ということにして、includeやlibのパスをinclude_directories,() link_directories()で手動設定。
ちなみにこの3つがないと、dsoのコアライブラリまではビルドできるが、それを使ったアプリ(dso_dataset)がビルドされない。
更にちなみに、BoostはVisualStudio 2015 (vc14, v140)でビルドされているが、v140からそれ以降と互換性があるらしく今回VisualtStudio2017 (vc15, v141)だが再ビルド不要らしい。
VisualStudio2017でDSOをビルドするなら、v141のライブラリじゃないとダメだった。そのため、Boost1.66を別途x86でビルドしてリンク。
Pangolinのビルド
Releaseモード
普通にビルド。ただし、私はOpenNI2を入れていた関係でそれ関係のビルドもONになってしまい、それがリンクエラーを誘発してしばらく詰まっていた。今回OpenNI2は使わないので、CMakeの段階でOFFにする(自動的に設定されたパスを削除してConfigureする)ことで対処。
Debugモード(DSOをDebugモードで動かしたい場合は必須)
DSO.slnとライブラリの種類を合わせないと、最後のDSOビルドでpangolin.lib関連で大量のリンクエラーが発生する。
/MDとか/MTとかmsvcrt.libとかlibc.libとかlibcmt.libとか - snipsnipsnip
Pangolinプロジェクトを右クリックして[構成プロパティ]→[C/C++]→[コード生成]→[ランタイムライブラリ]を /MTd から /MDd に変更。
OpenCVのDebugモードビルド(DSOをDebugモードで動かしたい場合は必須)
thirdparty/opencvにはRelease版しか入っていない。OpenCVはDebug時はDebug用、Release時はRelease用をちゃんとリンクしないとエラーになるので、x86のDebugを自分で別途ビルド。
(配布されているPrebuiltなOpenCVはx64でしかビルドされていないので自分でビルドするしかない)
libzipのビルド
TUMのデータセットは入力画像をzipで固めているのだが、そのzipのまま画像を読み取れるようにするためにはlibzipが必要。そしてlibzipのビルドにはzlibが必要。
ということで何も考えずにWindowsでビルドできるよう環境がそろった下記を持ってきた。
GitHub - kiyolee/zlib-win-build: zlib Windows build with Visual Studio.
GitHub - kiyolee/libzip-win-build: libzip Windows build with Visual Studio.
> cd {somewhere}\ > git clone https://github.com/kiyolee/zlib-win-build.git > git clone https://github.com/kiyolee/libzip-win-build.git
上記gitのREADMEにも書いてあるが、zlib→libzipの順序でビルドする必要がある。その際、libzipのVSソリューション内のzlibへのincludeやlibのパスは自分の環境に合わせなおす必要があることに注意。
後から気づいたが、Pangolinをビルドするとthirdparty/Pangolin/build/external/にzlibがビルドされているので、これを使ってthirdparty/libzip-1.1.1.tar.gzを解凍&ビルドすればよかったかも。
DSOビルド
ようやくメインのビルド。これもそのままではビルドできない。
zipオフライン映像を入力するよう改造1
Win版forkではWebカメラで動かすように改造されているようなので、本家のmain_dso_pangolin.cppから該当箇所を逆移植。
実際の改造コードの掲載はここでは省略する。やることは次の通り:
- main関数内のcv::VideoCapture関係の記述を削除
- main関数冒頭でparseArgumentするようにし、sourceなどのハードコード指定を削除
- 画像読み込みのwhile文を削除し、本家からfor文を移植
zipオフライン映像を入力するよう改造2
src\util\DatasetReader.hの中のgetdir関数がPOSIX仕様なので、下記を参考に書き換え。
ディレクトリ内のファイルリストを得る
#ifdef _MSC_VER #include <io.h> #else #include <dirent.h> #endif inline int getdir(std::string dir, std::vector<std::string> &files) { #ifdef _MSC_VER struct _finddata_t fdata; intptr_t fh = _findfirst(dir.c_str(), &fdata); if (-1 == fh) { return -1; } do { std::string name = std::string(fdata.name); if (name != "." && name != "..") files.push_back(name); } while (0 == _findnext(fh, &fdata)); _findclose(fh); #else // (省略) #endif std::sort(files.begin(), files.end()); if(dir.at( dir.length() - 1 ) != '/') dir = dir+"/"; for(unsigned int i=0;i<files.size();i++) { if(files[i].at(0) != '/') files[i] = dir + files[i]; } return files.size(); }
usleep削除
main_dso_pangolin.cpp内にusleep()が使われているがWindowsでは使えない。
WinAPIのQueryPerformanceCounter()に代替するのが正しいのだろうが、面倒なのでひとまず単純にコメントアウト。問題が生じたら後で上の修正をすることとする…
リンクするライブラリを追加
リンクするライブラリはmain_dso_pangolin.cppの冒頭で #pragma comment で指定されている。下記のように編集。
//#include <GL/freeglut.h> #pragma comment(lib, "glew.lib") #pragma comment(lib, "libpng16.lib") #pragma comment(lib, "jpeg.lib") #pragma comment(lib, "libzip.lib") #pragma comment(lib, "glu32.lib") #pragma comment(lib, "opengl32.lib") // Boost #ifdef _DEBUG #pragma comment(lib, "libboost_thread-vc141-mt-gd-x32-1_66.lib") #pragma comment(lib, "libboost_system-vc141-mt-gd-x32-1_66.lib") #pragma comment(lib, "libboost_date_time-vc141-mt-gd-x32-1_66.lib") #pragma comment(lib, "libboost_chrono-vc141-mt-gd-x32-1_66.lib") #else #pragma comment(lib, "libboost_thread-vc141-mt-s-x32-1_66.lib") #pragma comment(lib, "libboost_system-vc141-mt-s-x32-1_66.lib") #pragma comment(lib, "libboost_date_time-vc141-mt-s-x32-1_66.lib") #pragma comment(lib, "libboost_chrono-vc141-mt-s-x32-1_66.lib") #endif // OpenCV #ifdef _DEBUG #pragma comment(lib,"opencv_core341d.lib") #pragma comment(lib,"opencv_highgui341d.lib") #pragma comment(lib,"opencv_imgproc341d.lib") #pragma comment(lib,"opencv_imgcodecs341d.lib") #pragma comment(lib,"opencv_videoio341d.lib") #else #pragma comment(lib,"opencv_core341.lib") #pragma comment(lib,"opencv_highgui341.lib") #pragma comment(lib,"opencv_imgproc341.lib") #pragma comment(lib,"opencv_imgcodecs341.lib") #pragma comment(lib,"opencv_videoio341.lib") #endif
thirdparty/Pangolin/glewがあったので、要らんやろと思いfreeglutのincludeも消したが、thirdparty/freeglutがあったことに後から気づいた。
いざビルド&実行
ビルドできた。
その後、libpng16.dll, libzip.dll, opencv_*.dllが見つかるようにパスを通すと実行できた。