PAYATHON 2026

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):前两个轴表示候选位置,后三个轴表示窗口的高、宽和通道。第一种写法直接指定空间滑动轴,轴的含义更清楚。

备注:内容仅供参考。