使用网格分区在2D中进行最近邻搜索

时间:2013-04-04 19:39:29

标签: algorithm geometry nearest-neighbor

我在一组中有一组相当大的2D点(~20000),并且对于x-y平面中的每个点,想要确定该组中哪个点最接近。 (实际上,这些点的类型不同,我只想知道哪种类型最接近。而x-y平面是位图,比如640x480。)

this answer到问题" All k nearest neighbors in 2D, C++"我有了制作网格的想法。我创建了n * m C ++向量并将这些点放在向量中,具体取决于它落入哪个bin。这个想法是你只需要检查垃圾箱中的点的距离,而不是所有的点。如果垃圾箱中没有任何点,则以螺旋方式继续相邻的垃圾箱。

不幸的是,之后我只读了Oli Charlesworth的评论:

  

不幸的是,不仅仅是邻近(考虑到单元格中的两个点   东边可能比东北方向的小区更接近,   例如;这个问题在更高的维度上变得更糟糕)。   而且,如果相邻的小区恰好小于10,该怎么办?   他们分?在实践中,你需要"螺旋式的"。

幸运的是,我已经找到了螺旋式代码(一个不错的C++ version here,并且在同一个问题中还有其他版本)。但我仍然没有解决问题:

  • 如果我在一个单元格中找到一个点击,相邻单元格中可能会有更接近的击中(黄色是我的探测器,红色是错误的选择,绿色是实际的最近点):

    enter image description here

  • 如果我在相邻的小区中发现一个点击,那么在2步之外的小区中可能会有一个点击,正如Oli Charlesworth所说:

    enter image description here

  • 但更糟糕的是,如果我在两步之外的一个牢房中发现了一次撞击,那么在三步之外的撞击中仍然会有更接近的击中!这意味着我必须考虑所有具有dx,dy = -3 ... 3或49个细胞的细胞!

    enter image description here

现在,在实践中,这不会经常发生,因为我可以选择我的bin大小,以便细胞足够填充。尽管如此,我还是希望得到一个正确的结果,而不是迭代所有点。

那我怎么知道何时停止"螺旋式"或者搜索?我听说有一种方法有多个重叠的网格,但我并不太了解它。是否有可能挽救这种网格技术?

4 个答案:

答案 0 :(得分:1)

由于位图的尺寸不大,而您想计算每个 (x,y)的最近点,您可以使用动态编程。

V[i][j](i,j)到集合中最近点的距离,但考虑集合中“矩形”中的点[( 1,1),(i,j)]。

然后V[i][j] = 0如果(i, j)中有一个点,或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(平面的大小),这是最佳的。

答案 1 :(得分:1)

对于您的任务,通常使用Point Quadtree,尤其是当点数不均匀分布时。

要保存主存储器,您可以使用使用存储桶的PM或PMR-Quadtree。

你在你的细胞中进行搜索,在最坏的情况下,所有四元细胞都会在细胞周围进行搜索。

您还可以使用k-d tree

答案 2 :(得分:0)

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

假设您在级别1,2,4,8,...

创建分区

现在,搜索网格大小为1的点(基本上是在9个方格中搜索)。如果搜索区域中有一个点,并且到该点的距离小于1,则停止。否则,请转到下一个网格大小。

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

答案 3 :(得分:0)

尝试解决方案

  • 首先制作一个网格,使每个方框的平均值为1(如果你想要更大的扫描,则更多)。
  • 选择中心框。继续以循环方式选择邻居框,直到找到至少一个邻居。此时,您可以选择1或9个左右的框
  • 再选择一层相邻的方框
  • 现在你有一个相当小的点列表,通常不超过10,你可以打入距离公式找到最近的邻居。

由于每个盒子平均有1个点,因此您将主要选择9个盒子并比较9个距离。可以根据您的数据集属性调整网格大小,以获得更好的结果。

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