Маркеры Aruco с openCv, получить координаты угла 3d?

Я обнаружил напечатанный маркер Aruco, используя opencv 3.2:

aruco::estimatePoseSingleMarkers(corners, markerLength, camMatrix, distCoeffs, rvecs,tvecs);

это возвращает вектор перемещения и вращения для маркера. Что мне нужно, это 3D-координаты для каждого угла маркера.

Поскольку я знаю длину маркера, я мог бы сделать что-то вроде

corner1 = tvecs[0] - markerlength /2;
corner2 = tvecs[0] + markerlength /2;

….

Но есть ли лучший способ? Или существующая функция?
Подводя итог, я имею:

3d точка в центре 2-го квадрата.

длина сторон этого квадрата.

значение вращения квадрата.

Как я могу найти 3D-координаты углов?

1

Решение

Во-первых, давайте предположим, что у нас есть только один маркер с side = 2 * half_side,

введите описание изображения здесь

Во-вторых, aruco::detectMarker возвращает относительное положение камеры в мире маркера. Таким образом, я предполагаю, что вы ищете координаты углов в мире камеры.

Тогда в пространстве маркера:

     [ half_side ]      [     0     ]
E  = [     0     ], F = [ half_side ]
[     0     ]      [     0     ]

где центр O квадрат имеет координату tvec (в мире камеры) и вращающийся коврик маркера rot_mat вычисляется cv::Rodrigues(rvec,rot_mat),

Теперь, используя пинхол модель камеры, отношение между координатами точки P в мире кулачков и маркеров это:

[P_x_cam]             [P_x_marker]
[P_y_cam] = rot_mat * [P_y_marker] + tvec
[P_z_cam]             [P_z_marker]

например, центр O, который [0,0,0] в мире маркеров tvec в мире кулачка.

Итак, координаты E в мире кулачков есть:

[E_x_cam]             [half_side]
|E_y_cam| = rot_mat * |    0    | + tvec
[E_z_cam]             [    0    ]

Волшебно, это сумма rot_matпервый столбец, умноженный на half_size а также tvec, Так же,
каудинаты F является rot_matвторой столбец, умноженный на half_size а также tvec,

Теперь углы можно вычислить, например,

C - O = (E - O) + (F - O), B - O = (E - O) - (F - O)

где E-O это точно rot_matпервый столбец, умноженный на half_size,

Имея все это в виду, мы можем составить функцию:

vector<Point3f> getCornersInCameraWorld(double side, Vec3d rvec, Vec3d tvec){

double half_side = side/2;// compute rot_mat
Mat rot_mat;
Rodrigues(rvec, rot_mat);

// transpose of rot_mat for easy columns extraction
Mat rot_mat_t = rot_mat.t();

// the two E-O and F-O vectors
double * tmp = rot_mat_t.ptr<double>(0);
Point3f camWorldE(tmp[0]*half_side,
tmp[1]*half_side,
tmp[2]*half_side);

tmp = rot_mat_t.ptr<double>(1);
Point3f camWorldF(tmp[0]*half_side,
tmp[1]*half_side,
tmp[2]*half_side);

// convert tvec to point
Point3f tvec_3f(tvec[0], tvec[1], tvec[2]);

// return vector:
vector<Point3f> ret(4,tvec_3f);

ret[0] +=  camWorldE + camWorldF;
ret[1] += -camWorldE + camWorldF;
ret[2] += -camWorldE - camWorldF;
ret[3] +=  camWorldE - camWorldF;

return ret;
}

Примечание 1: я ненавижу, что ТАК не имеет MathJax

Примечание 2: должна быть более быстрая реализация, о которой я не знаю.

10

Другие решения

Основываясь на ответе @ Quang, C # код для преобразования любой точки в координаты камеры. Конечно это нужно R а также t векторы, поэтому вам понадобится маркер, чтобы их получить.

private Point3d GetWorldPoint(Point3d input, Vec3d rvec, Vec3d tvec)
{
var rot_mat = new Mat();

Cv2.Rodrigues(MatOfDouble.FromArray(rvec.Item0, rvec.Item1, rvec.Item2), rot_mat);

var pointProject = (rot_mat * MatOfDouble.FromArray(input.X, input.Y, input.Z)).ToMat();
return tvec + new Point3d(pointProject.Get<double>(0, 0), pointProject.Get<double>(0, 1), pointProject.Get<double>(0, 2));
}
0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector