現在、OpenCV でステレオ画像ペアを指定して 3D ポイントを生成しようとしています。これは、私が検索できる限りかなり行われています。
私が仮定しようとしているステレオ設定の外部パラメーターは、前頭並列構成であることを知っています (実際、それほど悪くはありません!)。焦点距離、基線はわかっているので、主点を画像の中心と仮定します (わかっています、わかっています...)。
StereoSGBM を使用して擬似まともな視差マップを計算し、次のように指定されている O'Reilly の Learning OpenCV book に従って Q 行列を手作業でコーディングしました。
Q = [ 1 0 0 -c_x
0 1 0 -c_y
0 0 0 f
0 0 -1/T_x (c_x - c_x')/T_x ]
( c_x, c_y ) は主点 (画像座標で指定)、f は焦点距離 (mm で記述)、T_x は 2 つのカメラまたはベースライン間の移動 (これはmm 単位で表示されます)。
int type = CV_STEREO_BM_BASIC;
double rescx = 0.25, rescy = 0.25;
Mat disparity, vdisparity, depthMap;
Mat frame1 = imread( "C:\\Users\\Administrator\\Desktop\\Flow\\IMG137.jpg", CV_LOAD_IMAGE_GRAYSCALE );
Mat frame1L = frame1( Range( 0, frame1.rows ), Range( 0, frame1.cols/2 ));
Mat frame1R = frame1( Range( 0, frame1.rows ), Range( frame1.cols/2, frame1.cols ));
resize( frame1L, frame1L, Size(), rescx, rescy );
resize( frame1R, frame1R, Size(), rescx, rescy );
int preFilterSize = 9, preFilterCap = 32, disparityRange = 4;
int minDisparity = 2, textureThreshold = 12, uniquenessRatio = 3;
int windowSize = 21, smoothP1 = 0, smoothP2 = 0, dispMaxDiff = 32;
int speckleRange = 0, speckleWindowSize = 0;
bool dynamicP = false;
StereoSGBM stereo( minDisparity*-16, disparityRange*16, windowSize,
smoothP1, smoothP2, dispMaxDiff,
preFilterCap, uniquenessRatio,
speckleRange*16, speckleWindowSize, dynamicP );
stereo( frame1L, frame1R, disparity );
double m1[3][3] = { { 46, 0, frame1L.cols/2 }, { 0, 46, frame1L.rows/2 }, { 0, 0, 1 } };
double t1[3] = { 65, 0, 0 };
double q[4][4] = {{ 1, 0, 0, -frame1L.cols/2.0 }, { 0, 1, 0, -frame1L.rows/2.0 }, { 0, 0, 0, 46 }, { 0, 0, -1.0/65, 0 }};
Mat cm1( 3, 3, CV_64F, m1), cm2( 3, 3, CV_64F, m1), T( 3, 1, CV_64F, t1 );
Mat R1, R2, P1, P2;
Mat Q( 4, 4, CV_64F, q );
//stereoRectify( cm1, Mat::zeros( 5, 1, CV_64F ), cm2, Mat::zeros( 5, 1, CV_64F ), frame1L.size(), Mat::eye( 3, 3, CV_64F ), T, R1, R2, P1, P2, Q );
normalize( disparity, vdisparity, 0, 256, NORM_MINMAX );
//convertScaleAbs( disparity, disparity, 1/16.0 );
reprojectImageTo3D( disparity, depthMap, Q, true );
imshow( "Disparity", vdisparity );
imshow( "3D", depthMap );
そこで、StereoSGBM とその Q 行列から得られた視差マップをフィードして 3D ポイントを取得し、それを ply ファイルに書き出します。
しかし、結果はこれです: http://i.stack.imgur.com/7eH9V.png
見るのは楽しいですが、私が必要とするものではありません:(。視差マップを16で割った後により良い結果が得られることをオンラインで読みましたが、実際にはわずかに良く見えました(実際にショットを撮ったカメラがあったようです!).
興味があれば、これは私の視差マップです: http://i.stack.imgur.com/lNPkO.png
キャリブレーションなしでは、最高の 3D プロジェクションのようには見えないことは理解していますが、もう少し良いものを期待していました。
助言がありますか?