繁体   English   中英

Python 中的点云到网格的距离 [关闭]

[英]Distance Point Cloud to Mesh in Python [closed]

我有一个大的 3D 点云和一个由三角形元素组成的网格。 我需要按照本文 ( https://www.geometrictools.com/Documentation/DistancePoint3Triangle3.pdf ) 中所述计算每个点到网格的最小距离。 然而,由于大量的点和元素,蛮力方法是不可行的。

据我了解,将元素和数据点存储在树结构(例如八叉树)中会大大加快计算速度。

是否有一个 Python 库可以让我非常有效地进行计算,即使对于大量的点和元素也是如此?

您可以使用scipy.spatial.cKDTree 使用 KD-tree 您可以在大约 O (N * log (M) * k) 中解决您的问题,其中 N 是点云中的点数,M 是网格中的顶点数,k 是平均数一个顶点的“相邻”三角形。

  1. 在网格顶点上构建 KD-tree:
tr = cKDTree(Mesh_vertexs)
  1. 构建一个 hash 表vertex -> list of "adjoining" triangles
  2. 学习找到一个点和一个三角形之间的距离(如果你不能)那么算法的伪代码非常简单:
for point in point_cloud:
    d,idx_of_point_in_mesh = tree.query(point)
    for triangle in Mesh_Triangles_near_vertex[idx_of_point_in_mesh]:
        d = min(d, distance(triangle,point))
    min_distance[point] = d

为了估计性能,对于网格中的 10 ^ 6 个顶点,一个查询tree.query (point)在我的笔记本电脑上占用27.5 µs ± 235 ns 对于 10 ^ 6 个点的云,时间将为27.5 µs * 10 ^ 6 = 27sec + 计算每个点的距离(三角形,点)的成本

La Lune De Idees提供的答案是一个很好的起点。 多亏了答案,我才能够通过仅使用 numpy 和 scipy 将我的代码加速 30 倍。

鉴于

顶点点作为 M x 3 vertice_points数组的网格

point_cloud点云作为 N x 3 numpy 数组来计算到的距离

我想出了下面完整的(对我来说工作的)例子:

# make efficient search tree
tree = cKDTree(vertice_points)

# get indices of closest three points to use as vetice to calculate distance to
d, idx_of_point_in_mesh = tree.query(point_cloud, 3)

# anchor point to span a plane from
anchor_points = vertice_points[idx_of_point_in_mesh[:,0],:]

# use next two nearest points to span a plane with two vectors
# from anchor point
plane_points = vertice_points[idx_of_point_in_mesh[:,1:],:]
plane_vecs = np.array(plane_points)
plane_vecs[:,0,:] -= anchor_points
plane_vecs[:,1,:] -= anchor_points

# calculate normal vectors of the planes
normals = np.cross(plane_vecs[:,0,:], plane_vecs[:,1,:], axis=1)

# distance from each point to its anchor point for spanning a plane
PQ = anchor_points - point_cloud
# distance is dot product between normal and PQ vector
# since normals and PQ are arrays of vectors 
# use einsum to calc dot product along first dimension
dists = np.einsum('ij,ij->i', PQ, normals)

注意:上面的代码假设网格中三个最近的点所跨越的顶点也是离该点最近的顶点,这是一个合理的假设,如果网格相对平坦并且点靠近网格的中心,并且相对于网格的延伸距离不远。 我的用例就是这种情况。

不幸的是我不能发表评论,但如果我没记错的话, Tobi 的非常有用的答案是缺乏法向量的归一化,导致错误的绝对距离值。 这可以使用np.linalg.norm解决:

normals = np.cross(plane_vecs[:, 0, :], plane_vecs[:, 1, :], axis=1)
normals_norm = normals / (np.linalg.norm(normals, ord=2, axis=1)[:, None])

另外,请注意距离的符号并未给出距离的方向。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM