OpenCVでいくつかのポイントを三角測量しようとしていますが、このcv::triangulatePoints()
関数が見つかりました。問題は、ドキュメントや例がほとんどないことです。
私はそれについていくつかの疑問を持っています。
どの方法を使用しますか?三角測量について小さな研究を行っていますが、いくつかの方法(線形、線形LS、固有値、反復LS、反復固有値、...)がありますが、できませんOpenCVで使用しているものを見つけます。
使用方法入力として投影行列とxN同種2Dポイントが必要なようです。 std::vector<cv::Point3d> pnts
として定義されていますが、出力として4xN配列が必要であり、std::vector<cv::Point4d>
が存在しないため作成できないことは明らかです。
私が試した2番目の質問:cv::Mat pnts3D(4,N,CV_64F);
とcv::Mat pnts3d;
、どちらも動作しないようです(例外をスローします)。
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またはそれ以前の場合、これはもはや真ではなく、pnts3D
はMat(4,N,CV_64FC1)
型でもあります。または、完全に空のままにしておくこともできます(通常、関数内で作成されます)。
@Ander Biguriの答えへの小さな追加。 _cam0pnts
_は2Dを想定しているため、undistort
ed以外の画像で画像ポイントを取得し、_cam1pnts
_および_cv::triangulatePoints
_でundistortPoints()
を呼び出す必要があります。 (カメラから独立した)正規化された座標内のポイントと_cam0
_および_cam1
_は、[R | t ^ T]で乗算する必要のない行列のみである必要があります- [〜#〜] a [〜#〜]。
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でなければなりません...
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)です。
あるいは、ここで実装されたHartley Zissermanのメソッドを使用できます。 http://www.morethantechnical.com/2012/01/04/simple-triangulation-with-opencv-from-harley-zisserman-w-code/