Speedup scipy griddata for multiple interpolations between two irregular grids

前端 未结 4 1096
一个人的身影
一个人的身影 2020-12-01 00:11

I have several values that are defined on the same irregular grid (x, y, z) that I want to interpolate onto a new grid (x1, y1, z1). i.e., I have <

4条回答
  •  孤城傲影
    2020-12-01 00:56

    Great thanks to Jaime for his solution (even if I don't really understand how the barycentric computation is done ...)

    Here you will find an example adapted from his case in 2D :

    import scipy.interpolate as spint
    import scipy.spatial.qhull as qhull
    import numpy as np
    
    def interp_weights(xy, uv,d=2):
        tri = qhull.Delaunay(xy)
        simplex = tri.find_simplex(uv)
        vertices = np.take(tri.simplices, simplex, axis=0)
        temp = np.take(tri.transform, simplex, axis=0)
        delta = uv - temp[:, d]
        bary = np.einsum('njk,nk->nj', temp[:, :d, :], delta)
        return vertices, np.hstack((bary, 1 - bary.sum(axis=1, keepdims=True)))
    
    def interpolate(values, vtx, wts):
        return np.einsum('nj,nj->n', np.take(values, vtx), wts)
    
    m, n = 101,201
    mi, ni = 1001,2001
    
    [Y,X]=np.meshgrid(np.linspace(0,1,n),np.linspace(0,2,m))
    [Yi,Xi]=np.meshgrid(np.linspace(0,1,ni),np.linspace(0,2,mi))
    
    xy=np.zeros([X.shape[0]*X.shape[1],2])
    xy[:,0]=Y.flatten()
    xy[:,1]=X.flatten()
    uv=np.zeros([Xi.shape[0]*Xi.shape[1],2])
    uv[:,0]=Yi.flatten()
    uv[:,1]=Xi.flatten()
    
    values=np.cos(2*X)*np.cos(2*Y)
    
    #Computed once and for all !
    vtx, wts = interp_weights(xy, uv)
    valuesi=interpolate(values.flatten(), vtx, wts)
    valuesi=valuesi.reshape(Xi.shape[0],Xi.shape[1])
    print "interpolation error: ",np.mean(valuesi-np.cos(2*Xi)*np.cos(2*Yi))  
    print "interpolation uncertainty: ",np.std(valuesi-np.cos(2*Xi)*np.cos(2*Yi))  
    

    It is possible to applied image transformation such as image mapping with a udge speed-up

    You can't use the same function definition as the new coordinates will change at every iteration but you can compute triangulation Once for all.

    import scipy.interpolate as spint
    import scipy.spatial.qhull as qhull
    import numpy as np
    import time
    
    # Definition of the fast  interpolation process. May be the Tirangulation process can be removed !!
    def interp_tri(xy):
        tri = qhull.Delaunay(xy)
        return tri
    
    
    def interpolate(values, tri,uv,d=2):
        simplex = tri.find_simplex(uv)
        vertices = np.take(tri.simplices, simplex, axis=0)
        temp = np.take(tri.transform, simplex, axis=0)
        delta = uv- temp[:, d]
        bary = np.einsum('njk,nk->nj', temp[:, :d, :], delta)  
        return np.einsum('nj,nj->n', np.take(values, vertices),  np.hstack((bary, 1.0 - bary.sum(axis=1, keepdims=True))))
    
    m, n = 101,201
    mi, ni = 101,201
    
    [Y,X]=np.meshgrid(np.linspace(0,1,n),np.linspace(0,2,m))
    [Yi,Xi]=np.meshgrid(np.linspace(0,1,ni),np.linspace(0,2,mi))
    
    xy=np.zeros([X.shape[0]*X.shape[1],2])
    xy[:,1]=Y.flatten()
    xy[:,0]=X.flatten()
    uv=np.zeros([Xi.shape[0]*Xi.shape[1],2])
    # creation of a displacement field
    uv[:,1]=0.5*Yi.flatten()+0.4
    uv[:,0]=1.5*Xi.flatten()-0.7
    values=np.zeros_like(X)
    values[50:70,90:150]=100.
    
    #Computed once and for all !
    tri = interp_tri(xy)
    t0=time.time()
    for i in range(0,100):
      values_interp_Qhull=interpolate(values.flatten(),tri,uv,2).reshape(Xi.shape[0],Xi.shape[1])
    t_q=(time.time()-t0)/100
    
    t0=time.time()
    values_interp_griddata=spint.griddata(xy,values.flatten(),uv,fill_value=0).reshape(values.shape[0],values.shape[1])
    t_g=time.time()-t0
    
    print "Speed-up:", t_g/t_q
    print "Mean error: ",(values_interp_Qhull-values_interp_griddata).mean()
    print "Standard deviation: ",(values_interp_Qhull-values_interp_griddata).std()
    

    On my laptop the speed-up is between 20 and 40x !

    Hope that can help someone

提交回复
热议问题