【问题标题】:Summing along a function in a 2D array沿二维数组中的函数求和
【发布时间】:2014-01-17 13:55:46
【问题描述】:

是否可以在二维数组上放置一个线性函数并将二维数组中与该函数重合的所有元素相加?例如,我将有一个形状为 (400, 500) 的二维数组。现在在某个地方,我将重叠一个从二维数组底部向顶部延伸的线性函数。我现在只想对与直线重叠的二维数组元素求和。

有没有一种快速的方法来仅对二维数组中与直线重合的元素求和?我已经能够通过在 for 循环中使用 for 循环来做到这一点。然而,这已经需要一些时间了。特别是如果我想开始将此技巧应用于更大的数组。

【问题讨论】:

  • 你能提供你正在寻找的样本输入和输出吗?
  • 可能!发布一个简化的示例 2D 数组、函数和预期输出。就目前而言,问题有点模糊(什么是“线性线”)?
  • 我认为您要求的是类似于离散线积分的东西,对吗?
  • 二维数组的最大形式可以定义为:numpy.arange((1002 * 1004)).reshape(1002, 1004)。直线由x cos(phi) + y sin(phi)定义,这里phi的顺序是pi/3。
  • xy 是什么?它们与二维数组有什么关系?

标签: python arrays performance numpy sum


【解决方案1】:

这在一定程度上取决于您准确如何定义线,以及哪些数组位置算作“在线”上。但一种简单的方法是使用布尔掩码。你可以很容易地使用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)

鉴于对Hough Transform 的充分了解,您应该完全可以将(r, theta) 对转换为斜率截距形式。不过,如果您需要更粗的线,这可能不是最好的方法。

【讨论】:

  • 我想使用的线性函数取决于不同的角度。直线由x cos(phi) + y sin(phi) 定义
  • @user2776885,现在我更困惑了。 x cos(phi) + y sin(phi) 是 x 和 y 的二维函数——它不是一条线。
  • 这是 Hough 变换,用于表示直线(y = ax + b)。但是,霍夫变换考虑直线的特征不是像点(x1,y1),(x2,y2),而是考虑斜率参数a和截距参数b。
  • @user2776885,嗯,这不是霍夫变换。去看看Hough Transform维基百科页面。它表明您提供的公式不完整。如果您了解该页面,则应该非常很容易根据您的问题调整我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-19
  • 1970-01-01
  • 1970-01-01
  • 2019-07-27
相关资源
最近更新 更多