简体   繁体   English

python中的平滑广义二维线性插值

[英]smooth, generalised 2D linear interpolation in python

I'm trying to find a method of linear interpolation in 2D over a regular grid using python, but each proposed type in scipy seems to have it's disadvantages. 我正在尝试使用python在常规网格上找到2D线性插值的方法,但是scipy中的每个建议的类型似乎都有其缺点。

My aim is basically: 我的目标基本上是:

  • Have smooth linearly interpolated data over a regular grid, or as close as possible 在规则网格上或尽可能接近的地方获得平滑的线性插值数据
  • The original data can be at arbitrary locations 原始数据可以在任意位置
  • (optional) Linearly extrapolate to the edges (可选)线性外推到边缘

But all the functions seem to have problems with this: 但是所有功能似乎都与此有关:

  • Functions like griddata, interp2d, LinearNDInterpolator appear to create triangles and interpolate within them, creating a bunch of hard lines/creases that I can't have. 诸如griddata,interp2d,LinearNDInterpolator之类的功能似乎可以创建三角形并在其中进行插值,从而创建了一堆我没有的硬线/折痕。
  • Rbf seems at first to do exactly what I want, but when presented with planes that are flat, it generates an interpolation based on some kind of sphere, creating a curved surface. Rbf乍看起来似乎完全可以满足我的要求,但是当呈现平面时,Rbf会基于某种球体生成插值,从而创建曲面。

If Rbf would simply interpolate a flat plane as a flat plane using the linear setting, as would be expected, it'd be perfect. 如果Rbf像预期的那样使用线性设置简单地将平面插值为平面,那将是完美的。

Are there any ideas on how to achieve this, or if there's another function that does what I'm after? 是否有关于如何实现此目标的想法,或者是否还有其他功能可以满足我的需求? I've attached a basic example below. 我在下面附加了一个基本示例。

import numpy as np
from scipy import interpolate
import matplotlib.pyplot as plt

#create some objects to store data
x=np.empty((2,2))
y=np.empty((2,2))
f_shape=(100,100,100)

#generate coordinates
x[0, :] =  0
x[-1, :] = f_shape[0]
y[:, 0] = 0
y[:, -1] = f_shape[1]

#--------constant height----------
z=np.full((2,2),50)

#create interpolation function and interpolate across grid
interp=interpolate.Rbf(x,y,z,function='linear')
grid=np.mgrid[0:f_shape[0],0:f_shape[1]]
result=interp(grid[0,:,:],grid[1,:,:])

plt.imshow(result) #incorrect curved surface from constant height!!!

#--------random heights-----------
z=np.random.uniform(25,75,(2,2))

#create interpolation function and interpolate across grid
interp=interpolate.Rbf(x,y,z,function='linear')
grid=np.mgrid[0:f_shape[0],0:f_shape[1]]
result=interp(grid[0,:,:],grid[1,:,:])

plt.imshow(result) #Apparently nice smooth linear-ish interpolation

Incorrect curved surface from constant height: 恒定高度的曲面不正确:

高度恒定时曲面不正确

Apparently nice smooth linear-ish interpolation: 显然不错的平滑线性ish插值:

显然不错的平滑线性ish插值

Scipy's griddata works just fine: Scipy的griddata可以正常工作:

import numpy as np
from scipy import interpolate as intp
import matplotlib.pyplot as plt
%matplotlib inline

grid_size = G = 100
height = H = 50

points = np.array([
    (0, 0),
    (G-1, 0),
    (0, G-1),
    (G-1, G-1)
], dtype=np.float32)

gy, gx = np.mgrid[:G, :G]
result = intp.griddata(points, np.full(points.shape[0], H), (gy, gx))

And the plot: 和剧情:

plt.imshow(result, interpolation='none')
plt.colorbar()

在此处输入图片说明

And just to be sure: 只是要确保:

>>> np.allclose(result, 50)
True

I've managed to write a function that suits my purpose. 我设法编写了一个适合我目的的函数。 It interpolates (fills in) a plane from a grid of coordinates by interpolating along the grid lines, then interpolating the plane in the x and y directions, and taking the average of the two. 通过沿网格线进行插值,然后在x和y方向上对平面进行插值,并取二者的平均值,可以从坐标网格内插(填充)平面。

It should be possible to speed this up a bit by reshaping the coordinates into a 1D vector, interpolating the plane in one go, then reshaping back into 2D. 应该可以通过将坐标重塑为一维矢量,一次插补平面,然后重塑为2D来加快速度。 However this code is certainly fast enough already for reasonable plane sizes. 但是,对于合理的平面尺寸,此代码肯定已经足够快。

Seems to work ok if the coordinates are outside of the plane too. 如果坐标也位于平面之外,则似乎可以正常工作。 Extrapolation also works if the grid is approximately regular. 如果网格近似规则,则外推法也适用。 It'll extrapolate regardless but you'll start to see some sharp creases away from the edge as the grid irregularity increases. 它将进行推断,但是随着网格不规则性的增加,您将开始看到边缘出现一些明显的折痕。

Here's the code. 这是代码。 An example is provided in the docstring. 文档字符串中提供了一个示例。

def interlin2d(x,y,z,fsize):
    """
    Linear 2D interpolation of a plane from arbitrary gridded points.

    :param x: 2D array of x coordinates
    :param y: 2D array of y coordinates
    :param z: 2D array of z coordinates
    :param fsize: Tuple of x and y dimensions of plane to be interpolated.
    :return: 2D array with interpolated plane.

    This function works by interpolating lines along the grid point in both dimensions,
    then interpolating the plane area in both the x and y directions, and taking the 
    average of the two. Result looks like a series of approximately curvilinear quadrilaterals.

    Note, the structure of the x,y,z coordinate arrays are such that the index of the coordinates
    indicates the relative physical position of the point with respect to the plane to be interpoalted.

    Plane is allowed to be a subset of the range of grid coordinates provided. 
    Extrapolation is accounted for, however sharp creases will start to appear
    in the extrapolated region as the grid of coordinates becomes increasingly irregular.

    Scipy's interpolation function is used for the grid lines as it allows for proper linear extrapolation. 
    However Numpy's interpolation function is used for the plane itself as it is robust against gridlines
    that overlap (divide by zero distance).


    Example:
    #set up number of grid lines and size of field to interpolate
    nlines=[3,3]
    fsize=(100,100,100)

    #initialize the coordinate arrays
    x=np.empty((nlines[0],nlines[1]))
    y=np.empty((nlines[0],nlines[1]))
    z=np.random.uniform(0.25*fsize[2],0.75*fsize[2],(nlines[0],nlines[1]))

    #set random ordered locations for the interior points
    spacings=(fsize[0]/(nlines[0]-2),fsize[1]/(nlines[1]-2))
    for k in range(0, nlines[0]):
        for l in range(0, nlines[1]):
            x[k, l] = round(random.uniform(0, 1) * (spacings[0] - 1) + spacings[0] * (k - 1) + 1)
            y[k, l] = round(random.uniform(0, 1) * (spacings[1] - 1) + spacings[1] * (l - 1) + 1)

    #fix the edge points to the edge
    x[0, :] = 0
    x[-1, :] = fsize[1]-1
    y[:, 0] = 0
    y[:, -1] = fsize[0]-1

    field = interlin2d(x,y,z,fsize)
    """

    from scipy.interpolate import interp1d
    import numpy as np

    #number of lines in grid in x and y directions
    nsegx=x.shape[0]
    nsegy=x.shape[1]

    #lines along the grid points to be interpolated, x and y directions
    #0 indicates own axis, 1 is height (z axis)
    intlinesx=np.empty((2,nsegy,fsize[0]))
    intlinesy=np.empty((2,nsegx,fsize[1]))

    #account for the first and last points being fixed to the edges
    intlinesx[0,0,:]=0
    intlinesx[0,-1,:]=fsize[1]-1
    intlinesy[0,0,:]=0
    intlinesy[0,-1,:]=fsize[0]-1

    #temp fields for interpolation in x and y directions
    tempx=np.empty((fsize[0],fsize[1]))
    tempy=np.empty((fsize[0],fsize[1]))

    #interpolate grid lines in the x direction
    for k in range(nsegy):
        interp = interp1d(x[:,k], y[:,k], kind='linear', copy=False, fill_value='extrapolate')
        intlinesx[0,k,:] = np.round(interp(range(fsize[0])))
        interp = interp1d(x[:, k], z[:, k], kind='linear', copy=False, fill_value='extrapolate')
        intlinesx[1, k, :] = interp(range(fsize[0]))
    intlinesx[0,:,:].sort(0)

    # interpolate grid lines in the y direction
    for k in range(nsegx):
        interp = interp1d(y[k, :], x[k, :], kind='linear', copy=False, fill_value='extrapolate')
        intlinesy[0, k, :] = np.round(interp(range(fsize[1])))
        interp = interp1d(y[k, :], z[k, :], kind='linear', copy=False, fill_value='extrapolate')
        intlinesy[1, k, :] = interp(range(fsize[1]))
    intlinesy[0,:,:].sort(0)

    #interpolate plane in x direction
    for k in range(fsize[1]):
        tempx[k, :] = np.interp(range(fsize[1]),intlinesx[0,:,k], intlinesx[1,:,k])

    #interpolate plane in y direction
    for k in range(fsize[1]):
        tempy[:, k] = np.interp(range(fsize[0]), intlinesy[0, :, k], intlinesy[1, :, k])

    return (tempx+tempy)/2

Example of interpolation based on 9 points (shown as red dots) 基于9点的插值示例(显示为红点)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM