Konvertieren von 2D-Punkten in 3D-Positionen


9

Ich habe eine feste Kamera mit bekannten cameraMatrixund distCoeffs. Ich habe auch ein Schachbrett, das ebenfalls repariert ist, transformund ein rotationVektor wird ebenfalls mit berechnetsolvePnP .

Ich frage mich, wie es möglich ist, die 3D-Position eines 2D-Punkts auf derselben Ebene zu ermitteln, auf der sich das Schachbrett befindet, wie im folgenden Bild dargestellt:

Geben Sie hier die Bildbeschreibung ein

Eine Sache ist sicher, dass das Z dieses Punktes 0 ist, aber wie man X und Y dieses Punktes erhält .


Können Sie mit Ihren Transformations- und Rotationsvektoren alle Schachbrettecken in 3D erklären?
— Micka

Wenn Sie sagen, dass Z 0 sein wird, ist es für Sie in Ordnung, nur die Ebenenkoordinaten dieses Punktes zu erhalten? Wie "10 cm in rote Richtung und minus 15 cm in grüne Richtung gehen?
— Micka

@ Micka das wird nicht funktionieren, weil Pixel näher an der Kamera größere Fläche darstellen
— EBAG

Es ist einfach, die Flugzeugkoordinaten mit einer petspektiven Homographie zu ermitteln. Wenn Sie jedoch die 3D-Punkte in Ihrem kamerazentrierten 3D-Raum benötigen, müssen Sie die Ebene anschließend entsprechend Ihren Rotations- und Translationsvektoren transformieren.
— Micka

Können Sie Ihr erwartetes Ergebnis dieser Punktkoordinaten angeben?
— AbdelAziz AbdelLatef

Antworten:


6

Sie können dies mit 3 einfachen Schritten lösen:

Schritt 1:

Berechnen Sie den im Koordinatenrahmen der Kamera ausgedrückten 3D-Richtungsvektor des Strahls, der dem angegebenen 2D-Bildpunkt entspricht, indem Sie das Kameraprojektionsmodell invertieren:

std::vector<cv::Point2f> imgPt = {{u,v}}; // Input image point
std::vector<cv::Point2f> normPt;
cv::undistortPoints     (imgPt, normPt, cameraMatrix, distCoeffs);
cv::Matx31f ray_dir_cam(normPt[0].x, normPt[0].y, 1);
// 'ray_dir_cam' is the 3d direction of the ray in camera coordinate frame
// In camera coordinate frame, this ray originates from the camera center at (0,0,0)

Schritt 2:

Berechnen Sie die 3D-Richtung des Vektors dieses Strahls in dem am Schachbrett angebrachten Koordinatenrahmen unter Verwendung der relativen Pose zwischen Kamera und Schachbrett:

// solvePnP typically gives you 'rvec_cam_chessboard' and 'tvec_cam_chessboard'
// Inverse this pose to get the pose mapping camera coordinates to chessboard coordinates
cv::Matx33f R_cam_chessboard;
cv::Rodrigues(rvec_cam_chessboard, R_cam_chessboard);
cv::Matx33f R_chessboard_cam = R_cam_chessboard.t();
cv::Matx31f t_cam_chessboard = tvec_cam_chessboard;
cv::Matx31f pos_cam_wrt_chessboard = -R_chessboard_cam*t_cam_chessboard;
// Map the ray direction vector from camera coordinates to chessboard coordinates
cv::Matx31f ray_dir_chessboard = R_chessboard_cam * ray_dir_cam;

Schritt 3:

Finden Sie den gewünschten 3D-Punkt, indem Sie den Schnittpunkt zwischen dem 3D-Strahl und der Schachbrettebene mit Z = 0 berechnen:

// Expressed in the coordinate frame of the chessboard, the ray originates from the
// 3d position of the camera center, i.e. 'pos_cam_wrt_chessboard', and its 3d
// direction vector is 'ray_dir_chessboard'
// Any point on this ray can be expressed parametrically using its depth 'd':
// P(d) = pos_cam_wrt_chessboard + d * ray_dir_chessboard
// To find the intersection between the ray and the plane of the chessboard, we
// compute the depth 'd' for which the Z coordinate of P(d) is equal to zero
float d_intersection = -pos_cam_wrt_chessboard.val[2]/ray_dir_chessboard.val[2];
cv::Matx31f intersection_point = pos_cam_wrt_chessboard + d_intersection * ray_dir_chessboard;

Ihre Methode funktioniert perfekt, danke :)
— EBAG

1

Da sich Ihr Fall auf die Ebenen beschränkt, besteht die einfache Möglichkeit darin, Homografie zu verwenden.

Verzerren Sie zuerst Ihr Bild. Verwenden Sie dann findHomography , um die Homographiematrix zu berechnen, die Ihre Pixelkoordinate (Bild) in eine echte Koordinate (euklidischer Raum, z. B. in cm) umwandelt. Ähnliches wie dieses:

#include <opencv2/calib3d.hpp>
//...

//points on undistorted image (in pixel). more is better
vector<Point2f>  src_points = { Point2f(123,321), Point2f(456,654), Point2f(789,987), Point2f(123,321) };
//points on chessboard (e.g. in cm)
vector<Point2f>  dst_points = { Point2f(0, 0), Point2f(12.5, 0), Point2f(0, 16.5), Point2f(12.5, 16.5) }; 
Mat H = findHomography(src_points, dst_points, RANSAC);

//print euclidean coordinate of new point on undistorted image (in pixel)
cout << H * Mat(Point3d(125, 521, 0)) << endl;

Ich habe getan, was Sie gesagt haben: Vektor <Point2f> Ecken, Vektor <Point2f> objectPoints2d; findChessboardCorners (img, patternSize, Ecken); calcChessboardCorners (patternSize, squareSize, objectPoints2d); chessboardHomography = findHomography (Ecken, objectPoints2d, RANSAC);
— EBAG

es funktioniert nicht und die zurückgegebene Koordinate ist nicht korrekt
— EBAG

Selbst wenn Sie die Homographiematrix mit dem Pixel multiplizieren, das sich auf dem Schachbrett befindet [0,0,0], wird [-192, -129, 0,33]
— EBAG

@EBAG Undistore Bild zuerst? Überprüfen Sie, ob objectPoints2d korrekt ist. Ereignis drucken und manuell überprüfen.
— Ma.mehralian
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.