使用Python有效地将区域划分成多个部分

时间:2018-07-14 21:56:03

标签: python algorithm computer-vision geometry computational-geometry

我有一个正方形网格,其中某些点标记为网格子部分的中心。我希望能够将网格内的每个位置分配给正确的子部分。例如,如果该区域的子部分以黑点为中心,那么我希望能够将红点分配给右下角的区域,因为它是最接近的黑点。

enter image description here

目前,我通过遍历每个可能的红点并将其与每个黑点的距离进行比较来实现此目的。但是,网格中黑点的宽度,长度和数量非常高,所以我想知道是否有更有效的算法。

我的特定数据是这样格式化的,其中数字只是占位符以与给定的示例相对应:

black_dots = [(38, 8), (42, 39), (5, 14), (6, 49)]
grid = [[0 for i in range(0, 50)] for j in range(0, 50)]

作为参考,在示例中,我希望能够用整数1、2、3、4填充grid,具体取决于它们是否最接近第一,第二,第三或第四。在black_dots中输入的内容最终将使我能够创建类似于下图的图片,其中每个整数都对应一种颜色(点保留在显示位置)。

enter image description here

总而言之,有/更有效的方法是什么?

3 个答案:

答案 0 :(得分:3)

您可以使用广度优先遍历来解决此问题。

  1. 创建先进先出队列。 (队列首先进行遍历。)

  2. 创建一个访问过的掩码,指示是否已将网格中的单元格添加到队列中。将蒙版设置为false。

  3. 创建一个父蒙版,以指示该单元格最终属于哪个黑点。

  4. 将所有黑点放入队列中,在“访问过的”蒙版中标记它们,并在“父”蒙版中为其分配唯一的ID。

  5. 从队列开始逐个弹出单元格。对于每个单元,迭代单元的邻居。将每个邻居放入队列,在“已访问”中进行标记,并将其在“父级”中的值设置为等于您刚刚弹出的单元格的值。

  6. 继续直到队列为空。

宽度优先遍历会产生一个从每个源像元向外扩展的波(黑点)。由于所有波都以相同的速度在您的网格中传播,因此每个波会吞噬最靠近其源的那些像元。

这解决了 O(N)时间内的问题。

答案 1 :(得分:2)

如果我正确理解了,您真正需要的是构建中心的Voronoi图:

enter image description here

可以用与计算凸包相同的计算复杂度非常有效地构造它。

通过Voronoi图,您可以构造围绕中心的最佳多边形,从而界定最靠近中心的区域。

具有Voronoi图,任务被简化以检测红点位于哪个多边形中。由于Voronoi单元是凸的,因此需要一种算法来确定点是否在凸多边形内。但是遍历所有多边形的复杂度为O(n)。

有几种算法可以加速点定位,因此可以在O(log n)中完成:

https://en.m.wikipedia.org/wiki/Voronoi_diagram

另请参见

https://en.m.wikipedia.org/wiki/Point_location

答案 2 :(得分:1)

通过两遍扫描线过程,可以有效地构建“ 8向” Voronoi图(线性时间与像素数成正比)。 (8向表示将距离视为两个像素之间最短的8连接路径的长度。)

为每个中心分配不同的颜色,并创建与图像大小相同的距离数组,在中心将其初始化为0,在其他位置以“无穷大”进行初始化。

在从上到下/从左到右的遍历中,将所有像素的距离更新为四个相邻像素W,NW,N和NE的最小距离加一,并为当前像素分配颜色达到最小值的邻居。

在自下而上/从右至左的过程中,将所有像素的距离更新为当前距离和四个相邻像素E,SE,S,SW的距离之和的最小值,然后分配当前像素达到最小值(或保持当前颜色)的邻居的颜色。


还可以高效地(在线性时间内)计算 Euclidean Voronoi图,但这需要更复杂的算法。它可以基于精彩的论文“计算距离的通用算法” A. MEIJSTER,J.B.T.M。ROERDINK和W.H. HESSELINK提出的“线性时间变换”,必须对造成最小距离的邻居进行一定的计算,才能增强这种效果。