其包含三个pro过程,其中modis_grid_warp
为主程序,modis_grid_geo_transform
、img_warp
为常规pro过程,read_h4
为自定义函数。
modis_grid_geo_transform
基于角点信息进行投影坐标数据集的生成并转化为经纬度数据集,img_warp
基于经纬度数据集进行重投影(GLT校正)
;+
; 函数用途:
; 该程序用于读取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
;+
; 函数用途:
; 基于经纬度数据集对目标数据集进行几何校正(重投影-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
;+
; 函数用途:
; 用于读取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
; @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~