web-dev-qa-db-ja.com

numpyやscipyで3Dボリュームを補間する

数時間後、Pythonで一見簡単に見える3D補間を行うことができないように見えるので、私は非常にイライラしています。 Matlabで私がしなければならなかったすべては

Vi = interp3(x,y,z,V,xi,yi,zi)

Scipyのndimage.map_coordinateまたは他のnumpyメソッドを使用したこれとまったく同じものは何ですか?

ありがとう

21
user1301295

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つは似ており、同じように使いやすいです。

19
Steve Byrnes

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を使用します。

6
buzjwa

基本的に、_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()
_
3
Joe Kington