web-dev-qa-db-ja.com

Python

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

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

15
Nick

いい質問です! 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()

enter image description here

17
wim

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パラメーターは、畳み込みが画像のエッジのピクセルを処理する方法を制御します(エッジのピクセルの場合、カーネルが確認する必要のある領域の半分は存在しません) 、したがって、画像を埋めるために何かを選択する必要があります)。

17
tacaswell

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

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

2)分離可能なカーネルを使用してから、フラット化された配列で2つの1D畳み込みを実行できます。1つはx方向、もう1つはy方向(転置を解く)です。これにより、2Dと同じ結果が得られます。畳み込み。

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

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

4
tom10