如何将圆盘形掩码应用于 NumPy 数组?

Posted

技术标签:

【中文标题】如何将圆盘形掩码应用于 NumPy 数组?【英文标题】:How to apply a disc shaped mask to a NumPy array? 【发布时间】:2012-01-28 15:23:50 【问题描述】:

我有一个这样的数组:

>>> np.ones((8,8))
array([[ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.]])

我正在创建一个半径为 3 的圆盘形蒙版:

y,x = np.ogrid[-3: 3+1, -3: 3+1]
mask = x**2+y**2 <= 3**2

这给出了:

>> mask
array([[False, False, False,  True, False, False, False],
       [False,  True,  True,  True,  True,  True, False],
       [False,  True,  True,  True,  True,  True, False],
       [ True,  True,  True,  True,  True,  True,  True],
       [False,  True,  True,  True,  True,  True, False],
       [False,  True,  True,  True,  True,  True, False],
       [False, False, False,  True, False, False, False]], dtype=bool)

现在,我希望能够将此掩码应用于我的数组,使用任何元素作为中心点。 因此,例如,中心点在 (1,1),我想得到一个像这样的数组:

>>> new_arr
array([[ True,  True,  True,  True,    1.,  1.,  1.,  1.],
       [ True,  True,  True,  True,  True,  1.,  1.,  1.],
       [ True,  True,  True,  True,    1.,  1.,  1.,  1.],
       [ True,  True,  True,  True,    1.,  1.,  1.,  1.],
       [ 1.,    True,    1.,    1.,    1.,  1.,  1.,  1.],
       [ 1.,      1.,    1.,    1.,    1.,  1.,  1.,  1.],
       [ 1.,      1.,    1.,    1.,    1.,  1.,  1.,  1.],
       [ 1.,      1.,    1.,    1.,    1.,  1.,  1.,  1.]])

有没有简单的方法来应用这个面具?

编辑:我不应该混合布尔值和浮点数 - 这是误导。

>>> new_arr
array([[ 255.,  255.,  255.,  255.,    1.,  1.,  1.,  1.],
       [ 255.,  255.,  255.,  255.,  255.,  1.,  1.,  1.],
       [ 255.,  255.,  255.,  255.,    1.,  1.,  1.,  1.],
       [ 255.,  255.,  255.,  255.,    1.,  1.,  1.,  1.],
       [ 1.,    255.,    1.,    1.,    1.,  1.,  1.,  1.],
       [ 1.,      1.,    1.,    1.,    1.,  1.,  1.,  1.],
       [ 1.,      1.,    1.,    1.,    1.,  1.,  1.,  1.],
       [ 1.,      1.,    1.,    1.,    1.,  1.,  1.,  1.]])

这更多是我需要的结果。

array[mask] = 255 

将使用中心点 (0+radius,0+radius) 屏蔽阵列。

但是,我希望能够在任何点 (y,x) 放置任何尺寸的蒙版,并自动修剪以适合。

【问题讨论】:

【参考方案1】:
def susanKernel(raduis):
    kernel = np.zeros((2*radius+1, 2*radius+1) ,np.uint8)
    y,x = np.ogrid[-radius:radius+1, -radius:radius+1]
    mask = x**2 + y**2 <= radius**2
    kernel[mask] = 1
    kernel[0,radius-1:kernel.shape[1]-radius+1] = 1
    kernel[kernel.shape[0]-1,radius-1:kernel.shape[1]-radius+1]= 1
    kernel[radius-1:kernel.shape[0]-radius+1,0] = 1
    kernel[radius-1:kernel.shape[0]-radius+1,kernel.shape[1]-1] = 1
    return kernel

【讨论】:

这如何回答这个问题? 这并没有提供问题的答案。您可以搜索similar questions,或参考页面右侧的相关和链接问题找到答案。如果您有一个相关但不同的问题,ask a new question,并包含指向此问题的链接以帮助提供上下文。见the tour 虽然这可能会回答这个问题,但如果可能的话,您应该edit 您的回答包括对如何此代码块回答问题的解释。这有助于提供上下文,并使您的答案对未来的读者更有用。【参考方案2】:

您可以使用 scipy 的 convolve 函数,它的好处是允许您一次将任何特定的掩码(又名内核)放置在数组中任意数量的给定坐标上:

import numpy as np
from scipy.ndimage.filters import convolve

首先创建一个坐标数组,其中您希望掩码(内核)居中的坐标标记为 2

background = np.ones((10,10))
background[5,5] = 2
print(background)

[[ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  2.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]]

创建你的面具:

y,x = np.ogrid[-3: 3+1, -3: 3+1]
mask = x**2+y**2 <= 3**2
mask = 254*mask.astype(float)
print(mask)

[[   0.    0.    0.  254.    0.    0.    0.]
 [   0.  254.  254.  254.  254.  254.    0.]
 [   0.  254.  254.  254.  254.  254.    0.]
 [ 254.  254.  254.  254.  254.  254.  254.]
 [   0.  254.  254.  254.  254.  254.    0.]
 [   0.  254.  254.  254.  254.  254.    0.]
 [   0.    0.    0.  254.    0.    0.    0.]]

对两个图像进行卷积:

b = convolve(background, mask)-sum(sum(mask))+1
print(b)

[[   1.    1.    1.    1.    1.    1.    1.    1.    1.    1.]
 [   1.    1.    1.    1.    1.    1.    1.    1.    1.    1.]
 [   1.    1.    1.    1.    1.  255.    1.    1.    1.    1.]
 [   1.    1.    1.  255.  255.  255.  255.  255.    1.    1.]
 [   1.    1.    1.  255.  255.  255.  255.  255.    1.    1.]
 [   1.    1.  255.  255.  255.  255.  255.  255.  255.    1.]
 [   1.    1.    1.  255.  255.  255.  255.  255.    1.    1.]
 [   1.    1.    1.  255.  255.  255.  255.  255.    1.    1.]
 [   1.    1.    1.    1.    1.  255.    1.    1.    1.    1.]
 [   1.    1.    1.    1.    1.    1.    1.    1.    1.    1.]]

请注意,卷积函数条目不通勤, 即 convolve(a,b) != convolve(b,a)

还请注意,如果您的点靠近边缘,则算法不会在坐标处重现内核。为了解决这个问题,您可以通过内核的最大轴填充背景,应用卷积,然后移除填充。

现在,您可以将任何内核映射到数组中的任意数量的点,但请注意,如果两个内核重叠,它们会在重叠处相加。如果需要,您可以设置阈值。

【讨论】:

【参考方案3】:

把它说成一个方便的功能:

def cmask(index,radius,array):
  a,b = index
  nx,ny = array.shape
  y,x = np.ogrid[-a:nx-a,-b:ny-b]
  mask = x*x + y*y <= radius*radius

  return(sum(array[mask]))

返回半径内的像素总和,或返回(array[mask] = 2) 用于任何需要。

【讨论】:

【参考方案4】:

我只是想和大家分享一下我刚刚不得不面对的这个技术的稍微高级一点的应用。

我的问题是应用这个循环内核来计算 2D 矩阵中每个点周围所有值的平均值。生成的内核可以通过以下方式传递给 scipy 的通用过滤器:

import numpy as np
from scipy.ndimage.filters import generic_filter as gf

kernel = np.zeros((2*radius+1, 2*radius+1))
y,x = np.ogrid[-radius:radius+1, -radius:radius+1]
mask = x**2 + y**2 <= radius**2
kernel[mask] = 1
circular_mean = gf(data, np.mean, footprint=kernel)

希望这会有所帮助!

【讨论】:

【参考方案5】:

我会这样做,其中 (a, b) 是你的面具的中心:

import numpy as np

a, b = 1, 1
n = 7
r = 3

y,x = np.ogrid[-a:n-a, -b:n-b]
mask = x*x + y*y <= r*r

array = np.ones((n, n))
array[mask] = 255

【讨论】:

【参考方案6】:

您是否尝试过制作掩码或零和一,然后使用每个元素的数组乘法?这是规范的方式,或多或少。

另外,您是否确定要在 numpy 数组中混合使用数字和布尔值?顾名思义,NumPy 最适用于数字。

【讨论】:

对于数字/布尔值组合的混淆,我深表歉意。希望这个问题不再具有误导性。你能再解释一下你的第一句话吗?【参考方案7】:

要获得与示例中相同的结果,您可以执行以下操作:

>>> new_arr = np.array(ones, dtype=object)
>>> new_arr[mask[2:, 2:]] = True
>>> print new_arr
array([[True, True, True, True, 1.0, 1.0, 1.0, 1.0],
       [True, True, True, True, True, 1.0, 1.0, 1.0],
       [True, True, True, True, 1.0, 1.0, 1.0, 1.0],
       [True, True, True, True, 1.0, 1.0, 1.0, 1.0],
       [1.0, True, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
       [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
       [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
       [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]], dtype=object)

【讨论】:

它可以工作......但这是一个相当的黑客,有数组重复并改变它的dtype......乘以0/1是@9000建议的规范方式。 @mac 是的,我同意。我希望从 OP 那里得到一些反馈,以找出他真正在寻找什么。 很抱歉误导了您。我在帖子中澄清了我的问题。我想要的是一种方法来获取原始数组中被掩码覆盖的元素,给定掩码的中心点(y,x)。然后我可以根据需要对它们进行操作。

以上是关于如何将圆盘形掩码应用于 NumPy 数组?的主要内容,如果未能解决你的问题,请参考以下文章

Cython 中 numpy 数组掩码的性能

如何在 Numpy 中将索引数组转换为掩码数组?

科学计算基础软件包NumPy入门讲座:掩码数组

科学计算基础软件包NumPy入门讲座:掩码数组

给定两个 2D numpy 数组 A 和 B,如何有效地将采用两个 1D 数组的函数应用于 A 和 B 行的每个组合?

在 NumPy 数组的每个单元格处对函数进行有效评估