我想卷积一个概念上是周期性的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中执行此操作?
请注意,我对创建内核不感兴趣,但主要是卷积的周期性,即结果图像中最左边的三个(如果有意义的话)。
答案 0 :(得分:3)
这已经内置了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
。
答案 1 :(得分:2)
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.]])
答案 2 :(得分: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]])