如何使用Python Basemap更快地绘制地理定位的RGB数据

5
我在使用Python的Basemap模块绘制具有纬度和经度数据的RGB图像时遇到了问题。虽然我能够制作所需的图形,但问题在于速度过慢。相比之下,绘制单通道数据要快得多,并且一般来说,绘制RGB图像本身也很快。由于我有纬度/经度数据,所以情况变得复杂起来。我查看了解决此问题的方法:如何使用Python和basemap绘制不规则间距的RGB图像?,这就是我现在所处的位置。实质上,它归结为以下问题。当使用basemap中的pcolormesh方法来绘制RGB数据时,您必须定义一个colorTuple参数,该参数将逐点映射RGB数据。由于数组大小约为2000x1000,这需要一些时间才能完成。下面是我所说的代码片段(完整工作代码进一步向下):
if one_channel:
    m.pcolormesh(lons, lats, img[:,:,0], latlon=True)
else:
    # This is the part that is slow, but I don't know how to
    # accurately plot the data otherwise.

    mesh_rgb = img[:, :-1, :]
    colorTuple = mesh_rgb.reshape((mesh_rgb.shape[0] * mesh_rgb.shape[1]), 3)

    # What you put in for the image doesn't matter because of the color mapping
    m.pcolormesh(lons, lats, img[:,:,0], latlon=True,color=colorTuple)

当绘制一个通道时,可以在大约10秒钟左右生成地图。当绘制RGB数据时,可能需要3-4分钟的时间。考虑到只有3倍的数据量,我认为一定有更好的方法,特别是当您制作矩形图像时,绘制RGB数据可以与一个通道数据一样快。
因此,我的问题是:是否有任何方法可以使这个计算更快,无论是使用其他绘图模块(例如Bokeh),还是通过任何方式改变颜色映射?我已经尝试使用imshow和精心选择的地图边界,但由于它只将图像拉伸到地图的完整范围内,这对于准确映射数据来说并不够好。
以下是一个简化版本的代码示例,可以使用正确的模块:
from pyhdf.SD import SD,SDC
import numpy as np
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap

def get_hdf_attr(infile,dataset,attr):

    f = SD(infile,SDC.READ)
    data = f.select(dataset)
    index = data.attr(attr).index()
    attr_out = data.attr(index).get()
    f.end()

    return attr_out

def get_hdf_dataset(infile,dataset):

    f = SD(infile,SDC.READ)
    data = f.select(dataset)[:]
    f.end()

    return data

class make_rgb:

    def __init__(self,file_name):

        sds_250 = get_hdf_dataset(file_name, 'EV_250_Aggr1km_RefSB')
        scales_250 = get_hdf_attr(file_name, 'EV_250_Aggr1km_RefSB', 'reflectance_scales')
        offsets_250 = get_hdf_attr(file_name, 'EV_250_Aggr1km_RefSB', 'reflectance_offsets')

        sds_500 = get_hdf_dataset(file_name, 'EV_500_Aggr1km_RefSB')
        scales_500 = get_hdf_attr(file_name, 'EV_500_Aggr1km_RefSB', 'reflectance_scales')
        offsets_500 = get_hdf_attr(file_name, 'EV_500_Aggr1km_RefSB', 'reflectance_offsets')

        data_shape = sds_250.shape

        along_track = data_shape[1]
        cross_track = data_shape[2]

        rgb = np.zeros((along_track, cross_track, 3))

        rgb[:, :, 0] = (sds_250[0, :, :] - offsets_250[0]) * scales_250[0]
        rgb[:, :, 1] = (sds_500[1, :, :] - offsets_500[1]) * scales_500[1]
        rgb[:, :, 2] = (sds_500[0, :, :] - offsets_500[0]) * scales_500[0]

        rgb[rgb > 1] = 1.0
        rgb[rgb < 0] = 0.0

        lin = np.array([0, 30, 60, 120, 190, 255]) / 255.0
        nonlin = np.array([0, 110, 160, 210, 240, 255]) / 255.0

        scale = interp1d(lin, nonlin, kind='quadratic')

        self.img = scale(rgb)

    def plot_image(self):

        fig = plt.figure(figsize=(10, 10))
        ax = fig.add_subplot(111)

        ax.set_yticks([])
        ax.set_xticks([])
        plt.imshow(self.img, interpolation='nearest')
        plt.show()

    def plot_geo(self,geo_file,one_channel=False):

        fig = plt.figure(figsize=(10, 10))
        ax = fig.add_subplot(111)

        lats = get_hdf_dataset(geo_file, 0)
        lons = get_hdf_dataset(geo_file, 1)

        lat_0 = np.mean(lats)
        lat_range = [np.min(lats), np.max(lats)]

        lon_0 = np.mean(lons)
        lon_range = [np.min(lons), np.max(lons)]

        map_kwargs = dict(projection='cass', resolution='l',
                          llcrnrlat=lat_range[0], urcrnrlat=lat_range[1],
                          llcrnrlon=lon_range[0], urcrnrlon=lon_range[1],
                          lat_0=lat_0, lon_0=lon_0)

        m = Basemap(**map_kwargs)

        if one_channel:
            m.pcolormesh(lons, lats, self.img[:,:,0], latlon=True)
        else:
            # This is the part that is slow, but I don't know how to
            # accurately plot the data otherwise.
            mesh_rgb = self.img[:, :-1, :]
            colorTuple = mesh_rgb.reshape((mesh_rgb.shape[0] * mesh_rgb.shape[1]), 3)
            m.pcolormesh(lons, lats, self.img[:,:,0], latlon=True,color=colorTuple)

        m.drawcoastlines()
        m.drawcountries()

        plt.show()

if __name__ == '__main__':

    # https://ladsweb.nascom.nasa.gov/archive/allData/6/MOD021KM/2015/183/
    data_file = 'MOD021KM.A2015183.1005.006.2015183195350.hdf'

    # https://ladsweb.nascom.nasa.gov/archive/allData/6/MOD03/2015/183/
    geo_file = 'MOD03.A2015183.1005.006.2015183192656.hdf'

    # Very Fast
    make_rgb(data_file).plot_image()

    # Also Fast, takes about 10 seconds
    make_rgb(data_file).plot_geo(geo_file,one_channel=True)

    # Much slower, takes several minutes
    make_rgb(data_file).plot_geo(geo_file)
1个回答

3

我通过将colorTuple的每个部分的值增加1.0来解决了这个问题,以将其转换为RGBA数组。我查看了pcolormesh函数,并发现它调用颜色转换器4次,每次大约需要50秒来将RGB转换为RGBA数组。如果你给它一个RGBA数组开始,它将绕过这个步骤并在合理的时间内生成绘图。下面是新增加的代码:

if one_channel:
    m.pcolormesh(lons, lats, img[:,:,0], latlon=True)
else:
    mesh_rgb = img[:, :-1, :]
    colorTuple = mesh_rgb.reshape((mesh_rgb.shape[0] * mesh_rgb.shape[1]), 3)

    # ADDED THIS LINE
    colorTuple = np.insert(colorTuple,3,1.0,axis=1)

    # What you put in for the image doesn't matter because of the color mapping
    m.pcolormesh(lons, lats, img[:,:,0], latlon=True,color=colorTuple)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接