web-dev-qa-db-ja.com

cv :: triangulatePoints()を正しく使用する方法

OpenCVでいくつかのポイントを三角測量しようとしていますが、このcv::triangulatePoints()関数が見つかりました。問題は、ドキュメントや例がほとんどないことです。

私はそれについていくつかの疑問を持っています。

  1. どの方法を使用しますか?三角測量について小さな研究を行っていますが、いくつかの方法(線形、線形LS、固有値、反復LS、反復固有値、...)がありますが、できませんOpenCVで使用しているものを見つけます。

  2. 使用方法入力として投影行列とxN同種2Dポイントが必要なようです。 std::vector<cv::Point3d> pntsとして定義されていますが、出力として4xN配列が必要であり、std::vector<cv::Point4d>が存在しないため作成できないことは明らかです。

私が試した2番目の質問:cv::Mat pnts3D(4,N,CV_64F);cv::Mat pnts3d;、どちらも動作しないようです(例外をスローします)。

29
Ander Biguri

1.- 方法使用されるのは最小二乗です。これよりも複雑なアルゴリズムがあります。それでも、最も一般的な方法です。他の方法は、場合によっては失敗する可能性があります(つまり、ポイントが平面または無限にある場合、他の方法は失敗します)。

メソッドはComputer Visionの複数ビュージオメトリ byRichard Hartleyおよびアンドリュー・ツィザーマン(p312)

2 .-使用法

cv::Mat pnts3D(1,N,CV_64FC4);
cv::Mat cam0pnts(1,N,CV_64FC2);
cv::Mat cam1pnts(1,N,CV_64FC2);

2つのシャネルポイントマトリックスを画像内のポイントで塗りつぶします。

cam0およびcam1は、Mat3x4カメラ行列(組み込みパラメーターおよび外部パラメーター)です。 A * RTを乗算することで構築できます。ここで、Aは固有のパラメーター行列で、RT回転変換3x4ポーズ行列です。

cv::triangulatePoints(cam0,cam1,cam0pnts,cam1pnts,pnts3D);

[〜#〜] note [〜#〜]pnts3D 4チャネルにする必要があります1xNcv::Mat定義されている場合、例外をスローします、しかし結果はcv::Mat(4,N,cv_64FC1)行列です。本当に混乱しますが、それは私が例外を得なかった唯一の方法です。


[〜#〜] update [〜#〜]:バージョン3.0またはそれ以前の場合、これはもはや真ではなく、pnts3DMat(4,N,CV_64FC1)型でもあります。または、完全に空のままにしておくこともできます(通常、関数内で作成されます)。

46
Ander Biguri

@Ander Biguriの答えへの小さな追加。 _cam0pnts_は2Dを想定しているため、undistorted以外の画像で画像ポイントを取得し、_cam1pnts_および_cv::triangulatePoints_でundistortPoints()を呼び出す必要があります。 (カメラから独立した)正規化された座標内のポイントと_cam0_および_cam1_は、[R | t ^ T]で乗算する必要のない行列のみである必要があります- [〜#〜] a [〜#〜]

10
Bálint Kriván

Ander Biguriに感謝します!彼の答えは私を大いに助けてくれました。しかし、私は常にstd :: vectorの代替を好むので、これに対する彼の解決策を編集しました:

std::vector<cv::Point2d> cam0pnts;
std::vector<cv::Point2d> cam1pnts;
// You fill them, both with the same size...

// You can pick any of the following 2 (your choice)
// cv::Mat pnts3D(1,cam0pnts.size(),CV_64FC4);
cv::Mat pnts3D(4,cam0pnts.size(),CV_64F);

cv::triangulatePoints(cam0,cam1,cam0pnts,cam1pnts,pnts3D);

したがって、ポイントでemplace_backを実行するだけです。主な利点:充填を開始する前にサイズNを知る必要はありません。残念ながら、cv :: Point4fは存在しないため、pnts3Dはcv :: Matでなければなりません...

4
Gines Hidalgo

Cv :: triangulatePointsを試しましたが、どういうわけかガベージを計算します。私は手動で線形三角形分割法を実装することを余儀なくされました。これは、三角形分割された3Dポイントの4x1行列を返します。

Mat triangulate_Linear_LS(Mat mat_P_l, Mat mat_P_r, Mat warped_back_l, Mat warped_back_r)
{
    Mat A(4,3,CV_64FC1), b(4,1,CV_64FC1), X(3,1,CV_64FC1), X_homogeneous(4,1,CV_64FC1), W(1,1,CV_64FC1);
    W.at<double>(0,0) = 1.0;
    A.at<double>(0,0) = (warped_back_l.at<double>(0,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,0) - mat_P_l.at<double>(0,0);
    A.at<double>(0,1) = (warped_back_l.at<double>(0,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,1) - mat_P_l.at<double>(0,1);
    A.at<double>(0,2) = (warped_back_l.at<double>(0,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,2) - mat_P_l.at<double>(0,2);
    A.at<double>(1,0) = (warped_back_l.at<double>(1,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,0) - mat_P_l.at<double>(1,0);
    A.at<double>(1,1) = (warped_back_l.at<double>(1,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,1) - mat_P_l.at<double>(1,1);
    A.at<double>(1,2) = (warped_back_l.at<double>(1,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,2) - mat_P_l.at<double>(1,2);
    A.at<double>(2,0) = (warped_back_r.at<double>(0,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,0) - mat_P_r.at<double>(0,0);
    A.at<double>(2,1) = (warped_back_r.at<double>(0,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,1) - mat_P_r.at<double>(0,1);
    A.at<double>(2,2) = (warped_back_r.at<double>(0,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,2) - mat_P_r.at<double>(0,2);
    A.at<double>(3,0) = (warped_back_r.at<double>(1,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,0) - mat_P_r.at<double>(1,0);
    A.at<double>(3,1) = (warped_back_r.at<double>(1,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,1) - mat_P_r.at<double>(1,1);
    A.at<double>(3,2) = (warped_back_r.at<double>(1,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,2) - mat_P_r.at<double>(1,2);
    b.at<double>(0,0) = -((warped_back_l.at<double>(0,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,3) - mat_P_l.at<double>(0,3));
    b.at<double>(1,0) = -((warped_back_l.at<double>(1,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,3) - mat_P_l.at<double>(1,3));
    b.at<double>(2,0) = -((warped_back_r.at<double>(0,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,3) - mat_P_r.at<double>(0,3));
    b.at<double>(3,0) = -((warped_back_r.at<double>(1,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,3) - mat_P_r.at<double>(1,3));
    solve(A,b,X,DECOMP_SVD);
    vconcat(X,W,X_homogeneous);
    return X_homogeneous;
}

入力パラメーターは、2つの3x4カメラ投影行列と、対応する左/右ピクセルペア(x、y、w)です。

3
YuZ

あるいは、ここで実装されたHartley Zissermanのメソッドを使用できます。 http://www.morethantechnical.com/2012/01/04/simple-triangulation-with-opencv-from-harley-zisserman-w-code/

0
Chris