ENVI IDL: 如何进行对MODIS GRID数据进行重投影?

01 说明

其包含三个pro过程,其中modis_grid_warp为主程序,modis_grid_geo_transformimg_warp为常规pro过程,read_h4为自定义函数。

modis_grid_geo_transform基于角点信息进行投影坐标数据集的生成并转化为经纬度数据集,img_warp基于经纬度数据集进行重投影(GLT校正)

02 完整代码

2.1 modis_grid_geo_transform过程

;+
;   函数用途:
;       该程序用于读取MODIS GRID产品的角点信息并返回经纬度数据集
;   函数参数:
;       h4_path: MODIS GRID文件的路径
;       extract_lon: 返回的经度数据集
;       extract_lat: 返回的纬度数据集
;       ds_size: (关键字参数)包含列号、行号的二元数组, 如果没有传入从文件中读取
;       helpme: 查看函数用法
;-
pro modis_grid_geo_transform, h4_path, extract_lon, extract_lat, ds_size=ds_size   

    ; 获取元数据
    h4_id = hdf_sd_start(h4_path, /read)
    metadata_ix = hdf_sd_attrfind(h4_id, 'StructMetadata.0')
    hdf_sd_attrinfo, h4_id, metadata_ix, data=metadata
    
    ; 获取行列号
    if ~keyword_set(ds_size) then begin
        ds_size = make_array(2, /double)
        ix_one = strpos(metadata, 'XDim')
        ix_two = strpos(metadata, 'YDim')
        ix_three = strpos(metadata, 'UpperLeftPointMtrs')
        ds_size[0] = (strsplit(strmid(metadata, ix_one, ix_two - ix_one), '=', /extract))[1]
        ds_size[1] = (strsplit(strmid(metadata, ix_two, ix_three - ix_two), '=', /extract))[1]
    endif else begin
        ds_size = double(ds_size)  ; 转换为双精度, 避免后续超出范围
    endelse
    
    ; 获取角点信息
    ix_one = strpos(metadata, 'UpperLeftPointMtrs')
    ix_two = strpos(metadata, 'LowerRightMtrs')
    ix_three = strpos(metadata, 'Projection')
    ul_coor = strsplit(strmid(metadata, ix_one, ix_two - ix_one), '=(,)', /extract)
    dr_coor = strsplit(strmid(metadata, ix_two, ix_three - ix_two), '=(,)', /extract)
    ul_coor = double(ul_coor[1:2])
    dr_coor = double(dr_coor[1:2])
    x_res = (dr_coor[0] - ul_coor[0]) / ds_size[0]
    y_res = (ul_coor[1] - dr_coor[1]) / ds_size[1]
    
    ; 计算-投影坐标数据集
    x_prj_coor = make_array(ds_size, /double)
    y_prj_coor = make_array(ds_size, /double)
    for ix=0, ds_size[0] - 1 do x_prj_coor[ix, *] = ul_coor[0] + x_res * ix + x_res / 2.0  ; 表示像元的中心位置
    for ix=0, ds_size[1] - 1 do y_prj_coor[*, ix] = ul_coor[1] - y_res * ix - y_res / 2.0
    x_prj_coor = reform(x_prj_coor, ds_size[0] * ds_size[1], /overwrite)  ; /overwrite避免复制加快速度
    y_prj_coor = reform(y_prj_coor, ds_size[0] * ds_size[1], /overwrite)
    ; 进行reform是为了适配map_proj_inverse函数的输入: An n-element vector containing the x values. 
    
    ; 投影坐标数据集  ==> 经纬度数据集
    prj_info = map_proj_init('Sinusoidal', /gctp, sphere_radius=6371007.181, $
        center_longitude=0.0, false_easting=0.0, false_northing=0.0)
    ; 需要说明的是gctp表示U.S. Geological Survey's General Cartographic Transformation Package (GCTP)来进行投影而不是IDL自己的投影库
    geo_coor = map_proj_inverse(x_prj_coor, y_prj_coor, map_structure=prj_info)
    extract_lon = geo_coor[0, *].reform(ds_size)
    extract_lat = geo_coor[1, *].reform(ds_size)
end

2.2 img_warp过程

;+
;   函数用途:
;       基于经纬度数据集对目标数据集进行几何校正(重投影-WGS84)
;   函数参数:
;       target: 待校正的目标数据集
;       lon: 对应目标数据集的经度数据集
;       lat: 对应目标数据集的纬度数据集
;       out_res: 输出的分辨率(°)
;       target_warped: 校正后的目标数据集
;       geo_info: 校正后的目标数据集对应的地理结构体
;       degree<关键字参数: 5>: 多项式的次数
;       interp<关键字参数: nearest>: 插值算法(包括: nearest, linear, cublic)
;       sub_percent<关键字参数: 0.1>: 默认使用10%的点位进行几何校正
;-
pro img_warp, target, lon, lat, out_res, target_warped, geo_info, degree=degree, interp=interp, $
    sub_percent=sub_percent

    ; 获取基本信息
    ds_size = size(target)
    lon_lat_corner = hash($  ; 考虑到min()max()为角点像元的中心处而非四个角点的边界
        'min_lon', min(lon) - out_res / 2.0d, $
        'max_lon', max(lon) + out_res / 2.0d, $
        'min_lat', min(lat) - out_res / 2.0d, $
        'max_lat', max(lat) + out_res / 2.0d)
    col_count_out = ceil((lon_lat_corner['max_lon'] - lon_lat_corner['min_lon']) / out_res)
    row_count_out = ceil((lon_lat_corner['max_lat'] - lon_lat_corner['min_lat']) / out_res)
    interp_code = hash($
        'nearest', 0, $
        'linear', 1, $
        'cublic', 2)
    if ~keyword_set(interp) then interp='nearest'
    if ~keyword_set(degree) then degree=5
    if ~keyword_set(sub_percent) then sub_percent = 0.1

    ; 原始的行列号矩阵
    row_ori = make_array(ds_size[1:2], /integer)
    col_ori = make_array(ds_size[1:2], /integer)
    for ix=0, ds_size[1]-1 do col_ori[ix, *] = ix
    for ix=0, ds_size[2]-1 do row_ori[*, ix] = ix
    
    ; 校正后的行列号矩阵
    col_warp = floor((lon - lon_lat_corner['min_lon']) / out_res)
    row_warp = floor((lon_lat_corner['max_lat'] - lat) / out_res)
    
    ; 获取sub_percent的均匀采样点索引
    all_count = ds_size[1] * ds_size[2]
    sample_count = floor(all_count * sub_percent)
    sample_ix = floor((findgen(sample_count) / double(sample_count)) * all_count)
    
    polywarp, col_ori[sample_ix], row_ori[sample_ix], col_warp[sample_ix], row_warp[sample_ix], $
        degree, k_col, k_row
    target_warped = poly_2d(target, k_col, k_row, interp_code[interp], $
        col_count_out, row_count_out, missing=!values.F_NAN)
    
    geo_info={$
        MODELPIXELSCALETAG: [out_res, out_res, 0.0], $  ; 分辨率
        MODELTIEPOINTTAG: [0.0, 0.0, 0.0, lon_lat_corner['min_lon'], lon_lat_corner['max_lat'], 0.0], $  ; 角点信息
        GTMODELTYPEGEOKEY: 2, $  ; 设置为地理坐标系
        GTRASTERTYPEGEOKEY: 1, $  ; 像素的表示类型, 北上图像(North-Up)
        GEOGRAPHICTYPEGEOKEY: 4326, $  ; 地理坐标系为WGS84
        GEOGCITATIONGEOKEY: 'GCS_WGS_1984', $
        GEOGANGULARUNITSGEOKEY: 9102}  ; 单位为度
end

2.3 read_h4函数

;+
;   函数用途:
;       用于读取HDF4文件的数据集及其属性
;   函数参数:
;       h4_path: 待读取的HDF4文件的路径
;       ds_name: 待读取的数据集的名称
;       attr_name<关键字参数>: 传入属性名称则返回数据集下的该属性信息
;       double<关键字参数, /double>: 若指定则将返回的数据集转换为双精度浮点型
;-
function read_h4, h4_path, ds_name, attr_name=attr_name, double=double
    ; 该函数用于读取HDF4文件数据集或者属性

    h4_id = hdf_sd_start(h4_path, /read)
    ds_index = hdf_sd_nametoindex(h4_id, ds_name)
    ds_id = hdf_sd_select(h4_id, ds_index)
    if keyword_set(attr_name) then begin
        attr_index = hdf_sd_attrfind(ds_id, attr_name)
        hdf_sd_attrinfo, ds_id, attr_index, data=data
    endif else begin
        hdf_sd_getdata, ds_id, data
        if keyword_set(double) then data = double(data)
    endelse

    hdf_sd_endaccess, ds_id
    hdf_sd_end, h4_id

    return, data
end

2.4 modis_grid_warp过程(主程序)

; @Author	: ChaoQiezi
; @Time		: 2023年10月19日-下午4:26:55
; @Email	: [email protected]

; 该程序用于 对MODIS GRID数据集进行重投影
pro modis_grid_warp
    ; 准备
    in_dir = 'D:\Objects\JuniorFallTerm\IDLProgram\Experiments\ExperimentalData\chapter_3\MYD11A1\'
    out_dir = 'D:\Objects\JuniorFallTerm\IDLProgram\Experiments\ExperimentalData\chapter_3\IDL_out_grid_warp_me\'
    if ~file_test(out_dir, /directory) then file_mkdir, out_dir
    lst_name = 'LST_Day_1km'
    range_name = 'valid_range'
    sf_name = 'scale_factor'
    out_res = 0.01  ; 度
    
    h4_paths = file_search(in_dir, '*.hdf', count=h4_paths_count)
    foreach h4_path, h4_paths do begin
        start_time = systime(1)
        ; 获取数据集以及属性等
        lst = read_h4(h4_path, lst_name, /double)
        valid_range = read_h4(h4_path, lst_name, attr_name=range_name)
        scale_factor = read_h4(h4_path, lst_name, attr_name=sf_name)
        lst_size = size(lst)
        
        ; LST数据预处理
        invalid_ix = where((lst lt valid_range[0]) or (lst gt valid_range[1]))
        lst[invalid_ix] = !values.F_NAN
        lst = lst * scale_factor[0]
        
        ; 获取经纬度数据集
        modis_grid_geo_transform, h4_path, lon, lat, ds_size=lst_size[1:2]
        
        ; 进行几何校正(重投影)
        img_warp, lst, lon, lat, out_res, lst_warped, geo_info

        ; 输出
        out_path = out_dir + file_basename(h4_path, '.hdf') + '.tiff'
        write_tiff, out_path, lst_warped, geotiff=geo_info, /float
        print, file_basename(h4_path, '.hdf'), systime(1) - start_time, format='%s: %0.2f s'
    endforeach
    
end

Bye~

你可能感兴趣的:(IDL,开发语言,经验分享)