Перетворення 2D точки в 3D-розташування


9

У мене є нерухома камера з відомими cameraMatrixі distCoeffs. У мене також є шахова дошка, яка теж фіксується, transformі rotationвектор також розраховується за допомогою solvePnP.

Мені цікаво, як можна отримати 3D-розташування 2D точки на тій же площині, на якій розташована шахова дошка, як на малюнку нижче:

введіть тут опис зображення

Однозначно, що Z цієї точки дорівнює 0, але як отримати X і Y цієї точки.


Ви можете пояснити свої куточки шахової дошки за допомогою 3D-векторів перетворення та обертання в 3D?
Micka

якщо ви скажете, що Z буде дорівнює 0, чи добре вам просто отримати площинні координати цієї точки? Як «збирається 10 см в червоній стороні і мінус 15 см в зеленому напрямку?
Micka

@Micka це не працює, тому що пікселі, розташовані ближче до камери, представляють більшу площу
EBAG

легко отримати площинні координати за допомогою перспективної гомографії. Але якщо вам потрібні 3D-точки в 3d-просторі, орієнтованому на камеру, вам слід згодом перетворити площину відповідно до векторів обертання та перекладу.
Micka

Чи можете ви надати очікуваний результат координат цієї точки?
AbdelAziz AbdelLatef

Відповіді:


6

Ви можете вирішити це за допомогою 3 простих кроків:

Крок 1:

Обчисліть 3d-напрямок вектора, виражений у координатному кадрі камери, променя, відповідного даній точці зображення 2d, шляхом інвертування моделі проекції камери:

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)

Крок 2:

Обчисліть 3d напрямок вектора цього променя в рамці координат, прикріпленій до шахової дошки, використовуючи відносну позу між камерою та шаховою дошкою:

// 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;

Крок 3:

Знайдіть потрібну 3d точку, обчисливши перетин між 3d-променем та площиною шахової дошки із Z = 0:

// 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;

Ваш метод працює чудово, дякую :)
EBAG

1

Оскільки ваш випадок обмежений рівнинами, найпростішим способом є використання гомографії.

Спочатку спотворюйте свій образ. Потім використовуйте findHomography для обчислення матриці гомографії, яка перетворює вашу піксельну координату (зображення) в реальну координату (евклідовий простір, наприклад, в см). Щось подібне до цього:

#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;

Я зробив те, що ви сказали: вектор <Point2f> кути, вектор <Point2f> objectPoints2d; findChessboardCorners (img, patternSize, кути); calcChessboardCorners (patternSize, squareSize, objectPoints2d); chessboardHomography = findHomography (куточки, objectPoints2d, RANSAC);
EBAG

це не працює, і координата, яку він повертає, не вірна
EBAG

навіть якщо ви помножите матрицю гомографії на піксель, який знаходиться на шаховій дошці [0,0,0], вона повернеться [-192, -129, 0.33]
EBAG

@EBAG Ви спочатку знімаєте зображення? перевірити objectPoints2d правильним. Роздрукувати події та перевірити їх вручну.
ma.mehralian
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.