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ビットへのキャストにあると思います。これを行うための最良の方法は何ですか
ありがとう
以下の@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
を使用します)。
これを行う別の方法は、2D畳み込み配列で scipy.signal.convolve2d
を使用することです。これは、おそらく最初にやりたかったことです。
すでにカーネルが分離されているので、scipyのsepfir2d関数を使用するだけです。
from scipy.signal import sepfir2d
convolved = sepfir2d(data, H_r, H_c)
一方、そこにあるコードは大丈夫に見えます...
おそらくそれは最も最適化されたソリューションではありませんが、これは私が以前に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
このコードが同じ疑問を持つ他の人に役立つことを願っています。
よろしく。
最初にラウンドしてからuint8にキャストしてみてください。
data = data.round().astype(np.uint8);