如何在Python中执行双线性插值

问题描述 投票:21回答:6

我想使用python执行blinear插值。我要对高度进行插值的示例gps点是:

B = 54.4786674627
L = 17.0470721369

使用具有已知坐标和高度值的四个相邻点:

n = [(54.5, 17.041667, 31.993), (54.5, 17.083333, 31.911), (54.458333, 17.041667, 31.945), (54.458333, 17.083333, 31.866)]

z01    z11

     z
z00    z10

这是我的原始尝试:

import math
z00 = n[0][2]
z01 = n[1][2]
z10 = n[2][2]
z11 = n[3][2]
c = 0.016667 #grid spacing
x0 = 56 #latitude of origin of grid
y0 = 13 #longitude of origin of grid
i = math.floor((L-y0)/c)
j = math.floor((B-x0)/c)
t = (B - x0)/c - j
z0 = (1-t)*z00 + t*z10
z1 = (1-t)*z01 + t*z11
s = (L-y0)/c - i
z = (1-s)*z0 + s*z1

其中z0和z1

z01  z0  z11

     z
z00  z1   z10

我得到31.964,但从其他软件得到31.961。我的脚本正确吗?您可以提供另一种方法吗?

python math coordinates interpolation geo
6个回答
41
投票
这是您可以使用的可重用功能。它包括doctest和数据验证:

def bilinear_interpolation(x, y, points): '''Interpolate (x,y) from values associated with four points. The four points are a list of four triplets: (x, y, value). The four points can be in any order. They should form a rectangle. >>> bilinear_interpolation(12, 5.5, ... [(10, 4, 100), ... (20, 4, 200), ... (10, 6, 150), ... (20, 6, 300)]) 165.0 ''' # See formula at: http://en.wikipedia.org/wiki/Bilinear_interpolation points = sorted(points) # order points by x, then by y (x1, y1, q11), (_x1, y2, q12), (x2, _y1, q21), (_x2, _y2, q22) = points if x1 != _x1 or x2 != _x2 or y1 != _y1 or y2 != _y2: raise ValueError('points do not form a rectangle') if not x1 <= x <= x2 or not y1 <= y <= y2: raise ValueError('(x, y) not within the rectangle') return (q11 * (x2 - x) * (y2 - y) + q21 * (x - x1) * (y2 - y) + q12 * (x2 - x) * (y - y1) + q22 * (x - x1) * (y - y1) ) / ((x2 - x1) * (y2 - y1) + 0.0)

您可以通过添加以下代码来运行测试代码:

if __name__ == '__main__': import doctest doctest.testmod()

在数据集上运行插值将产生:

>>> n = [(54.5, 17.041667, 31.993), (54.5, 17.083333, 31.911), (54.458333, 17.041667, 31.945), (54.458333, 17.083333, 31.866), ] >>> bilinear_interpolation(54.4786674627, 17.0470721369, n) 31.95798688313631


9
投票
不确定这是否有帮助,但是使用scipy进行线性插值时会得到不同的值:

>>> import numpy as np >>> from scipy.interpolate import griddata >>> n = np.array([(54.5, 17.041667, 31.993), (54.5, 17.083333, 31.911), (54.458333, 17.041667, 31.945), (54.458333, 17.083333, 31.866)]) >>> griddata(n[:,0:2], n[:,2], [(54.4786674627, 17.0470721369)], method='linear') array([ 31.95817681])


5
投票
[受here的启发,我想到了以下代码段。该API经过优化,可多次重复使用同一张表:

from bisect import bisect_left class BilinearInterpolation(object): """ Bilinear interpolation. """ def __init__(self, x_index, y_index, values): self.x_index = x_index self.y_index = y_index self.values = values def __call__(self, x, y): # local lookups x_index, y_index, values = self.x_index, self.y_index, self.values i = bisect_left(x_index, x) - 1 j = bisect_left(y_index, y) - 1 x1, x2 = x_index[i:i + 2] y1, y2 = y_index[j:j + 2] z11, z12 = values[j][i:i + 2] z21, z22 = values[j + 1][i:i + 2] return (z11 * (x2 - x) * (y2 - y) + z21 * (x - x1) * (y2 - y) + z12 * (x2 - x) * (y - y1) + z22 * (x - x1) * (y - y1)) / ((x2 - x1) * (y2 - y1))

您可以这样使用它:

table = BilinearInterpolation( x_index=(54.458333, 54.5), y_index=(17.041667, 17.083333), values=((31.945, 31.866), (31.993, 31.911)) ) print(table(54.4786674627, 17.0470721369)) # 31.957986883136307

此版本没有错误检查,如果尝试在索引边界(或更高)使用它,将会遇到麻烦。有关代码的完整版本,包括错误检查和可选的外推,请查看here

3
投票
您也可以参考interp function in matplotlib

2
投票
我认为执行floor函数的要点是,通常您希望插入一个其坐标位于两个离散坐标之间的值。但是,您似乎已经有了最接近点的实际实际坐标值,这使数学运算变得简单。

z00 = n[0][2] z01 = n[1][2] z10 = n[2][2] z11 = n[3][2] # Let's assume L is your x-coordinate and B is the Y-coordinate dx = n[2][0] - n[0][0] # The x-gap between your sample points dy = n[1][1] - n[0][1] # The Y-gap between your sample points dx1 = (L - n[0][0]) / dx # How close is your point to the left? dx2 = 1 - dx1 # How close is your point to the right? dy1 = (B - n[0][1]) / dy # How close is your point to the bottom? dy2 = 1 - dy1 # How close is your point to the top? left = (z00 * dy1) + (z01 * dy2) # First interpolate along the y-axis right = (z10 * dy1) + (z11 * dy2) z = (left * dx1) + (right * dx2) # Then along the x-axis

从您的示例进行翻译时,可能会有一些错误的逻辑,但是要点是,可以根据每个点与插值目标点​​的距离比其邻近点的距离更近,对每个点进行加权。

0
投票
我建议以下解决方案:
© www.soinside.com 2019 - 2024. All rights reserved.