Kameraposition in Weltkoordinaten von cv::solvePnP

Lesezeit: 4 Minuten

Kameraposition in Weltkoordinaten von cvsolvePnP
nkint

Ich habe eine kalibrierte Kamera (intrinsische Matrix und Verzerrungskoeffizienten) und möchte die Kameraposition wissen, indem ich einige 3D-Punkte und ihre entsprechenden Punkte im Bild (2D-Punkte) kenne.

ich weiß das cv::solvePnP könnte mir helfen, und nachdem ich dies und das gelesen habe, verstehe ich, dass ich die Ausgaben von PnP löse rvec und tvec sind die Rotation und Translation des Objekts im Kamerakoordinatensystem.

Also muss ich die Kamerarotation / -translation im Weltkoordinatensystem herausfinden.

Aus den obigen Links geht hervor, dass der Code in Python einfach ist:

found,rvec,tvec = cv2.solvePnP(object_3d_points, object_2d_points, camera_matrix, dist_coefs)
rotM = cv2.Rodrigues(rvec)[0]
cameraPosition = -np.matrix(rotM).T * np.matrix(tvec)

Ich kenne Python/Numpy-Zeugs nicht (ich verwende C++), aber das macht für mich nicht viel Sinn:

  • rvec, tvec-Ausgaben von solvePnP sind 3×1-Matrix, 3-Element-Vektoren
  • cv2.Rodrigues(rvec) ist eine 3×3-Matrix
  • cv2.Rodrigues(rvec)[0] ist eine 3×1-Matrix, 3 Elementvektoren
  • cameraPosition ist eine 3×1 * 1×3-Matrixmultiplikation, die eine 3×3-Matrix ist. wie kann ich das in opengl mit simple glTranslatef und glRotate Anrufe?

1643788806 594 Kameraposition in Weltkoordinaten von cvsolvePnP
ChronoTrigger

Wenn Sie mit “Weltkoordinaten” “Objektkoordinaten” meinen, müssen Sie die inverse Transformation des vom pnp-Algorithmus gelieferten Ergebnisses erhalten.

Es gibt einen Trick zum Invertieren von Transformationsmatrizen, mit dem Sie sich die normalerweise teure Invertierungsoperation sparen können, und der den Code in Python erklärt. Angesichts einer Transformation [R|t]wir haben das inv([R|t]) = [R'|-R'*t]wo R' ist die Transponierte von R. Sie können also codieren (nicht getestet):

cv::Mat rvec, tvec;
solvePnP(..., rvec, tvec, ...);
// rvec is 3x1, tvec is 3x1

cv::Mat R;
cv::Rodrigues(rvec, R); // R is 3x3

R = R.t();  // rotation of inverse
tvec = -R * tvec; // translation of inverse

cv::Mat T = cv::Mat::eye(4, 4, R.type()); // T is 4x4
T( cv::Range(0,3), cv::Range(0,3) ) = R * 1; // copies R into T
T( cv::Range(0,3), cv::Range(3,4) ) = tvec * 1; // copies tvec into T

// T is a 4x4 matrix with the pose of the camera in the object frame

Aktualisieren: Später zu verwenden T Bei OpenGL müssen Sie beachten, dass sich die Achsen des Kamerarahmens zwischen OpenCV und OpenGL unterscheiden.

OpenCV verwendet die normalerweise in Computer Vision verwendete Referenz: X zeigt nach rechts, Y nach unten, Z nach vorne (wie in dieses Bild). Der Rahmen der Kamera in OpenGL ist: X zeigt nach rechts, Y nach oben, Z nach hinten (wie auf der linken Seite von dieses Bild). Sie müssen also eine Drehung um die X-Achse von 180 Grad anwenden. Die Formel dieser Rotationsmatrix ist in Wikipedia.

// T is your 4x4 matrix in the OpenCV frame
cv::Mat RotX = ...; // 4x4 matrix with a 180 deg rotation around X
cv::Mat Tgl = T * RotX; // OpenGL camera in the object frame

Diese Transformationen sind immer verwirrend und ich kann mich bei einem Schritt irren, also nehmen Sie dies mit einem Körnchen Salz.

Berücksichtigen Sie schließlich, dass Matrizen in OpenCV in der Reihenfolge der wichtigsten Zeilen im Speicher gespeichert werden und die von OpenGL in der Reihenfolge der Spalten.

  • scheint zu funktionieren, ich bekomme die Winkel dafür glRotatef mit einer daraus abgeleiteten Formel: euclideanspace.com/maths/geometry/rotations/conversions/… und dann normale Umwandlung von Radialen in Grad. Aber wenn ich diese Werte in OpenGL einfüge, bekomme ich immer noch eine falsche Kamerarotation (Rotation X ist so etwas wie 45 ° falsch) und eine leicht falsche Übersetzung.

    – nkint

    6. September 13 um 7:21 Uhr

  • Das kann daran liegen, dass die Kamerarahmen in OpenCV und OpenGL unterschiedlich sind. Überprüfen Sie meine erweiterte Antwort.

    – ChronoTrigger

    6. September 13 um 12:47 Uhr

  • Ja, ich kenne den Unterschied in der Reihenfolge der Matrix im Speicher zwischen opencv und opengl. Und ich muss auch die y- und z-Achse umdrehen ( => opencv y als opengl z verwenden und opencv z als opengl y verwenden)

    – nkint

    6. September 13 um 17:21 Uhr

  • fast nah! die Ergebnisse stimmen mit mehreren Studien überein. Es scheint mir, dass es einen Fehler von 45 ° auf der X-Achse gibt (das könnte ein Unterschied im Rahmen zwischen opencv und opengl sein, den ich nicht verstehe) und von 10 ° auf dem y-Winkel (den ich nicht kenne wie interpretieren)

    – nkint

    6. September 13 um 17:21 Uhr

  • Bist du sicher, dass die Achsen so sind, wie du sagst? Ich denke, sie sind wie in meinem Beispiel, aber ich könnte mich irren. Überprüfen Sie auch, ob die Projektionsparameter der Kamera in opencv und opengl gleich sind.

    – ChronoTrigger

    7. September 13 um 7:25 Uhr

1643788807 581 Kameraposition in Weltkoordinaten von cvsolvePnP
Hammer

Wenn Sie es in eine Standard-4×4-Pose-Matrix umwandeln möchten, die die Position Ihrer Kamera angibt. Verwenden Sie rotM als oberes linkes 3×3-Quadrat, tvec als die 3 Elemente auf der rechten Seite und 0,0,0,1 als untere Reihe

pose = [rotation   tvec(0)
        matrix     tvec(1)
        here       tvec(2)
        0  , 0, 0,  1]

dann invertieren (um die Pose der Kamera anstelle der Pose der Welt zu erhalten)

.

738590cookie-checkKameraposition in Weltkoordinaten von cv::solvePnP

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy