2D中使用网格划分的最近邻搜索

4
我有一个相当大的2D点集(~20000),对于平面上的每个点,我想确定该集合中最接近的点是哪个(实际上,这些点是不同类型的,我只想知道哪种类型最接近。并且xy平面是位图,比如640x480)。
来自此答案的问题“All k nearest neighbors in 2D, C++”中我们可以得到创建一个网格的想法。我创建了n*m的C++向量,并将点放入向量中,具体取决于其所属的bin。这样做的想法是您只需要检查bin中的点的距离,而不是所有点的距离。如果bin中没有点,则继续以螺旋方式处理相邻的bin。
不幸的是,我在阅读Oli Charlesworth的评论之后才发现:

遗憾的是,不仅仅是相邻的(请考虑东部两个单元格中的点可能比东北方向直接的点更靠近,例如; 在更高维度下,这个问题会变得更加严重)。另外,如果相邻的单元格恰好少于10个点,则怎么办? 在实践中,您需要“螺旋形向外扩展”。

幸运的是,我已经想出了螺旋代码(这里有一个不错的C++版本,并且在同一问题中有其他版本)。但是我仍然面临一个问题:
  • 如果在一个单元格中找到匹配项,则相邻单元格可能会有更接近的匹配项(黄色是我的探针,红色是错误选择,绿色是实际最接近的点):

    enter image description here

  • 如果在相邻单元格中找到匹配项,则可能会在两步之外的单元格中找到匹配项,如Oli Charlesworth所指出的:

    enter image description here

  • 但更糟糕的是,如果我在两个步骤之外的单元格中发现匹配项,就可能仍然会有更接近的匹配项! 这意味着我必须考虑所有dx,dy = -3 ... 3或49个单元格!

    enter image description here

实际上,这种情况不经常发生,因为我可以选择我的bin大小,使单元格足够填充。仍然想得到正确的结果,而不必遍历所有点。

那么我如何知道何时停止"螺旋式"搜索呢?我听说有一种方法是使用多个重叠的网格,但我并没有完全理解。这个网格技术还能挽救吗?


你的点集是静态的还是动态的?一个点集执行了多少个“查找最近点”的查询? - MBo
有没有不使用已经存在的、内部使用kd-tree的成熟库(如ANN)的理由?还是只是出于好奇? - nbonneel
4个回答

2
由于您的位图尺寸不大,并且您想要计算每个(x,y)的最近点,因此您可以使用动态规划。
设V[i][j]是从(i,j)到集合中最近点的距离,但仅考虑在“矩形”[(1,1),(i,j)]中的集合中的点。
那么如果(i,j)中有一个点,则V[i][j]=0;否则,V[i][j]=min(V[i'][j'] + dist((i,j),(i',j'))),其中(i',j')是(i,j)的三个相邻点之一:

(i - 1, j) (i, j - 1) (i - 1, j - 1)
这给出了最小距离,但仅适用于“左上”矩形。我们对“右上”、“左下”和“右下”方向执行相同的操作,然后取最小值。
复杂度为平面大小的O,这是最优的。

2

通常情况下,使用Point Quadtree来完成您的任务,特别是当点的分布不均匀时。

为了节省主存储器,您也可以使用使用桶的PM或PMR-Quadtree。

您可以在单元格内搜索,并在最坏情况下搜索周围的所有四个象限。

您还可以使用k-d tree


k-d树专门处理这种情况,它考虑到了分割平面的另一侧:http://en.wikipedia.org/wiki/K-d_tree#Nearest_neighbour_search - fejesjoco

1
我正在尝试的解决方案:
  • 首先创建一个网格,使每个方框平均拥有1个点(如果您想进行更大的扫描,则可以拥有更多)。
  • 选择中心盒子。以循环方式继续选择相邻的盒子,直到找到至少一个相邻盒子。此时,您可以选择1或9或更多盒子。
  • 选择另外一层相邻的盒子
  • 现在您有一个相当小的点列表,通常不超过10个,您可以将它们输入距离公式中以找到最近的邻居。

由于每个盒子平均有1个点,因此您大多数情况下会选择9个盒子并比较9个距离。可以根据数据集属性调整网格大小以实现更好的结果。

此外,如果您的数据具有很大的差异性,则可以尝试2级网格(甚至更多),因此如果选择运作并返回单个查询中的50个以上的点,请开始使用网格大小为1/10的下一个网格搜索...


0

一个解决方案是构建多个具有不同网格大小的分区。

假设您在级别1、2、4、8等处创建分区。

现在,在大小为1的网格中搜索一个点(实际上您正在搜索9个正方形)。如果搜索区域内有一个点并且到该点的距离小于1,则停止。否则,继续移动到下一个网格大小。

您需要构建的网格数量大约是创建一个分区级别的两倍。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接