Open3D Distance Queries 距离查询

简介: Open3D Distance Queries 距离查询

Distance Queries 距离查询

Open3D 中的类RaycastingScene提供了一组距离查询,可用于将三角形网格转换为隐式函数、查询到表面的距离或确定点是否位于网格内。

在本教程中,我们将展示如何生成这些查询,以及如何从几何处理和 3D 机器学习中使用的网格生成隐式表示。

Converting a mesh to an implicit representation

使用三角网格初始化RaycastingScene

# Load mesh and convert to open3d.t.geometry.TriangleMesh
armadillo_data = o3d.data.ArmadilloMesh()
mesh = o3d.io.read_triangle_mesh(armadillo_data.path)
mesh = o3d.t.geometry.TriangleMesh.from_legacy(mesh)

# Create a scene and add the triangle mesh
scene = o3d.t.geometry.RaycastingScene()
_ = scene.add_triangles(mesh)  # we do not need the geometry ID for mesh

计算单个点的距离和占用

RaycastingScene 直接提供用于计算从点到网格表面的无符号和有符号距离的函数。它还提供了一个函数来计算查询点的占用率。

query_point = o3d.core.Tensor([[10, 10, 10]], dtype=o3d.core.Dtype.Float32)

# Compute distance of the query point from the surface
unsigned_distance = scene.compute_distance(query_point)
signed_distance = scene.compute_signed_distance(query_point)
occupancy = scene.compute_occupancy(query_point)

print("unsigned distance", unsigned_distance.numpy())
print("signed_distance", signed_distance.numpy())
print("occupancy", occupancy.numpy())

虽然始终可以计算无符号距离,但符号距离和占用率仅在网格是水密且内部和外部明确定义的情况下才有效。

如果查询点位于网格内,则有符号距离为负。对于网格外的点,占用率为 0,对于网格内的点,占用率为 1。

计算多个点和网格的距离

RaycastingScene允许一次进行多个查询。例如,我们可以通过一个[N,3]张量表示N个查询点,这些查询点可用于随机采样一个体积,以训练机器学习中的隐式神经表示。

min_bound = mesh.vertex['positions'].min(0).numpy()
max_bound = mesh.vertex['positions'].max(0).numpy()

N = 256
query_points = np.random.uniform(low=min_bound, high=max_bound,
                                 size=[N, 3]).astype(np.float32)

# Compute the signed distance for N random points
signed_distance = scene.compute_signed_distance(query_points)

RaycastingScene允许使用任意数量的前导维度来组织查询点。要查询格网(grid)的有符号距离,我们可以执行以下操作

xyz_range = np.linspace(min_bound, max_bound, num=32)

# query_points is a [32,32,32,3] array ..
query_points = np.stack(np.meshgrid(*xyz_range.T), axis=-1).astype(np.float32)

# signed distance is a [32,32,32] array
signed_distance = scene.compute_signed_distance(query_points)

# We can visualize a slice of the distance field directly with matplotlib
plt.imshow(signed_distance.numpy()[:, :, 15])

同样的过程也适用于 RaycastingScene.compute_distance和RaycastingScene.compute_occupancy ,可用于生成无符号距离和占用字段。

Computing distances with closest point queries 使用最近点查询计算距离

距离函数建立在compute_closest_points()函数之上。在这一部分中,我们将重新实现有符号距离,并演示如何利用函数compute_closest_points()返回的其他信息。

初始化

我们首先使用两个三角形网格初始化RaycastingScene。两个网格都是水密的,我们将放置它们,使它们之间没有交集。

cube = o3d.t.geometry.TriangleMesh.from_legacy(
    o3d.geometry.TriangleMesh.create_box().translate([-1.2, -1.2, 0]))
sphere = o3d.t.geometry.TriangleMesh.from_legacy(
    o3d.geometry.TriangleMesh.create_sphere(0.5).translate([0.7, 0.8, 0]))

scene = o3d.t.geometry.RaycastingScene()
# Add triangle meshes and remember ids
mesh_ids = {}
mesh_ids[scene.add_triangles(cube)] = 'cube'
mesh_ids[scene.add_triangles(sphere)] = 'sphere'

计算表面上最近的点

RaycastingScene.compute_closest_points()可以计算表面上相对于查询点的最近点。

query_point = o3d.core.Tensor([[0, 0, 0]], dtype=o3d.core.Dtype.Float32)

# We compute the closest point on the surface for the point at position [0,0,0].
ans = scene.compute_closest_points(query_point)

# Compute_closest_points provides the point on the surface, the geometry id,
# and the primitive id.
# The dictionary keys are
#.    points
#.    geometry_ids
#.    primitive_ids
print('The closest point on the surface is', ans['points'].numpy())
print('The closest point is on the surface of the',
      mesh_ids[ans['geometry_ids'][0].item()])
print('The closest point belongs to triangle', ans['primitive_ids'][0].item())

为了计算点是在内部还是外部,我们可以从查询点开始投射光线,并计算交集的数量。

rays = np.concatenate(
    [query_point.numpy(),
     np.ones(query_point.shape, dtype=np.float32)],
    axis=-1)
intersection_counts = scene.count_intersections(rays).numpy()
# A point is inside if the number of intersections with the scene is even
# This sssumes that inside and outside is we ll defined for the scene.
is_inside = intersection_counts % 2 == 1

我们可以将其组合成一个函数,以创建一个返回附加信息的特殊有符号距离函数:

def compute_signed_distance_and_closest_goemetry(query_points: np.ndarray):
    closest_points = scene.compute_closest_points(query_points)
    distance = np.linalg.norm(query_points - closest_points['points'].numpy(),
                              axis=-1)
    rays = np.concatenate([query_points, np.ones_like(query_points)], axis=-1)
    intersection_counts = scene.count_intersections(rays).numpy()
    is_inside = intersection_counts % 2 == 1
    distance[is_inside] *= -1
    return distance, closest_points['geometry_ids'].numpy()

我们可以使用该函数创建具有距离和几何 ID 信息的网格

# compute range
xyz_range = np.linspace([-2, -2, -2], [2, 2, 2], num=32)
# query_points is a [32,32,32,3] array ..
query_points = np.stack(np.meshgrid(*xyz_range.T), axis=-1).astype(np.float32)

sdf, closest_geom = compute_signed_distance_and_closest_goemetry(query_points)

# We can visualize a slice of the grids directly with matplotlib
fig, axes = plt.subplots(1, 2)
axes[0].imshow(sdf[:, :, 16])
axes[1].imshow(closest_geom[:, :, 16])

相关文章
|
8月前
|
算法
Light oj 1082 - Array Queries(区间最小值)
这里只要知道这种算法即可,因为数据量过大,都编译不通过,不过思想算法没有任何问题。
22 0
|
SQL Oracle 关系型数据库
【SQL开发实战技巧】系列(十五):查找最值所在行数据信息及快速计算总和百之max/min() keep() over()、fisrt_value、last_value、ratio_to_report
本篇文章讲解的主要内容是:***计算部门中那个工资等级的员工最多、通过返回部门10最大工资所在行的员工名称小案例来讲解max/min() keep() over()、通过查询工资最高的人小案例来介绍fisrt_value、last_value、通过计算各个部门的工资合计以及各个部门合计工资占总工资的比例小案例来介绍如何计算百分比及ratio_to_report分析函数的使用***
【SQL开发实战技巧】系列(十五):查找最值所在行数据信息及快速计算总和百之max/min() keep() over()、fisrt_value、last_value、ratio_to_report
LeetCode Contest 178-1368. 使网格图至少有一条有效路径的最小代价 Minimum Cost to Make at Least One Valid Path in a Grid
LeetCode Contest 178-1368. 使网格图至少有一条有效路径的最小代价 Minimum Cost to Make at Least One Valid Path in a Grid
|
存储 算法
PAT (Advanced Level) Practice 1046 Shortest Distance (20 分)
PAT (Advanced Level) Practice 1046 Shortest Distance (20 分)
78 0
PAT (Advanced Level) Practice 1046 Shortest Distance (20 分)