如何在Python中实现基于整块中值滤波的图像下采样?
解决中值滤波式图像下采样的问题
我完全懂你的痛点——skimage.measure.block_reduce的逐轴计算逻辑确实和咱们要的整块中值下采样不是一回事。你举的例子里,它会先对行轴分块取中值,再对列轴分块取中值,这和直接对2x2块取整体中值的结果天差地别,断言失败太正常了。
推荐的两种解决方案
方法1:纯Numpy实现(高效简洁)
利用Numpy的reshape把图像拆分成规整的块,直接在块维度上取中值,完全符合你的预期:
import numpy as np image = np.array([[4, 6, 6, 2], [6, 7, 9, 9], [3, 0, 9, 0], [0, 6, 6, 4]]) block_size = (2, 2) # 把图像reshape成 (块行数, 块高度, 块列数, 块宽度) 的结构 reshaped_img = image.reshape( image.shape[0] // block_size[0], block_size[0], image.shape[1] // block_size[1], block_size[1] ) # 对每个块的高度和宽度维度取中值 downsampled = reshaped_img.median(axis=(1, 3)) # 验证结果和预期一致 expected = np.array([ [np.median(image[0:2,0:2]), np.median(image[0:2,2:4])], [np.median(image[2:4,0:2]), np.median(image[2:4,2:4])] ]) assert np.array_equal(downsampled, expected) # 这次断言会成功!
方法2:用skimage的view_as_blocks(直观易懂)
skimage的view_as_blocks可以直接把图像分割成非重叠的块,然后对每个块取中值,逻辑更直观:
from skimage.util import view_as_blocks import numpy as np image = np.array([[4, 6, 6, 2], [6, 7, 9, 9], [3, 0, 9, 0], [0, 6, 6, 4]]) block_size = (2, 2) # 生成块视图,形状为 (块行数, 块列数, 块高, 块宽) blocks = view_as_blocks(image, block_size=block_size) # 对每个块的内部维度取中值 downsampled = blocks.median(axis=(2, 3)) # 验证结果 expected = np.array([ [np.median(image[0:2,0:2]), np.median(image[0:2,2:4])], [np.median(image[2:4,0:2]), np.median(image[2:4,2:4])] ]) assert np.array_equal(downsampled, expected)
为什么block_reduce不行?
简单说,block_reduce是逐轴依次应用函数,而不是对整个块一次性计算:
- 先沿行轴(axis=0)把图像分成2行一组的块,对每个块的每一列取中值,得到一个2×4的中间数组;
- 再沿列轴(axis=1)把中间数组分成2列一组的块,对每个块的每一行取中值,最终得到2×2的结果。
这个过程和直接对2×2块取整体中值的计算逻辑完全不同,所以结果自然不一致。
内容的提问来源于stack exchange,提问作者jan bernlöhr
相关产品推荐
相关产品推荐

