引#
如圖,已知一個 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
直接渲染。
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 源碼思考解決方案。