简体   繁体   中英

Distance Point Cloud to Mesh in Python [closed]

I have a large 3D point cloud and a mesh consisting of triangular elements. 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 ). 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?

You can use 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.

  1. build KD-tree on mesh vertexs:
tr = cKDTree(Mesh_vertexs)
  1. Build a hash table vertex -> list of "adjoining" triangles
  2. Learn to find the distance between a point and a triangle (if you can't) then the pseudocode of the algorithm is extremely simple:
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 . 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

The answer provided by La Lune De Idees is a very good starting point. Thanks to the answer I was able to speed up my code by 30x through using only numpy and scipy.

Given

vertice_points a mesh as M x 3 numpy array

and

point_cloud a point cloud as N x 3 numpy array to calculate the distances to

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. This can be solved using 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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