Interpoluj objętość 3D za pomocą numpy i lub scipy
Jestem bardzo sfrustrowany, ponieważ po kilku godzinach nie mogę wykonać pozornie łatwej interpolacji 3D w Pythonie. W Matlab wszystko co musiałem zrobić to
Vi = interp3(x,y,z,V,xi,yi,zi)
Jaki jest dokładny odpowiednik tego używając ndimage scipy ' ego.map_coordinate czy inne metody numpy?
Thanks
4 answers
W scipy 0.14 lub nowszym istnieje nowa funkcja scipy.interpolate.RegularGridInterpolator
który bardzo przypomina interp3
.
Polecenie MATLAB Vi = interp3(x,y,z,V,xi,yi,zi)
przetłumaczyłoby na coś takiego:
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)
Oto pełny przykład pokazujący oba; pomoże Ci zrozumieć dokładne różnice...
KOD 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);
Wynikiem jest Vi=[268 357]
, która jest rzeczywiście wartością w tych dwóch punktach (2,6,8)
i (3,5,7)
.
KOD 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))
Znowu jest [268,357]
. Więc widzisz niektóre niewielkie różnice: Scipy używa X,y, Z indeksów, podczas gdy MATLAB używa y,X,Z (dziwnie); w Scipy definiujesz funkcję w oddzielnym kroku i kiedy ją wywołasz, współrzędne są pogrupowane jak (x1,y1,z1),(x2,y2,z2),... podczas gdy matlab używa (x1, x2,...), (y1, y2,...), (z1,z2,...).
Poza tym oba są podobne i równie łatwe w użyciu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-24 16:34:22
The exact odpowiednik MATLAB 's interp3
będzie używał scipy' s interpn
dla interpolacji jednorazowej:
import numpy as np
from scipy.interpolate import interpn
Vi = interpn((x,y,z), V, np.array([xi,yi,zi]).T)
Domyślną metodą dla MATLAB i scipy jest interpolacja liniowa, którą można zmienić za pomocą argumentu method
. Zauważ, że tylko interpolacja liniowa i najbliższa jest obsługiwana przez interpn
dla 3 wymiarów i powyżej, w przeciwieństwie do MATLAB, który obsługuje również interpolację sześcienną i splajnową.
Podczas wykonywania wielu wywołań interpolacyjnych na taką samą siatkę najlepiej zastosować obiekt interpolacji RegularGridInterpolator
, jak w zaakceptowanej odpowiedzi powyżej . interpn
używa RegularGridInterpolator
wewnętrznie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-27 09:56:49
Zasadniczo, ndimage.map_coordinates
działa we współrzędnych "indeksowych" (vel "voxel" lub "Pixel" współrzędne). Interfejs do niego wydaje się na początku trochę niezgrabny, ale daje dużo elastyczności.
Jeśli chcesz określić interpolowane współrzędne podobne do interp3
matlab, musisz przekonwertować współrzędne intput na współrzędne" indeksowe".
Istnieje również dodatkowa zmarszczka, która map_coordinates
zawsze zachowuje dtype tablicy wejściowej na wyjściu. Jeśli Interpoluj tablicę liczb całkowitych, a otrzymasz wynik liczb całkowitych, który może być, ale nie musi być tym, czego chcesz. Dla poniższego fragmentu kodu, zakładam, że zawsze chcesz dane zmiennoprzecinkowe. (Jeśli nie, to w rzeczywistości jest to prostsze.)
Postaram się dodać więcej wyjaśnień później wieczorem (to raczej gęsty kod).
Podsumowując, Funkcja interp3
, którą posiadam, jest bardziej złożona, niż może być potrzebna do Twoich dokładnych celów. Howver, powinno mniej więcej odwzorowywać zachowanie interp3
jak I zapamiętaj to (ignorując funkcję "zooming" interp3(data, zoom_factor)
, którą scipy.ndimage.zoom
obsługuje.)
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()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-17 22:28:39
Pytanie jest stare, ale myślę, że wymaga wyjaśnienia, ponieważ nikt nie zauważył, że żądana operacja (interpolacja trójliniowa ) może być łatwo zaimplementowana od podstaw przy konsekwentnej oszczędności czasu obliczeniowego (około 10 razy szybciej) w.r.t. scipy.interpolate
'S RegularGridInterpolator
.
Kod
import numpy as np
from itertools import product
def trilinear_interpolation(x_volume, y_volume, z_volume, volume, x_needed, y_needed, z_needed):
"""
Trilinear interpolation (from Wikipedia)
:param x_volume: x points of the volume grid
:type crack_type: list or numpy.ndarray
:param y_volume: y points of the volume grid
:type crack_type: list or numpy.ndarray
:param x_volume: z points of the volume grid
:type crack_type: list or numpy.ndarray
:param volume: volume
:type crack_type: list or numpy.ndarray
:param x_needed: desired x coordinate of volume
:type crack_type: float
:param y_needed: desired y coordinate of volume
:type crack_type: float
:param z_needed: desired z coordinate of volume
:type crack_type: float
:return volume_needed: desired value of the volume, i.e. volume(x_needed, y_needed, z_needed)
:type volume_needed: float
"""
# dimensinoal check
if np.shape(volume) != (len(x_volume), len(y_volume), len(z_volume)):
raise ValueError(f'dimension mismatch, volume must be a ({len(x_volume)}, {len(y_volume)}, {len(z_volume)}) list or numpy.ndarray')
# check of the indices needed for the correct control volume definition
i = searchsorted(x_volume, x_needed)
j = searchsorted(y_volume, y_needed)
k = searchsorted(z_volume, z_needed)
# control volume definition
control_volume_coordinates = np.array(
[[x_volume[i - 1], y_volume[j - 1], z_volume[k - 1]], [x_volume[i], y_volume[j], z_volume[k]]])
xd = (np.array([x_needed, y_needed, z_needed]) - control_volume_coordinates[0]) / (control_volume_coordinates[1] - control_volume_coordinates[0])
# interpolation along x
c2 = [[0, 0], [0, 0]]
for m, n in product([0, 1], [0, 1]):
c2[m][n] = volume[i - 1][j - 1 + m][k - 1 + n] * (1 - xd[0]) + volume[i][j - 1 + m][k - 1 + n] * xd[0]
# interpolation along y
c1 = [0, 0]
c1[0] = c2[0][0] * (1 - xd[1]) + c2[1][0] * xd[1]
c1[1] = c2[0][1] * (1 - xd[1]) + c2[1][1] * xd[1]
# interpolation along z
volume_needed = c1[0] * (1 - xd[2]) + c1[1] * xd[2]
return volume_needed
def searchsorted(l, x):
for i in l:
if i >= x: break
return l.index(i)
from scipy.interpolate import RegularGridInterpolator
def trilin_interp_regular_grid(x_volume, y_volume, z_volume, volume, x_needed, y_needed, z_needed):
# dimensinoal check
if np.shape(volume) != (len(x_volume), len(y_volume), len(z_volume)):
raise ValueError(f'dimension mismatch, volume must be a ({len(x_volume)}, {len(y_volume)}, {len(z_volume)}) list or numpy.ndarray')
# trilinear interpolation on a regular grid
fn = RegularGridInterpolator((x_volume,y_volume,z_volume), volume)
volume_needed = fn(np.array([x_needed, y_needed, z_needed]))
return volume_needed
Przykład
import numpy as np
import time
the_volume = np.array(
[[[0.902, 0.985, 1.12, 1.267, 1.366],
[0.822, 0.871, 0.959, 1.064, 1.141],
[0.744, 0.77, 0.824, 0.897, 0.954],
[0.669, 0.682, 0.715, 0.765, 0.806],
[0.597, 0.607, 0.631, 0.667, 0.695]],
[[1.059, 1.09, 1.384, 1.682, 1.881],
[0.948, 0.951, 1.079, 1.188, 1.251],
[0.792, 0.832, 0.888, 0.940, 0.971],
[0.726, 0.733, 0.754, 0.777, 0.792],
[0.642, 0.656, 0.675, 0.691, 0.700]]])
x_needed = np.linspace(100, 1000, 2)
y_needed = np.linspace(0.3, 1, 3)
z_needed = np.linspace(0, 1, 3)
start = time.time()
manual_trilint = []
for x in x_needed:
for y in y_needed:
for z in z_needed:
manual_trilint.append(trilinear_interpolation([100, 1000], [0.2, 0.4, 0.6, 0.8, 1], [0, 0.2, 0.5, 0.8, 1], the_volume, x, y, z))
end = time.time()
print(end - start)
start = time.time()
auto_trilint = []
for x in x_needed:
for y in y_needed:
for z in z_needed:
auto_trilint.append(trilin_interp_regular_grid([100, 1000], [0.2, 0.4, 0.6, 0.8, 1], [0, 0.2, 0.5, 0.8, 1], the_volume, x, y, z))
end = time.time()
print(end - start)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-29 16:17:21