1

给定与平面(地面)相对应的相机透视图中的一组 3D 点,是否有任何快速有效的方法来找到平面相对于相机平面的方向?还是只能通过在点云上运行更重的“表面匹配”算法来实现?

我尝试使用estimateAffine3Dand findHomography,但我的主要限制是我没有表面平面上的点坐标 - 我只能从深度图像中选择一组点,因此必须从一组 3D 点中工作相机框架。

我写了一个简单的几何方法,它需要几个点并根据深度测量计算垂直和水平角度,但我担心这既不是很稳健也不是很精确。

编辑:按照@Micka 的建议,我尝试将这些点拟合到相机框架上的二维平面,具有以下功能:

#include <opencv2/opencv.hpp>

//------------------------------------------------------------------------------
/// @brief      Fits a set of 3D points to a 2D plane, by solving a system of linear equations of type aX + bY + cZ + d = 0
///
/// @param[in]  points             The points
///
/// @return     4x1 Mat with plane equations coefficients [a, b, c, d]
///
cv::Mat fitPlane(const std::vector< cv::Point3d >& points) {
    // plane equation: aX + bY + cZ + d = 0
    // assuming c=-1 ->  aX + bY + d = z

    cv::Mat xys = cv::Mat::ones(points.size(), 3, CV_64FC1);
    cv::Mat zs  = cv::Mat::ones(points.size(), 1, CV_64FC1);

    // populate left and right hand matrices
    for (int idx = 0; idx < points.size(); idx++) {
        xys.at< double >(idx, 0) = points[idx].x;
        xys.at< double >(idx, 1) = points[idx].y;
        zs.at< double >(idx, 0)  = points[idx].z;
    }

    // coeff mat
    cv::Mat coeff(3, 1, CV_64FC1);

    // problem is now xys * coeff = zs
    // solving using SVD should output coeff
    cv::SVD svd(xys);
    svd.backSubst(zs, coeff);

    // alternative approach -> requires mat with 3D coordinates & additional col
    // solves xyzs * coeff = 0
    // cv::SVD::solveZ(xyzs, coeff);  // @note: data type must be double (CV_64FC1)

    // check result w/ input coordinates (plane equation should output null or very small values)
    double a = coeff.at< double >(0);
    double b = coeff.at< double >(1);
    double d = coeff.at< double >(2);
    for (auto& point : points) {
        std::cout << a * point.x + b * point.y + d - point.z << std::endl;
    }

    return coeff;

}

为简单起见,假设相机已正确校准并且 3D 重建是正确的 - 我之前已经验证过,因此超出了本问题的范围。我使用鼠标选择深度/颜色帧对上的点,重建 3D 坐标并将它们传递给上面的函数。

我还尝试了其他方法cv::SVD::solveZ(),例如反转xyzcv::invert()cv::solve()但它总是以非常小的值或关于矩阵大小和/或类型的运行时错误结束。

4

0 回答 0