2D-свертка в Python, аналогичная Matlab conv2

Я пытаюсь выполнить свертку 2D-матрицы с помощью SciPy и Numpy, но не удалось. Для SciPy я попробовал, sepfir2d и scipy.signal.convolve и Convolve2D для Numpy. Есть ли простая функция, например conv2 в Matlab для Python?

Вот пример:

 A= [ 5     4     5     4;
      3     2     3     2;
      5     4     5     4;
      3     2     3     2 ]

Я хочу свернуть его с помощью [0.707 0.707]

И результат как conv2 из Matlab есть

3.5350    6.3630    6.3630    6.3630    2.8280
2.1210    3.5350    3.5350    3.5350    1.4140
3.5350    6.3630    6.3630    6.3630    2.8280
2.1210    3.5350    3.5350    3.5350    1.4140

Некоторая функция для вычисления этого вывода в Python? Я буду благодарен за ответ.

Ответы

Ответ 1

Существует несколько способов сделать это с помощью scipy, но 2D свертка напрямую не включена в numpy. (Это также легко реализовать с помощью fft, используя только numpy, если вам нужно избегать скудной зависимости.)

scipy.signal.convolve2d, scipy.signal.convolve, scipy.signal.fftconvolve и scipy.ndimage.convolve будут обрабатывать 2D-свертку (последние три - N-d) по-разному.

scipy.signal.fftconvolve выполняется свертка в fft-области (где это простое умножение). Это намного быстрее во многих случаях, но может привести к очень небольшим различиям в краевых эффектах, чем к дискретному случаю, и ваши данные будут принудительно введены в плавающие точки с этой конкретной реализацией. Кроме того, ненужное использование памяти при свертывании небольшого массива с гораздо большим массивом. В целом, методы на основе fft могут быть значительно быстрее, но существуют некоторые распространенные случаи использования, когда scipy.signal.fftconvolve не является идеальным решением.

scipy.signal.convolve2d, scipy.signal.convolve и scipy.ndimage.convolve все используют дискретную свертку, реализованную на C, однако они реализуют ее по-разному.

scipy.ndimage.convolve сохраняет один и тот же тип данных и дает вам контроль над местоположением вывода для минимизации использования памяти. Если вы свертываете uint8 (например, данные изображения), это часто лучший вариант. Выход всегда будет иметь ту же форму, что и первый входной массив, что имеет смысл для изображений, но, возможно, не для более общей свертки. ndimage.convolve дает вам большой контроль над обработкой краевых эффектов с помощью mode kwarg (который работает совершенно иначе, чем scipy.signal mode kwarg).

Избегайте scipy.signal.convolve, если вы работаете с массивами 2d. Он работает для случая N-d, но он субоптимален для 2d-массивов, а scipy.signal.convolve2d существует, чтобы сделать то же самое более эффективно. Функции свертки в scipy.signal дают вам контроль над формой вывода с помощью mode kwarg. (По умолчанию они будут вести себя точно так же, как matlab conv2.) Это полезно для общей математической свертки, но менее полезно для обработки изображений. Однако scipy.signal.convolve2d обычно медленнее, чем scipy.ndimage.convolve.

Есть много разных вариантов, частично из-за дублирования в разных подмодулях scipy и отчасти потому, что существуют различные способы реализации свертки, которые имеют разные компромиссы производительности.

Если вы можете немного подробнее рассказать о своем прецеденте, мы можем рекомендовать лучшее решение. Если вы свертываете два массива примерно того же размера, и они уже плавают, fftconvolve - отличный выбор. В противном случае scipy.ndimage.convolve может побить его.

Ответ 2

scipy convolved1d() делает то, что вы хотите, просто обрабатывает края по-разному:

sp.ndimage.filters.convolve1d(A,[0.707,0.707],axis=1,mode='constant')

предоставит вам:

array([[ 6.363,  6.363,  6.363,  2.828],
       [ 3.535,  3.535,  3.535,  1.414],
       [ 6.363,  6.363,  6.363,  2.828],
       [ 3.535,  3.535,  3.535,  1.414]])

Если вы хотите получить тот же результат, просто добавьте столбец нулей в следующим образом:

sp.ndimage.filters.convolve1d(np.c_[np.zeros((4,1)),A],[0.707,0.707],axis=1,mode='constant')

и вы получите:

array([[ 3.535,  6.363,  6.363,  6.363,  2.828],
       [ 2.121,  3.535,  3.535,  3.535,  1.414],
       [ 3.535,  6.363,  6.363,  6.363,  2.828],
       [ 2.121,  3.535,  3.535,  3.535,  1.414]])

Из моего опыта вы можете сделать в scipy/numpy большую часть того, что вы делаете в Matlab очень легко (и многое другое).

Ответ 3

Почему бы не реализовать его самостоятельно?, обратите внимание, что conv2 использует прямолинейную формальную реализацию двумерного уравнения свертки в пространственной форме. Если a и b являются функциями двух дискретных переменных, n1 и n2, то формула для двумерной свертки a и b: enter image description here

Однако на практике conv2 вычисляет свертку для конечных интервалов.