找到统一网格上点云中最近点的距离

时间:2010-04-29 06:19:14

标签: algorithm

我有一个大小为AxBxC的3D网格,网格中的点之间的距离d相等。给定下面的假设,给出了多个点,找到每个网格点最近点的距离的最佳方法是什么(每个网格点应包含到点云中最近点的距离)?

假设A,B和C相对于d非常大,给出的网格可能是500x500x500,并且将有大约100万个点。

还假设如果到最近点的距离超出D的距离,我们不关心最近的点距离,并且可以安全地设置为某个大数(D可能是2到10倍d)< / p>

由于会有大量的网格点和点来搜索,所以简单详尽无遗:

for each grid point:
   for each point:
     if distance between points < minDistance:
       minDistance = distance between points

不是一个好的选择。

我正想着做一些事情:

create a container of size A*B*C where each element holds a container of points
for each point:
  define indexX = round((point position x - grid min position x)/d)
  // same for y and z
  add the point to the correct index of the container

for each grid point:
  search the container of that grid point and find the closest point
  if no points in container and D > 0.5d:
    search the 26 container indices nearest to the grid point for a closest point
  .. continue with next layer until a point is found or the distance to that layer 
        is greater than D

基本上:将点放在桶中并向外进行径向搜索,直到找到每个网格点的点。这是解决问题的好方法,还是有更好/更快的方法?优选用于并行化的解决方案。

5 个答案:

答案 0 :(得分:2)

看看octrees。它们是一种数据结构,通常用于有效地划分3d空间,以提高在空间上彼此接近的对象的查找效率。

答案 1 :(得分:2)

您可以在样本点上构建nearest neighbor search structure(维基百科),然后询问每个网格点。维基百科页面上提到了许多算法。也许octtrees,kd-trees或R-trees是合适的。

答案 2 :(得分:2)

实际上,我认为我有更好的方法,因为网格点的数量远远大于采样点的数量。设|网格| = N,|样本| = M,那么最近邻搜索算法将类似于O(N lg M),因为您需要查找所有N个网格点,并且每个查找都是(最佳情况)O(lg M)。

相反,循环遍历采样点。为每个网格点存储到目前为止找到的最近样本点。对于每个样本点,只需检查样本距离D内的所有网格点,以查看当前样本是否比先前处理的样本更接近。

运行时间为O(N +(D / d)^ 3 M),当D / d较小时,运行时间应该更好。

即使D / d较大,如果你能制定一个截止策略,你仍然可以。例如,如果我们从样本中检查网格点距离5,并且该网格点已经标记为距前一个样本的距离1,那么不需要检查“超出”该网格点的所有网格点因为前一个样本保证比我们正在处理的当前样本更接近。你所要做的就是(我认为这很简单,但应该是可行的)定义“超出”意味着什么,并弄清楚如何遍历网格以避免为“超出”这样的网格点的区域做任何工作

答案 3 :(得分:1)

一种方法可能适合您的应用,也可能不适合您的应用,是重新思考并将每个网格“点”定义为将空间划分为单元格的立方体的中心。然后,您将拥有此类单元格的3D数组,并将这些点存储在单元格中 - 选择最合适的数据结构。要使用您自己的话,首先将点放在存储桶中。

我想您可能正在运行某种大规模模拟,我建议的方法在此类应用程序中并不罕见。在每个时间步(如果我猜对了)你必须重新计算从细胞到最近点的距离,并将点从细胞移动到细胞。这很容易并行化。

编辑:在粒子 - 粒子粒子 - 粒子 - 粒子 - 网格上搜索可能会为你提出一些想法。

答案 4 :(得分:1)

关于Keith Randall方法的说明, 在起点周围展开贝壳或立方体:
人们可以扩展各种订单。这是一些python风格的伪代码:

S = set of 1m startpoints
near = grid 500x500x500 -> nearest s in S
    initially s for s in S, else 0
for r in 1 .. D:
    for s in S:
        nnew = 0 
        for p in shell of radius r around s:
            if near[p] == 0:
                near[p] = s
                nnew += 1
        if nnew == 0:
            remove s from S  # bonk, stop expanding from s

“从早期开始不断扩张”在1d中很好(bonk left,bonk right); 但是2d / 3d炮弹是不规则的 一次完成整个立方体更容易/更快:

near = grid 500x500x500 -> { dist, nearest s in S }
    initially { 0, s } for s in self, else { infinity, 0 }
for s in S:
    for p in approximatecube of radius D around s:
        if |p - s| < near[p].dist:  # is s nearer ?
            near[p] = { |p - s|, s }

这里“approximatecube”可能是一个完整的DxDxD立方体, 或者你可以像(这里2d)那样砍掉角落

0 1 2 3 4 
1 1 2 3 4 
2 2 3 4 4
3 3 4 4
4 4 4

也是fwiw, 用erik的数字,平均有500 ^ 3 / 1M~2 ^ 7~5 ^ 3个空箱 每个样本点。 所以我起初认为5x5x5立方体大约有1M个样本点 将覆盖整个网格的大部分。 不是这样,〜1 / e的网格点保持空白 - Poisson distibution。