ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MODIS地表温度数据处理实战:从HDF下载到QC掩膜与重投影

MODIS地表温度数据处理实战:从HDF下载到QC掩膜与重投影 简介一套面向遥感与地理信息研究者的 MODIS 数据综合处理软件及配套使用手册可帮助用户完成植被指数、蒸散发、陆面温度、叶面积指数、植被生产力等多类陆面产品的批量导入、统计分析与可视化制图支持一次处理多个文件并利用多核 CPU 并行加速适合需要高效处理 MODIS 长时间序列或区域数据的科研人员。资源包共包含 2000 个文件约 176.28MB以 js、json、html、css 等前端资源构建软件界面以 py、xml、yaml 等文件提供功能配置与脚本支持并附有 pdf、md、txt 类型的使用手册与说明文档便于快速上手。软件内置多种可视化工具可将统计特征与趋势变化直接以图形形式呈现帮助用户更直观地理解数据规律。目前已有 140 人学习/下载该资源适合地理科学、生态遥感等相关方向的入门与进阶用户使用。1. MODIS 数据综合处理软件 V1.0地表温度数据下载后为什么不能直接当产品用很多刚接触遥感的人会问MODIS 地表温度数据下载后可以直接用吗答案是否定的。你从 NASA 拉下来的 MOD11A1 是一个 HDF-EOS 格式文件里面装着 12 个以上的科学数据集SDS有比例因子、有偏移量、有质量控制层还叠着一条条正弦投影轨道——直接拖进 ArcGIS 后看到「正常」的 0~30000 灰度第一反应以为是温度其实那是原始 DN 值。我见过不止一个人把 MOD11A1 未缩放的值当成开尔文温度去和站点数据对比结果偏差少则十几度、多则离谱到没法看。MODIS 数据综合处理软件 V1.0 要解决的就是这条从「下载成功」到「栅格数值在研究尺度上可信」的处理链。它适合做生态、农业、气候相关研究的从业者也适合刚接手 MODIS 产品、想知道每个参数该怎么设的建模同学。2. MODIS 数据综合处理软件要解决的核心问题原始数据与科学产品之间的距离2.1 MODIS HDF 文件的多维结构隐藏在二进制里的科学数据集与元数据MODIS 陆地产品比如 MOD11A1、MOD13Q1、MOD09GA都遵循 HDF-EOS 格式说穿了是一种自描述的二进制容器。打开后你会看到一个层级结构根组下面是科学数据集每个数据集带一组属性属性里写着单位、比例因子、偏移量、有效范围和填充值。很多做数值模拟的人第一次处理 MODIS会在这一步卡很久他们用 GDAL 打开文件然后直接ReadAsArray()拿到的数组和物理量没有任何关系。这里有个关键点MODIS 数据综合处理软件 V1.0 的第一版处理逻辑就是围绕「读属性、查元数据」设计的。它不像普通的图像查看器那样把 HDF 当成一张图而是先把文件里的每个 SDS 名称和属性表列出来让使用者确认到底要取哪一个科学数据集。比如 MOD11A1 的地表温度标准做法是取名字为LST_Day_1km的这一层而不是笼统地把整个文件读成波段。除非你确认过产品说明否则同一个 HDF 文件里不同 SDS 的空间尺度、数据位数、单位可能完全不同。以 MOD11A1 为例常见的几个 SDS 包括白天地表温度、夜间地表温度、白天质量保证QC_Day、观测时间、观测角度等。一个典型的初始检查脚本长这样import h5py import numpy as np hdf_path MOD11A1.A2020201.h25v06.061.2020202182547.hdf with h5py.File(hdf_path, r) as f: def walk(name, obj): if isinstance(obj, h5py.Dataset): attrs {k: v for k, v in obj.attrs.items()} print(f[SDS] {name} shape{obj.shape} dtype{obj.dtype}) print(f attrs{attrs}) f.visititems(walk)这段代码会把 HDF 文件里所有数据集名称、形状、数据类型以及属性一次性打印出来。逻辑很简单visititems会递归遍历文件内部的所有节点判断节点是不是数据集然后再读取属性字典。属性里最需要关注的是scale_factor、add_offset、valid_range、_FillValue这四个参数直接决定物理量怎么换算。以 061 版本的 MOD11A1 为例LST_Day_1km的scale_factor通常是 0.02也就是原始整数乘以 0.02 之后得到的才是开尔文温度偏移量是 0。如果你不乘这个系数算出来的是 0~30000 的整数放进统计分析模型里就是个黑匣子谁也解释不了系数含义。2.2 重投影与瓦片拼接为什么软件要把正弦投影转成你想要的研究坐标系MODIS 陆地产品的标准投影是正弦投影Sinusoidal数据按瓦片划分比如 h25v06、h26v05每个瓦片约 1200 公里见方。这就带来两个问题第一很多研究区会跨两三个瓦片需要先拼接再裁剪第二生态模型和 GIS 底图通常用地理坐标经纬度 WGS84或者 UTM直接使用正弦投影会导致图层叠不齐。MODIS 数据综合处理软件 V1.0 在这里的定位就是一个「转换中枢」输入若干瓦片路径输出一个统一坐标系的 GeoTIFF。常见做法是把重投影拆成两步。第一步用 GDAL 的gdalwarp把每个瓦片转成目标坐标系第二步用gdal_merge.py或gdalbuildvrt做拼接。实际生产时我一般反过来先用gdalbuildvrt把相邻瓦片拼成一个虚拟栅格再对虚拟栅格整体做重投影可以省掉一次中间文件的磁盘开销。注意边界上会出现一个常见麻烦两个瓦片重叠区或者扫描带边缘会有 NO DATA 值如果不设置重采样时的 NO DATA 处理拼接区域会出现黑色条纹。具体处理在后面的踩坑部分展开。在 MODIS 数据综合处理软件 V1.0 里面重投影参数不是固定写死的而是按研究区可配置的集合。下面是一个最简配置文件的结构{ input_tiles: [ MOD11A1.A2020201.h25v05.061.*.hdf, MOD11A1.A2020201.h25v06.061.*.hdf ], target_srs: EPSG:4326, target_resolution: [0.01, 0.01], resample_method: near, output_path: lst_2020201_wgs84.tif }这里target_resolution用的是度单位是 0.01 度约等于 1 公里。很多人在这会把分辨率填成 1000但如果你的坐标系是 EPSG:4326单位是度1000 表示的不是 1000 米而是 1000 度处理结果会变成一个极小范围的文件。选near最近邻法是有意的地表温度本身是像元尺度的物理量重采样不宜用双线性或三次卷积引入平滑误差这一点与 NDVI 之类的指数不同。如果使用软件时输出结果范围变得异常优先检查这个 JSON 里的坐标系和分辨率单位。2.3 时间维度的合成与缺失轨迹标称日期不是真实观测日期MODIS 地表温度产品还有一条容易被忽略的时间规则文件名里的A2020201是标称日期而每个像元的真实观测时间记录在另一个 SDS 里。对单日 LST 产品来说由于轨道覆盖间隙部分像元可能根本没有有效观测。另一个更高频的场景是用户拿 MODIS 逐日产品做日平均温度序列却不管某一天某像元是否被云覆盖导致冬季数据光滑得像用手描过一样。真实地表温度的日内变化、云遮蔽、扫描角切换都会在逐日数据里形成锯齿状噪声。V1.0 处理的策略是让 QC 层早于重投影介入在几何变换之前就把无效像元排除避免无效值在插值重采样时污染周边像元。3. 用 MODIS 数据综合处理软件 V1.0 跑通一条最小链路从 HDF 下载到可用 LST GeoTIFF3.1 用 wget 批量拉取 MODIS 地表温度产品的登录配置与下载命令想处理 MODIS 数据第一步永远是从 NASA Earthdata 下载。Earthdata 用的是 Bearer Token 登录机制不能简单地在 URL 里填用户名密码完事。常见做法是先造一个有 NASA 账号的用户然后用wget配合.netrc文件或者用 Python 的earthaccess库完成认证和下载。如果你的工作环境连的是服务器没有图形界面earthaccess是最省事的选择。pip install earthaccess然后写一个下载脚本把指定时间范围和瓦片集合的产品拉下来import earthaccess import pathlib out_dir pathlib.Path(ech_2020_tiles) out_dir.mkdir(exist_okTrue) auth earthaccess.login(strategynetrc) # 第一次会提示输入账号密码之后自动读 .netrc files earthaccess.search_data( short_nameMOD11A1, version061, bounding_box(90, 25, 135, 45), # 东经90~135北纬25~45 temporal(2020, 1, 1, 2020, 1, 31) ) downloaded earthaccess.download(files, local_pathout_dir) print(fdownloaded {len(downloaded)} granules)这个脚本的逻辑是先建立认证然后按产品、空间范围和时间范围搜文件最后下载到本地目录。注意bounding_box的坐标顺序是左下角和右上角经度、纬度minx, miny, maxx, maxy有人习惯填经纬度先经后纬结果搜出来的文件落在太平洋里这是很常见的翻车原因。temporal参数要求起点和终点都给出如果你只写了起始日期接口会报错。下载时还有一个细节NASA 默认给了 Access token但有的代理配置会拦截 Bearer 头需要设置earthaccess.login(strategynetrc)后检查auth对象的状态。如果打印出来是None基本就是账号权限没开通需要先去 Earthdata 的 Profile 里启用 MODIS 产品的下载权限。3.2 HDF 文件结构拆解读取科学数据集、检查比例尺与质量层拿到文件后不要急着转 GeoTIFF。我会让 MODIS 数据综合处理软件先执行一次「体检」把每个数据集的属性、有效范围、填充值、比例因子和偏移量列出来再做后续处理。这个过程看起来多此一举但能避免后面批量处理时因为个别文件属性不一致而无声地出错。from osgeo import gdal ds gdal.Open(MOD11A1.A2020201.h25v06.061.2020202182547.hdf) if ds is None: raise RuntimeError(无法打开文件请检查文件完整性和HDF4插件) subdatasets ds.GetSubDatasets() for sds_name, desc in subdatasets: print(f[{desc.split(])[0]}] {desc.split(] )[-1]}) # 打开其中第一层 lst_path subdatasets[0][0] # 形如 HDF4_EOS:EOS_GRID:...:LST_Day_1km lst_ds gdal.Open(lst_path) band lst_ds.GetRasterBand(1) print(scale_factor:, band.GetMetadata().get(scale_factor)) print(add_offset:, band.GetMetadata().get(add_offset)) print(fill_value:, band.GetMetadata().get(_FillValue)) print(valid_range:, band.GetMetadata().get(valid_range))代码里GetSubDatasets()返回的是 HDF 内部全部子数据集入口。这里最常见的一个坑是GDAL 打开 HDF-EOS 有时候会同时列出用不同视图如纬度和经度层组成的虚拟子集如果你直接取subdatasets[0]取到的未必是地表温度而可能是经纬度偏移场。建议在代码里按名字过滤例如只保留包含LST_Day_1km的那个入口。另外061 版本的 MOD11A1 元数据里scale_factor是字符串还是浮点型不同编译环境下 GDAL 返回类型有差异处理时要先做一次float()转换再参与运算。血泪经验如果读取元数据时不做类型转换Python 里字符串乘数字会把整个数组复制成 0.02 重复一遍结果就是一张全部为 0.02 的栅格拼图。3.3 缩放、QC 掩膜与重投影的一键输出最小处理回路的完整命令确认文件结构没问题之后就可以进入核心处理环节。V1.0 的最小链路包含四件事按比例因子缩放、按 QC 层生成掩膜、裁剪到研究区、输出为指定坐标系和格式。以下是完整的 Python 处理流程适合在本地或服务器上直接跑import numpy as np from osgeo import gdal, gdalconst hdf MOD11A1.A2020201.h25v06.061.2020202182547.hdf lst_path fHDF4_EOS:EOS_GRID:{hdf}:MODIS_Grid_Daily_1km:LST_Day_1km qc_path fHDF4_EOS:EOS_GRID:{hdf}:MODIS_Grid_Daily_1km:QC_Day scale 0.02 fill_value 0 lst_ds gdal.Open(lst_path) qc_ds gdal.Open(qc_path) lst lst_ds.GetRasterBand(1).ReadAsArray().astype(np.float32) qc qc_ds.GetRasterBand(1).ReadAsArray() # 1. 比例尺缩放温度单位变为开尔文 lst lst * scale # 2. 标记填充值 lst[lst fill_value] np.nan # 3. QC 掩膜只保留质量标识为 0高质量的像元 valid_qc_mask (qc 0xFF) 0 lst[~valid_qc_mask] np.nan # 4. 写出临时 GeoTIFF out_tmp lst_temp_kelvin.tif driver gdal.GetDriverByName(GTiff) out_ds driver.Create(out_tmp, lst.shape[1], lst.shape[0], 1, gdal.GDT_Float32) out_ds.SetGeoTransform(lst_ds.GetGeoTransform()) out_ds.SetProjection(lst_ds.GetProjection()) out_ds.GetRasterBand(1).WriteArray(lst) out_ds.GetRasterBand(1).SetNoDataValue(np.nan) out_ds None逻辑说明先把 LST 原始整数乘以 0.02 得到开尔文温度然后把值为 0 的填充像元置为 NaN再进行 QC 掩膜操作把非高质量像元也置为 NaN最后用原文件的坐标变换和投影信息写临时文件。QC 按位与(qc 0xFF)取的是质量控制层的最低 8 位0 表示 LST 质量好、误差在 1 开尔文以内。这个判断针对 MOD11A1 的 061 版本是成立的如果换成像 MOD11A2 这类 8 日合成产品QC 的位定义虽然一致但具体位含义要重新查用户手册。写临时文件时用np.nan做 NoData而对 GeoTIFF 来说最稳妥的做法是统一使用一个数值比如-9999然后写进金字塔时再配置-9999为 NoData。用 NaN 在 GDAL 某些驱动里容易导致输出文件在读取时出现异常尤其是当CompressDEFLATE时。一步到位的重投影和裁剪可以通过gdalwarp命令完成这也是软件 V1.0 里最常被调用的外部程序gdalwarp -t_srs EPSG:4326 -te 90 25 135 45 \ -tr 0.01 0.01 -r near -dstnodata -9999 \ lst_temp_kelvin.tif lst_wgs84_final.tif参数逐一解释-t_srs指定目标坐标系-te设定输出范围顺序是最小经度、最小纬度、最大经度、最大纬度-tr是目标分辨率单位与目标坐标系一致-r near控制重采样方法为最近邻-dstnodata -9999把目标文件里的无效值统一写成 -9999。这里容易出问题的是-te的顺序如果你先写纬度后写经度GDAL 不会报错但输出的地理位置会偏移到海面上。另一个高频坑是-tr跟-te的分辨率不匹配导致输出栅格的像元数计算出现一行或一列的轻微偏差这在做后续时间序列抽取时会让每个像元的经纬度对不上。4. MODIS 数据综合处理软件 V1.0 的 4 个必调参数与质量控制的取舍4.1 比例因子与偏移量不放大就直接用地表温度会整体漂移十几开尔文MODIS 官方产品的热红外波段 LST 数据集普遍采用整数存储加比例因子的策略。比如 MOD11A1 的LST_Day_1km比例因子是 0.02偏移量是 0而像 MOD09GA 的反射率数据则不同有些波段的比例因子是 0.0001偏移量是 0还有些火情产品里偏移量不为 0。V1.0 在读取数据集时会自动把属性里的scale_factor和add_offset解析出来生成一个换算配置表。如果你在软件里手动修改了比例因子输出的物理量单位就会对不上后续做温度统计分析时结论可能是颠倒的。我处理过的一个农村站点案例是用户拿 MOD11A1 做 2020 年夏季高温评估直接把未缩放的 DN 值当成地表温度逐像元得出的平均「温度」超过 30000 K。检查后发现问题就出在缩放环节——原始整数 0~30000乘以 0.02 后映射到 0~600 开尔文未缩放的值根本没有物理意义。所以 V1.0 的默认策略是读到任何 SDS 后先检查属性中的scale_factor再检查add_offset两者都存在时一律先做换算输出层的单位统一写进 GeoTIFF 元数据避免下游人误读。4.2 QC 质量控制层的筛选阈值白天与夜晚场景下不能使用同一套位运算MOD11A1 的 QC_Day 和 QC_Night 是独立的质量控制层。很多新手会直接对 QC 整数做条件筛选比如只保留 QC0 的像元但这样会把一些误差在 1~2 开尔文、但仍可用的像元全部过滤掉导致研究区边缘大面积缺值。QC 层本质上是二进制位掩码最低的两位表示 LST 误差范围再往上的位表示云掩膜标识和数据来源。V1.0 提供了一组可配置的 QC 筛选位默认保留等级 0 和 1相当于允许误差不超过 2 开尔文对多数气候分析已经够用。QC 最低两位取值含义是否建议保留应用场景00LST 误差 ≤ 1 K是站点验证、高精度分析01LST 误差 ≤ 2 K是区域气候统计10LST 误差 ≤ 3 K谨慎缺少站点数据的补充11LST 误差 3 K否不建议进入统计白天产品和夜间产品的云检测逻辑不同不能共用同一份 QC 掩膜。比如在夏季白天的晴空条件下QC_Day 里的云标识位与地表覆盖类型耦合比较强山区林地带容易出现云误判导致有效像元被切掉一片。我一般会先统计研究区 QC 取值的分布再决定阈值。如果有效像元占比低于 60%多半是阈值加得过头了可以把保留范围扩大到 2 或 3同时在下游统计时给这些像元加权低一点算是折中方案。4.3 输出分辨率与研究区的匹配1000 米分辨率在 4326 投影下怎么填才不会翻车分辨率参数在 MODIS 处理里最容易出问题。若目标坐标系是地理坐标EPSG:4326分辨率的单位是度0.01 度在高纬度对应的实际距离比赤道短所以同样是 0.01 度实际像元面积在不同纬度上有差异。V1.0 的处理方式是允许用户填写目标分辨率数值但建议先根据研究区纬度大致换算目标尺度。比如要做 1 公里网格在纬度 30° 附近经度方向约需要 0.01 度纬度方向约 0.009 度在纬度 60° 附近经度方向只要约 0.006 度。我一般建议直接用-tr 0.01 0.01框一个略粗的网格避免因分辨率过高导致输出栅格行数接近百万而内存溢出。如果研究区需要投影到 UTM分辨率直接填米数就直观得多。例如北纬 35°、东经 105° 附近可用EPSG:32648-tr 1000 1000输出网格间距就是真正的 1 公里。MODIS 原始瓦片空间分辨率约 0.05°在赤道处约 5 公里需要澄清——实际上 1 公里产品标注的是 1 公里原生网格约为 926 米经重投影后略有拉伸。V1.0 的默认设置是保留与产品官方分辨率相近的输出尺度而不是强行取整到 1000 米以减少重采样导致的像素信息冗余。4.4 填充值判定边界什么时候用 -9999 替代 NaN防止影像镶嵌出现接缝填充值处理策略决定了你在后续裁剪、拼接、统计时会不会出现「空洞」。MODIS 单日产品的大块 NoData 一般来自云检测和轨道空隙填充值常见为 0也有的 SDS 填充值是 -286.66 之类的特殊值。V1.0 里统一把不同来源的无效值转成同一个 NoData 值 -9999 输出这样后续用 GDAL 做gdalbuildvrt时只需要处理一类 NoData。如果不做统一同一个研究区里有的瓦片填充值是 NaN有的是 0有的是 -9999拼接后会出现不规则的白色斑点你以为数据质量差其实是 NoData 类型混装造成的假象。另外一个细节是统计时的填充值判定。很多统计软件里 NaN 能被自动排除而 -9999 会被当作异常大值参与计算。所以 V1.0 在统计阶段会再做一次过滤把等于 NoData 的像元转换成 NaN再进行均值和标准差计算。处理批量数据时我会要求最终输出的 GeoTIFF 元数据中写清楚NoData-9999并在流程序里同时维护一个valid_mask栅格。这样任何一个环节的输出别人拿来都能立刻判断像元是否有效不会出现统计结果被 NoData 拉偏的尴尬。5. MODIS 数据综合处理常见问题排查5 个高频踩坑记录与应对方法5.1 下载后文件名正常但文件大小只有 0 字节现象通过earthaccess.download下载后本地文件存在但查看大小全部是 0 字节打开 HDF 时 GDAL 返回 None。原因我遇到过两次一次是磁盘满了另一次是 Earthdata 给的下载链接是临时重定向地址wget和requests在没开启跟随重定向时只拉到了响应头。更隐蔽的情况是账号 Token 过期Earthdata 返回了 401 页面但文件名被提前创建好。解决下载完成后立刻检查循环对每个文件判断os.path.getsize(path) 1024不满足就重试。如果你用命令行下载建议加wget --continue配合重试机制。常见做法是写一个下载队列脚本失败任务挂到重试队列里最多重复三次第三次仍失败就打印出 HTTP 状态码。检查.netrc是否存在以及权限是否为 600也是排查这个方法时的必做项。5.2 输出的 LST 数值范围看起来正常但均值比站点观测高十几度现象处理完的栅格温度在 290~320 K 范围均值却比同期的气象站 2 米气温高出 8~12 K用户怀疑处理流程有问题。原因这里要分清楚地表温度LST与气温Ta的概念差。MODIS 反演的是地表辐射温度不是百叶箱里的 2 米气温夏季阳光下地表温度比气温高出 10 K 是正常现象。另一个可能原因是 QC 掩膜没生效混入了云边缘像元云顶低温会让均值偏低而不是偏高如果同时用了白天数据且没有排除建筑物密集区的像元城市热岛效应也会把区域温度拉高。解决先用地面站点坐标提取栅格值对比时要区分 Land Surface Temperature 与 air temperature并在论文里明确写明对比对象。如果确实需要与气温对比推荐用 MOD11A2 的 8 日合成产品做一些时间尺度上的平滑或者用夜间 LST 做最低温近似。排除城市像元可以使用土地覆盖产品叠加掩膜这会显著降低两者差值。5.3 重投影之后影像边缘出现黑色斑块或条纹现象gdalwarp执行成功但输出影像的边界出现大量黑色条纹像栅格被人划了道子。原因这是最典型的 NoData 参与重采样问题。原文件与输出范围的边界不是严格对齐的重采样过程中边缘像元会引用外部区域的无效值如果没给-dstnodata这部分会默认是 0显示为黑色。另一个原因是在拼接相邻轨道时相邻影像的有效区域之间本来就有一道扫描间隙间隙像元在源文件里是填充值重投影后仍被保留为 0。解决在执行gdalwarp时显式写-dstnodata -9999和-srcnodata -9999。如果源文件的 NoData 是 0要把-srcnodata 0也加上。对嵌入的扫描间隙我一般不会用插值去补因为地表温度在云覆盖区插值出来的结果毫无检验依据更稳妥的做法是在后续统计时把该区域当作缺测处理。5.4 用 QC 掩膜后研究区有效像元只剩下不到三分之一现象按要求执行了(qc 0xFF) 0的掩膜结果大片森林和山地像元被过滤有效面积急剧缩小。原因MODIS 的 QC_Day 层里位信息不仅代表 LST 误差还包含云检测结果和相邻像元贡献信息。在高海拔或地表异质性强的区域算法本身容易把晴空像元判成疑似云或者标记为「相邻像元反演」这会体现在 QC 高位上。直接比较整个字节的最低两位等于把很多实际可用的像元一刀切掉。解决把 QC 判断放宽到(qc 0b00000011)允许误差等级 0 和 1即取值 0 或 1同时检查qc 0b00001100的云掩膜位把确定有云的像元筛掉而对「可能云」的像元保留并标记。这样做 QC 之后有效像元占比通常能回到 70% 上下。如果你研究的区域正好是热带雨林或青藏高原这种调节几乎是必须的否则后期时间序列会缺得让人头疼。5.5 跨瓦片拼接后重叠区域出现明显的数值断层现象两个相邻瓦片拼在一起重叠区左右两边数值差 2~3 K色带上看出明显的一条缝。原因MODIS 瓦片之间存在轨道重叠同一地物在相邻瓦片上的观测时间可能相差数小时地表温度日变化会在这几小时内产生明显差异这种差异本身不是处理错误。另一个原因是在处理时没有先做统一 QC两个瓦片一个留了云边缘像元一个没留造成拼接边界处的均值差异被放大。解决拼接时优先用gdalbuildvrt建立虚拟栅格并确保两张瓦片都通过相同 QC 阈值。如果还有断层可以在重叠区域做一定宽度的羽化过渡但 V1.0 默认不开启羽化因为需要保留温度的真实空间异质性。遇到这种问题最常见做法是在最终统计分析前不做单个像元的日值对比而是用 8 日合成或月合成数据来吸收轨道差异。6. 进阶批量时序 MODIS 数据的自动化处理与结果验证6.1 用 Python 让逐日数据自动滑过整年时序批量处理脚本骨架单日数据处理通了真正的战场在长时序。逐日 MOD11A1 一年 365 个文件如果每个文件都手动跑一遍gdalwarp很容易出错。V1.0 的批量模式通常用文件通配符和时间循环组织任务每一步只用项目内部的临时目录最后输出一个完整的时间序列堆栈。import glob import subprocess hdf_files sorted(glob.glob(MOD11A1.A2020*.h25v*.hdf)) for hdf in hdf_files: doy hdf.split(.)[1][1:] # A2020201 - 2020201 out_tif flst_{doy}.tif cmd [ gdalwarp, -t_srs, EPSG:4326, -tr, 0.01, 0.01, -r, near, -dstnodata, -9999, hdf, out_tif ] subprocess.run(cmd, checkTrue) print(f{doy} done)这个循环的灵魂在glob按年、按瓦片匹配文件然后逐个转出 GeoTIFF。checkTrue会在失败时把错误抛出来比静默通过更安全。如果你想构建一个带所有 LST 层的三维数组可以用xarray配合rioxarray读取所有 TIFF按时间维堆叠。V1.0 的进阶用法里我会建议把每天的 QC 掩膜也同步输出这样做质量过滤时不需要重新打开 HDF能省掉大块 I/O 时间。6.2 与地面站点交叉验证R² 和偏差的检验流程最终交付前必须做一步验证拿研究区内气象站点的实测地表温度或气温去对比 MODIS LST 栅格值。通常做法是把站点经纬度转成栅格行列号索引对应位置的 LST 值然后计算偏差、均方根误差和相关系数。验证指标常见目标值说明平均偏差MBE±2 K 内负值表示 MODIS 偏低温均方根误差RMSE≤ 3 K受云边缘和地表异质性影响R² 0.8日尺度 LST 与站点对比时较难达到这里有一个需要提前处理的坑站点坐标通常是 WGS84 经纬度而栅格可能是 UTM 投影。我的习惯是在gdalwarp阶段直接输出 EPSG:4326 的 GeoTIFF并把行列换算逻辑统一放在经度/纬度上省去每次验证时都要反算投影的麻烦。交叉验证得到偏差较大时先看站点附近的 QC 掩膜如果站点落在一个被云污染的像元里剔除该样本后再统计往往 R² 立刻上去。6.3 我的一个落地习惯任何处理链都保留中间层避免全部重跑做完上面这整套流程后我最大的教训是不要为了省磁盘把中间结果全部删掉。数据综合处理软件 V1.0 在我的工作流里承担的就是「每个环节都可追溯」的角色保留了明文参数配置、保留了 QC 掩膜输出、保留了缩放后但未重投影的临时层。这样一来当研究区范围调整或投影需求变化时不需要从头下载和做 QC只需重新跑重投影一步。很多人在这一步舍不得空间最后修改一个小参数就要重跑整条链浪费的时间远超磁盘成本。希望这个整套流程能帮你在 MODIS 数据落地这条路上少绕几个弯也把你的处理链做成别人拿过来就能看懂、能复现的样子。本文还有配套的精品资源点击获取
返回列表