簡體   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