web-dev-qa-db-fra.com

interpoler le volume 3D avec numpy et ou scipy

Je suis extrêmement frustré car après plusieurs heures, je n'arrive pas à faire une interpolation 3D apparemment facile en python. A Matlab, tout ce que j'avais à faire était

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

Quel est l'équivalent exact de cela en utilisant ndimage.map_coordinate de scipy ou d'autres méthodes numpy?

Merci

21
user1301295

Dans scipy 0.14 ou version ultérieure, il existe une nouvelle fonction scipy.interpolate.RegularGridInterpolator qui ressemble étroitement à interp3.

La commande MATLAB Vi = interp3(x,y,z,V,xi,yi,zi) se traduirait par quelque chose comme:

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)

Voici un exemple complet démontrant les deux; cela vous aidera à comprendre les différences exactes ...

CODE 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);

Le résultat est Vi=[268 357] Qui est en effet la valeur à ces deux points (2,6,8) Et (3,5,7).

CODE SCIPY:

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))

Encore une fois, c'est [268,357]. Vous voyez donc quelques légères différences: Scipy utilise l'ordre d'index x, y, z tandis que MATLAB utilise y, x, z (étrangement); Dans Scipy, vous définissez une fonction dans une étape distincte et lorsque vous l'appelez, les coordonnées sont regroupées comme (x1, y1, z1), (x2, y2, z2), ... tandis que matlab utilise (x1, x2, .. .), (y1, y2, ...), (z1, z2, ...).

En dehors de cela, les deux sont similaires et tout aussi faciles à utiliser.

19
Steve Byrnes

Le équivalent exact au interp3 De MATLAB utiliserait interpn de scipy pour une seule fois interpolation:

import numpy as np
from scipy.interpolate import interpn

Vi = interpn((x,y,z), V, np.array([xi,yi,zi]).T)

La méthode par défaut pour MATLAB et scipy est l'interpolation linéaire, et cela peut être modifié avec l'argument method. Notez que seule l'interpolation linéaire et le plus proche voisin est prise en charge par interpn pour 3 dimensions et plus, contrairement à MATLAB qui prend également en charge l'interpolation cubique et spline.

Lorsque vous effectuez plusieurs appels d'interpolation sur la même grille, il est préférable d'utiliser l'objet d'interpolation RegularGridInterpolator , comme dans la réponse acceptée ci-dessus . interpn utilise RegularGridInterpolator en interne.

6
buzjwa

Fondamentalement, ndimage.map_coordinates Fonctionne en coordonnées "index" (aussi connues en coordonnées "Voxel" ou "pixel"). L'interface avec celle-ci semble un peu maladroite au début, mais elle vous donne beaucoup de flexibilité.

Si vous souhaitez spécifier des coordonnées interpolées similaires à interp3 De matlab, vous devrez convertir vos coordonnées d'entrée en coordonnées "index".

Il y a aussi la ride supplémentaire qui map_coordinates Préserve toujours le dtype du tableau d'entrée dans la sortie. Si vous interpolez un tableau entier, vous obtiendrez une sortie entière, qui peut ou non être ce que vous voulez. Pour l'extrait de code ci-dessous, je suppose que vous voulez toujours une sortie en virgule flottante. (Si vous ne le faites pas, c'est en fait plus simple.)

J'essaierai d'ajouter plus d'explications plus tard ce soir (c'est un code assez dense).

Dans l'ensemble, la fonction interp3 Que j'ai est plus complexe qu'elle ne doit l'être pour vos besoins exacts. Cependant, il devrait plus ou moins reproduire le comportement de interp3 Tel que je m'en souviens (en ignorant la fonctionnalité de "zoom" de interp3(data, zoom_factor), que scipy.ndimage.zoom Gère.)

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