【问题标题】:Distance Point Cloud to Mesh in Python [closed]Python中点云到网格的距离[关闭]
【发布时间】:2022-02-18 07:08:35
【问题描述】:

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

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

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

【问题讨论】:

  • 解决您的问题所需的所有代码、数据、背景信息、错误消息等都必须作为文本包含在您的问题正文中。您可以在每个页面顶部的帮助部分中阅读有关 SO 要求的更多信息。照原样,如果链接到的页面不可用,您的 Q 将变得无用,并且 SO 的质量会受到影响。此外,没有人想在互联网上单击以找出您的问题是什么——并非所有链接都可以信任。努力使它尽可能简单和吸引人,以便志愿者选择你的 Q 而不是另一个。代码必须是最小可行示例。
  • 此外,请求库或教程的问题超出了 SO 旨在处理的问题范围。 StackExchange 网络中有专门针对此类问题的姊妹站点。也许,您可以改写您的问题,使其指向特定的编码问题,而不是请求外部资源?

标签: python mesh point-clouds


【解决方案1】:

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

  1. 在网格顶点上构建 KD 树:
tr = cKDTree(Mesh_vertexs)
  1. 建立哈希表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 + 计算每个点的距离(三角形、点)的成本

【讨论】:

    【解决方案2】:

    很遗憾,我无法发表评论,但如果我没记错的话,Tobi's very helpful answer 缺少法线向量的归一化,导致绝对距离值错误。这可以使用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])
    

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

    【讨论】:

      【解决方案3】:

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

      给定

      vertice_points 一个网格为 M x 3 numpy 数组

      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)
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-06-26
        • 1970-01-01
        • 2022-01-20
        • 1970-01-01
        • 2019-08-14
        • 1970-01-01
        • 2017-04-19
        • 2011-07-10
        相关资源
        最近更新 更多