不规则网格上的插值

Posted

技术标签:

【中文标题】不规则网格上的插值【英文标题】:Interpolation over an irregular grid 【发布时间】:2011-03-15 14:49:16 【问题描述】:

所以,我有三个 numpy 数组,它们在网格上存储纬度、经度和一些属性值——也就是说,我有 LAT(y,x)、LON(y,x) 和温度 T( y,x),对于 x 和 y 的某些限制。网格不一定是规则的——事实上,它是三极的。

然后我想将这些属性(温度)值内插到一组不同的纬度/经度点(存储为 lat1(t)、lon1(t),大约 10,000 吨...),这些点不落在实际的网格点。我已经尝试过 matplotlib.mlab.griddata,但这需要的时间太长了(毕竟它并不是为我正在做的事情而设计的)。我也尝试过 scipy.interpolate.interp2d,但出现 MemoryError(我的网格大约为 400x400)。

有没有一种巧妙的,最好是快速的方法来做到这一点?我不禁认为答案很明显......谢谢!

【问题讨论】:

标题中的“不规则网格”让我有点失望。您有一个恰好分布在空间中的点样本,但您没有matplotlib.org/examples/pylab_examples/tripcolor_demo.html 中的网格结构您的数据是分散在一个字段中的点,您可以假设它有些平滑。可以使用 matplotlib.tri matplotlib.org/api/tri_api.html 对不规则或非结构化网格或网格进行插值,以考虑场中的不连续性。 【参考方案1】:

尝试反距离加权和 scipy.spatial.KDTree SO中描述的 inverse-distance-weighted-idw-interpolation-with-python。 Kd-trees 在 2d 3d 中很好地工作......,反距离加权是平滑和局部的, 并且 k= 最近邻居的数量可以根据速度/准确性进行权衡。

【讨论】:

你,我的朋友,是个天才。 KDTree 课程很棒!正是我需要的...... 我在使用 vanilla 逆权重时遇到了一些麻烦。发现当样本点在点簇之外时,它有一些严重的伪影。我通过将线性近似(而不是常数近似)拟合到 N 最近邻的加权数据来解决这个问题。这在相同的搜索量下产生了相当不错的结果,只是求解 NxN 线性系统的开销。 @Michael,你的数据是 2d 的,有多分散,Nnear 是什么?你能举一个行为不端的距离和价值观的例子吗?例如距离 1 1 1 1 1 10,值 1 1 1 1 1 10 => 插值 (6 / 5.1) = 1.18。另外,NxN ?在 2d 中,将平面 ax + by + c 拟合到 N 个点(权重为 1/dist)是 numpy.linalg .lstsq Nx3 或 .solve 3x3 。 我的数据是 3D,但即使是 1D 也会出现问题。使用线性数据 (1,1) (2,2),(3,3) 取 N=3,在 2.5 处采样,您会得到大约 2.3 的结果(低估 10%)。如果我们估计为 3.5,情况会更糟,产生接近 2.5 而不是“真实” 3.5 的值。有人会说我们现在是在做外推而不是插值,但如果我们的数据点在 1,2,3,10 那么 1,2,3 仍然是最接近 3.5 的三个点......我们最终会得到同样的结果。这就是我所说的集群之外的值。拟合一条线给出了“正确”的结果——至少对于我的数据而言【参考方案2】:

如果您对此感兴趣,有一个nice inverse distance example by Roger Veciana i Rovira 以及一些使用 GDAL 写入 geotiff 的代码。

这对于常规网格来说是粗略的,但假设您首先使用 pyproj 或其他工具将数据投影到像素网格,同时要小心您的数据使用什么投影。

他的算法和示例脚本的副本

from math import pow  
from math import sqrt  
import numpy as np  
import matplotlib.pyplot as plt  
  
def pointValue(x,y,power,smoothing,xv,yv,values):  
    nominator=0  
    denominator=0  
    for i in range(0,len(values)):  
        dist = sqrt((x-xv[i])*(x-xv[i])+(y-yv[i])*(y-yv[i])+smoothing*smoothing);  
        #If the point is really close to one of the data points, return the data point value to avoid singularities  
        if(dist<0.0000000001):  
            return values[i]  
        nominator=nominator+(values[i]/pow(dist,power))  
        denominator=denominator+(1/pow(dist,power))  
    #Return NODATA if the denominator is zero  
    if denominator > 0:  
        value = nominator/denominator  
    else:  
        value = -9999  
    return value  
  
def invDist(xv,yv,values,xsize=100,ysize=100,power=2,smoothing=0):  
    valuesGrid = np.zeros((ysize,xsize))  
    for x in range(0,xsize):  
        for y in range(0,ysize):  
            valuesGrid[y][x] = pointValue(x,y,power,smoothing,xv,yv,values)  
    return valuesGrid  
      
  
if __name__ == "__main__":  
    power=1  
    smoothing=20  
  
    #Creating some data, with each coodinate and the values stored in separated lists  
    xv = [10,60,40,70,10,50,20,70,30,60]  
    yv = [10,20,30,30,40,50,60,70,80,90]  
    values = [1,2,2,3,4,6,7,7,8,10]  
      
    #Creating the output grid (100x100, in the example)  
    ti = np.linspace(0, 100, 100)  
    XI, YI = np.meshgrid(ti, ti)  
  
    #Creating the interpolation function and populating the output matrix value  
    ZI = invDist(xv,yv,values,100,100,power,smoothing)  
  
  
    # Plotting the result  
    n = plt.normalize(0.0, 100.0)  
    plt.subplot(1, 1, 1)  
    plt.pcolor(XI, YI, ZI)  
    plt.scatter(xv, yv, 100, values)  
    plt.title('Inv dist interpolation - power: ' + str(power) + ' smoothing: ' + str(smoothing))  
    plt.xlim(0, 100)  
    plt.ylim(0, 100)  
    plt.colorbar()  
  
    plt.show() 

【讨论】:

【参考方案3】:

这里有很多选项,哪个最好取决于您的数据... 但是我不知道为您提供开箱即用的解决方案

您说您的输入数据来自三极数据。该数据的结构主要有以下三种情况。

    从三极空间中的 3d 网格采样,投影回 2d LAT、LON 数据。 从三极空间的二维网格中采样,投影到二维 LAT LON 数据中。 三极空间中的非结构化数据投影到二维 LAT LON 数据中

其中最简单的是 2。不是在 LAT LON 空间中插值,而是“只是”将您的点转换回源空间并在那里插值。

另一个适用于 1 和 2 的选项是搜索从三极空间映射以覆盖您的样本点的单元格。 (您可以使用 BSP 或网格类型结构来加快搜索速度)选择一个单元格,然后在其中插入。

最后有一堆非结构化插值选项.. 但它们往往很慢。 我个人最喜欢的是使用最近 N 点的线性插值,找到那些 N 点可以再次通过网格或 BSP 完成。另一个不错的选择是 Delauney 对非结构化点进行三角剖分并在生成的三角形网格上进行插值。

就我个人而言,如果我的网格是案例 1,我会使用非结构化策略,因为我担心必须处理具有重叠投影的单元格的搜索。选择“正确”的单元格会很困难。

【讨论】:

+1: ..对于 BSP 树的提及,通常把我得到的东西比我管理的更重要:-) 你可以通过将每个 BSP 节点集中在其中一个上来形成 BSP新数据点,然后简单地向下钻取以找到所有相邻点。 不错!共识似乎是我将不得不在这方面工作一点,但这没关系。我很喜欢你对 BSP 技术的建议......非常感谢! 案例 3 的一部分可能是您在非结构化网格上定义了一个数据,其中生成的 Delauney 凸包可能不合适。例如。 matplotlib.org/examples/pylab_examples/tripcolor_demo.html 然后在给定的三角形网格上插值可能会很好:matplotlib.org/api/tri_api.html【参考方案4】:

我建议您看看 GRASS(一个开源 GIS 包)插值功能 (http://grass.ibiblio.org/gdp/html_grass62/v.surf.bspline.html)。它不在 python 中,但您可以重新实现它或与 C 代码接口。

【讨论】:

嗯,这当然看起来不错,虽然需要重新实现一些工作!我会调查的。谢谢! 无需重新实现,调用即可。使用 SEXTANTE 工具箱查看 QGIS。【参考方案5】:

我是否认为您的数据网格看起来像这样(红色是旧数据,蓝色是新插值数据)?

alt text http://www.geekops.co.uk/photos/0000-00-02%20%28Forum%20images%29/DataSeparation.png

这可能是一种有点蛮力的方法,但是将现有数据渲染为位图怎么样(opengl 将通过配置正确的选项为您进行简单的颜色插值,并且您可以将数据渲染为三角形,这应该相当快)。然后,您可以在新点的位置对像素进行采样。

或者,您可以对第一组点进行空间排序,然后找到新点周围最近的旧点,并根据到这些点的距离进行插值。

【讨论】:

网格的想法是正确的,虽然我实际上是在跟踪虚拟粒子穿过网格时的属性,所以蓝点看起来更像是面包屑的痕迹:!mesh希望那张照片有效。图像渲染的想法很有趣——我确实有可用的 PIL,所以我可以试一试。谢谢!【参考方案6】:

有一个名为BIVAR的FORTRAN库,非常适合这个问题。通过一些修改,您可以使用 f2py 在 python 中使用它。

来自描述:

BIVAR 是一个 FORTRAN90 库,它对分散的二元数据进行插值,作者是 Hiroshi Akima。

BIVAR 接受一组散布在 2D 中的 (X,Y) 数据点,以及相关的 Z 数据值,并且能够构造与给定数据一致的平滑插值函数 Z(X,Y),并且可以在平面的其他点进行评估。

【讨论】:

以上是关于不规则网格上的插值的主要内容,如果未能解决你的问题,请参考以下文章

使用 Akima 包线性插值:interp 用于非常不规则的网格

python对不规则(x,y,z)网格进行4D插值

网格数据的快速插值

Python用线性插值正则化不规则时间序列

Pandas 使用其他不规则时间列表重新采样和插值不规则时间序列

寻找最长路径网格