web-dev-qa-db-ja.com

pythonとnumpyを使用した2次元畳み込み

Numpyを使用してpython)で2D畳み込みを実行しようとしています

次のような2次元配列があり、行にはカーネルH_r、列にはH_cがあります。

data = np.zeros((nr, nc), dtype=np.float32)

#fill array with some data here then convolve

for r in range(nr):
    data[r,:] = np.convolve(data[r,:], H_r, 'same')

for c in range(nc):
    data[:,c] = np.convolve(data[:,c], H_c, 'same')

data = data.astype(np.uint8);

期待した出力が生成されません。このコードは問題ないように見えますか。問題はfloat32から8ビットへのキャストにあると思います。これを行うための最良の方法は何ですか

ありがとう

15
mikip

編集[2019年1月]

以下の@Tashusのコメントは正しいので、 @ dudemeisterの回答 はおそらくもっと的を射ているでしょう。彼が提案した関数は、直接2D畳み込みとそれに伴う操作の数を回避することにより、より効率的でもあります。

考えられる問題

1つ目は列ごと、2つ目は行ごとの2つの1d畳み込みを実行し、最初の結果を2番目の結果に置き換えていると思います。

numpy.convolve'same'引数を指定すると、指定された最大の配列と同じ形状の配列が返されるため、最初の畳み込みを行うときに、data配列全体に既に値が設定されていることに注意してください。

これらの手順で配列を視覚化する良い方法の1つは、 ヒントンダイアグラム を使用することです。これにより、どの要素にすでに値があるかを確認できます。

考えられる解決策

畳み込み行列が次のように1次元のdata[:,c] += ..およびdata[:,c] =行列を使用した結果である場合は、2つの畳み込みの結果を追加してみることができます(2番目のforループでH_rの代わりにH_cを使用します)。

convolution core addition

これを行う別の方法は、2D畳み込み配列で scipy.signal.convolve2d を使用することです。これは、おそらく最初にやりたかったことです。

5
berna1111

すでにカーネルが分離されているので、scipyのsepfir2d関数を使用するだけです。

from scipy.signal import sepfir2d
convolved = sepfir2d(data, H_r, H_c)

一方、そこにあるコードは大丈夫に見えます...

4
dudemeister

おそらくそれは最も最適化されたソリューションではありませんが、これは私が以前にPython用のnumpyライブラリで使用した実装です。

def convolution2d(image, kernel, bias):
    m, n = kernel.shape
    if (m == n):
        y, x = image.shape
        y = y - m + 1
        x = x - m + 1
        new_image = np.zeros((y,x))
        for i in range(y):
            for j in range(x):
                new_image[i][j] = np.sum(image[i:i+m, j:j+m]*kernel) + bias
return new_image

このコードが同じ疑問を持つ他の人に役立つことを願っています。

よろしく。

4
omotto

最初にラウンドしてからuint8にキャストしてみてください。

data = data.round().astype(np.uint8);
0