【问题标题】:Vectorizing a positionally reliant function in NumPy在 NumPy 中对位置相关的函数进行矢量化
【发布时间】:2021-07-14 09:10:56
【问题描述】:

我了解矢量化的概念,以及当您想调整每个单独的元素时如何避免使用循环遍历元素,但是当我们有条件时我不知道如何做到这一点基于像素的相邻值。

例如,如果我有一个面具:

mask = np.array([[0,0,0,0],
                 [1,0,0,0],
                 [0,0,0,1], 
                 [1,0,0,0]])

我想通过评估掩码中的相邻组件来更改元素,如下所示:

if sum(mask[j-1:j+2,i-1:i+2].flatten())>1 and mask[j,i]!=1:
    out[j,i]=1

当我特别需要访问相邻元素时如何向量化操作?

提前致谢。

完整循环:

import numpy as np

mask = np.array([[0,0,0,0], [1,0,0,0], [0,0,0,1],  [1,0,0,0]])
out = np.zeros(mask.shape)
for j in range(len(mask)):
    for i in range(len(mask[0])):
        if sum(mask[j-1:j+2,i-1:i+2].flatten())>1 and mask[j,i]!=1:
            out[j,i]=1

输出:

[[0. 0. 0. 0.]
 [0. 0. 0. 0.]
 [0. 1. 0. 0.]
 [0. 0. 0. 0.]]

【问题讨论】:

  • 你确定你的索引吗?如果 i == 0,则 i-1 = -1。负索引不会给你一个邻域元素。
  • 顺便说一句,sum(mask[j-1:j+2,i-1:i+2].flatten())>1 应该只是 mask[j-1:j+2,i-1:i+2].sum() > 1
  • @Corralien 是的,在实际工作中我没有考虑边缘效应,但是你是正确的,使用 -1 索引将返回数组另一端的元素。
  • 我认为mask[j,i]!=1 没用。如果为1,则out[j,i]的值已经为1,如果不设置out[j,i]为1。最后如果sum(mask[j-1:j+2,i-1:i+2].flatten())>1out[j,i]应该为1。所以只有第一个条件就足够了。
  • @Corralien 这不是真的,因为如果您将所有 1 的掩码图像化,那么输出中的每个值也将是一个,而没有这种条件的实现。

标签: python numpy vectorization


【解决方案1】:

这种“邻域求和”运算通常称为二维卷积。在您的情况下,由于您没有任何权重,因此可以在(IMO 名称有点不好)scipy.ndimage.uniform_filter 中有效地实现它,它可以计算邻域的平均值(总和是 只是平均值乘以大小)。

import numpy as np
from scipy.ndimage import uniform_filter

mask = np.array([[0,0,0,0], [1,0,0,0], [0,0,0,1], [1,0,0,0]])
neighbor_sum = 9 * uniform_filter(mask.astype(np.float32), 3, mode="constant")
neighbor_sum = np.rint(neighbor_sum).astype(int)
out = ((neighbor_sum > 1) & (mask != 1)).astype(int)
print(out)

输出(与您的示例不同,但手动查看是正确的,假设您不希望边缘环绕):

[[0 0 0 0]
 [0 0 0 0]
 [1 1 0 0]
 [0 0 0 0]]

如果您确实希望边缘环绕(或其他边缘行为),请查看 uniform_filtermode 参数。

【讨论】:

  • 感谢您的回复。由于我的代码没有正确评估边缘,因此这确实具有正确的输出(仅凭肉眼观察)。与我的方法相比,还有大约 2 倍的速度提升。并不是说我反对使用 scipy,但是有没有办法专门使用 NumPy 来实现这一点?
  • “与我的方法相比,速度也大约提高了 2 倍。” 可能只有很小的 4 x 4 图像。我无法想象这不会比你原来的大图像方法快很多。 “并不是说我反对使用 scipy,但是有没有办法专门用 NumPy 来实现这一点?”可以,但很烦人。 scipynumpy 经常齐头并进,uniform_filter 正是你想要的,所以我强烈建议只使用它。
  • 感谢您的回复。你的两个观点都是正确的,后者我是出于好奇而不是必要的。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 2020-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多