在cv :: solvePnP的世界坐标中的摄像机位置
我有一个校准摄像机(固有的matrix和失真系数),我想知道相机的位置知道一些3d点和它们在图像中的相应点(2d点)。
我知道cv::solvePnP
可以帮助我,读完这个后 ,我明白了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 ++),但是这对我来说并没有什么意义:
- rvec,solvePnP的tvec输出是3x1matrix,3个元素的向量
- cv2.Rodrigues(rvec)是一个3x3matrix
- cv2.Rodrigues(rvec)[0]是一个3x1matrix,3个元素向量
- cameraPosition是一个3×1 * 1x3matrix乘法,即一个.. 3x3matrix。 我怎么可以在opengl中使用简单的
glTranslatef
和glRotate
调用?
如果用“世界坐标”表示“对象坐标”,则必须获得由pnpalgorithm给出的结果的逆向变换。
有一个技巧可以反转转换matrix,使您可以保存反转操作,这通常很昂贵,并解释了Python中的代码。 给定一个变换[R|t]
,我们有inv([R|t]) = [R'|-R'*t]
,其中R'
是R'
的转置。 所以,你可以编码(未testing):
cv::Mat rvec, tvec; solvePnP(..., rvec, tvec, ...); // rvec is 3x1, tvec is 3x1 cv::Mat R; cv::Rodrigues(rvec, R); // R is 3x3 R = Rt(); // rotation of inverse tvec = -R * tvec; // translation of inverse cv::Mat T(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 // fill the last row of T (NOTE: depending on your types, use float or double) double *p = T.ptr<double>(3); p[0] = p[1] = p[2] = 0; p[3] = 1; // T is a 4x4 matrix with the pose of the camera in the object frame
更新:稍后,要在OpenGL中使用T
,必须牢记OpenCV和OpenGL之间相机框架的轴是不同的。
OpenCV使用通常在计算机视觉中使用的参考:X指向右边,Y指向前方(如本图所示 )。 OpenGL中相机的框架是:X指向右边,Y指向上,Z指向后面(如图中所示 )。 所以,你需要绕180度的X轴旋转。 这个旋转matrix的公式是在维基百科 。
// 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中的matrix以行优先顺序存储在内存中,而OpenGL中的列按主要顺序存储。
如果你想把它变成一个标准的4×4姿势matrix,指定你的相机的位置。 使用rotM作为左上angular的3×3平方,tvec作为右侧的3个元素,0,0,0,1作为最下一行
pose = [rotation tvec(0) matrix tvec(1) here tvec(2) 0 , 0, 0, 1]
然后颠倒它(获得相机的姿势而不是世界的姿势)