Open3D 渲染 mesh 的 partial view 点云

引

如图，已知一个 mesh 模型（以及它在世界坐标系下的 pose），有应用希望得到在指定 camera pose 下渲染得到带颜色的 point cloud 数据。

我的应用是将一个预测的已知 pose 的 mesh 与实际观测的点云做带尺度的配准。我认为先渲染得到 mesh 的对应区域点云再配准，即使是存在遮挡的情况下准确性也会高一些。

相关

How to capture depth image from a point cloud? · Issue #1152 · isl-org/Open3D · GitHub 渲染已知点云，使用 open3d 的 capture_depth_float_buffer 函数。但不关注如何重投影回点云，经我验证关键是后面的步骤。

3d - How do I generate a partial view of a mesh as a point cloud in Python? - Stack Overflow 是一样的问题，使用 open3d 的 capture_screen_image 和 capture_depth_image 函数。这个方案由于是保存离散化的深度图像 (0~255)，因此尺度完全丢失。且它发现由于这两个函数的 camera params 与使用 create_from_rgbd_image 投影会点云时的 camera params 并不一致，因此还会有变形。

我使用 capture_depth_float_buffer 加上 create_from_rgbd_image 重投影测试发现同样存在尺度和变形问题。

方案

使用 open3d 的 capture_depth_point_cloud 直接渲染。

Copy
def render_mesh_depth(mesh, depth):
center_mesh = np.mean(np.array(mesh.vertices), axis=0)
depth_data_center = np.mean(depth_data, axis=0)
mesh.vertices = o3d.utility.Vector3dVector(np.array(mesh.vertices) - center_mesh + depth_data_center)

# 设置相机的姿态
camera_pose = np.array([
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
])

# 创建渲染器和渲染选项
vis = o3d.visualization.Visualizer()
vis.create_window(visible=False) # 创建一个不可见的渲染窗口
vis.add_geometry(mesh)

# 设置相机参数和视口
ctr = vis.get_view_control()
cam_params = ctr.convert_to_pinhole_camera_parameters()
cam_params.extrinsic = camera_pose
ctr.convert_from_pinhole_camera_parameters(cam_params)

# 渲染深度图像
vis.capture_depth_point_cloud("o3d_tmp.ply", do_render=True, convert_to_world_coordinate=True)
vis.destroy_window()

# 从深度图像生成点云
pcd = o3d.io.read_point_cloud("o3d_tmp.ply")
os.remove("o3d_tmp.ply")
return pcd

期间还遇到一个 open3d 的 bug Visualizer.get_view_control() gives a copy. · Issue #6009 · isl-org/Open3D · GitHub。open3d 版本 0.17.0 的 get_view_control 函数得到的 view_control 是不起作用的。将版本调整为 0.16.0 后正常工作。

后续

目前需要先保存成文件后再读取、再删除。使用 capture_depth_float_buffer 不会有这个问题但有尺度和变形问题。猜测就是 camera params 渲染和重投影所使用的不一致。可以参考 VisualizerRender.cpp 源码思考解决方案。