如果您有完整的信息数组进行插值,线性插值并不难。只是稍微耗费一些时间,但如果您可以将数组适配到RAM中,那么只需要几秒钟的时间即可完成。
诀窍在于线性插值可以逐个轴进行。因此,对于每个轴:
- 找到要进行插值的最近点
- 找到这些点之间的相对距离(
d = 0..1),例如,如果您有540和550 nm,并且您想在548 nm处拥有数据,则
d = 0.8。
- 对所有轴重复此过程;每一轮都会将维度数量减少一个。
就像这样:
import numpy as np
def ndim_interp(A, ranges, p):
for i in range(A.ndim):
if p[i] <= ranges[i][0]:
A = A[0]
continue
if p[i] >= ranges[i][-1]:
A = A[-1]
continue
right = np.searchsorted(ranges[i], p[i])
left = right - 1
d = (p[i] - ranges[i][left]) / (ranges[i][right] - ranges[i][left])
A = (1 - d) * A[left] + d * A[right]
return A
作为一个例子:
arng = [1, 2, 3]
brng = [100, 200]
crng = [540, 550, 560]
A = np.array([
[[1., 2., 3.], [2., 3., 4.]],
[[0.5, 1.5, 2.], [1.5, 2.0, 3.0]],
[[0., 0.5, 1.], [1., 1., 1.]]])
print ndim_interp(A, (arng, brng, crng), (2.3, 130., 542.))
如果您想要做更复杂的事情(立方样条等),则可以使用
scipy.ndimage.interpolation.map_coordinates
。那么配方如下所示:
import numpy as np
import scipy.ndimage.interpolation
def ndim_interp(A, ranges, p):
p_arr = []
for i in range(A.ndim):
if p[i] <= ranges[i][0]:
p_arr.append(0)
continue
if p[i] >= ranges[i][-1]:
p_arr.append(A.shape[i] - 1)
continue
right = np.searchsorted(ranges[i], p[i])
left = right - 1
d = (p[i] - ranges[i][left]) / (ranges[i][right] - ranges[i][left])
p_arr.append(left + d)
coords = np.array(p_arr).reshape(A.ndim, -1)
return scipy.ndimage.interpolation.map_coordinates(A, coords, order=1, mode='nearest')[0]
当然,如果使用最简单的设置(
order=1
等于线性插值),那么使用它是没有意义的,但即使是采用三次样条插值,编写自己的插值算法也并不简单。
当然,如果你的网格在所有方向上都是等距的,那么代码会更简单,因为不需要先进行正确位置的插值(一个简单的除法就可以了)。
cKDTree
... - user2379410;)
但是仔细想想,我觉得使用scipy.interpolate.RegularGridInterpolator
更好。使用values
来作为您的 LUT,points
则是各自维度上的np.arange
的元组(每个维度的大小)。或者...更好的方法是使用您已经有的“标签”。如果您愿意,我可以给出一个例子。 - user2379410