Ray Casting 光线投射
Open3D 中的类RaycastingScene提供了基本的光线投射功能。在本教程中,我们将展示如何创建场景并执行光线交叉测试。您还可以使用RaycastingScene从网格(例如 CAD 模型)创建虚拟点云。
Initialization
首先用网格初始化RaycastingScene.
# Load mesh and convert to open3d.t.geometry.TriangleMesh cube = o3d.geometry.TriangleMesh.create_box().translate([0, 0, 0]) cube = o3d.t.geometry.TriangleMesh.from_legacy(cube) # Create a scene and add the triangle mesh scene = o3d.t.geometry.RaycastingScene() cube_id = scene.add_triangles(cube)
add_triangles()返回添加的几何图形的 ID。此 ID 可用于识别光线击中的网格。
print(cube_id)
Casting rays 投射光线
我们现在可以生成具有原点和方向的6D矢量射线。
# We create two rays: # The first ray starts at (0.5,0.5,10) and has direction (0,0,-1). # The second ray start at (-1,-1,-1) and has direction (0,0,-1). rays = o3d.core.Tensor([[0.5, 0.5, 10, 0, 0, -1], [-1, -1, -1, 0, 0, -1]], dtype=o3d.core.Dtype.Float32) ans = scene.cast_rays(rays)
结果包含有关与场景中几何图形的可能交集的信息。
print(ans.keys())
t_hit是到交叉路口的距离。该单位由射线方向的长度定义。如果没有交集,则为inf
geometry_ids给出了光线击中的几何图形的 id。如果未命中几何图形,则为RaycastingScene.INVALID_ID
primitive_ids是命中的三角形的三角形索引,或者RaycastingScene.INVALID_ID
primitive_uvs是三角形内交点的重心坐标。
primitive_normals是命中三角形的法线。
我们可以从t_hit和geometry_ids看到,第一条光线确实击中了网格,但第二条光线错过了。
print(ans['t_hit'].numpy(), ans['geometry_ids'].numpy())
Creating images
现在,我们创建一个包含多个对象的场景
# Create meshes and convert to open3d.t.geometry.TriangleMesh cube = o3d.geometry.TriangleMesh.create_box().translate([0, 0, 0]) cube = o3d.t.geometry.TriangleMesh.from_legacy(cube) torus = o3d.geometry.TriangleMesh.create_torus().translate([0, 0, 2]) torus = o3d.t.geometry.TriangleMesh.from_legacy(torus) sphere = o3d.geometry.TriangleMesh.create_sphere(radius=0.5).translate( [1, 2, 3]) sphere = o3d.t.geometry.TriangleMesh.from_legacy(sphere) scene = o3d.t.geometry.RaycastingScene() scene.add_triangles(cube) scene.add_triangles(torus) _ = scene.add_triangles(sphere)
RaycastingScene允许组织具有任意数量的前导尺寸的光线。例如,我们可以生成一个形状为[h,w,6]的数组来组织光线以创建图像。该类还提供了用于为针孔相机创建光线的帮助器函数。下面创建具有形状[480,640,6]的射线张量。
rays = o3d.t.geometry.RaycastingScene.create_rays_pinhole( fov_deg=90, center=[0, 0, 2], eye=[2, 3, 0], up=[0, 1, 0], width_px=640, height_px=480, ) # We can directly pass the rays tensor to the cast_rays function. ans = scene.cast_rays(rays)
输出张量保留了光线的形状,我们可以直接使用matplotlib可视化命中距离以获得深度图。
import matplotlib.pyplot as plt plt.imshow(ans['t_hit'].numpy()) plt.show()#如果没有显示图片,需要加这一句。
此外,我们可以绘制其他结果以可视化原始法线,…
# use abs to avoid negative values plt.imshow(np.abs(ans['primitive_normals'].numpy())) plt.show() plt.imshow(ans['geometry_ids'].numpy(), vmax=3) plt.show()
Creating a virtual point cloud
我们还可以使用命中距离来计算交叉点的 XYZ 坐标。这些是通过将虚拟3D传感器放置在射线原点而获得的点。
hit = ans['t_hit'].isfinite() points = rays[hit][:,:3] + rays[hit][:,3:]*ans['t_hit'][hit].reshape((-1,1)) pcd = o3d.t.geometry.PointCloud(points) # Press Ctrl/Cmd-C in the visualization window to copy the current viewpoint o3d.visualization.draw_geometries([pcd.to_legacy()], front=[0.5, 0.86, 0.125], lookat=[0.23, 0.5, 2], up=[-0.63, 0.45, -0.63], zoom=0.7) # o3d.visualization.draw([pcd]) # new API