Ich versuche, einige Punkte mit OpenCV zu triangulieren, und ich habe diese cv::triangulatePoints()
- Funktion gefunden. Das Problem ist, dass es so gut wie keine Dokumentation oder Beispiele dafür gibt.
Ich habe einige Zweifel daran.
Welche Methode benutzt es? Ich habe eine kleine Forschung über Triangulationen gemacht und es gibt verschiedene Methoden (lineares, lineares LS, Eigen, iteratives LS, iteratives Eigen, ...), aber ich kann nicht finden, welche in OpenCV verwendet wird .
Wie soll ich es benutzen? Es scheint, dass es als Eingabe eine Projektionsmatrix und 3xN homogene 2D Punkte benötigt. Ich habe sie als std::vector<cv::Point3d> pnts
definiert, aber als Ausgabe benötigt sie 4xN Arrays und offensichtlich kann ich keinen std::vector<cv::Point4d>
erstellen, da er nicht existiert. Wie soll ich also den Ausgabevektor definieren?
Für die zweite Frage habe ich versucht: cv::Mat pnts3D(4,N,CV_64F);
und cv::Mat pnts3d;
, scheint keiner zu funktionieren (es gibt eine Ausnahme).
1.- Die Methode verwendet wird, Least Squares. Es gibt komplexere Algorithmen als diesen. Es ist immer noch die häufigste Methode, da die anderen Methoden in einigen Fällen fehlschlagen können (d. H. Einige andere schlagen fehl, wenn sich die Punkte auf einer Ebene oder auf unendlich befinden).
Die Methode ist zu finden in Multiple View Geometry in Computer Vision von Richard Hartley und Andrew Zisserman (p312)
2 .-Die Verwendung:
cv::Mat pnts3D(1,N,CV_64FC4);
cv::Mat cam0pnts(1,N,CV_64FC2);
cv::Mat cam1pnts(1,N,CV_64FC2);
Füllen Sie die 2 Kanalpunktmatrizen mit den Punkten in den Bildern.
cam0
und cam1
sind Mat3x4
Kameramatrizen (intrinsische und extrinsische Parameter). Sie können sie erstellen, indem Sie A * RT multiplizieren, wobei A die intrinsische Parametermatrix und RT die 3x4-Posenmatrix für die Rotationsverschiebung ist.
cv::triangulatePoints(cam0,cam1,cam0pnts,cam1pnts,pnts3D);
NOTE : pnts3D
MUSS ein 4-Kanal sein 1xNcv::Mat
wenn definiert, Löst eine Ausnahme aus, wenn nicht, aber das Ergebnis ist eine cv::Mat(4,N,cv_64FC1)
- Matrix. Wirklich verwirrend, aber nur so habe ich keine Ausnahme gemacht.
UPDATE : Ab Version 3.0 oder möglicherweise früher trifft dies nicht mehr zu, und pnts3D
kann auch vom Typ Mat(4,N,CV_64FC1)
oder kann komplett leer gelassen werden (wird wie üblich innerhalb der Funktion erstellt).
Eine kleine Ergänzung zu @Ander Biguris Antwort. Sie sollten Ihre Bildpunkte auf einem nicht-undistort
ed Bild erhalten und undistortPoints()
für cam0pnts
Und cam1pnts
Aufrufen, da cv::triangulatePoints
erwartet, dass die 2D-Punkte in normalisierten Koordinaten (unabhängig von der Kamera) und cam0
und cam1
nur [R | t ^ T] Matrizen sind, die Sie nicht benötigen multipliziere es mit A .
Danke an Ander Biguri! Seine Antwort hat mir sehr geholfen. Aber ich ziehe immer die Alternative mit std :: vector vor, ich habe seine Lösung dazu editiert:
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);
Sie müssen also nur emplace_back in den Punkten ausführen. Hauptvorteil: Sie müssen die Größe N
nicht kennen, bevor Sie mit dem Füllen beginnen. Leider gibt es kein cv :: Point4f, also muss pnts3D ein cv :: Mat sein ...
Ich habe cv :: triangulatePoints ausprobiert, aber es berechnet irgendwie Müll. Ich wurde gezwungen, eine lineare Triangulationsmethode manuell zu implementieren, die eine 4x1-Matrix für den triangulierten 3D-Punkt zurückgibt:
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;
}
die Eingabeparameter sind zwei 3x4-Kameraprojektionsmatrizen und ein entsprechendes linkes/rechtes Pixelpaar (x, y, w).
Alternativ können Sie die hier implementierte Methode von Hartley & Zisserman verwenden: http://www.morethantechnical.com/2012/01/04/simple-triangulation-with-opencv-von-harley-zisserman-w-code/