[英]Distance Point Cloud to Mesh in Python [closed]
I have a large 3D point cloud and a mesh consisting of triangular elements.我有一个大的 3D 点云和一个由三角形元素组成的网格。 I need to calculate the minimum distance of every point to the mesh as described in this paper ( https://www.geometrictools.com/Documentation/DistancePoint3Triangle3.pdf ).我需要按照本文 ( https://www.geometrictools.com/Documentation/DistancePoint3Triangle3.pdf ) 中所述计算每个点到网格的最小距离。 However, because of the large number of points and elements a brute force approach is not feasible.然而,由于大量的点和元素,蛮力方法是不可行的。
It is my understanding that storing the elements and data points in a tree-structure (eg octree), would considerably speed up the calculation.据我了解,将元素和数据点存储在树结构(例如八叉树)中会大大加快计算速度。
Is there a Python library that would allow me to do the calculation very efficiently even for a large number of points and elements?是否有一个 Python 库可以让我非常有效地进行计算,即使对于大量的点和元素也是如此?
You can use scipy.spatial.cKDTree .您可以使用scipy.spatial.cKDTree 。 With KD-tree you can solve your problem in approximately O (N * log (M) * k), where N is the number of points in the point cloud, M is the number of vertices in the mesh, k is the average number of "adjacent" triangles to one vertex.使用 KD-tree 您可以在大约 O (N * log (M) * k) 中解决您的问题,其中 N 是点云中的点数,M 是网格中的顶点数,k 是平均数一个顶点的“相邻”三角形。
tr = cKDTree(Mesh_vertexs)
vertex -> list of "adjoining" triangles
构建一个 hash 表vertex -> list of "adjoining" triangles
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
To estimate the performance, for 10 ^ 6 vertices in a mesh, one query tree.query (point)
takes on my laptop 27.5 µs ± 235 ns
.为了估计性能,对于网格中的 10 ^ 6 个顶点,一个查询tree.query (point)
在我的笔记本电脑上占用27.5 µs ± 235 ns
。 For a cloud of 10 ^ 6 points, the time will be 27.5 µs * 10 ^ 6 = 27sec
+ the cost of calculating distance (triangle, point) for each point对于 10 ^ 6 个点的云,时间将为27.5 µs * 10 ^ 6 = 27sec
+ 计算每个点的距离(三角形,点)的成本
The answer provided by La Lune De Idees is a very good starting point. La Lune De Idees提供的答案是一个很好的起点。 Thanks to the answer I was able to speed up my code by 30x through using only numpy and scipy.多亏了答案,我才能够通过仅使用 numpy 和 scipy 将我的代码加速 30 倍。
Given鉴于
vertice_points
a mesh as M x 3 numpy array顶点点作为 M x 3 vertice_points
数组的网格
and和
point_cloud
a point cloud as N x 3 numpy array to calculate the distances to point_cloud
点云作为 N x 3 numpy 数组来计算到的距离
I came up with the full (for me working) example below:我想出了下面完整的(对我来说工作的)例子:
# 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)
NOTE : The code above assumes that the vertice spanned by the three nearest points in the mesh is also the nearest vertice to the point, which is a reasonable assumption, if the mesh is relatively flat and the points are close to the center of the mesh, and not far distanced relative to the extend of the mesh.注意:上面的代码假设网格中三个最近的点所跨越的顶点也是离该点最近的顶点,这是一个合理的假设,如果网格相对平坦并且点靠近网格的中心,并且相对于网格的延伸距离不远。 Which is the case for my use case.我的用例就是这种情况。
Unfortunately I cannot comment, but if I am not mistaken, Tobi's very helpful answer is lacking normalization of the normal vectors, resulting in wrong absolute distance-values.不幸的是我不能发表评论,但如果我没记错的话, Tobi 的非常有用的答案是缺乏法向量的归一化,导致错误的绝对距离值。 This can be solved using np.linalg.norm
:这可以使用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])
Also, be aware that the sign of the distances is not giving a direction of the distance.另外,请注意距离的符号并未给出距离的方向。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.