在 2D numpy 数组的每个滚动窗口中获得最大值



我有一个 2D numpy 数组,我想获取每个 2D 滚动窗口中包含的最大值,该窗口从左到右、从上到下开始,每次滚动一行或一列。最朴素的方法是遍历所有滚动窗口,并获取此滚动窗口中包含的所有值的最大值。我在下面写下了这种方法:

import numpy as np
shape=(1050,300)
window_size=(120,60)
a = np.arange(shape[1]*shape[0]).reshape(shape[1],shape[0])
max_Map=np.full((shape[1]-window_size[1]+1,shape[0]-window_size[0]+1),0,dtype='uint32')
for i in range(shape[1]-window_size[1]+1):
for j in range(shape[0]-window_size[0]+1):
window_max=np.max(a[i:i+window_size[1],j:j+window_size[0]])
max_Map[i][j]=window_max

但这非常低效,因为每次滑动之间只有 2 行(或 2 列)变化,但我的代码没有考虑 2 个连续滚动窗口之间的任何相关性。我能想到的一个改进是对于每个滑动窗口(假设水平滚动),我将计算最左侧列的最大值和其余列的最大值,并将 2 个值的最大值作为当前窗口最大值。对于下一个滚动窗口,最大值将是新添加的列和之前剩余列的最大值......但我仍然不认为这是优化的...

如果有人能指出我正确的方向,我将不胜感激,我觉得这应该是一个经过充分研究的问题,但我在任何地方都找不到解决方案...... 提前感谢!

方法 #1使用Scipy's 2D max filter-

from scipy.ndimage.filters import maximum_filter as maxf2D
# Store shapes of inputs
N,M = window_size
P,Q = a.shape
# Use 2D max filter and slice out elements not affected by boundary conditions
maxs = maxf2D(a, size=(M,N))
max_Map_Out = maxs[M//2:(M//2)+P-M+1, N//2:(N//2)+Q-N+1]

方法#2使用Scikit's 2D sliding window views-

from skimage.util.shape import view_as_windows
N,M = window_size
max_Map_Out = view_as_windows(a, (M,N)).max(axis=(-2,-1))

关于窗口大小及其使用的注意事项:原始方法以翻转方式对齐窗口大小,即window_size的第一个形状参数沿第二个轴滑动,而第二个形状参数决定窗口如何沿第一个轴滑动。对于执行滑动最大滤波的其他问题,情况可能并非如此,我们通常将第一个形状参数用于2D数组的第一个轴,类似地对第二个形状参数使用。因此,要解决这些情况,只需使用 :M,N = window_size并按原样使用其余代码。

运行时测试

方法-

def org_app(a, window_size):
shape = a.shape[1], a.shape[0]
max_Map=np.full((shape[1]-window_size[1]+1,
shape[0]-window_size[0]+1),0,dtype=a.dtype)
for i in range(shape[1]-window_size[1]+1):
for j in range(shape[0]-window_size[0]+1):
window_max=np.max(a[i:i+window_size[1],j:j+window_size[0]])
max_Map[i][j]=window_max
return max_Map
def maxf2D_app(a, window_size):
N,M = window_size
P,Q = a.shape
maxs = maxf2D(a, size=(M,N))
return maxs[M//2:(M//2)+P-M+1, N//2:(N//2)+Q-N+1]
def view_window_app(a, window_size):
N,M = window_size
return view_as_windows(a, (M,N)).max(axis=(-2,-1))

时间和验证 -

In [573]: # Setup inputs
...: shape=(1050,300)
...: window_size=(120,60)
...: a = np.arange(shape[1]*shape[0]).reshape(shape[1],shape[0])
...: 
In [574]: np.allclose(org_app(a, window_size), maxf2D_app(a, window_size))
Out[574]: True
In [575]: np.allclose(org_app(a, window_size), view_window_app(a, window_size))
Out[575]: True
In [576]: %timeit org_app(a, window_size)
1 loops, best of 3: 2.11 s per loop
In [577]: %timeit view_window_app(a, window_size)
1 loops, best of 3: 1.14 s per loop
In [578]: %timeit maxf2D_app(a, window_size)
100 loops, best of 3: 3.09 ms per loop
In [579]: 2110/3.09  # Speedup using Scipy's 2D max filter over original approach
Out[579]: 682.8478964401295

最新更新