【问题标题】:Very slow interpolation using `scipy.interpolate.griddata`使用`scipy.interpolate.griddata`进行非常慢的插值
【发布时间】:2015-04-21 05:35:18
【问题描述】:

当我尝试将“几乎”规则网格化的数据插入地图坐标以便地图和数据都可以用matplotlib.pyplot.imshow 绘制时,scipy.interpolate.griddata 的性能极其缓慢,因为matplotlib.pyplot.pcolormesh 花费的时间太长而且不会与alpha 相处融洽。

最好展示一个例子(输入文件可以下载here):

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

map_extent = (34.4, 36.2, 30.6, 33.4)
# data corners:
lon = np.array([[34.5,        34.83806236],
                [35.74547079, 36.1173923]])
lat = np.array([[30.8,        33.29936152],
                [30.67890411, 33.17826563]])

# load saved files
topo = np.load('topo.npy')
lons = np.load('lons.npy')
lats = np.load('lats.npy')
data = np.load('data.npy')

# get max res of data
dlon = abs(np.array(np.gradient(lons))).max()
dlat = abs(np.array(np.gradient(lats))).max()

# interpolate the data to the extent of the map
loni,lati = np.meshgrid(np.arange(map_extent[0], map_extent[1]+dlon, dlon),
                        np.arange(map_extent[2], map_extent[3]+dlat, dlat))
zi = griddata((lons.flatten(),lats.flatten()),
              data.flatten(), (loni,lati), method='linear')

绘图:

fig, (ax1,ax2) = plt.subplots(1,2)
ax1.axis(map_extent)
ax1.imshow(topo,extent=extent,cmap='Greys')

ax2.axis(map_extent)
ax2.imshow(topo,extent=extent,cmap='Greys')

ax1.imshow(zi, vmax=0.1, extent=extent, alpha=0.5, origin='lower')
ax1.plot(lon[0],lat[0], '--k', lw=3, zorder=10)
ax1.plot(lon[-1],lat[-1], '--k', lw=3, zorder=10)
ax1.plot(lon.T[0],lat.T[0], '--k', lw=3, zorder=10)
ax1.plot(lon.T[-1],lat.T[-1], '--k', lw=3, zorder=10)


ax2.pcolormesh(lons,lats,data, alpha=0.5)
ax2.plot(lon[0],lat[0], '--k', lw=3, zorder=10)
ax2.plot(lon[-1],lat[-1], '--k', lw=3, zorder=10)
ax2.plot(lon.T[0],lat.T[0], '--k', lw=3, zorder=10)
ax2.plot(lon.T[-1],lat.T[-1], '--k', lw=3, zorder=10)

结果:

注意,这不能通过简单地用仿射变换旋转数据来完成。

griddata 每次调用我的真实数据需要 80 多秒,pcolormesh 需要更长的时间(超过 2 分钟!)。我已经查看了 Jaimi 的回答 here 和 Joe Kington 的回答 here,但我无法找到一种让它为我工作的方法。

我所有的数据集都具有完全相同的lonslats,所以基本上我需要将它们映射一次到地图的坐标,并对数据本身应用相同的转换。问题是我该怎么做?

【问题讨论】:

    标签: python numpy matplotlib scipy


    【解决方案1】:

    在长时间忍受scipy.interpolate.griddata 极其缓慢的性能之后,我决定放弃griddata,转而使用OpenCV 进行图像转换。具体来说,Perspective Transformation

    所以对于上面的例子,上面问题中的那个,你可以获得输入文件here,这是一段需要 1.1 毫秒的代码,而不是需要重新网格化部分的 692 毫秒上面的例子。

    import cv2
    new_data = data.T[::-1]
    
    # calculate the pixel coordinates of the
    # computational domain corners in the data array
    w,e,s,n = map_extent
    dx = float(e-w)/new_data.shape[1]
    dy = float(n-s)/new_data.shape[0]
    x = (lon.ravel()-w)/dx
    y = (n-lat.ravel())/dy
    
    computational_domain_corners = np.float32(zip(x,y))
    
    data_array_corners = np.float32([[0,new_data.shape[0]],
                                     [0,0],
                                     [new_data.shape[1],new_data.shape[0]],
                                     [new_data.shape[1],0]])
    
    # Compute the transformation matrix which places
    # the corners of the data array at the corners of
    # the computational domain in data array pixel coordinates
    tranformation_matrix = cv2.getPerspectiveTransform(data_array_corners,
                                                       computational_domain_corners)
    
    # Make the transformation making the final array the same shape
    # as the data array, cubic interpolate the data placing NaN's
    # outside the new array geometry
    mapped_data = cv2.warpPerspective(new_data,tranformation_matrix,
                                      (new_data.shape[1],new_data.shape[0]),
                                      flags=2,
                                      borderMode=0,
                                      borderValue=np.nan)
    

    我看到此解决方案的唯一缺点是数据中的轻微偏移,如附加图像中的非重叠轮廓所示。黑色的重新网格化数据轮廓(可能更准确)和“jet”色阶中的 warpPerspective 数据轮廓。

    目前,我在性能优势的差异中生活得很好,我希望这个解决方案也能帮助其他人。

    有人(不是我……)应该找到一种方法来提高 griddata 的性能 :) 享受吧!

    【讨论】:

      【解决方案2】:

      我使用了 numpy ndimage.map_coordinates。效果很好!

      http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.ndimage.interpolation.map_coordinates.html

      复制自以上链接:

      scipy.ndimage.interpolation.map_coordinates(input, coordinates, output=None, order=3, mode='constant', cval=0.0, prefilter=True)

      通过插值将输入数组映射到新坐标。

      坐标数组用于为输出中的每个点查找输入中的对应坐标。这些坐标处的输入值由请求顺序的样条插值确定。

      输出的形状是通过删除第一个轴从坐标数组的形状导出的。沿第一个轴的数组值是输入数组中找到输出值的坐标。

          from scipy import ndimage
          a = np.arange(12.).reshape((4, 3))
          a
          array([[  0.,   1.,   2.],
                  [  3.,   4.,   5.],
                  [  6.,   7.,   8.],
                  [  9.,  10.,  11.]])
          ndimage.map_coordinates(a, [[0.5, 2], [0.5, 1]], order=1)
          [ 2.  7.]
      

      【讨论】:

      • @user3197748,您能否尝试将您的答案应用到上面给出的示例中?你可以在这里下载文件:dropbox.com/s/m215o0ko304173d/input.zip
      • 对不起,只有在阅读您的代码并尝试运行它时,我才发现使用 scipy.ndimage.interpolation.map_coordinates 是不合适的。但是当我运行你的代码的第一个版本(带有网格数据的那个)时,只做了小的修改(extent=>map_extent),我发现代码很快就运行了。也许是因为我使用的是 Anaconda numpy-mkl。
      猜你喜欢
      • 2017-11-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-29
      • 2019-10-11
      • 1970-01-01
      • 2012-10-18
      • 2018-03-19
      相关资源
      最近更新 更多