You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Open3D:如何将2D深度图转为3D曲面及选用更优数据结构?

深度图转3D曲面可视化(Open3D C++)

需求与已尝试方案

需求:希望在Open3D中实现深度图的3D可视化,效果如示例图右侧所示。

已尝试方案:将预处理得到的单通道深度图转换为PointCloud并完成可视化,代码如下:

// @image_8uc1 is single channel depth image.
std::shared_ptr<geometry::PointCloud> DepthMap2PointCloud(const cv::Mat& image_8uc1,
  const bool normalized = false) {
  std::shared_ptr<geometry::PointCloud> cloud(new geometry::PointCloud);
  for (int y = 0; y < image_8uc1.rows; y++) {
    const uchar* ptr = image_8uc1.ptr<uchar>(y);
    for (int x = 0; x < image_8uc1.cols; x++) {
      if (normalized) {
        const double _x = ((float)x / (float)image_8uc1.cols);
        const double _y = ((float)y / (float)image_8uc1.rows);
        const double _z = (float)ptr[x] / 255.0;
        Eigen::Vector3d p(_x, _y, _z);
        cloud->points_.push_back(p);
      }
      else {
        Eigen::Vector3d p(x, y, ptr[x]);
        cloud->points_.push_back(p);
      }
    }
  }
  return cloud;
}

// ... 
auto cloud = DepthMap2PointCloud(map);
visualization::Visualizer visualizer;
visualizer.CreateVisualizerWindow("Open3D", 1600, 900);
visualizer.AddGeometry(cloud);
visualizer.Run();
visualizer.DestroyVisualizerWindow();

可视化结果如图所示。

问题

  1. 如何利用深度图中所有相邻点(x,y)间距一致的结构特性创建曲面?
  2. 在Open3D中,除open3d::geometry::PointCloud外,是否有更有效的数据结构解决该问题?

解决方案

针对问题1:利用深度图结构创建曲面

深度图的像素点是规则网格排列的,相邻点(x,y)间距一致,这种结构天然适合构建三角网格(TriangleMesh),具体步骤:

  • 先按原有逻辑生成所有顶点的3D坐标;
  • 遍历所有非边缘的像素点,为每一组相邻的四个像素((x,y)、(x+1,y)、(x,y+1)、(x+1,y+1))创建两个三角面:
    • 第一个三角面:顶点索引为 y*width + x、y*width + x+1、(y+1)*width + x
    • 第二个三角面:顶点索引为 y*width + x+1、(y+1)*width + x+1、(y+1)*width + x
  • 完成遍历后即可得到连续的曲面网格。

针对问题2:更高效的数据结构

Open3D中**open3d::geometry::TriangleMesh**是更适配的结构,原因如下:

  • 它直接存储顶点和面的拓扑关系,可视化时渲染为连续曲面,而非离散点;
  • 相比点云,三角网格的渲染效率更高,GPU可批量处理面绘制;
  • 针对深度图的规则网格,生成三角网格的逻辑简单高效,无需额外点云重建算法(如泊松重建)。

如果需要保留深度图纹理,还可以结合open3d::geometry::Image为三角网格添加纹理坐标,实现带纹理的3D曲面可视化。

示例代码(深度图转TriangleMesh)

#include <open3d/geometry/TriangleMesh.h>

std::shared_ptr<open3d::geometry::TriangleMesh> DepthMap2TriangleMesh(const cv::Mat& image_8uc1, bool normalized = false) {
    auto mesh = std::make_shared<open3d::geometry::TriangleMesh>();
    int width = image_8uc1.cols;
    int height = image_8uc1.rows;

    // 生成顶点
    for (int y = 0; y < height; y++) {
        const uchar* ptr = image_8uc1.ptr<uchar>(y);
        for (int x = 0; x < width; x++) {
            double _x, _y, _z;
            if (normalized) {
                _x = static_cast<float>(x) / width;
                _y = static_cast<float>(y) / height;
                _z = static_cast<float>(ptr[x]) / 255.0;
            } else {
                _x = x;
                _y = y;
                _z = ptr[x];
            }
            mesh->vertices_.push_back(Eigen::Vector3d(_x, _y, _z));
        }
    }

    // 生成三角面
    for (int y = 0; y < height - 1; y++) {
        for (int x = 0; x < width - 1; x++) {
            int idx0 = y * width + x;
            int idx1 = y * width + x + 1;
            int idx2 = (y + 1) * width + x;
            int idx3 = (y + 1) * width + x + 1;

            // 添加两个三角形
            mesh->triangles_.push_back(Eigen::Vector3i(idx0, idx1, idx2));
            mesh->triangles_.push_back(Eigen::Vector3i(idx1, idx3, idx2));
        }
    }

    // 计算法向量(可选,提升曲面光照效果)
    mesh->ComputeVertexNormals();
    return mesh;
}

// 可视化调用
auto mesh = DepthMap2TriangleMesh(map);
open3d::visualization::Visualizer visualizer;
visualizer.CreateVisualizerWindow("Open3D Mesh", 1600, 900);
visualizer.AddGeometry(mesh);
visualizer.Run();
visualizer.DestroyVisualizerWindow();

内容的提问来源于stack exchange,提问作者wsys

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 20:01:17