10 votes

Convertir un point 2D en une position 3D

J'ai une caméra fixe avec une cameraMatrix et des distCoeffs connus. J'ai aussi un chessboard qui est fixe également, et les vecteurs transform et rotation sont également calculés en utilisant solvePnP.

Je me demande comment il est possible d'obtenir la localisation 3D d'un point 2D sur le même plan que le chessboard, comme sur l'image ci-dessous :

entrer la description de l'image ici

Une chose est sûre, le Z de ce point est 0, mais comment obtenir les valeurs de X et de Y de ce point.

0 votes

Avec vos vecteurs de transformation et de rotation, êtes-vous capable d'expliquer tous les coins de l'échiquier en 3D?

0 votes

Si vous dites que Z sera 0, est-il acceptable pour vous d'obtenir simplement les coordonnées de l'avion de ce point? Comme "aller 10 cm dans la direction rouge et moins 15 cm dans la direction verte?

0 votes

@Micka cela ne fonctionnera pas, car les pixels plus proches de l'appareil photo représentent une zone plus grande

7voto

AldurDisciple Points 6208

Vous pouvez résoudre cela en 3 étapes simples:

Étape 1:

Calculez le vecteur de direction 3D, exprimé dans le repère de la caméra, du rayon correspondant au point d'image 2D donné en inversant le modèle de projection de la caméra:

std::vector imgPt = {{u,v}}; // Point d'image d'entrée
std::vector normPt;
cv::undistortPoints     (imgPt, normPt, cameraMatrix, distCoeffs);
cv::Matx31f ray_dir_cam(normPt[0].x, normPt[0].y, 1);
// 'ray_dir_cam' est la direction 3D du rayon dans le repère de la caméra
// Dans le repère de la caméra, ce rayon prend son origine au centre de la caméra à (0,0,0)

Étape 2:

Calculez la direction 3D du vecteur de ce rayon dans le repère attaché à l'échiquier, en utilisant la pose relative entre la caméra et l'échiquier:

// solvePnP vous donne généralement 'rvec_cam_chessboard' et 'tvec_cam_chessboard'
// Inversez cette pose pour obtenir la pose qui mappe les coordonnées de la caméra aux coordonnées de l'échiquier
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;
// Mappez le vecteur de direction du rayon des coordonnées de la caméra aux coordonnées de l'échiquier
cv::Matx31f ray_dir_chessboard = R_chessboard_cam * ray_dir_cam;

Étape 3:

Trouvez le point 3D désiré en calculant l'intersection entre le rayon 3D et le plan de l'échiquier avec Z=0:

// Exprimé dans le repère de l'échiquier, le rayon prend son origine
// de la position 3D du centre de la caméra, c'est-à-dire 'pos_cam_wrt_chessboard', et son 3D
// le vecteur de direction est 'ray_dir_chessboard'
// Tout point sur ce rayon peut être exprimé de manière paramétrique en utilisant sa profondeur 'd':
// P(d) = pos_cam_wrt_chessboard + d * ray_dir_chessboard
// Pour trouver l'intersection entre le rayon et le plan de l'échiquier, nous
// calculons la profondeur 'd' pour laquelle la coordonnée Z de P(d) est égale à zéro
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;

1voto

ma.mehralian Points 343

Étant donné que votre cas est limité aux plaines, le moyen le plus simple est d'utiliser l'Homographie.

Tout d'abord, déformez votre image. Ensuite, utilisez findHomography pour calculer la matrice Homographie qui transforme vos coordonnées de pixels (image) en coordonnées réelles (espace euclidien par exemple en cm). Quelque chose de similaire à ceci :

#include 
//...

//points on undistorted image (in pixel). more is better
vector  src_points = { Point2f(123,321), Point2f(456,654), Point2f(789,987), Point2f(123,321) };
//points on chessboard (e.g. in cm)
vector  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;

0 votes

J'ai fait ce que vous avez dit: vector coins, vector pointsObjets2d; findChessboardCorners(img, patternSize, coins); calcChessboardCorners(patternSize, squareSize, pointsObjets2d); chessboardHomographie = findHomography(coins, pointsObjets2d, RANSAC);

0 votes

Cela ne fonctionne pas, et les coordonnées retournées ne sont pas correctes

0 votes

Même si vous multipliez la matrice d'homographie par le pixel situé sur l'échiquier [0,0,0], il renverra [-192, -129, 0.33]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X