本文介绍如何利用 numpy 的 reshape 与轴变换技巧,对二维(或三维)数组进行无重叠的 k×k 分块切分,并高效计算每块像素均值,避免显式 python 循环,适用于图像下采样、特征图池化等场景。
本文介绍如何利用 numpy 的 reshape 与轴变换技巧,对二维(或三维)数组进行无重叠的 k×k 分块切分,并高效计算每块像素均值,避免显式 python 循环,适用于图像下采样、特征图池化等场景。
在计算机视觉和数值计算中,常需对图像(如形状为 (H, W, C) 的 RGB 图)执行非重叠二维滑动窗口操作(即“分块”或“tiling”),并对每个窗口内像素取均值(类似平均池化)。关键要求是:窗口不重叠、步长等于窗口大小 k,且全程基于向量化操作以保障性能。
核心思想是:将原始数组按块重新组织为高维张量,再沿块内维度求均值。以二维输入 x(形状 (m*k, n*k))为例,步骤如下:
- 重塑为四维张量:x.reshape(m, k, n, k) → 形状 (块行数, 块高, 块列数, 块宽)
- 调整轴顺序(可选,提升可读性):np.moveaxis(..., -3, -2) 得 (m, n, k, k)
- 沿最后两维求均值:np.mean(..., axis=(-2, -1)),输出形状为 (m, n)
✅ 示例代码(含三维支持):
import numpy as np
def mean_pool_2d_nonoverlapping(x, k, pad_mode='reflect'):
"""
对 (H, W, C) 或 (H, W) 数组执行 k×k 非重叠均值池化
若 H/W 不被 k 整除,自动 padding 至可整除(默认 reflect,也可设 'constant' + constant_values=np.nan)
"""
if x.ndim == 3:
H, W, C = x.shape
# 将通道维前置,便于统一处理各通道
x = np.transpose(x, (2, 0, 1)) # → (C, H, W)
out_shape = (C, H // k, W // k) if (H % k == 0 and W % k == 0) else None
elif x.ndim == 2:
H, W = x.shape
x = x[np.newaxis, ...] # 临时升维为 (1, H, W)
out_shape = (1, H // k, W // k) if (H % k == 0 and W % k == 0) else None
else:
raise ValueError("Only 2D or 3D arrays supported")
# 处理不可整除情况:padding
H, W = x.shape[1], x.shape[2]
pad_h = (k - H % k) % k
pad_w = (k - W % k) % k
if pad_h > 0 or pad_w > 0:
x = np.pad(x, ((0, 0), (0, pad_h), (0, pad_w)), mode=pad_mode)
# 重塑 + 求均值
C, H_padded, W_padded = x.shape
x_reshaped = x.reshape(C, H_padded // k, k, W_padded // k, k)
pooled = x_reshaped.mean(axis=(2, 4)) # 沿 k×k 两个维度平均
# 还原通道维位置(若原为3D)
if x.ndim == 3:
pooled = np.transpose(pooled, (1, 2, 0)) # → (H//k, W//k, C)
else:
pooled = pooled[0] # 去掉临时通道维
return pooled
# 测试二维示例(题目所给 4×4 矩阵,k=2)
x_2d = np.array([
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]
])
result = mean_pool_2d_nonoverlapping(x_2d, k=2)
print(result)
# 输出:
# [[ 3.5 5.5]
# [11.5 13.5]]
# 对应四个 2×2 块:[1,2;5,6]→3.5, [3,4;7,8]→5.5, [9,10;13,14]→11.5, [11,12;15,16]→13.5
⚠️ 注意事项:
- 整除前提:该方法天然要求 H % k == 0 and W % k == 0;否则必须 padding(推荐 'reflect' 或 'edge')或截断。若需保留原始尺寸信息,可结合 np.pad(..., constant_values=np.nan) + np.nanmean。
- 内存友好性:reshape 和 mean 均为视图或惰性计算,不产生中间大数组,内存效率高。
- 替代方案:scikit-image 提供 skimage.util.view_as_blocks(返回视图,更直观),但需额外依赖;scipy.ndimage.uniform_filter 适合重叠池化,不适用本场景。
- 扩展性:本方案可轻松推广至任意 k×k,且天然支持多通道并行处理,无需循环。
总结:通过 reshape → axis rearrangement → reduction 三步,即可零循环实现高性能非重叠二维池化。这是 NumPy 向量化思维的典型范例——用数据形状变换代替迭代逻辑,兼顾简洁性与工业级性能。











