it-swarm.com.de

So verwenden Sie cv :: triangulatePoints () richtig

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. 

  1. 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 . 

  2. 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).

27
Ander Biguri

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).

46
Ander Biguri

Eine kleine Ergänzung zu @Ander Biguris Antwort. Sie sollten Ihre Bildpunkte auf einem nicht-undistorted 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 .

10
Bálint Kriván

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 ...

3
Gines Hidalgo

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).

2
YuZ

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/

0
Chris