新しいサイズで画像データを表すnumpy配列をリサンプリングする方法を探しています。できれば、補間方法(最近接、双線形など)を選択できます。知っている
scipy.misc.imresize
これは、PILのサイズ変更機能をラップすることにより、まさにこれを行います。唯一の問題は、PILを使用しているため、numpy配列が画像形式に準拠しなければならず、最大4つの「カラー」チャンネルが提供されることです。
任意の数の「カラー」チャンネルを使用して、任意の画像のサイズを変更できるようにします。 scipy/numpyでこれを行う簡単な方法があるのか、それとも自分でロールバックする必要があるのか疑問に思っていました。
自分で1つを調合する方法について、2つのアイデアがあります。
scipy.misc.imresize
を実行する関数scipy.ndimage.interpolation.affine_transform
を使用して独自に作成する最初の方法は、大規模なデータの場合はおそらく低速であり、2番目の方法は、スプライン以外の補間方法を提供していないようです。
説明に基づいて、 scipy.ndimage.zoom
が必要です。
双線形補間はorder=1
になり、最も近いのはorder=0
になり、キュービックがデフォルト(order=3
)になります。
zoom
は、新しい解像度にリサンプリングする定期的にグリッド化されたデータ専用です。
簡単な例として:
import numpy as np
import scipy.ndimage
x = np.arange(9).reshape(3,3)
print 'Original array:'
print x
print 'Resampled by a factor of 2 with nearest interpolation:'
print scipy.ndimage.zoom(x, 2, order=0)
print 'Resampled by a factor of 2 with bilinear interpolation:'
print scipy.ndimage.zoom(x, 2, order=1)
print 'Resampled by a factor of 2 with cubic interpolation:'
print scipy.ndimage.zoom(x, 2, order=3)
そして結果:
Original array:
[[0 1 2]
[3 4 5]
[6 7 8]]
Resampled by a factor of 2 with nearest interpolation:
[[0 0 1 1 2 2]
[0 0 1 1 2 2]
[3 3 4 4 5 5]
[3 3 4 4 5 5]
[6 6 7 7 8 8]
[6 6 7 7 8 8]]
Resampled by a factor of 2 with bilinear interpolation:
[[0 0 1 1 2 2]
[1 2 2 2 3 3]
[2 3 3 4 4 4]
[4 4 4 5 5 6]
[5 5 6 6 6 7]
[6 6 7 7 8 8]]
Resampled by a factor of 2 with cubic interpolation:
[[0 0 1 1 2 2]
[1 1 1 2 2 3]
[2 2 3 3 4 4]
[4 4 5 5 6 6]
[5 6 6 7 7 7]
[6 6 7 7 8 8]]
Edit:Matt S.が指摘したように、マルチバンド画像をズームするにはいくつかの注意事項があります。私は 以前の回答 のいずれかから、ほとんど逐語的に以下の部分をコピーしています。
ズームは3D(およびnD)配列でも機能します。ただし、たとえば2倍にズームすると、all軸に沿ってズームすることに注意してください。
data = np.arange(27).reshape(3,3,3)
print 'Original:\n', data
print 'Zoomed by 2x gives an array of shape:', ndimage.zoom(data, 2).shape
これにより以下が得られます。
Original:
[[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]]
[[ 9 10 11]
[12 13 14]
[15 16 17]]
[[18 19 20]
[21 22 23]
[24 25 26]]]
Zoomed by 2x gives an array of shape: (6, 6, 6)
マルチバンド画像の場合、通常、「z」軸に沿って補間して新しいバンドを作成したくないでしょう。
ズームしたい3バンドのRGB画像のようなものがある場合は、ズーム係数としてタプルのシーケンスを指定することでこれを行うことができます。
print 'Zoomed by 2x along the last two axes:'
print ndimage.zoom(data, (1, 2, 2))
これにより以下が得られます。
Zoomed by 2x along the last two axes:
[[[ 0 0 1 1 2 2]
[ 1 1 1 2 2 3]
[ 2 2 3 3 4 4]
[ 4 4 5 5 6 6]
[ 5 6 6 7 7 7]
[ 6 6 7 7 8 8]]
[[ 9 9 10 10 11 11]
[10 10 10 11 11 12]
[11 11 12 12 13 13]
[13 13 14 14 15 15]
[14 15 15 16 16 16]
[15 15 16 16 17 17]]
[[18 18 19 19 20 20]
[19 19 19 20 20 21]
[20 20 21 21 22 22]
[22 22 23 23 24 24]
[23 24 24 25 25 25]
[24 24 25 25 26 26]]]
リサンプリングする場合は、Scipyのクックブックで rebinning を探してください。特に、最後に定義されたcongrid
関数は、リビニングまたは補間をサポートします(同じ名前のIDLの関数と同等)。補間が必要ない場合、これが最速のオプションです。
scipy.ndimage.map_coordinates
を直接使用することもできます。これは、あらゆる種類のリサンプリング(非構造化グリッドを含む)のスプライン補間を行います。 map_coordinatesは、大きな配列(nx、ny> 200)で遅いことがわかりました。
構造化グリッドでの補間には、 scipy.interpolate.RectBivariateSpline
を使用する傾向があります。スプラインの次数(線形、二次、三次など)を選択でき、各軸に対して個別に選択することもできます。例:
import scipy.interpolate as interp
f = interp.RectBivariateSpline(x, y, im, kx=1, ky=1)
new_im = f(new_x, new_y)
この場合、双線形補間(kx = ky = 1)
を実行しています。 「最も近い」種類の補間はサポートされていません。これは、長方形メッシュ上のスプライン補間のみであるためです。また、最速の方法ではありません。
バイリニアまたはバイキュービック補間を使用している場合、一般的に2つの1D補間を行う方がはるかに高速です。
f = interp.interp1d(y, im, kind='linear')
temp = f(new_y)
f = interp.interp1d(x, temp.T, kind='linear')
new_im = f(new_x).T
kind='nearest'
を使用することもできますが、その場合は、横断アレイを削除します。
Scikit-image を見ましたか?そのtransform.pyramid_*
関数は役に立つかもしれません。
最近、scipy.ndimage.interpolation.zoomの問題を発見しました。これはバグレポートとして提出しました。 https://github.com/scipy/scipy/issues/32
代替手段として(または少なくとも私にとって)、scikit-imageのskimage.transform.resizeが正しく機能することがわかりました。 http://scikit-image.org/docs/dev/api/skimage.transform .html#skimage.transform.resize
ただし、scipyのInterpolation.zoomとは動作が異なります。複数の値を指定するのではなく、目的の出力形状を指定します。これは2Dおよび3D画像で機能します。
ちょうど2D画像の場合、transform.rescaleを使用して、interpolation.zoomの場合と同様に乗数またはスケールを指定できます。
このソリューションは、RGBチャンネルに影響を与えることなく、フィードされた画像のXとYをスケーリングします。
import numpy as np
import scipy.ndimage
matplotlib.pyplot.imshow(scipy.ndimage.zoom(image_np_array, zoom = (7,7,1), order = 1))
これが役立つことを願っています。