[英]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 是平均數一個頂點的“相鄰”三角形。
tr = cKDTree(Mesh_vertexs)
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
為了估計性能,對於網格中的 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.