การแปลงจุด 2D เป็นตำแหน่ง 3D


9

ผมมีกล้องคงมีที่รู้จักกันและcameraMatrix distCoeffsฉันยังมีกระดานหมากรุกซึ่งได้รับการแก้ไขด้วยtransformและrotationเวกเตอร์ก็คำนวณโดยใช้solvePnPเช่นกัน

ฉันสงสัยว่าเป็นไปได้อย่างไรในการรับตำแหน่ง 3D ของจุด 2D บนระนาบเดียวกับที่กระดานหมากรุกตั้งอยู่เช่นเดียวกับภาพด้านล่าง:

ป้อนคำอธิบายรูปภาพที่นี่

สิ่งหนึ่งที่แน่นอนก็คือค่าZของจุดนั้นคือ 0 แต่ทำอย่างไรจึงจะได้XและYจากจุดนั้น


ด้วยการแปลงและการหมุนเวกเตอร์คุณสามารถอธิบายมุมกระดานหมากรุกทั้งหมดในแบบ 3 มิติได้หรือไม่?
Micka

ถ้าคุณบอกว่า Z จะเป็น 0 คุณสามารถเอาพิกัดระนาบของจุดนั้นได้หรือไม่? เช่น "ไป 10 ซม. ในทิศทางสีแดงและลบ 15 ซม. ในทิศทางสีเขียว?
Micka

@Micka สิ่งนี้ใช้งานไม่ได้เพราะพิกเซลที่อยู่ใกล้กับกล้องแสดงพื้นที่ขนาดใหญ่กว่า
EBAG

มันเป็นเรื่องง่ายที่จะได้รับพิกัดของเครื่องบินด้วย homography สัตว์เลี้ยง แต่ถ้าคุณต้องการจุด 3 มิติในพื้นที่ 3 มิติของกล้องคุณต้องเปลี่ยนเครื่องบินตามการหมุนและเวกเตอร์การแปลของคุณหลังจากนั้น
Micka

คุณสามารถให้ผลลัพธ์ที่คาดหวังของพิกัดจุดนี้ได้หรือไม่?
AbdelAziz AbdelLatef

คำตอบ:


6

คุณสามารถแก้ปัญหานี้ได้ด้วย 3 ขั้นตอนง่าย ๆ :

ขั้นตอนที่ 1:

คำนวณเวกเตอร์ทิศทาง 3 มิติที่แสดงในกรอบพิกัดของกล้องของรังสีที่ตรงกับจุดภาพ 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:

คำนวณทิศทาง 3 มิติของเวกเตอร์ของรังสีนี้ในกรอบพิกัดที่แนบมากับกระดานหมากรุกโดยใช้ท่าทางสัมพัทธ์ระหว่างกล้องกับกระดานหมากรุก:

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

ค้นหาจุด 3 มิติที่ต้องการโดยคำนวณจุดตัดระหว่าง 3d ray และระนาบกระดานหมากรุกด้วย 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

ตั้งแต่กรณีของคุณ จำกัด อยู่ที่ที่ราบวิธีง่ายๆคือใช้ Homography

ก่อนอื่นให้ยกเลิกการจัดเรียงภาพของคุณ จากนั้นใช้findHomographyเพื่อคำนวณ Homography matrix ซึ่งเปลี่ยนพิกัดพิกเซลของคุณ (ภาพ) เป็นพิกัดจริง (euclidean space เช่นหน่วยเป็น cm) สิ่งที่คล้ายกับอันนี้:

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

ฉันทำสิ่งที่คุณพูดแล้ว: vector <Point2f> มุม, เวกเตอร์ <Point2f> objectPoints2d; findChessboardCorners (img, ขนาดรูปแบบ, มุม); calcChessboardCorners (patternSize, squareSize, objectPoints2d); chessboardHomography = findHomography (มุม, objectPoints2d, RANSAC);
EBAG

มันใช้งานไม่ได้และพิกัดที่ส่งคืนนั้นไม่ถูกต้อง
EBAG

แม้ว่าคุณคูณเมทริกซ์ homography ด้วยพิกเซลซึ่งตั้งอยู่บนกระดานหมากรุก [0,0,0] มันจะส่งคืน [-192, -129, 0.33]
EBAG

@EBAG คุณเลิกลบภาพก่อนหรือไม่? ตรวจสอบ objectPoints2d ให้ถูกต้อง พิมพ์กิจกรรมและตรวจสอบด้วยตนเอง
ma.mehralian
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.