使用Python和NumPy进行二维卷积

22 投票
11 回答
103196 浏览
提问于 2025-04-15 20:27

我正在尝试在Python中使用numpy进行二维卷积。

我有一个二维数组,行的卷积核是H_r,列的卷积核是H_c。

data = np.zeros((nr, nc), dtype=np.float32)

#fill array with some data here then convolve

for r in range(nr):
    data[r,:] = np.convolve(data[r,:], H_r, 'same')

for c in range(nc):
    data[:,c] = np.convolve(data[:,c], H_c, 'same')

data = data.astype(np.uint8);

但是输出结果并不是我预期的那样,这段代码看起来还好吗?我觉得问题可能出在从float32转换到8位整数上。有什么好的方法来解决这个问题吗?

谢谢!

11 个回答

5

既然你已经把内核分开了,那么你可以直接使用scipy里的sepfir2d函数:

from scipy.signal import sepfir2d
convolved = sepfir2d(data, H_r, H_c)

另一方面,你那段代码看起来也没什么问题……

7

编辑 [2019年1月]

@Tashus 下面的评论是对的,@dudemeister 的回答 可能更准确。他建议的函数效率更高,因为它避免了直接进行二维卷积和由此产生的大量运算。

可能的问题

我觉得你在做两次一维卷积,第一次是针对列,第二次是针对行,然后用第二次的结果替换第一次的结果。

注意,使用 numpy.convolve 并加上 'same' 参数时,会返回一个和最大的输入数组形状相同的数组,所以当你进行第一次卷积时,整个 data 数组已经被填满了。

在这些步骤中,一个很好的可视化方法是使用 Hinton 图,这样你可以检查哪些元素已经有值了。

可能的解决方案

你可以尝试将两次卷积的结果相加(在第二个 for 循环中使用 data[:,c] += .. 而不是 data[:,c] =),如果你的卷积矩阵是使用一维的 H_rH_c 矩阵得到的,像这样:

卷积核心相加

另一种方法是使用 scipy.signal.convolve2d 进行二维卷积,这可能是你最初想要做的。

26

这可能不是最优的解决方案,但这是我之前用Python的numpy库实现的一个例子:

def convolution2d(image, kernel, bias):
    m, n = kernel.shape
    if (m == n):
        y, x = image.shape
        y = y - m + 1
        x = x - m + 1
        new_image = np.zeros((y,x))
        for i in range(y):
            for j in range(x):
                new_image[i][j] = np.sum(image[i:i+m, j:j+m]*kernel) + bias
    return new_image

希望这段代码能帮助到有同样疑问的朋友们。

祝好。

撰写回答