python - 有效地将 2D numpy mask 在所有方向上扩展 n 个单元格

标签 python arrays numpy

我有一个代表 cloud mask for GIS data 的 bool 数据的 MxN numpy 数组.我想通过在所有方向上移动 n 个单元格来扩展蒙版。这是一种去除蒙版中的云阴影(位于云像素旁边)的简单方法。 这些 numpy 数组通常介于 1000x1000 和 10000x10000 像素之间。

我的问题与此类似one但在 2 个维度上。

我的非常简单但效率低下的解决方案如下所示:

def expand_for(arr, shiftx=1, shifty=1):
    arr_b = arr.copy().astype(bool)
    for i in range(arr.shape[0]):
        for j in range(arr.shape[1]):
            if(arr[i,j]):
                i_min, i_max = max(i-shifty, 0), min(i+shifty+1, arr.shape[0])
                j_min, j_max = max(j-shiftx, 0), min(j+shiftx+1, arr.shape[1])
                arr_b[i_min:i_max, j_min:j_max] = True
    return arr_b

另一种解决方案是:

def shift_array(arr, x, y):
    d, u, r, l = max(y, 0), max(-y, 0), max(x, 0), max(-x, 0)
    ret = np.pad(arr, ((d, u), (r, l)), mode='constant')
    return ret[u or None: -d or None, l or None: -r or None]

def expand_array(arr, shiftx=1, shifty=1):
    return np.dstack([shift_array(arr, x, y)
                      for x in range(-shiftx, shiftx + 1) for y in range(-shifty, shifty + 1)]).any(axis=2)

但是复杂度会随着 shiftx 和 shifty 的大小而增加。

这是我正在尝试做的一个非常简单的例子:

a = np.array([[0,0,0,0,0],
             [0,0,0,0,0],
             [0,0,1,0,0],
             [0,0,0,0,0],
             [0,0,0,0,0]])
expand_for(a, 1, 1)

>>> array([[False, False, False, False, False],
       [False,  True,  True,  True, False],
       [False,  True,  True,  True, False],
       [False,  True,  True,  True, False],
       [False, False, False, False, False]])

我一直在使用这段代码来生成更复杂的测试数据:

N = 100    # or 1000, 10000...
a = np.random.random((N,N))
a = (a < 0.30)*1

最佳答案

这可以通过应用 dilation 使用 cv2 库来完成到阵列。例如:

import numpy as np

N = 10

# the initial array
a = np.zeros((N, N), dtype='uint8')
a[[2, 4, 9], [2, 4, 7]] = 1
print(a)

这给出:

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

将每次出现的 1 展开为 1 的 3x3 子数组:

import cv2

kernel = np.ones((3, 3), dtype='uint8')
out = cv2.dilate(a, kernel)
print(out)

结果:

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

如果你希望结果是一个 bool 值数组,那么你可以改变它的数据类型:

out = out.astype('bool')

关于python - 有效地将 2D numpy mask 在所有方向上扩展 n 个单元格,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73798936/

相关文章:

python - Brew 升级 python 返回 "python not installed"

javascript - ESLint 说数组从未被修改,即使元素被插入数组

python - 为什么 Numpy 对待 a+=b 和 a=a+b 的方式不同

javascript - 从更改数组中获取静态值

python - Pyspark 中的 SparseVector 到 DenseVector 转换

python - 获取灰度图像的空间频率分割(二维数组)

python - 如何从 gridSearchCV 的输出中获取特征名称

python - 应该如何设置一个不变的 Python 函数的参数?

python - 尝试使用 Cloud TPU 恢复更新的 BERT 模型检查点时出现 InfeedEnqueueTuple 问题

c - 使用 malloc 初始化 char 指针 VS 不使用 malloc 直接将字符串赋给 char 指针