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 .

EBAG
quelle
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;
BConic
quelle
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;
ma.mehralian
quelle
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