圆圈测试中的快点{n}

时间:2017-02-19 19:27:02

标签: performance numpy scipy geometry

我有大量(x,y)网格点和整数坐标,我想测试它们是否是由半径和中心给出的少量圆圈。这些点是图像的一些标记部分,这意味着存在少量不规则形状的块,其包含点。我想检查碰撞并计算一个圆圈内的点数。我目前的方法相当慢(使用python和numpy)。

现在我有两个任务:

  1. 测试,如果集合A的任何点在任何圆圈中
  2. 计算集合B的点数,它们是圆圈
  3. 我当前的实现看起来像这样(setAsetBNx2 numpy数组,center1x2数组。):

    1)对于每个圆圈,创建一个point - center数组,将其按元素取方并取总和,然后检查它是否小于radius**2

    for circle in circles:
        if (((setA - circle.center)**2).sum(axis=1) < circle.radius**2).any():
            return "collision"
    return "no collision"
    

    这可以通过使用python循环并打破第一次碰撞来优化,但通常numpy循环比python循环快很多,实际上两个版本都比预期慢。

    2)对于每个圆圈,创建一个距离数组,并进行元素小于半径测试。添加所有数组并计算结果的非零元素。

    pixels = sp.zeros(len(setB))
    for circle in circles:
        pixels += (((setB - circle.center)**2).sum(axis=1) < circle.radius**2)
    return np.count_nonzero(pixels)
    

    有没有一个简单的方法来加速这个?

    我不想过度优化(并使程序变得更复杂),但只是以最有效的方式使用numpy,尽可能使用numpy矢量化。

    所以构建最完美的空间树或类似的并不是我的目标,但我认为对于几千个点和10-20个圆圈的O(n ^ 2)算法应该可以快速实现今天普通的台式电脑。

1 个答案:

答案 0 :(得分:3)

利用坐标为整数:

创建查找图像

radius = max([circle.radius for circle in circles])
mask = np.zeros((image.shape[0] + 2*radius, image.shape[1] + 2*radius), dtype=int)
for circle in circles:
    center = circle.center + radius
    mask[center[0]-circle.radius:center[0]+circle.radius + 1,
         center[1]-circle.radius:center[1]+circle.radius + 1] += circle.mask

circle.mask是一个小方形贴片,包含内部圆盘的掩模

计算碰撞现在就像

一样简单
mask[radius:-radius, radius:-radius][setB[:,0], setB[:,1]].sum()

快速创建光盘(没有乘法,没有平方根):

r = circle.radius
h2 = np.r_[0, np.add.accumulate(np.arange(1, 2*r+1, 2))]
w = np.searchsorted(h2[-1] - h2[::-1], h2)
q = np.zeros(((r+1), (r+1)), dtype=int)
q[np.arange(r+1), w[::-1]] = 1
q[1:, 0] -= 1
q = np.add.accumulate(q.ravel()).reshape(r+1, r+1)
h = np.c_[q, q[:, -2::-1]]
circle.mask = np.r_[h, h[-2::-1]]