NumPy 3D 数组滑动窗口匹配如何去除多余维度?
数据小许
结论
将滑动窗口限制在 img 的前两个轴上,再把窗口轴移到通道轴之后。这样,每个候选窗口的形状都与 pat 的 (3, 3, 3) 一致。沿窗口的三个轴归约后,matches 就是形状为 (3, 3) 的布尔数组。
wins = np.lib.stride_tricks.sliding_window_view(
img,
window_shape=(3, 3),
axis=(0, 1),
)
# 初始轴顺序:位置 y、位置 x、通道、窗口 y、窗口 x
# 调整为:位置 y、位置 x、窗口 y、窗口 x、通道
wins = wins.transpose(0, 1, 3, 4, 2)
matches = np.all(wins == pat, axis=(2, 3, 4))
print(matches)
对题目中的数据,结果是:
[[False False False]
[False True False]
[False False False]]
matches[y, x] 表示以 img[y, x] 为左上角的 3 × 3 区域是否与 pat 完全相同。因此,唯一的匹配位置是 (1, 1)。
多余维度从哪里来
原代码调用:
np.lib.stride_tricks.sliding_window_view(img, window_shape=(3, 3, 3))
这会在数组的三个轴上都应用窗口。由于 img 的通道长度和窗口的通道长度都是 3,通道方向上只有一个窗口位置,结果形状为 (3, 3, 1, 3, 3, 3)。这些轴依次表示两个滑动位置轴、通道方向的位置轴,以及窗口的三个轴。
接着,win == pat 会将 pat 广播到窗口末尾的 (3, 3, 3) 轴上。不过,np.all(..., axis=(0, 1)) 归约的是两个滑动位置轴,而不是窗口内部的轴,因此结果不是每个候选位置对应一个布尔值。
也可以沿用原来的窗口
如果要保留原来的 win,可以先去掉通道方向上长度为 1 的位置轴,再归约窗口内部的轴:
matches = np.all(win[:, :, 0] == pat, axis=(2, 3, 4))
这里,win[:, :, 0] 的形状是 (3, 3, 3, 3, 3):前两个轴表示候选位置,后三个轴表示窗口的高、宽和通道。第一种写法直接指定空间滑动轴,轴的含义更清楚。
备注:内容仅供参考。
