用python进行周期图像卷积

4

我希望对一个概念上为周期性的n维图像进行卷积。

我的意思是:如果我有一张2D图像

>>> image2d = [[0,0,0,0],
...            [0,0,0,1],
...            [0,0,0,0]]

我想将它与这个内核卷积:

>>> kernel = [[ 1,1,1],
...           [ 1,1,1],
...           [ 1,1,1]]

那么我希望你能将结果翻译为:

>>> result = [[1,0,1,1],
...           [1,0,1,1],
...           [1,0,1,1]]

如何在Python/numpy/scipy中实现这个?请注意,我不感兴趣的是创建内核,而主要是卷积的周期性,即结果图像中的最左边的三个(如果有意义的话)。

我认为你将不得不自己编写代码,使用FFT和卷积定理相当容易。唯一棘手的部分可能是如何填充核以获得正确的答案。 - Jaime
3个回答

4

这已经内置在中了,利用scipy.signal.convolve2d的可选参数 boundary='wrap' 来进行卷积时对周期性边界条件进行填充。此处的mode选项为'same',以使输出结果和输入大小匹配。

In [1]: image2d = [[0,0,0,0],
    ...            [0,0,0,1],
    ...            [0,0,0,0]]

In [2]: kernel = [[ 1,1,1],
    ...           [ 1,1,1],
    ...           [ 1,1,1]]

In [3]: from scipy.signal import convolve2d

In [4]: convolve2d(image2d, kernel, mode='same', boundary='wrap')
Out[4]: 
array([[1, 0, 1, 1],
       [1, 0, 1, 1],
       [1, 0, 1, 1]])

这里唯一的缺点是你不能使用通常更快的scipy.signal.fftconvolve函数。

3
image2d = [[0,0,0,0,0],
           [0,0,0,1,0],
           [0,0,0,0,0],
           [0,0,0,0,0]]
kernel = [[1,1,1],
          [1,1,1],
          [1,1,1]]
image2d = np.asarray(image2d)
kernel = np.asarray(kernel)

img_f = np.fft.fft2(image2d)
krn_f = np.fft.fft2(kernel, s=image2d.shape)

conv = np.fft.ifft2(img_f*krn_f).real

>>> conv.round()
array([[ 0.,  0.,  0.,  0.,  0.],
       [ 1.,  0.,  0.,  1.,  1.],
       [ 1.,  0.,  0.,  1.,  1.],
       [ 1.,  0.,  0.,  1.,  1.]])

请注意,卷积核在图像中的左上角位置放置在数字1的位置。您需要滚动结果才能得到您想要的内容:
k_rows, k_cols = kernel.shape
conv2 = np.roll(np.roll(conv, -(k_cols//2), axis=-1),
                -(k_rows//2), axis=-2)
>>> conv2.round()
array([[ 0.,  0.,  1.,  1.,  1.],
       [ 0.,  0.,  1.,  1.,  1.],
       [ 0.,  0.,  1.,  1.,  1.],
       [ 0.,  0.,  0.,  0.,  0.]])

1
这种“周期卷积”更为人所知的是循环卷积。参见http://en.wikipedia.org/wiki/Circular_convolution
对于n维图像,就像在这个问题中一样,可以使用scipy.ndimage.convolve函数。它有一个参数mode,可以设置为wrap进行循环卷积。
result = scipy.ndimage.convolve(image,kernel,mode='wrap')

>>> import numpy as np
>>> image = np.array([[0, 0, 0, 0],
...                   [0, 0, 0, 1],
...                   [0, 0, 0, 0]])
>>> kernel = np.array([[1, 1, 1],
...                    [1, 1, 1],
...                    [1, 1, 1]])
>>> from scipy.ndimage import convolve
>>> convolve(image, kernel, mode='wrap')
array([[1, 0, 1, 1],   
       [1, 0, 1, 1],
       [1, 0, 1, 1]])

scipy.signal.fftconvolve 不支持“wrap”模式。 - askewchan
不是,但它执行循环卷积。 - ABDreverhaven
我的系统上它不支持循环条件,无论文档中列出的任何模式。在使用数据之前,请务必使用样本进行测试。 - askewchan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接