web-dev-qa-db-ja.com

Python Matlabのconv2に類似した2D畳み込み

SciPyとNumpyを使用して2Dマトリックスの畳み込みを実行しようとしましたが、失敗しました。私が試したSciPyの場合は、sepfir2dとscipy.signal.convolve、Numpyの場合はConvolve2Dです。 Matlab for Pythonにconv2のような単純な関数はありますか?

次に例を示します。

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

[0.707 0.707]で畳み込みたい

そして、Matlabからのconv2による結果は次のとおりです。

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でこの出力を計算する関数はありますか?お返事をいただければ幸いです。

15
user1343318

scipyを使用してこれを行うにはさまざまな方法がありますが、2D畳み込みはnumpyに直接含まれていません。 (scipyの依存関係を回避する必要がある場合は、numpyのみを使用してfftで実装することも簡単です。)

scipy.signal.convolve2dscipy.signal.convolvescipy.signal.fftconvolve、およびscipy.ndimage.convolveはすべて、異なる方法で2D畳み込み(最後の3つはN-d)を処理します。

scipy.signal.fftconvolveはfftドメインで畳み込みを行います(単純な乗算です)。これは多くの場合はるかに高速ですが、個別の場合よりもエッジ効果にごくわずかな違いが生じる可能性があり、この特定の実装ではデータが浮動小数点に強制変換されます。さらに、小さな配列をはるかに大きな配列で畳み込む場合、不要なメモリ使用量があります。全体として、fftベースのメソッドは劇的に高速になる可能性がありますが、scipy.signal.fftconvolveが理想的なソリューションではない一般的なユースケースがいくつかあります。

scipy.signal.convolve2dscipy.signal.convolve、およびscipy.ndimage.convolveはすべて、Cで実装された離散畳み込みを使用しますが、実装方法は異なります。

scipy.ndimage.convolveは同じデータ型を維持し、メモリ使用量を最小限に抑えるために出力の場所を制御できます。 uint8(画像データなど)を畳み込む場合は、多くの場合、これが最良のオプションです。出力は常に最初の入力配列と同じ形状になります。これは画像には意味がありますが、より一般的な畳み込みには意味がありません。 ndimage.convolveを使用すると、mode kwarg(scipy.signalmode kwargとはまったく異なる機能)を介してエッジ効果を処理する方法を細かく制御できます。

2D配列を使用している場合は、scipy.signal.convolveを避けてください。これはN-dの場合には機能しますが、2d配列には最適ではなく、まったく同じことをもう少し効率的に行うためにscipy.signal.convolve2dが存在します。 scipy.signalの畳み込み関数を使用すると、modekwargを使用して出力形状を制御できます。 (デフォルトでは、matlabのconv2と同じように動作します。)これは、一般的な数学的畳み込みには役立ちますが、画像処理にはあまり役立ちません。ただし、scipy.signal.convolve2dは一般的にscipy.ndimage.convolveよりも低速です。

scipyのさまざまなサブモジュールでの重複と、パフォーマンスのトレードオフが異なる畳み込みを実装するさまざまな方法があるため、さまざまなオプションがあります。

ユースケースについてもう少し詳しく説明していただければ、より良いソリューションをお勧めします。ほぼ同じサイズの2つの配列を畳み込み、それらがすでに浮動小数点になっている場合は、fftconvolveが最適です。そうでなければ、scipy.ndimage.convolveがそれを打ち負かす可能性があります。

31
Joe Kington

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]])

まったく同じ結果が必要な場合は、次のようにAにゼロの列を追加するだけです。

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]])

私の経験から、Matlabで行うことのほとんど(およびそれ以上)をscipy/numpyで行うことができます。

5
Bitwise