如何高效统计Numpy滑动窗口视图中像素的使用次数?
高效统计滑动窗口补丁的像素覆盖次数
问题背景
使用numpy.lib.stride_tricks.sliding_window_view从100×100图像生成19×19个10×10间隔采样补丁(步长5)时,需要统计每个像素被多少个补丁覆盖。直接对滑动窗口视图执行+=1会导致所有像素仅被加1(视图重叠区域的内存共享导致赋值覆盖),而Python嵌套循环虽然能实现正确计数,但性能极差。
最优解决方案
以下两种方案均基于Numpy向量化操作,完全规避Python循环的性能损耗:
方案1:分段求和(最简洁高效)
通过创建全1补丁数组,利用np.add.reduceat按步长分段累加,直接得到像素覆盖次数:
import numpy as np from numpy.lib.stride_tricks import sliding_window_view # 初始化100×100图像 img = np.random.random((100, 100)) patch_shape = (10, 10) stride = 5 # 生成间隔采样的补丁视图 patches = sliding_window_view(img, patch_shape)[::stride, ::stride] patch_grid_shape = patches.shape[:2] # (19,19) # 构建全1的补丁数组,按步长分段求和得到计数 counts = np.add.reduceat( np.add.reduceat( np.ones(patch_grid_shape + patch_shape, dtype=int), np.arange(0, patch_grid_shape[0] * stride, stride), axis=0 ), np.arange(0, patch_grid_shape[1] * stride, stride), axis=1 )
方案2:卷积法(逻辑直观)
将补丁采样位置标记为掩码,用全1补丁核做卷积,结果即为像素覆盖次数:
import numpy as np from numpy.lib.stride_tricks import sliding_window_view img = np.random.random((100, 100)) patch_shape = (10, 10) stride = 5 patches = sliding_window_view(img, patch_shape)[::stride, ::stride] patch_h, patch_w = patches.shape[:2] # 创建补丁起始位置掩码 kernel = np.zeros(img.shape, dtype=int) kernel[::stride, ::stride] = 1 # 用10×10全1核卷积得到计数 counts = np.convolve( np.convolve(kernel.ravel(), np.ones(patch_shape[0]*patch_shape[1], dtype=int), mode='same'), mode='same' ).reshape(img.shape)
为什么直接修改视图无效?
sliding_window_view返回的是原始数组的内存视图,而非独立副本。执行zpatches +=1时,Numpy会通过广播将视图内所有位置赋值为1,但重叠区域的内存是共享的,最终每个像素仅保留最后一次赋值结果,导致所有像素仅被加1。
内容的提问来源于stack exchange,提问作者CrashandCern
相关产品推荐
相关产品推荐

