从 Python 使用 C++ 进行直接线性变换

Direct Linear Transformation in C++ from Python

提问人:user2062604 提问时间:8/26/2023 更新时间:8/30/2023 访问量:97

问:

我对 Python 没有经验,但我想使用这个 Python 函数来执行我从这篇博文中获得的直接线性转换:

https://temugeb.github.io/opencv/python/2021/02/02/stereo-camera-calibration-and-triangulation.html

我试图将这个函数转换为 C++。下面是原始的Python函数以及我的C++版本。我的 C++ 版本是否正确?P1 和 P2 是 3x4 矩阵,point1 和 point2 是二维向量。

问题是我没有得到我期望的结果,我不知道是因为我没有正确重现这个 DLT 函数,还是其他原因。

def DLT(P1, P2, point1, point2):

    A = [point1[1]*P1[2,:] - P1[1,:],
         P1[0,:] - point1[0]*P1[2,:],
         point2[1]*P2[2,:] - P2[1,:],
         P2[0,:] - point2[0]*P2[2,:]
        ]
    A = np.array(A).reshape((4,4))
    #print('A: ')
    #print(A)

    B = A.transpose() @ A
    from scipy import linalg
    U, s, Vh = linalg.svd(B, full_matrices = False)

    print('Triangulated point: ')
    print(Vh[3,0:3]/Vh[3,3])
    return Vh[3,0:3]/Vh[3,3]

这是我的 C++ 版本,我希望它是正确的:

// Perform direct linear transformation
cv::Point3f DLT(cv::Mat P1, cv::Mat P2, cv::Point2f point1, cv::Point2f point2)
{
    // The 3D point to return
    cv::Point3f Retv(0.0f, 0.0f, 0.0f);

    // Build the DLT A 4x4 matrix
    cv::Mat A(4, 4, CV_64F);

    // First row
    A.at<double>(0, 0) = ((point1.y * P1.at<double>(2, 0)) - P1.at<double>(1, 0));
    A.at<double>(0, 1) = ((point1.y * P1.at<double>(2, 1)) - P1.at<double>(1, 1));
    A.at<double>(0, 2) = ((point1.y * P1.at<double>(2, 2)) - P1.at<double>(1, 2));
    A.at<double>(0, 3) = ((point1.y * P1.at<double>(2, 3)) - P1.at<double>(1, 3));

    // Second row
    A.at<double>(1, 0) = (P1.at<double>(0, 0) - (point1.x * P1.at<double>(2, 0)));
    A.at<double>(1, 1) = (P1.at<double>(0, 1) - (point1.x * P1.at<double>(2, 1)));
    A.at<double>(1, 2) = (P1.at<double>(0, 2) - (point1.x * P1.at<double>(2, 2)));
    A.at<double>(1, 3) = (P1.at<double>(0, 3) - (point1.x * P1.at<double>(2, 3)));

    // Third row
    A.at<double>(2, 0) = ((point2.y * P2.at<double>(2, 0)) - P2.at<double>(1, 0));
    A.at<double>(2, 1) = ((point2.y * P2.at<double>(2, 1)) - P2.at<double>(1, 1));
    A.at<double>(2, 2) = ((point2.y * P2.at<double>(2, 2)) - P2.at<double>(1, 2));
    A.at<double>(2, 3) = ((point2.y * P2.at<double>(2, 3)) - P2.at<double>(1, 3));

    // Fourth row
    A.at<double>(3, 0) = (P2.at<double>(0, 0) - (point2.x * P2.at<double>(2, 0)));
    A.at<double>(3, 1) = (P2.at<double>(0, 1) - (point2.x * P2.at<double>(2, 1)));
    A.at<double>(3, 2) = (P2.at<double>(0, 2) - (point2.x * P2.at<double>(2, 2)));
    A.at<double>(3, 3) = (P2.at<double>(0, 3) - (point2.x * P2.at<double>(2, 3)));

    // Calculate A transpose
    cv::Mat ATranspose;
    cv::transpose(A, ATranspose);

    // Compute the final matrix on which to perform singular value decomposition
    cv::Mat B = ATranspose * A;

    // Compute singular value decomposition
    cv::Mat w, u, vt;
    cv::SVD::compute(B, w, u, vt);

    // If the result is of the expected size
    if ((4 == vt.rows) && (4 == vt.cols))
    {
        // Get the fourth in homogeneous coordinates
        const double dDivisor = vt.at<double>(3, 3);

        // If we have a non-zero fourth in the homogeneous coordinates
        if (dDivisor != 0.0)
        {
            // Fill in the point to return
            Retv.x = static_cast<float>(vt.at<double>(3, 0) / dDivisor);
            Retv.y = static_cast<float>(vt.at<double>(3, 1) / dDivisor);
            Retv.z = static_cast<float>(vt.at<double>(3, 2) / dDivisor);
        }
    }

    // Return the point we just calculated
    return Retv;
}
Python C++ OpenCV 计算机视觉 SVD

评论

0赞 Tim Roberts 8/26/2023
这看起来大致正确。还有多远?疯狂地离开,还是只是一个阴影?
0赞 user2062604 8/26/2023
@TimRoberts 他们非常糟糕。 最初我是这样做的,正如我在之前的 SO 问题中解释的那样:stackoverflow.com/questions/76956101/......但我决定尝试关注这篇博文,改为做DLT。原来的方法给了我几毫米的结果,我对此不满意,但这种方式给了我完全的垃圾。
0赞 Tim Roberts 8/26/2023
你能尝试那个确切的 Python 代码吗?它是否产生合理的结果?
0赞 Christoph Rackwitz 8/26/2023
我刚刚阅读了 en.wikipedia.org/wiki/Direct_linear_transformation,并认为该链接在这里很有用
0赞 user2062604 8/30/2023
@TimRoberts 谢谢,我确实继续按照示例进行操作,并且我已经验证了我的 DLT 翻译是正确的(通过与 cv::triangulatePoints() 的结果进行比较)。我会继续发布正确答案。

答:

0赞 user2062604 8/30/2023 #1

通过将 OP 链接中的整个示例翻译成 C++ 并将我的 DLT 中的答案与 cv::triangulatePoints() 中的答案进行比较,我已经验证了我的原始翻译是正确的。