在NumPy数组外进行切片

6
给定一个二维矩阵,例如:
A = array([[ 0,  1,  2,  3],
          [ 4,  5,  6,  7],
          [ 8,  9, 10, 11],
          [12, 13, 14, 15]])

如何选择以给定元素为中心的 NxN 窗口,使得如果窗口超出原始数组,则用任意值(例如平均值)填充窗口?

示例:

neighbors(A, x=0, y=0, N=3)

会产生

array([[ 2.5,  2.5,  2.5],
       [ 2.5,    0,    1],
       [ 2.5,    4,    5]])

2
顺便提一下,如果你想在n维数组上操作“移动窗口”样式,并类似于此填充边界,请查看scipy.ndimage.generic_filter - Joe Kington
3个回答

7
你可以对数组进行填充。填充将使用所需的边界条件扩展数组(请参阅所有可能选项的mode参数)。
>>> A = np.array([[ 0,  1,  2,  3],
                  [ 4,  5,  6,  7],
                  [ 8,  9, 10, 11],
                  [12, 13, 14, 15]])
>>> N = 5 # 5x5 windows
>>> B = np.pad(A, N//2, mode='reflect')
>>> B
array([[10,  9,  8,  9, 10, 11, 10,  9],
       [ 6,  5,  4,  5,  6,  7,  6,  5],
       [ 2,  1,  0,  1,  2,  3,  2,  1],
       [ 6,  5,  4,  5,  6,  7,  6,  5],
       [10,  9,  8,  9, 10, 11, 10,  9],
       [14, 13, 12, 13, 14, 15, 14, 13],
       [10,  9,  8,  9, 10, 11, 10,  9],
       [ 6,  5,  4,  5,  6,  7,  6,  5]])

正如您所看到的,原始数组位于矩阵中心,被2行2列(左/右和上/下都是 N//2 = 5//2 = 2)填充。填充元素是反射的。

对于这个新数组,您可以通过正常索引数组来访问所需的邻居窗口:

>>> x = 1; y = 1 # corresponds to number 5 in the original array
>>> B[y:y+N, x:x+N]
array([[ 5,  4,  5,  6,  7],
       [ 1,  0,  1,  2,  3],
       [ 5,  4,  5,  6,  7],
       [ 9,  8,  9, 10, 11],
       [13, 12, 13, 14, 15]])

你可以选择其他填充方法,mean 是其中之一的选项。

2

我认为这并不太离谱:

def neighbors(arr, x, y, N):
    left = max(0, x - N)
    right = min(arr.shape[0], x + N)
    top = max(0, y - N)
    bottom = min(arr.shape[1], y + N)

    window = arr[left:right+1,top:bottom+1]
    fillval = window.mean()

    result = np.empty((2*N+1, 2*N+1))
    result[:] = fillval

    ll = N - x
    tt = N - y
    result[ll+left:ll+right+1,tt+top:tt+bottom+1] = window

    return result

2

这里有一种使用 np.lib.padnp.ix_ 的方法 -

Ap = np.lib.pad(A.astype(float),1, 'constant', constant_values=(np.nan,np.nan))
Acut = Ap[np.ix_(np.arange(N)+x,np.arange(N)+y)]
Acut[np.isnan(Acut)] = np.nanmean(Acut)

样例运行 -

In [76]: A
Out[76]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15]])

In [77]: x=1; y=0; N = 3

In [78]: Ap = np.lib.pad(A.astype(float),1, 'constant', constant_values=(np.nan,np.nan))
    ...: Acut = Ap[np.ix_(np.arange(N)+x,np.arange(N)+y)]
    ...: Acut[np.isnan(Acut)] = np.nanmean(Acut)
    ...: 

In [79]: Acut
Out[79]: 
array([[ 4.5,  0. ,  1. ],
       [ 4.5,  4. ,  5. ],
       [ 4.5,  8. ,  9. ]])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接