2D 점을 3D 위치로 변환


9

알려진 cameraMatrix및 고정 카메라가 있습니다 distCoeffs. 나도 체스 판이 고정되어 transform있으며 rotation벡터를 사용하여 계산됩니다 solvePnP.

아래 그림과 같이 체스 판이있는 동일한 평면에서 2D 점의 3D 위치를 얻는 방법이 궁금합니다.

여기에 이미지 설명을 입력하십시오

한 가지 확실한 점은 그 점 의 Z 가 0이지만 그 점의 XY 를 얻는 방법 입니다.


변형 및 회전 벡터를 사용하여 모든 체스 판 모서리를 3D로 설명 할 수 있습니까?
Micka

Z가 0이라고 말하면 그 점의 평면 좌표를 얻는 것이 괜찮습니까? "빨간색 방향으로 10cm, 녹색 방향으로 빼기 15cm로?"
Micka

@Micka 카메라에 더 가까운 픽셀이 더 넓은 영역을 나타 내기 때문에 작동하지 않습니다
EBAG

Petspective Homoography로 평면 좌표를 얻는 것이 쉽습니다. 그러나 카메라 중심의 3D 공간에서 3D 점이 필요한 경우 나중에 회전 및 평행 이동 벡터에 따라 평면을 변환해야합니다.
Micka

이 점 좌표의 예상 결과를 제공 할 수 있습니까?
AbdelAziz AbdelLatef

답변:


6

간단한 3 단계로이 문제를 해결할 수 있습니다.

1 단계:

카메라 투영 모델을 반전시켜 주어진 2d 이미지 포인트에 해당하는 광선의 카메라 좌표 프레임으로 표현 된 3d 방향 벡터를 계산합니다.

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 단계 :

Z = 0으로 3D 광선과 체스 판 평면 간의 교점을 계산하여 원하는 3d 점을 찾으십시오.

// 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 를 사용 하여 픽셀 좌표 (이미지)를 실제 좌표 (예 : cm)와 같은 좌표로 변환하는 Homography 매트릭스를 계산하십시오. 이것과 비슷한 것 :

#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> 모서리, vector <Point2f> objectPoints2d; findChessboardCorners (img, patternSize, corners); calcChessboardCorners (patternSize, squareSize, objectPoints2d); chessboardHomography = findHomography (코너, objectPoints2d, RANSAC);
EBAG

작동하지 않고 반환하는 좌표가 올바르지 않습니다.
EBAG

체스 판 [0,0,0]에 위치한 픽셀에 호모 그래피 행렬을 곱하더라도 [-192, -129, 0.33]을 반환합니다.
EBAG

@ EBAG 이미지를 먼저 undistore합니까? objectPoints2d가 올바른지 확인하십시오. 이벤트 인쇄 및 수동 확인
ma.mehralian
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.