我非常沮丧,因为几个小时后我似乎无法在python中做一个看似简单的3D插值。在Matlab中我所要做的就是
Vi = interp3(x,y,z,V,xi,yi,zi)
使用scipy的ndimage.map_coordinate或其他numpy方法的确切等价是什么?
由于
答案 0 :(得分:19)
在scipy 0.14或更高版本中,有一个与interp3
非常相似的新函数scipy.interpolate.RegularGridInterpolator
。
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,6,8)
和(3,5,7)
的值。
SCIPY CODE:
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,...)。
除此之外,两者相似且同样易于使用。
答案 1 :(得分:4)
完全等同于MATLAB的interp3
将使用scipy的interpn
进行一次性插值:
import numpy as np
from scipy.interpolate import interpn
Vi = interpn((x,y,z), V, np.array([xi,yi,zi]).T)
MATLAB和scipy的默认方法是线性插值,可以使用method
参数进行更改。请注意,interpn
仅支持3维及以上的线性和最近邻插值,不像MATLAB支持三次和样条插值。
在同一网格上进行多次插值调用时,最好使用插值对象RegularGridInterpolator
,如接受的答案above。 interpn
在内部使用RegularGridInterpolator
。
答案 2 :(得分:2)
基本上,ndimage.map_coordinates
在“索引”坐标(a.k.a。“体素”或“像素”坐标)中工作。它的界面起初看起来有点笨拙,但它确实给你一个灵活的很多。
如果要指定类似于matlab的interp3
的插值坐标,则需要将输入坐标转换为“索引”坐标。
还有额外的皱纹map_coordinates
总是保留输出中输入数组的dtype。如果插入整数数组,您将得到整数输出,这可能是您想要的,也可能不是。对于下面的代码片段,我假设您总是想要浮点输出。 (如果你不这样做,那实际上更简单。)
我将在今晚晚些时候尝试添加更多解释(这是相当密集的代码)。
总而言之,我所拥有的interp3
函数比您确切需要的函数更复杂。但是,它应该或多或少地复制interp3
的行为,因为我记得它(忽略了interp3(data, zoom_factor)
处理的scipy.ndimage.zoom
的“缩放”功能。)
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 :(得分:0)
这个问题很老,但是我认为它需要澄清,因为没有人指出所请求的操作(trilinear interpolation)可以很容易地从头开始实现,并且可以节省一贯的计算时间(快10倍左右)。 scipy.interpolate
的{{1}}。
代码
RegularGridInterpolator
示例
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