首页 文章

如何正确使用cv :: triangulatePoints()

提问于
浏览
28

我试图用OpenCV对一些点进行三角测量,我发现了这个 cv::triangulatePoints() 函数 . 问题是几乎没有文档或示例 .

我有一些疑问 .

  • What method does it use? 我've making a small research about triangulations and there are several methods (Linear, Linear LS, eigen, iterative LS, iterative eigen,...) but I can't在OpenCV中查找它使用的是哪一个 .

  • How should I use it? 似乎作为输入它需要一个投影矩阵和 3xN 同质 2D 点 . 我将它们定义为 std::vector<cv::Point3d> pnts ,但作为输出它需要 4xN 数组,显然我不能创建 std::vector<cv::Point4d> ,因为它不存在,那么我该如何定义输出向量?

对于我尝试的第二个问题: cv::Mat pnts3D(4,N,CV_64F);cv::Mat pnts3d; ,似乎都不起作用(它抛出异常) .

5 回答

  • 10

    1.- The method 使用的是最小二乘法 . 有比这更复杂的算法 . 它仍然是最常见的一种,因为在某些情况下其他方法可能会失败(即,如果点在平面上或在无限上,则其他方法会失败) .

    该方法可以在Richard Hartley和Andrew Zisserman的 Multiple View Geometry in Computer Vision 中找到(p312)

    2.- The usage

    cv::Mat pnts3D(1,N,CV_64FC4);
    cv::Mat cam0pnts(1,N,CV_64FC2);
    cv::Mat cam1pnts(1,N,CV_64FC2);
    

    用图像中的点填充2个chanel点矩阵 .

    cam0cam1Mat3x4 摄像机矩阵(内部和外部参数) . 您可以通过乘以A * RT来构造它们,其中A是内在参数矩阵,RT是旋转平移3x4姿势矩阵 .

    cv::triangulatePoints(cam0,cam1,cam0pnts,cam1pnts,pnts3D);
    

    NOTEpnts3D 在定义时需要为4通道 1xN cv::Mat ,如果没有则抛出异常,但结果为 cv::Mat(4,N,cv_64FC1) 矩阵 . 真的很混乱,但这是我没有例外的唯一方法 .


    UPDATE :从版本3.0或更早版本开始,这不再是真的, pnts3D 也可以是 Mat(4,N,CV_64FC1) 类型,或者可以保持完全为空(通常,它是在函数内部创建的) .

  • 46

    @Ander Biguri回答的一小部分内容 . 您应该在非 undistort ed图像上获取图像点,并在 cam0pntscam1pnts 上调用 undistortPoints() ,因为 cv::triangulatePoints 期望标准化坐标中的2D点(独立于摄像机)和 cam0cam1 应该只是 [R|t^T] matricies你没有需要多次使用 A .

  • 0

    感谢Ander Biguri!他的回答对我很有帮助 . 但我总是喜欢使用std :: vector的替代方案,我编写了他的解决方案:

    std::vector<cv::Point2d> cam0pnts;
    std::vector<cv::Point2d> cam1pnts;
    // You fill them, both with the same size...
    
    // You can pick any of the following 2 (your choice)
    // cv::Mat pnts3D(1,cam0pnts.size(),CV_64FC4);
    cv::Mat pnts3D(4,cam0pnts.size(),CV_64F);
    
    cv::triangulatePoints(cam0,cam1,cam0pnts,cam1pnts,pnts3D);
    

    所以你只需要在点上做emplace_back . 主要优点:在开始填充之前,您不需要知道 N 的大小 . 不幸的是,没有cv :: Point4f,所以pnts3D必须是cv :: Mat ...

  • 2

    我试过cv :: triangulatePoints,但不知怎的,它计算垃圾 . 我被迫手动实现线性三角测量方法,它为三角形3D点返回一个4x1矩阵:

    Mat triangulate_Linear_LS(Mat mat_P_l, Mat mat_P_r, Mat warped_back_l, Mat warped_back_r)
    {
        Mat A(4,3,CV_64FC1), b(4,1,CV_64FC1), X(3,1,CV_64FC1), X_homogeneous(4,1,CV_64FC1), W(1,1,CV_64FC1);
        W.at<double>(0,0) = 1.0;
        A.at<double>(0,0) = (warped_back_l.at<double>(0,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,0) - mat_P_l.at<double>(0,0);
        A.at<double>(0,1) = (warped_back_l.at<double>(0,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,1) - mat_P_l.at<double>(0,1);
        A.at<double>(0,2) = (warped_back_l.at<double>(0,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,2) - mat_P_l.at<double>(0,2);
        A.at<double>(1,0) = (warped_back_l.at<double>(1,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,0) - mat_P_l.at<double>(1,0);
        A.at<double>(1,1) = (warped_back_l.at<double>(1,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,1) - mat_P_l.at<double>(1,1);
        A.at<double>(1,2) = (warped_back_l.at<double>(1,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,2) - mat_P_l.at<double>(1,2);
        A.at<double>(2,0) = (warped_back_r.at<double>(0,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,0) - mat_P_r.at<double>(0,0);
        A.at<double>(2,1) = (warped_back_r.at<double>(0,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,1) - mat_P_r.at<double>(0,1);
        A.at<double>(2,2) = (warped_back_r.at<double>(0,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,2) - mat_P_r.at<double>(0,2);
        A.at<double>(3,0) = (warped_back_r.at<double>(1,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,0) - mat_P_r.at<double>(1,0);
        A.at<double>(3,1) = (warped_back_r.at<double>(1,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,1) - mat_P_r.at<double>(1,1);
        A.at<double>(3,2) = (warped_back_r.at<double>(1,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,2) - mat_P_r.at<double>(1,2);
        b.at<double>(0,0) = -((warped_back_l.at<double>(0,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,3) - mat_P_l.at<double>(0,3));
        b.at<double>(1,0) = -((warped_back_l.at<double>(1,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,3) - mat_P_l.at<double>(1,3));
        b.at<double>(2,0) = -((warped_back_r.at<double>(0,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,3) - mat_P_r.at<double>(0,3));
        b.at<double>(3,0) = -((warped_back_r.at<double>(1,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,3) - mat_P_r.at<double>(1,3));
        solve(A,b,X,DECOMP_SVD);
        vconcat(X,W,X_homogeneous);
        return X_homogeneous;
    }
    

    输入参数是两个3×4相机投影矩阵和相应的左/右像素对(x,y,w) .

  • 3

    或者你也可以使用Hartley&Zisserman在这里实现的方法:http://www.morethantechnical.com/2012/01/04/simple-triangulation-with-opencv-from-harley-zisserman-w-code/

相关问题