Depth From Sequenceのc++コア部分をMSVCで動かしてお勉強
(編集中)
twitterで@ginrou799さんの開発されたiPhoneで奥行き推定するプログラム[1][2]、という、とても興味深い記事が紹介されていました。今日の現実逃避活動は、これのお勉強にしてみます。
iPhoneで、とありますが、コア部分はc++で開発されているそうなので、MSVCでも動かせるはずです。とりあえず、サンプル画像を入力としてデプス出力をとることを目標にしてみます。
ソースコードのダウンロード
[1]からDepthFromSequenceのソースコードをzipでダウンロードしてきて解凍します。c++コア部分だけが必要なので、libフォルダとsampleフォルダを自分のプロジェクトにコピーしてきます。普通にプロジェクトを作って、ビルドして、すんなり動いてくれればいいのですが、何か所かエラーが出ます。これを動くように改造していきます。
環境は、
- MSVC2012
- opencv300alpha
です。
修正箇所の羅列(後で整理)
main.cpp
#include <opencv2/opencv.hpp>
using namespace cv;#include "depth_from_sequence.hpp"
#include "refocus.hpp"#if _DEBUG
#pragma comment(lib, "E:\\opencv300\\build\\x86\\vc11\\lib\\opencv_world300d.lib")
#else
#pragma comment(lib, "E:\\opencv300\\build\\x86\\vc11\\lib\\opencv_world300.lib")
#endif
main.cpp
CV_LOAD_IMAGE_COLOR->IMREAD_COLOR
main.cpp
// setup ROI
cv::Rect roi;
cv::Size img_size = input_images.front().size();
if ( img_size.width > img_size.height ) {
roi = cv::Rect( (img_size.width-img_size.height)/2, 0, img_size.height, img_size.height);
} else {
roi = cv::Rect( 0, (img_size.height-img_size.width)/2, img_size.width, img_size.width);
}
depth_from_sequence.cpp
CV_RGB2GRAY->cv::COLOR_RGB2GRAY
depth_from_sequence.cpp
if ( track_points.front().size() < 70 ) return FeatureTrackingFailed;
70を変数に置き換えた方がいい
if ( solver.reprojection_error() >= 1.0 ) return BundleAdjustmentFailed;
1.0を変数に置き換えた方がいい
bundle_adjustment.cpp
double BundleAdjustment::Solver::reprojection_error() {
double error = 0.0;int n = 0;
for( int i = 0; i < (int)Nc; ++i ) {
for( int j = 0; j < (int)Np; ++j ) {
Point2d reproj = ba_reproject(points[j], camera_params[i] );
double ex = captured[i][j].x - reproj.x, ey = captured[i][j].y - reproj.y;
error += ex*ex + ey*ey;
n++;
}
}
エラーの評価値が発散してしまうので、画像サイズに応じて正規化するように変更。正しいかどうかちょっと不安。
bundle_adjustment.cppのvoid BundleAdjustment::Solver::run_one_step()内
// update valiables
for ( int k = 0, l = 0; k < (int)this->K; ++k ) {
if ( k == 0 ) continue;
if ( k == 1 ) continue;
if ( k == Nc ) continue;
if ( k == 2*Nc ) continue;
if ( k == 3*Nc ) continue;
if ( k == 4*Nc ) continue;
if ( k == 5*Nc ) continue;if(update.size().area() <= k || solved.size().area() <= l){ /*l++;*/ continue; }
update.at<double>(k) = solved.at<double>(l);
l++;
}
なぜか、メモリの範囲外を参照することがあるので強制的に排除。後で、慎重に要確認。
for ( int j = 0; j < (int)Np; ++j ) {
if(update.size().area() <= (int)(j + 0*Np + 6*Nc)) continue;
if(update.size().area() <= (int)(j + 1*Np + 6*Nc)) continue;
if(update.size().area() <= (int)(j + 2*Np + 6*Nc)) continue;
points[j].x += update.at<double>( j + 0*Np + 6*Nc );
points[j].y += update.at<double>( j + 1*Np + 6*Nc );
points[j].z += update.at<double>( j + 2*Np + 6*Nc );
}
同じく、参照外のエラーを弾く。
plane_sweep.cpp
Point2d ps_homogenious_point( Matx33d homo_mat, Point2d ref_point) {
Matx31d dst = homo_mat * Matx31d(ref_point.x, ref_point.y, 1.0);
return Point2d( dst(0,0)/dst(2,0), dst(1,0)/dst(2,0) );
//cout << dst(2, 0) << " " << dst(1, 0) << " " << dst(0, 0) << endl;
//return Point2d( dst(0,0)/dst(0,2), dst(0,1)/dst(0,2) );
}
行列の指定が逆で0割が発生するのを直す。
depth_from_sequence.hpp
DepthFromSequence(std::vector<cv::Mat3b> images, cv::Rect roi)
:_images(images),
_roi(roi)
{
// Default value
_min_depth = 500.0;
_fov = 50.0;
_depth_resolution = 127; //20
}
のdepth解像度を大きくしておく。普通のPCならCPUスペックやメモリに余裕があります。
main.cpp
imwrite("depth_smooth.png", (int)(256/_depth_resolution) * dfs._depth_smooth);
imwrite("depth_raw.png", (int)(256/_depth_resolution) * dfs._depth_raw);
imwrite("depth_color.png", dfs._depth_color);
imshow("depth_smooth", (int)(256/_depth_resolution) * dfs._depth_smooth);
imshow("depth_raw", (int)(256/_depth_resolution) * dfs._depth_raw);
imshow("depth_color", dfs._depth_color);
実行結果
サンプルとちょっと違うので、何か間違いがあるかも。。。
KLTトラッカーをAKAZEに変えても面白いかもしれませんね。