是否可以在二维数组上放置线性函数,并对二维数组中与该函数一致的所有元素求和?例如,我会有一个2D阵列,形状是(400500)。现在,在某个地方,我会重叠一个线性函数,它从2D阵列的底部向顶部延伸。我现在只想求和2D阵列中与直线重叠的元素。
有没有一种快速的方法可以只对2D阵列中与直线重合的元素求和?通过在for循环中使用for循环,我已经能够做到这一点。然而,这已经需要退出一段时间。特别是如果我想开始将这个技巧应用于更大的数组。
这在一定程度上取决于如何准确地定义行,以及哪些数组位置算作"在"行。但一个简单的方法是使用布尔掩码。使用numpy.mgrid
:,可以很容易地沿直线定义遮罩
>>> grid = numpy.mgrid[0:5,0:5]
>>> grid
array([[[0, 0, 0, 0, 0],
[1, 1, 1, 1, 1],
[2, 2, 2, 2, 2],
[3, 3, 3, 3, 3],
[4, 4, 4, 4, 4]],
[[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4]]])
正如你所看到的,这是一个x和y值的网格,然后你可以将它们联系在一个方程中,如下所示:
>>> grid[0] == 2 * grid[1]
array([[ True, False, False, False, False],
[False, False, False, False, False],
[False, True, False, False, False],
[False, False, False, False, False],
[False, False, True, False, False]], dtype=bool)
>>> grid[0] == grid[1]
array([[ True, False, False, False, False],
[False, True, False, False, False],
[False, False, True, False, False],
[False, False, False, True, False],
[False, False, False, False, True]], dtype=bool)
>>> grid[0] == grid[1] / 2
array([[ True, True, False, False, False],
[False, False, True, True, False],
[False, False, False, False, True],
[False, False, False, False, False],
[False, False, False, False, False]], dtype=bool)
请注意,您可能需要仔细思考为什么grid[0] == grid[1] / 2
给出了一条"连续"线,而grid[0] == 2 * grid[1]
没有,并准确地找出您想要的行为。(使用稍微复杂一点的方程式,您可以指定一个允许创建不同厚度线条的公差值。)
然后,您可以使用生成的掩码进行求和:
>>> a = numpy.arange(25).reshape(5, 5)
>>> a
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]])
>>> a[grid[0] == grid[1] / 2]
array([ 0, 1, 7, 8, 14])
>>> a[grid[0] == grid[1] / 2].sum()
30
这比嵌套for循环快得多,因为numpy
非常快。但它仍然执行相同数量的操作。
另一种方法可以是从x
值直接计算y
值。这样做的优点是它不必做那么多操作,因此对于非常非常大的阵列来说会更快:
>>> x = numpy.arange(5)
>>> y = x * 2
>>> valid_indices = (x < 5) & (y < 5)
>>> a[x[valid_indices], y[valid_indices]]
array([ 0, 7, 14])
然后使用.sum()
。显示线路现在的样子:
>>> a[x[valid_indices], y[valid_indices]] = -1
>>> a
array([[-1, 1, 2, 3, 4],
[ 5, 6, -1, 8, 9],
[10, 11, 12, 13, -1],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]])
同样,正如你所看到的,这条线中有一些缺口;如果你想消除这些间隙,你必须通过"拉伸"x或y值来稍微改变一下。这里有一个函数,它使用一个简单的斜率截距规范来实现这一点。你仍然需要为0
和无限斜率添加特殊的外壳,但这做了很多必要的工作,并且在我测试的所有情况下都会产生一条漂亮、平滑的线:
def linear_index(slope, intercept, x_range, y_range):
if numpy.abs(slope) < 1:
intercept = intercept / slope
slope = 1 / slope
y, x = linear_index(slope, intercept, y_range, x_range)
return x, y
x_min, x_max = x_range
y_min, y_max = y_range
x = numpy.linspace(x_min, x_max - 1, (x_max - x_min - 1) * slope + 1)
y = x * slope + intercept
print x, y
valid_indices = (y >= y_min) & (y < y_max)
return x[valid_indices].astype(int), y[valid_indices].astype(int)
如果对霍夫变换有足够的理解,将(r, theta)
对转换为斜率截距形式应该不会有任何问题。不过,如果你需要更粗的线,这可能不是最好的方法。