首先,假设我们只有一个标记为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) 计算得出。
现在,使用针孔camera model,凸轮世界中的点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 在 cam 的世界中的坐标是:
[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:我讨厌 SO 没有 MathJax
注意 2:一定有一些我不知道的更快的实现。