【问题标题】:Depth map from calibrated image and triangular mesh using OpenCV and Matlab使用 OpenCV 和 Matlab 校准图像和三角形网格的深度图
【发布时间】:2016-02-18 03:29:42
【问题描述】:

我想使用从 Matlab 2014b 调用的 OpenCV(使用 OpenCV 绑定)从校准图像和三角形网格中提取深度图。我是 Matlab 的普通用户,但对 OpenCV 很陌生。我有以下输入:

im - 场景的未失真 RGB 图像

或 - 相机位置向量

R - 描述相机位姿的旋转矩阵

points - 表示场景的 nx3 三角形网格顶点列表

faces - mx3 三角网格面列表

EFL - 以像素为单位的图像有效焦距

我已经编写了一个原生 Matlab 光线追踪引擎来从这些输入中提取深度图,但这很慢并且存在高重投影错误(我想将 OpenCV 函数的结果与我自己的结果进行比较以确定这些错误是否存在与我的实现或只是相机校准不准确有关)。

如何使用从 Matlab 调用的 OpenCV 从这些输入中获取深度图?

任何帮助将不胜感激

谢谢

托马斯

【问题讨论】:

    标签: matlab opencv mesh raytracing camera-calibration


    【解决方案1】:

    建议的策略

    您可以将网格中的顶点投影到 2D 像素坐标中(使用校准的相机模型)。然后对于每个面,您可以找到由其投影顶点形成的 2D 三角形中包含的所有像素中心(晶格点)。在重叠的情况下,您可能必须跟踪哪个三角形最近。现在您知道哪个面对应于每个像素。这应该非常快,除非您的网格比您的图像分辨率高得多。

    然后您可以使用相机模型找到与每个像素对应的 3D 射线,并将射线与该像素的已知面相交以计算深度(听起来您已经完成了这部分)。既然您知道飞机,这也不应该花太长时间。

    有关相机投影的更多信息

    OpenCV 有 a good resource 使用相机模型(下)。 基本上,您可以将3D点M'投影到像素坐标m';这就是您将顶点投影到像素位置的方式。往另一个方向发展,规模是不可恢复的——你得到的是射线M'/s,而不是点M'。您正在寻找的深度是s,它是相机帧中3D 点的Z 坐标。如果您的网格位于以相机为中心的框架中(X 向右,Y 向下,Z 向外),R = Identityt = 0。如果不是,[R|t] 将其转换为。

    扩展每个因素可以让我们看到矩阵的构成。

    您在下面建议的代码使用 OpenCV 的 projectPoints 函数,该函数实现了上述等式以及一些失真校准(请参阅主要 OpenCV 参考)。您必须填充矩阵并将它们相乘。 projectPoints 的另一个示例是可用的on GitHub,我相信在this SO question 中讨论了这个相同的示例。

    提问者建议的代码

    显然,以下代码可以完成这项工作。我可能需要一些时间 鉴于我的 C++ 知识几乎为零(我 意识到它被注释掉了顺便说一句):

           //CString str;
           //cv::Mat CamMatrix(3, 3, CV_64F);
           //cv::Mat distCoeffs(5, 1, CV_64F);
           //m_CamCalib.GetOpenCVInfo(&CamMatrix, &distCoeffs);
           //vector<Point3d> GCP_Points;
           //vector<Point2d> Image_Points;
           //cv::Mat RVecs(3, 3, CV_64F); // rotation matrix
           //cv::Mat TranRVecs(3, 3, CV_64F); // rotation matrix
           //cv::Mat TVecs(3, 1, CV_64F); // translation vector
           //RVecs.at<double>(0, 0) = m_CamPosMtrx.m_pMtrx[0];
           //RVecs.at<double>(1, 0) = m_CamPosMtrx.m_pMtrx[1];
           //RVecs.at<double>(2, 0) = m_CamPosMtrx.m_pMtrx[2];
    
           //RVecs.at<double>(0, 1) = m_CamPosMtrx.m_pMtrx[4];
           //RVecs.at<double>(1, 1) = m_CamPosMtrx.m_pMtrx[5];
           //RVecs.at<double>(2, 1) = m_CamPosMtrx.m_pMtrx[6];
    
           //RVecs.at<double>(0, 2) = m_CamPosMtrx.m_pMtrx[8];
           //RVecs.at<double>(1, 2) = m_CamPosMtrx.m_pMtrx[9];
           //RVecs.at<double>(2, 2) = m_CamPosMtrx.m_pMtrx[10];
           //transpose(RVecs, TranRVecs);
           //TVecs.at<double>(0, 0) = 0;
           //TVecs.at<double>(1, 0) = 0;
           //TVecs.at<double>(2, 0) = 0;
           //GCP_Points.push_back(Point3d((x - m_CamPosMtrx.m_pMtrx[12]), (y - m_CamPosMtrx.m_pMtrx[13]), (z - m_CamPosMtrx.m_pMtrx[14])));
           //Image_Points.push_back(Point2d(0, 0));
           //projectPoints(GCP_Points, TranRVecs, TVecs, CamMatrix, distCoeffs, Image_Points);
    
    /bool CCameraCalibration::GetOpenCVInfo(Mat * cameraMatrix, Mat * distCoeffs)
    //{
    //            int i,j;
    //            Mat projMatrix;
    //            CMatrix4x4 m1;
    //            if(cameraMatrix->rows==0) cameraMatrix->create(3,3, CV_64F);
    //            if(distCoeffs->rows==0) distCoeffs->create(5, 1, CV_64F);
    //            for(i=0;i<3;i++)
    //            for(j=0;j<3;j++){
    //                   cameraMatrix->at<double>(i,j)=m_pCameraMatrix[i][j];
    //            }
    //            for(i=0;i<5;i++)
    //                   distCoeffs->at<double>(i,0)=m_pCoefficients[i];
    //     return false;
    //}
    

    【讨论】:

    • 我喜欢你的方法。目前,Matlab代码使用八叉树细分来划分网格(重新划分八叉树分割TIN模型的网格是第一个瓶颈:Matlab中的ismember search函数伸缩性很差)。然后我使用 Smit 算法定位 box-ray 交叉点,然后搜索每个盒子的内容并使用 Moller 和 Trumbore 算法解决 Ray-tri 交叉点。尽管您的方法似乎更好,但速度不是我的主要问题:我正在努力设置光线树,因为这似乎是重新投影错误的来源。如何使用 OpenCV 进行设置?谢谢。托马斯
    • 嗯,当一个人脸经过几个八叉树细分时会发生什么?你是把它加到每片叶子上,只加一个,还是把脸分成几个三角形来做每个细分?在 3D 中进行此搜索肯定会增加复杂性。尽管这意味着开始一种新方法,但二维搜索可能仍然更容易上手。
    • 干杯 kmac。空间分割和光线框搜索在光线追踪文献(即 BSP 树)中是相当标准的。正如我认为您已经发现的那样,共享三角形在跨区箱中重复(这种搜索确实会降低操作速度)。我从一位同事那里获得了一些 C++ 代码,该代码应该使用 OpenCV 执行像素投影。作为一个 C++/OpenCV 菜鸟,我仍然在挑选它。也许它会对那里的其他人有所帮助....我将在下面发布:
    • 在 OpenCV can be found here 中使用针孔相机模型(用于 3D 到 2D 投影和 2D 到 3D 射线)的一个很好的资源。我将在答案中对其进行一些扩展。
    • 回到你在 OpenCV 中设置光线树的原始点——我还没有在 OpenCV 中进行任何光线追踪;也许其他人将能够建议免费的全 3D 方法。
    猜你喜欢
    • 2013-11-24
    • 2015-11-16
    • 2014-04-02
    • 2016-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-30
    相关资源
    最近更新 更多