15

我正在尝试使用我的网络摄像头从具有已知全局位置的四个基准点的图像中获得全局姿态估计。

我检查了许多 stackexchange 问题和一些论文,但似乎无法得到正确的解决方案。我得到的位置数字是可重复的,但绝不与相机移动成线性比例。仅供参考,我正在使用 C++ OpenCV 2.1。

在此链接上显示了我的坐标系和下面使用的测试数据。

% Input to solvePnP():
imagePoints =     [ 481, 831; % [x, y] format
                    520, 504;
                   1114, 828;
                   1106, 507]
objectPoints = [0.11, 1.15, 0; % [x, y, z] format
                0.11, 1.37, 0; 
                0.40, 1.15, 0;
                0.40, 1.37, 0]

% camera intrinsics for Logitech C910
cameraMat = [1913.71011, 0.00000,    1311.03556;
             0.00000,    1909.60756, 953.81594;
             0.00000,    0.00000,    1.00000]
distCoeffs = [0, 0, 0, 0, 0]

% output of solvePnP():
tVec = [-0.3515;
         0.8928; 
         0.1997]

rVec = [2.5279;
       -0.09793;
        0.2050]
% using Rodrigues to convert back to rotation matrix:

rMat = [0.9853, -0.1159,  0.1248;
       -0.0242, -0.8206, -0.5708;
        0.1686,  0.5594, -0.8114]

到目前为止,有人能看出这些数字有什么问题吗?如果有人将它们签入例如 MatLAB(上面的代码对 m 文件友好),我将不胜感激。

从这一点来看,我不确定如何从 rMat 和 tVec 获得全局姿势。从我在这个问题中读到的内容,从 rMat 和 tVec 获取姿势很简单:

position = transpose(rMat) * tVec   % matrix multiplication

但是,我从其他来源怀疑我读过它并不是那么简单。

要获得相机在现实世界坐标中的位置,我需要做什么? 由于我不确定这是否是一个实现问题(但很可能是一个理论问题),我希望在 OpenCV 中成功使用 solvePnP 函数的人来回答这个问题,尽管也欢迎任何想法!

非常感谢您的宝贵时间。

4

3 回答 3

12

我前段时间解决了这个问题,为一年的延迟道歉。

在我使用的 python OpenCV 2.1 和较新的版本 3.0.0-dev 中,我已经验证要在全局框架中获取相机的姿势,您必须:

_, rVec, tVec = cv2.solvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs)
Rt = cv2.Rodrigues(rvec)
R = Rt.transpose()
pos = -R * tVec

现在 pos 是在全局框架中表示的相机位置(表示 objectPoints 的同一框架)。R 是一个姿态矩阵 DCM,它是存储姿态的一种很好的形式。如果您需要欧拉角,那么您可以在给定 XYZ 旋转序列的情况下使用以下方法将 DCM 转换为欧拉角:

roll = atan2(-R[2][1], R[2][2])
pitch = asin(R[2][0])
yaw = atan2(-R[1][0], R[0][0])
于 2015-01-09T10:09:11.040 回答
4

如果你的意思是全局姿势是一个 4x4 的相机姿势矩阵,它可以在 OpenGL 中使用,我是这样做的

CvMat* ToOpenGLCos( const CvMat* tVec, const CvMat* rVec )
{
    //** flip COS 180 degree around x-axis **//

    // Rodrigues to rotation matrix
    CvMat* extRotAsMatrix = cvCreateMat(3,3,CV_32FC1);
    cvRodrigues2(rVec,extRotAsMatrix);

    // Simply merge rotation matrix and translation vector to 4x4 matrix 
    CvMat* world2CameraTransformation = CreateTransformationMatrixH(tVec,
    extRotAsMatrix );

    // Create correction rotation matrix (180 deg x-axis)
    CvMat* correctionMatrix = cvCreateMat(4,4,CV_32FC1);
    /* 1.00000   0.00000   0.00000   0.00000
       0.00000  -1.00000  -0.00000   0.00000
       0.00000   0.00000  -1.00000   0.00000
       0.00000   0.00000   0.00000   1.00000 */
    cvmSet(correctionMatrix,0,0,1.0); cvmSet(correctionMatrix,0,1,0.0);
    ... 

    // Flip it
    CvMat* world2CameraTransformationOpenGL = cvCreateMat(4,4,CV_32FC1);
    cvMatMul(correctionMatrix,world2CameraTransformation,   world2CameraTransformationOpenGL);

    CvMat* camera2WorldTransformationOpenGL = cvCreateMat(4,4,CV_32FC1);
    cvInv(world2CameraTransformationOpenGL,camera2WorldTransformationOpenGL,
    CV_LU );

    cvReleaseMat( &world2CameraTransformationOpenGL );
    ...

    return camera2WorldTransformationOpenGL;
}

我认为翻转坐标系是必要的,因为 OpenCV 和 OpenGL/VTK/等。使用不同的坐标系,如图所示OpenGL and OpenCV Coordinate Systems

好吧,它是这样工作的,但有人可能会有更好的解释。

于 2013-12-04T11:21:14.700 回答
2

相机的位置将是 {- transpose( r ) * t } 。就是这样。

除了 cv::solvePnp 提供 (4 x 1) 向量用于翻译,如果我没记错的话,您已经正确完成了所有操作,您必须将 x 、 y 、 z 与 w 坐标相除。

于 2013-04-30T18:20:15.157 回答