python活用gdal库进行批量重投影、重采样、裁剪

自然地理的数据经常保存为nc文件,因为nc文件包含经纬度、时间三个轴的基本信息。另一种保存方式是保存为tif文件,但tif文件只有经纬度信息,丢失了时间信息,折衷方案是对每个tif文件进行包含时间信息的命名,例如著名的GIMMS NDVI数据"PKU_GIMMS_NDVI_V1.2_19820101.tif"。

这会导致一个问题,就是一个日期的数据都保存为一个tif,如果要处理1982-2020年总共39年的NDVI数据,就需要循环很多次(39*24次)。arcgis的模型构建器或arcgis自带的python功能可以解决这个问题,反正循环就对了,但是我对arcgis的低效处理速度深恶痛绝,因而结合其他人的博客探索出了基于python的gdal库进行批量重投影、重采样、裁剪的高效方案。

具体来说,我不希望一个日期一个tif,那我就把所有数据组合成一个tif文件(参考我的前一篇博客:Python进行nc文件、tif文件、ndarray数据的相互转换-优快云博客)。我希望能快速重采样、裁剪、重投影,那我就用gdal库的warp功能。最终效果就是一次性对所有数据进行重采样/裁剪/重投影。下面是我分别对GRACE卫星数据进行裁剪、重采样的最后结果,运行速度10s以内。

1. 批量重投影

下面代码是针对tif文件的重投影,你可能会问哪里批处理了,好问题。只要我把所有数据保存为一个tif,再运行下面的代码就是批处理了

def gdal_reprojection(input_tif_path, output_tif_path, reference_tif_path=None):

    input_tif = gdal.Open(input_tif_path)

    if reference_tif_path==None:
        dstSRS = 'EPSG:4326'
    else:
        reference_tif = gdal.Open(reference_tif_path)
        dstSRS = reference_tif.GetProjection()

    gdal.Warp(output_tif_path,
              input_tif,
              dstSRS=dstSRS,  # 目标投影 (WGS 84)
              resampleAlg=gdal.GRA_NearestNeighbour,  # 重采样算法 (可选择其他,如 GRA_NearestNeighbour)
              dstNodata=-9999)  # 设置 NoData 值(可选)

    print("重投影完成,输出文件路径:", output_tif_path)

    return

2. 批量重采样

input_file_path是多个tif合并后的单个tif文件输入路径,reference_file_path是最后输出的参考tif文件,会修改原文件的投影方式、地理转换参数、经纬度范围(就是arcgis的重采样功能),重采样的模式可修改输入参数method。提供两种重采样的方案,gdal.ReprojectImage()和gdal.Warp(),两种都可以,亲测结果一致,用户只需使用的话,准备好输入文件就行,不用深究两种方案的差异。


def gdal_resample(input_file_path, reference_file_path, output_root=None, output_file_name=None, method=gdal.gdalconst.GRA_Bilinear):

    # 获取待重采样影像信息
    input_ras_file = gdal.Open(input_file_path, gdal.GA_ReadOnly)
    input_proj = input_ras_file.GetProjection()
    input_RasterCount = input_ras_file.RasterCount
    input_nodata = input_ras_file.GetRasterBand(1).GetNoDataValue()

    # 获取参考影像信息
    reference_file = gdal.Open(reference_file_path, gdal.GA_ReadOnly)
    reference_file_proj = reference_file.GetProjection()
    reference_file_trans = reference_file.GetGeoTransform()
    Width = reference_file.RasterXSize
    Height = reference_file.RasterYSize
    reference_lons = np.array([reference_file_trans[0] + i * reference_file_trans[1] for i in range(Width)])  # 经度
    reference_lats = np.array([reference_file_trans[3] + i * reference_file_trans[5] for i in range(Height)])  # 纬度
    
    # 创建输出文件路径
    if output_root is None:
        output_root = os.path.split(input_file_path)[0]
    input_file_name = os.path.basename(input_file_path)
    if output_file_name is None:
        output_file_name = os.path.splitext(input_file_name)[0] + "_resample.tif"
    output_file_path = os.path.join(output_root, output_file_name)

    ##### 重采样 方案1
    driver = gdal.GetDriverByName('GTiff')
    ds_output = driver.Create(output_file_path, Width, Height, input_RasterCount, gdal.GDT_Float32)
    ds_output.SetGeoTransform(reference_file_trans)
    ds_output.SetProjection(reference_file_proj)
    ds_output.GetRasterBand(1).SetNoDataValue(input_nodata)
    gdal.ReprojectImage(input_ras_file, ds_output, input_proj, reference_file_proj, method, 0.0, 0.0, )
    # 上一行的输入变量含义:输入数据集、输出数据集、输入投影、参考投影、重采样方法(最邻近内插\双线性内插\三次卷积等)、回调函数

    # gdalconst.GRA_NearestNeighbour: 'near',
    # gdalconst.GRA_Bilinear: 'bilinear',
    # gdalconst.GRA_Cubic: 'cubic',
    # gdalconst.GRA_CubicSpline: 'cubicspline',
    # gdalconst.GRA_Lanczos: 'lanczos',
    # gdalconst.GRA_Average: 'average',
    # gdalconst.GRA_RMS: 'rms',
    # gdalconst.GRA_Mode: 'mode',
    # gdalconst.GRA_Max: 'max',
    # gdalconst.GRA_Min: 'min',
    # gdalconst.GRA_Med: 'med',
    # gdalconst.GRA_Q1: 'q1',
    # gdalconst.GRA_Q3: 'q3',
    # gdalconst.GRA_Sum: 'sum',

    ##### 重采样 方案2
    # options = gdal.WarpOptions(
    #     outputBounds=(reference_lons.min(), reference_lats.min()+reference_file_trans[5], reference_lons.max()+reference_file_trans[1], reference_lats.max()),
    #     xRes=reference_file_trans[1],
    #     yRes=reference_file_trans[5],
    #     srcSRS=input_proj,
    #     dstSRS=reference_file_proj,
    #     resampleAlg=method,
    #     format='GTiff',
    #     dstNodata=input_nodata,
    #     srcNodata=input_nodata
    #     )
    # gdal.Warp(output_file_path, input_ras_file, options=options)

    print(output_file_path, ' 重采样完成')
    return

3. 批量裁剪

其实第2部分的代码也提供了裁剪的功能,与之不同的是,第2部分的裁剪是根据参考tif文件的网格信息进行裁剪的,第3部分的代码是根据shapefile文件裁剪的,分别对应于arcgis中使用矢量文件和栅格文件裁剪的功能。


def gdal_warp(input_file_path, shp_file_path=None, output_root=None, output_file_name=None):

    # 获取输出影像信息
    input_ras_file = gdal.Open(input_file_path, gdal.GA_ReadOnly)
    input_nodata = input_ras_file.GetRasterBand(1).GetNoDataValue()

    # 创建输出文件路径
    if output_root is None:
        output_root = os.path.split(input_file_path)[0]
    input_file_name = os.path.basename(input_file_path)
    if output_file_name is None:
        output_file_name = os.path.splitext(input_file_name)[0] + "_warp.tif"
    output_file_path = os.path.join(output_root, output_file_name)

    # 输入边界shp文件
    if shp_file_path is None:
        shp_file_path = r'F:\Arcgis\Boundary\Shp boundary\result.shp'

    # 裁剪
    gdal.Warp(output_file_path, input_ras_file,
                format='GTiff',
                cutlineDSName=shp_file_path,
                cropToCutline=True,
                srcNodata=input_nodata,
                dstNodata=input_nodata,)

    print(output_file_path, ' 裁剪完成')
    return

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值