4

我正在尝试学习一种使用 numpy 有效解决在各种情况下涉及滑动窗口的问题的方法。这是一个示例,说明了我感兴趣的问题类型:

我有一个大的二维矩阵,我想对矩阵中每个元素的邻居进行计算。例如,我可能想在每个索引处找到最大值,排除索引处 (x-1,y)(x+1,y+1) 处的一些特殊值,并将结果放入另一个不同的 2d"解”矩阵。

请注意,convolution2d 虽然有用,但在这种情况下对我不起作用,因为我对每个像素都有特定的操作要做,并且只想在特定的邻居(每个像素的)上做。

还有一个好处是确保我不会越界。

最后,是否也可以使用任何状态?在所有邻居都是 0 的情况下,我希望分配一个新的整数 id,每次发生这种情况时我都会递增。

这是一个例子:

Window:

0 0 1
1 0 0
0 0 0


Input:

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 9 9 0 0 9 0 0
0 0 0 0 0 0 0 0 0

Output:

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 0 0 2 0 0
0 0 0 0 0 0 0 0 0
4

4 回答 4

3

使用 np.roll() 创建二级矩阵。然后在初始矩阵和辅助矩阵之间执行您需要的任何操作。例如,取中心单元和两个邻居的平均值:

sec_a = np.roll(mtrx, -1, axis=0)
sec_b = np.roll(mtrx, -1, axis=1)

result = (mtrx + sec_a + sec_b) / 3

此外,roll() 围绕边缘滚动,因此无需担心边界。

于 2015-09-18T21:11:41.537 回答
1

我曾经创建了这个函数来将二维数组中的滑动块存储到列中,这样我们曾经认为在二维数组的滑动窗口中应用的任何操作都可以很容易地沿着列应用。阅读更多关于它的this solution信息Implement Matlab's im2col 'sliding' in python

现在,NumPy 支持沿指定轴应用其大部分功能。因此,使用这个工具,我们将能够有效地以某种vectorized方式在滑动窗口中应用几乎任何操作。这是它的正式定义-

def im2col(A,BLKSZ):   

    # Parameters
    M,N = A.shape
    col_extent = N - BLKSZ[1] + 1
    row_extent = M - BLKSZ[0] + 1

    # Get Starting block indices
    start_idx = np.arange(BLKSZ[0])[:,None]*N + np.arange(BLKSZ[1])

    # Get offsetted indices across the height and width of input array
    offset_idx = np.arange(row_extent)[:,None]*N + np.arange(col_extent)

    # Get all actual indices & index into input array for final output
    return np.take (A,start_idx.ravel()[:,None] + offset_idx.ravel())

下面是我们如何使用这个工具来解决手头的问题,假设A为 2D 输入数组 -

# Get 3x3 sliding blocks from A and set them as columns.
Acol = im2col(A,[3,3])

# Setup kernel mask
kernel = np.ones((3,3),dtype=bool)
kernel[2,1:] = 0

# Mask rows of Acol with kernel and perform any operation, let's say MAX
out = Acol[kernel.ravel()].max(0).reshape(A.shape[0]-2,A.shape[1]-2)

样品运行 -

In [365]: A
Out[365]: 
array([[83, 84, 46,  9, 25],
       [32,  8, 31, 45, 58],
       [14,  8,  0, 51, 27],
       [31, 40,  7, 27, 71]])

In [366]: kernel = np.ones((3,3),dtype=bool)
     ...: kernel[2,1:] = 0
     ...: 

In [367]: im2col(A,[3,3])[kernel.ravel()].max(0).reshape(A.shape[0]-2,A.shape[1]-2)
Out[367]: 
array([[84, 84, 58],
       [32, 51, 58]])
于 2015-09-18T21:23:29.503 回答
1

假设您的原始二维矩阵名为 A 并且大小为 (n, m)

# extraction of 3x3 sub-matrices and storage in a new 2D matrix
B = [ [ A[i-1:i+2, j-1:j+2] for i in range(1, n-1) ] for j in range(1, m-1) ]
# conversion to a mask array
B = np.ma.array( B, mask=False )
# masking the unwanted elements of each sub-matrix
B.mask[:, :, 1, 2] = True
B.mask[:, :, 2, 2] = True

注意:在创建子矩阵时 i 和 j 的范围已被选择以避免边界。

对子矩阵 B[i, j] 的操作将忽略被屏蔽的元素。

现在,要对每个子矩阵执行 numpy 操作(例如,子矩阵的最大值)并将结果存储在 2D 矩阵中:

C = [ [ np.max(B[i,j]) for i in range(n-2) ] for j in range(m-2) ]
于 2015-09-18T22:20:15.043 回答
0

我使用以下作为可读的解决方案:

import numpy as np

def get_windows(arr, window_size=64, step=32):
  windows = []
  row = 0
  col = 0
  max_row, max_col = arr.shape
  while row < max_row:
    while col < max_col:
      windows.append(arr[row:row+window_size, col:col+window_size])
      col += step
    row += step
    col = 0
  return windows

a = np.random.rand(4, 4)
windows = get_windows(a, window_size=2, step=1)
于 2018-03-31T23:36:23.457 回答