我正在尝试实现立方形状 (k,k) 的 2D 滑动窗口,以便我可以迭代帧 (n,m,3) 并计算每个窗口中像素值的平均值。 我希望每次迭代时,窗口都会显示下一张幻灯片,而没有任何重叠的值; 即给定这个矩阵:
[
[1, 2, 3, 4],
[5, 6, 7 ,8],
[9, 10, 11, 12],
[13, 14, 15, 16]
]
对于 k = 2 我会得到如下的东西:
[
[1, 2],
[5, 6]
]
第二个窗口的值如下:
[
[3, 4],
[7, 8]
]
等等。
我尝试过使用 numpy.lib.stride_tricks.as_strided。 但没有任何成功。
使用 numpy 或任何其他高效的库也很重要,因为使用 python for 循环实现此代码对于该操作来说太昂贵了。
忽略第三个维度,既然它似乎没有进入问题,那么怎么样:
# Generate array of size (m*k, n*k)
# my m, n are your m, n divided by k
m, n = 2, 4
k = 3
x = np.arange(m*n*k*k).reshape((m*k, n*k))
# array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
# [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23],
# [24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35],
# [36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47],
# [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
# [60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71]])
# Calculate means of each block
y = x.reshape((m, k, n, k))
z = np.moveaxis(y, -3, -2) # now shape is (m, n, k, k)
np.mean(z, axis=(-2, -1)) # take mean over last two axes
# or just np.mean(y, axis=(-3, -1))
# array([[13., 16., 19., 22.],
# [49., 52., 55., 58.]])
要保留第三维并分别对每个颜色通道进行计算,只需在开始时将其移开(例如,移至轴
0
),然后在末尾将其移回。
如果行数和/或列数不能被
k
整除,您可以使用数据中未出现的一些哨兵值(例如 nan
)填充数组,直到行数/列数可整除由k
。然后,以某种方式采用忽略标记值的方法(例如 nanmean
)。 (或者,拆分剩余的行/列,单独处理它们,然后合并结果。)
scipy.ndimage
或 scikit-image 中可能有一些东西可以在一行中完成此操作。我尝试过 zoom
,但没有找到能够给出所需结果的神奇设置组合。
In [374]: win = np.lib.stride_tricks.sliding_window_view(arr,(2,2))
In [375]: win.shape
Out[375]: (3, 3, 2, 2)
采用每隔一个、不重叠的窗口:
In [376]: win[::2,::2]
Out[376]:
array([[[[ 1, 2],
[ 5, 6]],
[[ 3, 4],
[ 7, 8]]],
[[[ 9, 10],
[13, 14]],
[[11, 12],
[15, 16]]]])
重塑替代方案:
In [378]: arr.reshape(2,2,2,2).transpose(0,2,1,3)
Out[378]:
array([[[[ 1, 2],
[ 5, 6]],
[[ 3, 4],
[ 7, 8]]],
[[[ 9, 10],
[13, 14]],
[[11, 12],
[15, 16]]]])
这是一个张量流解决方案:
from tensorflow.keras.layers import AveragePooling2D
x = np.array([[1, 2, 3, 4],[5, 6, 7 ,8],[9, 10, 11, 12],[13, 14, 15, 16]])
y = x.reshape(1,*x.shape, 1).astype(float) # you need 4d
AveragePooling2D(2, 2)(y).numpy().squeeze()
array([[ 3.5, 5.5],
[11.5, 13.5]], dtype=float32)
AveragePooling2D(pool_size = (2,2), strides = (1,1))(y).numpy().squeeze()
array([[ 3.5, 4.5, 5.5],
[ 7.5, 8.5, 9.5],
[11.5, 12.5, 13.5]], dtype=float32)