我有大量(x,y)
网格点和整数坐标,我想测试它们是否是由半径和中心给出的少量圆圈。这些点是图像的一些标记部分,这意味着存在少量不规则形状的块,其包含点。我想检查碰撞并计算一个圆圈内的点数。我目前的方法相当慢(使用python和numpy)。
现在我有两个任务:
我当前的实现看起来像这样(setA
和setB
是Nx2
numpy数组,center
是1x2
数组。):
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)算法应该可以快速实现今天普通的台式电脑。
答案 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]]