在不规则网格上插值

时间:2010-07-13 23:37:19

标签: python numpy scipy interpolation

所以,我有三个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)。

有没有任何光滑的,最好快速的方法吗?我不禁想到答案显而易见......谢谢!!

6 个答案:

答案 0 :(得分:9)

尝试反距离加权和组合 scipy.spatial.KDTree 在SO中描述 inverse-distance-weighted-idw-interpolation-with-pythonKd-trees 在2d 3d中很好地工作...,反距离加权是平滑的和局部的, 并且k =最近邻居的数量可以改变以折衷速度/准确度。

答案 1 :(得分:4)

有一个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() 

答案 2 :(得分:1)

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

您说您的输入数据来自三极数据。关于如何构建这些数据有三个主要案例。

  1. 从三极空间的三维网格中采样,投射回2d LAT,LON数据。
  2. 从三极空间的2d网格中采样,投影到2d LAT LON数据中。
  3. 三极空间中的非结构化数据投影到2d LAT LON数据
  4. 最简单的是2.不是在LAT LON空间内插,而是“只是”将你的点转换回源空间并插入那里。

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

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

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

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

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

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

答案 5 :(得分:0)

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

来自说明:

  

BIVAR是一个FORTRAN90库,由Hiroshi Akima插入分散的双变量数据。

     

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