Mengubah titik 2D ke lokasi 3D

9

Saya memiliki kamera tetap dengan yang dikenal cameraMatrixdan distCoeffs. Saya juga punya papan catur yang diperbaiki juga, transformdan rotationvektor juga dihitung menggunakan solvePnP.

Saya bertanya-tanya bagaimana mungkin untuk mendapatkan lokasi 3D dari titik 2D di pesawat yang sama dengan papan catur itu berada, seperti gambar di bawah ini:

masukkan deskripsi gambar di sini

Satu hal yang pasti adalah bahwa Z dari titik itu adalah 0, tetapi bagaimana mendapatkan X dan Y dari titik itu.

EBAG
sumber
dengan vektor transformasi dan rotasi Anda, apakah Anda dapat menjelaskan semua sudut papan catur dalam 3D?
Micka
jika Anda mengatakan bahwa Z akan menjadi 0, apakah Anda boleh mendapatkan koordinat pesawat pada titik itu? Seperti "bergerak 10 cm ke arah merah dan minus 15 cm ke arah hijau?
Micka
@Micka ini tidak akan berfungsi, karena piksel yang lebih dekat ke kamera mewakili area yang lebih besar
EBAG
mudah untuk mendapatkan koordinat pesawat dengan homografi hewan peliharaan. Tetapi jika Anda membutuhkan titik-titik 3d di ruang 3d berpusat kamera Anda, Anda harus mengubah bidang sesuai dengan rotasi Anda dan vektor terjemahan sesudahnya.
Micka
Bisakah Anda memberikan hasil yang diharapkan dari koordinat titik ini?
AbdelAziz AbdelLatef

Jawaban:

6

Anda dapat menyelesaikan ini dengan 3 langkah sederhana:

Langkah 1:

Hitung vektor arah 3d, yang diekspresikan dalam bingkai koordinat kamera, dari sinar yang sesuai dengan titik gambar 2d yang diberikan dengan membalikkan model proyeksi kamera:

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)

Langkah 2:

Hitung arah 3d dari vektor sinar ini dalam bingkai koordinat yang terpasang pada papan catur, menggunakan pose relatif antara kamera dan papan catur:

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

Langkah 3:

Temukan titik 3d yang diinginkan dengan menghitung persimpangan antara sinar 3d dan bidang papan catur dengan 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
sumber
Metode Anda bekerja dengan sempurna, terima kasih :)
EBAG
1

Karena kasing Anda terbatas pada dataran, Cara sederhana adalah menggunakan Homografi.

Pertama, undistort gambar Anda. Kemudian gunakan findHomography untuk menghitung matriks Homografi yang mengubah koordinat piksel Anda (gambar) menjadi koordinat nyata (ruang euclidean misalnya dalam cm). Sesuatu yang mirip dengan ini:

#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.mehralia
sumber
Saya melakukan apa yang Anda katakan: sudut vektor <Point2f>, vektor <Point2f> objectPoints2d; findChessboardCorners (img, patternSize, sudut); calcChessboardCorners (patternSize, squareSize, objectPoints2d); chessboardHomography = findHomography (sudut, objectPoints2d, RANSAC);
EBAG
tidak berfungsi, dan koordinat yang dikembalikannya tidak benar
EBAG
bahkan jika Anda mengalikan matriks homografi dengan piksel yang terletak di papan catur [0,0,0] itu akan mengembalikan [-192, -129, 0,33]
EBAG
@EBAG Anda membatalkan undistore gambar dulu? periksa objectPoints2d benar. Cetak acara dan periksa secara manual.
ma.mehralia