Python numpy阵列中子矩阵的矢量化提取

Python numpy阵列中子矩阵的矢量化提取,python,numpy,image-processing,computer-vision,vectorization,Python,Numpy,Image Processing,Computer Vision,Vectorization,我的目标是实现一个中值滤波器,这是一个函数,它用周围像素的中值替换(大部分)2d阵列中的每个像素。它可以用于图像去噪 我的实现从原始矩阵中提取子矩阵,其中包含像素本身及其邻域。这个提取目前是使用for循环完成的,正如您所想象的,for循环占用了大约95%的执行时间 以下是我当前的实现: def中值模糊(img,fsize=3): img_intermediate=np.zero((img.shape[0]+2,img.shape[1]+2),np.uint8)#第一个中间img,用于填充原始图像

我的目标是实现一个中值滤波器,这是一个函数,它用周围像素的中值替换(大部分)2d阵列中的每个像素。它可以用于图像去噪

我的实现从原始矩阵中提取子矩阵,其中包含像素本身及其邻域。这个提取目前是使用for循环完成的,正如您所想象的,for循环占用了大约95%的执行时间

以下是我当前的实现:

def中值模糊(img,fsize=3):
img_intermediate=np.zero((img.shape[0]+2,img.shape[1]+2),np.uint8)#第一个中间img,用于填充原始图像
img_intermediate[1:img.shape[0]+1,1:img.shape[1]+1]=img
img_result=np.empty((*img.shape,fsize,fsize),np.uint8)将包含结果,首先接收内核子矩阵
#从图像中提取子矩阵
对于范围内的i(img.shape[0]):
对于范围内的j(img.形状[1]):
img_结果[i,j]=img_中间[i:i+fsize,j:j+fsize]
img_结果=img_结果。重塑(*img.shape,fsize**2)#重塑结果矩阵
img_结果=np。中位数(img_结果,轴=2)#一次性计算中位数
返回img_result.astype('uint8')
如何使用矢量化操作提取这些子矩阵?

作为奖励,如果有计算机视觉经验的人正在读这篇文章:除了将中值滤波器应用于中间零填充矩阵之外,还有更好的实现中值滤波器的方法吗


非常感谢。

这是一个矢量化解决方案。但是,通过注意图像阵列的内存顺序,您可以想出一个更快的解决方案:

from numpy.lib.stride_tricks import as_strided

img_padded = np.pad(img, 1, mode='constant')
sub_shape = (fsize, fsize)
view_shape = tuple(np.subtract(img_padded.shape, sub_shape) + 1) + sub_shape
sub_img = as_strided(img_padded, view_shape, img_padded.strides * 2)
sub_img = sub_img.reshape(img.shape + (fsize**2,))
result = np.median(sub_img, axis=2).astype(int)
首先使用
pad
功能进行pad,然后使用
作为步幅
获得子矩阵,最后将
中值
应用于步幅

更新:使用@Divakar在评论中建议的
查看窗口

from skimage.util.shape import view_as_windows

img_padded = np.pad(img, 1, mode='constant')
sub_shape = (fsize, fsize)
view_shape = view_as_windows(img_padded, sub_shape, 1)
sub_img = view_shape.reshape(img.shape + (fsize**2,))
result = np.median(sub_img, axis=2).astype(int)
view\u as\u windows
还提供了类似于步幅的子矩阵

示例图像和输出:

img: 
[[ 1  2  3  4  5  6]
 [ 7  8  9 10 11 12]
 [13 14 15 16 17 18]
 [19 20 21 22 23 24]]

median_filtered: 
[[ 0  2  3  4  5  0]
 [ 2  8  9 10 11  6]
 [ 8 14 15 16 17 12]
 [ 0 14 15 16 17  0]]

您的用例包含在@edoput中。它包含在几个库(scipy、scikit image、opencv…)中,但我的目标是以最高效的方式实现它。使用
view-as\u-windows
:然后使用
np.median
?@Divakar感谢您的提及,我不知道这个函数!它不是唯一的numpy解决方案,但肯定会满足我的要求。
view\u as\u windows
是一个独立的函数代码库。所以,你可以从源头上找到它。太美了!这使我现有的解决方案快了约7倍!你能详细说明一下可能的记忆顺序增益吗?很高兴这有帮助。如果您知道自己的数据类型,那么可能有一种更快的方法可以使用numba或stripped循环来实现这一点。如果您的数组是以
C连续的方式保存的(意思是先保存行),您可能会从中受益<如果您的数组不是
C-连续的
,则code>view\u as\u窗口将创建一个新数组。我希望在你大踏步的时候也能做到,但我不确定。一般来说,任何比这更快的操作都可能需要进入
C-continuous/F-continuous
内存分配并了解您的数据类型。