15

入力された画像を滑らかにする簡単な関数を書きたいと思いました。Image および numpy ライブラリを使用してこれを実行しようとしていました。畳み込みマスクを使用することがこの問題へのアプローチになると考えていましたが、numpy には畳み込み関数が組み込まれていることがわかっています。

numpy.convolveを使用して画像を滑らかにするにはどうすればよいですか?

4

3 に答える 3

19

いい質問です! ここでのtcaswellの投稿は素晴らしい提案ですが、scipy がすべての作業を行っているため、この方法では多くを学ぶことはできません! あなたの質問は、関数を試して書きたいと述べたので、畳み込みなどの背後にある数学をよりよく理解して改善できることを期待して、すべてを手動で行うためのもう少し粗くて基本的な方法を示します。あなたのアイデアと努力で!

注: カーネルの形状/サイズが異なると、異なる結果が得られます。ガウスは通常の方法ですが、楽しみのために他の方法 (余弦、三角形など) を試すこともできます。これはその場で作ったもので、一種のピラミッド型のものだと思います。

import scipy.signal
import numpy as np
import matplotlib.pyplot as plt

im = plt.imread('example.jpg')
im /= 255.   # normalise to 0-1, it's easier to work in float space

# make some kind of kernel, there are many ways to do this...
t = 1 - np.abs(np.linspace(-1, 1, 21))
kernel = t.reshape(21, 1) * t.reshape(1, 21)
kernel /= kernel.sum()   # kernel should sum to 1!  :) 

# convolve 2d the kernel with each channel
r = scipy.signal.convolve2d(im[:,:,0], kernel, mode='same')
g = scipy.signal.convolve2d(im[:,:,1], kernel, mode='same')
b = scipy.signal.convolve2d(im[:,:,2], kernel, mode='same')

# stack the channels back into a 8-bit colour depth image and plot it
im_out = np.dstack([r, g, b])
im_out = (im_out * 255).astype(np.uint8) 

plt.subplot(2,1,1)
plt.imshow(im)
plt.subplot(2,1,2)
plt.imshow(im_out)
plt.show()

ここに画像の説明を入力

于 2013-02-08T05:37:21.213 に答える
17

ndimageのモジュールであるを見たいとしますscipy。すべて関数として設定された多数のフィルターと、任意のカーネルを畳み込むための優れたラッパーがあります。

例えば、

img_gaus = ndimage.filters.gaussian_filter(img, 2, mode='nearest')

シグマが 2 のガシアンでイメージを畳み込みます。

任意のカーネルを畳み込みたい場合は、クロスと言います

k = np.array([[0, 1, 0],
              [1, 1, 1],
              [0, 1, 0]])

img2 = ndimage.convolve(img, k, mode='constant')

これらの関数は高次元にも適しているため、ほぼ同じコード (カーネルの次元を拡大するだけ) を使用して、高次元のデータを平滑化できます。

modeパラメータとパラメータはcval、たたみ込みが画像の端にあるピクセルを処理する方法を制御します (端のピクセルの場合、カーネルが見る必要がある領域の半分が存在しないため、画像を埋めるために何かを選択する必要がありますと)。

于 2013-02-08T05:04:29.613 に答える
4

scipy を使用したくない場合は、次の 3 つのオプションがあります。

1) numpy には 2D FFT があるため、畳み込み定理をフーリエ変換と組み合わせて使用​​できます。

2) 分離可能なカーネルを使用して、平坦化された配列で 2 つの 1D 畳み込みを実行できます。1 つは x 方向で、もう 1 つは y 方向です (転置を分解)。畳み込み。

3) 小さなカーネル、たとえば 3x3 の場合、たたみ込みを乗算と合計として書き出すだけで十分簡単です。これは面倒に思えますが、それほど悪くはありません。

scipy を使用したい場合は、tcaswell が示唆するように ngimage を使用できます。scipy には convolve2d もあります。

于 2013-02-08T05:23:56.533 に答える