如何用NumPy、SciPy或Scikit-image实现3x3窗口的2D均值滤波?
问题解答
首先,你使用np.average的方式并不适用于2D滑动窗口均值滤波——该函数的weights参数在输入数组与权重数组形状不同时,仅支持一维权重,它的设计目标并非实现滑动窗口式的滤波操作。
NumPy实现2D均值滤波的方法
NumPy本身没有内置的滑动窗口均值滤波函数,但可以通过np.lib.stride_tricks.sliding_window_view(NumPy 1.20及以上版本支持)手动构造滑动窗口,再计算均值:
import numpy as np a = np.arange(25).reshape(5, 5) # 生成所有3x3的滑动窗口 windows = np.lib.stride_tricks.sliding_window_view(a, window_shape=(3, 3)) # 对每个窗口的所有元素求均值,得到3x3的滤波结果 filtered = windows.mean(axis=(2, 3))
上述代码会截断原矩阵的边缘(5x5矩阵滑3x3窗口后得到3x3结果),如果需要保留原矩阵尺寸,可以先用np.pad对原矩阵进行边缘填充,比如:
# 用0填充边缘,填充后矩阵为7x7 padded_a = np.pad(a, pad_width=1, mode='constant', constant_values=0) windows = np.lib.stride_tricks.sliding_window_view(padded_a, window_shape=(3, 3)) filtered = windows.mean(axis=(2, 3)) # 结果为5x5,与原矩阵尺寸一致
SciPy的实现方案
SciPy的scipy.ndimage.uniform_filter是专门用于均值滤波的函数,使用非常简便,还支持多种边缘填充模式:
from scipy.ndimage import uniform_filter a = np.arange(25).reshape(5, 5) # 3x3窗口均值滤波,默认用0填充边缘,可通过mode参数调整 filtered = uniform_filter(a, size=3) # 示例:使用反射模式填充边缘 filtered_reflect = uniform_filter(a, size=3, mode='reflect')
mode参数可选值包括'constant'(默认,常数填充)、'reflect'(边缘反射)、'nearest'(最近邻填充)等。
Scikit-image的实现方案
Scikit-image提供了多个可用于均值滤波的函数:
box_filter:适合浮点型输入,支持归一化(即均值滤波):
from skimage.filters import box_filter a = np.arange(25).reshape(5, 5) # size指定窗口大小,normalize=True表示计算均值 filtered = box_filter(a, size=3, normalize=True)
rank.mean:适合处理整数类型的图像数据,需要配合结构元素使用:
from skimage.filters.rank import mean from skimage.util import img_as_ubyte a = np.arange(25).reshape(5, 5) # 将数组转换为uint8类型(rank类函数要求输入为整数类型) a_ubyte = img_as_ubyte(a / a.max()) # 用3x3的全1结构元素做均值滤波 filtered = mean(a_ubyte, np.ones((3, 3)))
内容的提问来源于stack exchange,提问作者Paul Jurczak
相关产品推荐
相关产品推荐

