Chuyển đổi điểm 2D sang vị trí 3D


9

Tôi có một máy ảnh cố định với biết cameraMatrixdistCoeffs. Tôi cũng có một bàn cờ cũng được cố định transformrotationvectơ cũng được tính toán bằng cách sử dụng solvePnP.

Tôi đang tự hỏi làm thế nào có thể có được vị trí 3D của một điểm 2D trên cùng mặt phẳng mà bàn cờ được đặt, như hình dưới đây:

nhập mô tả hình ảnh ở đây

Một điều chắc chắn là Z của điểm đó là 0, nhưng làm thế nào để lấy XY của điểm đó.


với các vectơ biến đổi và xoay của bạn, bạn có thể giải thích tất cả các góc của bàn cờ trong 3D không?
Micka

nếu bạn nói rằng Z sẽ là 0, bạn có thể lấy tọa độ mặt phẳng của điểm đó không? Giống như "đi 10 cm theo hướng đỏ và trừ 15 cm theo hướng xanh?
Micka

@Micka điều này sẽ không hoạt động, vì các pixel gần camera hơn đại diện cho diện tích lớn hơn
EBAG

thật dễ dàng để có được tọa độ máy bay với một bản đồ đồng nhất. Nhưng nếu bạn cần các điểm 3d trong không gian 3d ở giữa máy ảnh của mình, bạn phải biến đổi mặt phẳng theo các vectơ xoay và dịch của bạn sau đó.
Micka

Bạn có thể cung cấp kết quả dự kiến ​​của bạn về tọa độ điểm này?
AbdelAziz AbdelLatef

Câu trả lời:


6

Bạn có thể giải quyết điều này bằng 3 bước đơn giản:

Bước 1:

Tính toán vectơ chỉ hướng 3d, được biểu thị trong khung tọa độ của máy ảnh, của tia tương ứng với điểm hình ảnh 2d đã cho bằng cách đảo ngược mô hình chiếu của máy ảnh:

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)

Bước 2:

Tính hướng 3d của vectơ của tia này trong khung tọa độ được gắn vào bàn cờ, sử dụng tư thế tương đối giữa máy ảnh và bàn cờ:

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

Bước 3:

Tìm điểm 3d mong muốn bằng cách tính giao điểm giữa tia 3d và mặt phẳng bàn cờ với 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;

Phương pháp của bạn hoạt động hoàn hảo, cảm ơn :)
EBAG

1

Vì trường hợp của bạn giới hạn ở đồng bằng, Cách đơn giản là sử dụng Homography.

Đầu tiên undistort hình ảnh của bạn. Sau đó, sử dụng findHomography để tính toán ma trận Homography biến đổi tọa độ pixel (hình ảnh) của bạn thành tọa độ thực (không gian euclide, ví dụ tính bằng cm). Một cái gì đó tương tự như thế này:

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

Tôi đã làm những gì bạn nói: vector <Point2f> góc, vector <Point2f> objectPoints2d; findChessboardCorners (img, patternSize, góc); calcChessboardCorners (patternSize, SquareSize, objectPoints2d); bàn cờHomography = findHomography (góc, objectPoints2d, RANSAC);
EBAG

nó không hoạt động và tọa độ mà nó trả về là không chính xác
EBAG

ngay cả khi bạn nhân ma trận homography với pixel nằm trên bàn cờ [0,0,0], nó sẽ trả về [-192, -129, 0,33]
EBAG

@EBAG bạn có cởi quần áo hình ảnh đầu tiên không? kiểm tra objectPoints2d có đúng không. Sự kiện in và kiểm tra chúng bằng tay.
ma.mehralian
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.