从OpenCV中的SolvPnP函数获取正确的rvec和tvec用于相机姿态估计

时间:2017-08-02 10:44:46

标签: opencv camera computational-geometry camera-calibration

我正在尝试测量相机的姿势,我已完成以下操作。

  1. Mark world 3-D(假设z = 0,因为它是平的)指向平面上正方形的角上并假设一个世界坐标系。(以厘米为单位)
  2. 将方块的左上角作为我的原点,并按以下顺序(x,y)或(col,row)给出世界点: (0,0),( - 12.8,0),( - 12.8,12.8),(0,12.8) - in cms

    1. 检测图像中的这些点。(以像素为单位) 图像点和世界点的顺序相同。

    2. 我已经为内在矩阵失真系数校准了相机。

    3. 我使用 SolvePnP 函数获取rvec和tvec。

    4. 我使用 Rodrigues 函数来获取旋转矩阵。

    5. 要检查rvec和tvec是否正确,我使用 ProjectPoints 将三维点(z = 0)投影到图像平面中,并在图像上正确获取点X轴上的误差为3像素。

    6. 现在我继续使用公式计算我在世界框架中的相机位置:

    7. cam_worl_pos = - inverse(R)* tvec 。 (这个公式我已在许多博客中验证过,这也很有意义)

      1. 但我的 cam_worl_pos cms中的x,y和z似乎不正确。
      2. 我怀疑的是,如果我能够使用rvec和tvec将3-D世界点投影回图像平面(X轴上 3像素误差,Y轴几乎没有误差,希望它是不是太糟糕),那么为什么我没有在世界框架中获得相机位置。

        另外,我对SolvPnP rvec和tvec解决方案有疑问,它们可能是多种解决方案之一,但不是我想要的解决方案之一。

        如何从SolvPnp获得正确的rvec和tvec或任何其他建议来获得rvec和tvec也会有所帮助。

        编辑

        图片尺寸 - 720(行)* 1280(col)

        相机看到的校准图案

        The link has the picture of calibration pattern used.

        新编辑

        遵循右手规则的世界坐标系和图像中检测到的相应点

        This link has the picture of the world coordinate coordinate system and also the corresponding points detected in the image plane

        左方是我的世界坐标系,是一个边长12.8cm的正方形,左上角是世界原点(0,0)。红点是图像中检测到的三维世界点。

        所见图像是在鱼眼镜头相机的径向畸变校正之后。

        相机参数

        cameraMatrix_Front=[908.65   0     642.88
                             0     909.28   364.95
                             0        0        1]
        
        distCoeffs_Front=[-0.4589, 0.09462, -1.46*10^-3, 1.23*10^-3]
        

        OpenCV C ++代码

        vector<Point3f> front_object_pts;
        Mat rvec_front;
        Mat tvec_front;
        Mat rotation_front;
        Mat world_position_front_cam;
        
        
        //Fill front object points(x-y-z order in cms)
        //It is square of side 12.8cms on Z=0 plane
        front_object_pts.push_back(Point3f(0, 0, 0));
        front_object_pts.push_back(Point3f(-12.8, 0, 0));
        front_object_pts.push_back(Point3f(-12.8,12.8,0));
        front_object_pts.push_back(Point3f(0, 12.8, 0));
        
        
        //Corresponding Image points detected in the same order as object points
        front_image_pts.push_back(points_front[0]);
        front_image_pts.push_back(points_front[1]);
        front_image_pts.push_back(points_front[2]);
        front_image_pts.push_back(points_front[3]);
        
        //Detected points in image matching the 3-D points in the same order
        //(467,368)
        //(512,369)
        //(456,417)
        //(391,416)
        
        //Get rvec and tvec using Solve PnP
        solvePnP(front_object_pts, front_image_pts, cameraMatrix_Front,
                 Mat(4,1,CV_64FC1,Scalar(0)), rvec_front, tvec_front, false, CV_ITERATIVE);
        
        //Output of SolvePnP
        //tvec=[-26.951,0.6041,134.72]  (3 x 1 matrix)
        //rvec=[-1.0053,0.6691,0.3752]  (3 x 1 matrix)
        
        
        //Check rvec and tvec is correct or not by projecting the 3-D object points to image
        vector<Point2f>check_front_image_pts
        projectPoints(front_object_pts, rvec_front, tvec_front, 
                     cameraMatrix_Front, distCoeffs_Front, check_front_image_pts);
        
        
        //Here to note that I have made **distCoefficents**, 
        //a 0 vector since my   image points are detected after radial distortion is removed
        
        //Get rotation matrix
        Rodrigues(rvec_front, rotation_front);
        
        //Get rotation matrix inverse
        Mat rotation_inverse;
        transpose(rotation_front, rotation_inverse);
        
        //Get camera position in world cordinates
        world_position_front_cam = -rotation_inverse * tvec_front;
        

        //相机的实际位置(测量的手动近似值)

        X = -47cm

        Y =18厘米

        Z =25厘米

        //获得位置

        X = -110cm

        Y =71厘米

        Z =40厘米

        提前致谢。

1 个答案:

答案 0 :(得分:0)

您如何知道cam_worl_pos不正确?

cam_worl_pos是相机的位置。您可以尝试测量相机与3D点所在平面之间的实际距离,并将其与tvecstd::sqrt(tx²+ty²+tz²))的标准进行比较。如果您不共享代码或不同参数的值,很难说出现了什么问题。

修改

如果您计算tvec的距离,则会137.390683 cmstd::sqrt(26.951*26.951+0.6041*0.6041+134.72*134.72)

您可以通过测量实际距离来检查这是否正确!

另外,您如何手动测量相机相对于世界框架的位置?

<强> EDIT2

如果没有得到正确的值,那么solvePnP函数的参数就会出错:

  • 您的cameraMatrix_Front似乎是正确的。但请确保908.65 * CCD (mm)=focal length (mm)
  • 将校准得到的失真系数的实际值传递给solvePnP

  • solvePnP至少需要4个点(越多越好点),为了更准确,不要让你的计划(你的方格在哪里)与图像计划平行如下:

enter image description here

但更像是这样,从任何方向来看: enter image description here

<强> EDIT3

  • 尝试使用不同方形位置的更多图像,以及为什么不在现场和移动相机
  • 确保你做过我之前问你的一切 EDIT2 cameraMatrix_Front,失真系数..等等