Свертка периодического изображения с помощью Python

Я хочу свернуть 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?

Обратите внимание, что меня не интересует создание ядра, а в основном периодичность свертки, то есть три крайних левых в результирующем изображении (если это имеет смысл).


person ABDreverhaven    schedule 11.08.2013    source источник
comment
Я думаю, вам придется накрутить свой собственный код, довольно легко с помощью БПФ и теоремы свертки . Единственная сложная часть может заключаться в том, как дополнить ядро, чтобы получить правильный ответ.   -  person Jaime    schedule 11.08.2013


Ответы (3)


Он уже встроен с дополнительным boundary='wrap' scipy.signal.convolve2d, который задает периодические граничные условия в качестве заполнения для свертки. Параметр 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, что часто бывает быстрее.

person askewchan    schedule 12.08.2013

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.]])
person Jaime    schedule 11.08.2013

Этот вид «периодической свертки» более известен как круговая или циклическая свертка. См. 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]])
person ABDreverhaven    schedule 22.08.2013
comment
scipy.signal.fftconvolve не поддерживает режим 'wrap'. - person askewchan; 25.08.2013
comment
Нет, но он выполняет круговую свертку. - person ABDreverhaven; 26.08.2013
comment
Он не выполняет циклических условий в моей системе, ни в одном из режимов, перечисленных в документации. Просто не забудьте протестировать любой из них на образце перед использованием данных. - person askewchan; 26.08.2013