我有一个校准过的相机(内在矩阵和失真系数),我想知道相机位置知道图像中的一些3d点及其对应点(2d点)。
我知道cv::solvePnP
可以帮助我,在阅读this和this后,我了解到solvePnP rvec
和tvec
的输出是在相机坐标系中旋转和平移物体。
所以我需要在世界坐标系中找出相机的旋转/平移。
从上面的链接看来,代码很简单,在python中:
found,rvec,tvec = cv2.solvePnP(object_3d_points, object_2d_points, camera_matrix, dist_coefs)
rotM = cv2.Rodrigues(rvec)[0]
cameraPosition = -np.matrix(rotM).T * np.matrix(tvec)
我不知道python / numpy的东西(我正在使用C ++),但这对我来说没有多大意义:
glTranslatef
和glRotate
来电?答案 0 :(得分:48)
如果使用“世界坐标”表示“对象坐标”,则必须对pnp算法给出的结果进行逆变换。
有一个技巧可以反转转换矩阵,它允许你保存反转操作,这通常是昂贵的,并解释了Python中的代码。鉴于转化[R|t]
,我们有inv([R|t]) = [R'|-R'*t]
,其中R'
是R
的转置。所以,你可以编码(未测试):
cv::Mat rvec, tvec;
solvePnP(..., rvec, tvec, ...);
// rvec is 3x1, tvec is 3x1
cv::Mat R;
cv::Rodrigues(rvec, R); // R is 3x3
R = R.t(); // rotation of inverse
tvec = -R * tvec; // translation of inverse
cv::Mat T = cv::Mat::eye(4, 4, R.type()); // T is 4x4
T( cv::Range(0,3), cv::Range(0,3) ) = R * 1; // copies R into T
T( cv::Range(0,3), cv::Range(3,4) ) = tvec * 1; // copies tvec into T
// T is a 4x4 matrix with the pose of the camera in the object frame
更新:稍后,要在OpenGL中使用T
,您必须记住,相机框架的轴在OpenCV和OpenGL之间有所不同。
OpenCV使用计算机视觉中常用的参考:X指向右侧,Y指向下方,Z指向前方(如this image中所示)。 OpenGL中相机的框架是:X指向右侧,Y指向上方,Z指向后方(如this image的左侧)。因此,您需要围绕180度的X轴应用旋转。此旋转矩阵的公式为wikipedia。
// T is your 4x4 matrix in the OpenCV frame
cv::Mat RotX = ...; // 4x4 matrix with a 180 deg rotation around X
cv::Mat Tgl = T * RotX; // OpenGL camera in the object frame
这些转变总是令人困惑,我在某些方面可能是错的,所以请稍等一下。
最后,考虑到OpenCV中的矩阵按行主要顺序存储在内存中,而OpenGL则按列主顺序存储。
答案 1 :(得分:3)
如果要将其转换为指定相机位置的标准4x4姿势矩阵。使用rotM作为左上角3x3 square,tvec作为右边3个元素,0,0,0,1作为底行
pose = [rotation tvec(0)
matrix tvec(1)
here tvec(2)
0 , 0, 0, 1]
然后反转它(以获得相机的姿势而不是世界的姿势)