Konwersja punktu 2D na lokalizację 3D

9

Mam stały aparat ze znanymi cameraMatrixi distCoeffs. Mam również szachownicę, która jest również naprawiona, transforma rotationwektor jest również obliczany za pomocą solvePnP.

Zastanawiam się, w jaki sposób można uzyskać lokalizację 3D punktu 2D na tej samej płaszczyźnie, na której znajduje się szachownica, jak na poniższym obrazku:

wprowadź opis zdjęcia tutaj

Jedno jest pewne, że Z tego punktu wynosi 0, ale jak uzyskać X i Y tego punktu.

EBAG
źródło
czy potrafisz wyjaśnić wszystkie narożniki szachownicy w 3D za pomocą wektorów transformacji i obrotu?
Micka
jeśli powiesz, że Z będzie wynosić 0, czy możesz po prostu uzyskać współrzędne samolotu tego punktu? Jak „iść 10 cm w kierunku czerwonym i minus 15 cm w kierunku zielonym?”
Micka
@Micka to nie zadziała, ponieważ piksele bliżej kamery reprezentują większy obszar
EBAG
łatwo jest uzyskać współrzędne samolotu za pomocą homografii prospektywnej. Ale jeśli potrzebujesz punktów 3d w centralnej przestrzeni 3D kamery, musisz później przekształcić płaszczyznę zgodnie z wektorem obrotu i translacji.
Micka
Czy możesz podać oczekiwany wynik współrzędnych punktu?
AbdelAziz AbdelLatef

Odpowiedzi:

6

Możesz to rozwiązać za pomocą 3 prostych kroków:

Krok 1:

Obliczyć wektor kierunku 3d, wyrażony w ramce współrzędnej kamery, promienia odpowiadającego danemu punktowi obrazu 2d, odwracając model projekcji kamery:

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)

Krok 2:

Obliczyć kierunek 3d wektora tego promienia w ramce współrzędnych przymocowanej do szachownicy, używając względnej pozycji między kamerą a szachownicą:

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

Krok 3:

Znajdź żądany punkt 3d, obliczając przecięcie promienia 3d z płaszczyzną szachownicy za pomocą 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;
BConic
źródło
Twoja metoda działa idealnie, dzięki :)
EBAG
1

Ponieważ twoja sprawa ogranicza się do równin, najprostszym sposobem jest użycie homografii.

Najpierw cofnij zniekształcenie obrazu. Następnie użyj findHomography, aby obliczyć macierz homografii, która przekształci twoją współrzędną pikselową (obraz) w rzeczywistą współrzędną (przestrzeń euklidesowa np. W cm). Coś podobnego do tego:

#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;
ma.mehralian
źródło
Zrobiłem to, co powiedziałeś: wektor <Point2f> rogi, wektor <Point2f> objectPoints2d; findChessboardCorners (img, patternSize, rogi); calcChessboardCorners (patternSize, squareSize, objectPoints2d); chessboardHomography = findHomography (rogi, objectPoints2d, RANSAC);
EBAG
nie działa, a współrzędna, którą zwraca, jest niepoprawna
EBAG
nawet jeśli pomnożysz macierz homografii przez piksel znajdujący się na szachownicy [0,0,0], zwróci [-192, -129, 0.33]
EBAG
@EBAG najpierw usuwasz obraz? sprawdź, czy objectPoints2d jest poprawny. Wydrukuj zdarzenie i sprawdź je ręcznie.
ma.mehralian