数時間後、Pythonで一見簡単に見える3D補間を行うことができないように見えるので、私は非常にイライラしています。 Matlabで私がしなければならなかったすべては
Vi = interp3(x,y,z,V,xi,yi,zi)
Scipyのndimage.map_coordinateまたは他のnumpyメソッドを使用したこれとまったく同じものは何ですか?
ありがとう
Scipy 0.14以降では、_scipy.interpolate.RegularGridInterpolator
_によく似た新しい関数 _interp3
_ があります。
MATLABコマンドVi = interp3(x,y,z,V,xi,yi,zi)
は次のように変換されます。
_from numpy import array
from scipy.interpolate import RegularGridInterpolator as rgi
my_interpolating_function = rgi((x,y,z), V)
Vi = my_interpolating_function(array([xi,yi,zi]).T)
_
これは両方を示す完全な例です。正確な違いを理解するのに役立ちます...
MATLABコード:
_x = linspace(1,4,11);
y = linspace(4,7,22);
z = linspace(7,9,33);
V = zeros(22,11,33);
for i=1:11
for j=1:22
for k=1:33
V(j,i,k) = 100*x(i) + 10*y(j) + z(k);
end
end
end
xq = [2,3];
yq = [6,5];
zq = [8,7];
Vi = interp3(x,y,z,V,xq,yq,zq);
_
結果は_Vi=[268 357]
_で、これは実際にこれらの2つのポイント_(2,6,8)
_および_(3,5,7)
_での値です。
スキピーコード:
_from scipy.interpolate import RegularGridInterpolator
from numpy import linspace, zeros, array
x = linspace(1,4,11)
y = linspace(4,7,22)
z = linspace(7,9,33)
V = zeros((11,22,33))
for i in range(11):
for j in range(22):
for k in range(33):
V[i,j,k] = 100*x[i] + 10*y[j] + z[k]
fn = RegularGridInterpolator((x,y,z), V)
pts = array([[2,6,8],[3,5,7]])
print(fn(pts))
_
ここでも_[268,357]
_です。したがって、わずかな違いがあります。Scipyはx、y、zのインデックス順序を使用し、MATLABは(奇妙な)y、x、zを使用します。 Scipyでは、関数を別のステップで定義し、それを呼び出すと、座標は(x1、y1、z1)、(x2、y2、z2)、...のようにグループ化されますが、MATLABは(x1、x2、.. 。)、(y1、y2、...)、(z1、z2、...)。
それ以外は、2つは似ており、同じように使いやすいです。
MATLABのinterp3
と同等のexactは、scipyの interpn
を使用して1回限りの補間を行います:
import numpy as np
from scipy.interpolate import interpn
Vi = interpn((x,y,z), V, np.array([xi,yi,zi]).T)
MATLABとscipyの両方のデフォルトの方法は線形補間であり、これはmethod
引数で変更できます。 3次以上のinterpn
では、3次補間とスプライン補間もサポートしているのとは異なり、線形補間と最近傍補間のみがサポートされています。
同じグリッド上で複数の補間呼び出しを行う場合、受け入れられた回答 上記 のように、補間オブジェクト RegularGridInterpolator
を使用することをお勧めします。 interpn
は内部でRegularGridInterpolator
を使用します。
基本的に、_ndimage.map_coordinates
_は「インデックス」座標(別名「ボクセル」または「ピクセル」座標)で機能します。インターフェースは最初は少し不格好に見えますが、lotの柔軟性が得られます。
MATLABの_interp3
_と同様に補間された座標を指定する場合は、入力座標を「インデックス」座標に変換する必要があります。
_map_coordinates
_が入力配列のdtypeを常に出力に保持するという追加のしわもあります。整数配列を補間すると、整数出力が得られます。これは、必要な場合とそうでない場合があります。以下のコードスニペットでは、常に浮動小数点出力が必要であると想定します。 (そうしないと、実際にはもっと簡単になります。)
今夜後半に説明を追加しようと思います(これはかなり密なコードです)。
全体として、私が持っている_interp3
_関数は、正確な目的のために必要な場合よりも複雑です。しかし、私が覚えているように、それは多かれ少なかれ_interp3
_の動作を再現するはずです(_scipy.ndimage.zoom
_が処理するinterp3(data, zoom_factor)
の「ズーム」機能は無視します)。
_import numpy as np
from scipy.ndimage import map_coordinates
def main():
data = np.arange(5*4*3).reshape(5,4,3)
x = np.linspace(5, 10, data.shape[0])
y = np.linspace(10, 20, data.shape[1])
z = np.linspace(-100, 0, data.shape[2])
# Interpolate at a single point
print interp3(x, y, z, data, 7.5, 13.2, -27)
# Interpolate a region of the x-y plane at z=-25
xi, yi = np.mgrid[6:8:10j, 13:18:10j]
print interp3(x, y, z, data, xi, yi, -25 * np.ones_like(xi))
def interp3(x, y, z, v, xi, yi, zi, **kwargs):
"""Sample a 3D array "v" with pixel corner locations at "x","y","z" at the
points in "xi", "yi", "zi" using linear interpolation. Additional kwargs
are passed on to ``scipy.ndimage.map_coordinates``."""
def index_coords(corner_locs, interp_locs):
index = np.arange(len(corner_locs))
if np.all(np.diff(corner_locs) < 0):
corner_locs, index = corner_locs[::-1], index[::-1]
return np.interp(interp_locs, corner_locs, index)
orig_shape = np.asarray(xi).shape
xi, yi, zi = np.atleast_1d(xi, yi, zi)
for arr in [xi, yi, zi]:
arr.shape = -1
output = np.empty(xi.shape, dtype=float)
coords = [index_coords(*item) for item in Zip([x, y, z], [xi, yi, zi])]
map_coordinates(v, coords, order=1, output=output, **kwargs)
return output.reshape(orig_shape)
main()
_