寻找邻居

时间:2011-02-10 03:19:40

标签: matlab computational-geometry nearest-neighbor delaunay voronoi

我需要在一组点中找到“附近”的邻居。

pointSet

上图中有10个点。红线是Delaunay Triangulation的边缘,黑色星标记边缘的中线,蓝线是Voronoi tesselation。点1具有三个“近”邻居,即4,6和7,但不是2和3,它们几乎与边缘1-7一致,但距离更远。

识别近邻(或“好”边缘)的好方法是什么?看看这个图,在我看来,要么选择中点落在与Voronoi线交叉点的边缘,要么考虑作为“近”邻居那些触摸Voronoi单元的边缘可能是一个很好的解决方案(3-5的分类)可以去任何一种方式)。有没有一种有效的方法来实现Matlab中的任何一个解决方案(我很乐意得到一个好的通用算法,然后我可以转换为Matlab,顺便说一下)?

3 个答案:

答案 0 :(得分:8)

通过使用DelaunayTri class及其edgesnearestNeighbor方法,您可以实现选择中点落在与Voronoi线的交点上的边的第一个想法。以下是10个随机对xy值的示例:

x = rand(10,1);                     %# Random x data
y = rand(10,1);                     %# Random y data
dt = DelaunayTri(x,y);              %# Compute the Delaunay triangulation
edgeIndex = edges(dt);              %# Triangulation edge indices
midpts = [mean(x(edgeIndex),2) ...  %# Triangulation edge midpoints
          mean(y(edgeIndex),2)];
nearIndex = nearestNeighbor(dt,midpts);  %# Find the vertex nearest the midpoints
keepIndex = (nearIndex == edgeIndex(:,1)) | ...  %# Find the edges where the
            (nearIndex == edgeIndex(:,2));       %#   midpoint is not closer to
                                                 %#   another vertex than it is
                                                 %#   to one of its end vertices
edgeIndex = edgeIndex(keepIndex,:);      %# The "good" edges

现在edgeIndex是一个N×2矩阵,其中每一行包含xy的索引,用于定义“近”连接的一条边。下图说明了Delaunay三角剖分(红线),Voronoi图(蓝线),三角剖分边缘的中点(黑色星号),以及edgeIndex(粗红线)中的“良好”边缘:< / p>

triplot(dt,'r');  %# Plot the Delaunay triangulation
hold on;          %# Add to the plot
plot(x(edgeIndex).',y(edgeIndex).','r-','LineWidth',3);  %# Plot the "good" edges
voronoi(dt,'b');  %# Plot the Voronoi diagram
plot(midpts(:,1),midpts(:,2),'k*');  %# Plot the triangulation edge midpoints

enter image description here

工作原理......

Voronoi图由一系列Voronoi多边形或单元组成。在上图中,每个单元表示给定三角测量顶点周围的区域,该区域包围空间中比任何其他顶点更靠近该顶点的所有点。因此,当您有2个顶点不接近任何其他顶点(如图像中的顶点6和8)时,连接这些顶点的线的中点落在Voronoi单元格之间的分隔线上顶点。

然而,当存在接近连接2个给定顶点的线的第三个顶点时,第三个顶点的Voronoi单元可以在2个给定顶点之间延伸,穿过连接它们的线并将该线包围在中点。因此,该第三顶点可以被认为是2个给定顶点的“更近”邻居,而不是2个顶点彼此相邻。在图像中,顶点7的Voronoi单元格延伸到顶点1和2(以及1和3)之间的区域,因此顶点7被认为是顶点1的邻近,而不是顶点2(或3)。

在某些情况下,即使他们的Voronoi单元接触,该算法也可能不会将两个顶点视为“近”邻居。图像中的顶点3和5就是这样的一个例子,其中顶点2被认为是顶点3或5的近邻,而顶点3或5彼此相邻。

答案 1 :(得分:1)

我同意共享小区边缘是一个很好的邻居标准(基于这个例子)。如果你使用面向网格的数据结构(比如来自Gts的东西),那么识别共享边缘将是微不足道的。

另一方面,Matlab使这更“有趣”。假设voronoi单元格存储为补丁,您可以尝试获取“Faces”补丁属性(请参阅this reference)。这应该返回类似于标识连接顶点的邻接矩阵。从那里(和一点魔术),您应该能够确定共享顶点,然后推断共享边。根据我的经验,这种“搜索”问题不太适合Matlab - 如果可能的话,我建议转移到更适合网状连接查询的系统。

答案 2 :(得分:0)

另一种比创建三角测量或voronoi图更简单的可能性是使用邻域矩阵

首先将所有点放入2D方阵中。然后,您可以运行完整或部分空间排序,因此点将在矩阵内排序。

具有小Y的点可以移动到矩阵的顶行,同样,具有大Y的点将移动到底行。具有小X坐标的点也会发生同样的情况,这些点应移动到左侧的列。对称地,具有大X值的点将转到右列。

在进行空间排序后(有许多方法可以通过串行或并行算法实现这一点),您可以通过访问点P实际存储在其中的相邻单元格来查找给定点P的最近点。邻域矩阵。

您可以在下面的论文中阅读有关此想法的更多详细信息(您可以在线找到它的PDF副本):基于紧急行为的GPU上的超大规模人群模拟

排序步骤为您提供有趣的选择。您可以使用本文中描述的奇偶换位排序,这种排序非常简单(即使在CUDA中)。如果你只运行一次,它会给你一个局部排序,如果矩阵接近排序,这可能已经很有用了。也就是说,如果你的点移动缓慢,它将为你节省大量的计算。

如果你需要一个完整的排序,你可以多次运行这种奇偶换位传递(如下面的维基百科页面所述):

http://en.wikipedia.org/wiki/Odd%E2%80%93even_sort