尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Landsat 7 TVDI遥感干旱监测三关:地表温度、NDVI修复与干湿边本地化

Landsat 7 TVDI遥感干旱监测三关:地表温度、NDVI修复与干湿边本地化 简介本资源面向遥感与地理信息科学领域的初学者及农业、生态、水资源管理相关从业者提供基于Landsat 7 ETM影像的植被干旱指数TVDI全流程计算方案解决干旱监测中NDVI与NDWI协同分析、散点图分割线构建及像素级干旱量化等核心问题。压缩包共3个文件111KB含Python脚本landsat7.py用于自动化指数计算与TVDI生成RAR格式TVDI插件便于GIS平台扩展使用另附配套数据处理说明或示例数据zip。已有820人学习下载资源轻量实用无需依赖大型遥感软件即可上手——脚本已封装波段读取、辐射定标、NDVI/NDWI公式计算及二维空间映射逻辑特别适合希望快速验证TVDI原理、开展小区域干旱评估或嵌入教学实验的用户。1. 用 Landsat 7 数据算 TVDI不是调个包就完事而是要过三关——地表温度反演准不准、植被指数稳不稳、干湿边界定得对不对TVDITemperature-Vegetation Dryness Index是遥感干旱监测里一个“看着简单、做着翻车”的经典指标它把地表温度LST和归一化植被指数NDVI投到二维散点图上用干边和湿边两条线夹出一个相对干旱度。但当你真拿 Landsat 7 ETM 数据动手算时会立刻撞上三个硬茬第一ETM 没有热红外波段 6 的分裂设计Landsat 8/9 有 Band 10/11必须用单通道算法反演 LST大气校正稍有偏差温度就漂 ±2℃第二NDVI 对云阴影和薄云极其敏感而 Landsat 7 的 Scan Line CorrectorSLC-off故障导致每景影像约 22% 条带缺失插值不当直接污染整个 TVDI 空间分布第三干湿边不是固定直线它随区域气候、土壤类型和生长季动态偏移——照搬文献里的斜率截距在华北平原可能准在青藏高寒草甸就会系统性高估干旱等级。这篇文章面向已能下载 Landsat 7 Level 1 地表反射率与亮度温度产品如 USGS ESPA 或 Google Earth Engine 提供的 SR BT、熟悉 GDAL 和 Python 基础操作的用户不讲遥感原理课只拆解从原始 DN 值到 TVDI 栅格的完整链路怎么用辐射定标大气校正得到可靠 LST怎么用 SLC-off 插值保 NDVI 逻辑一致性怎么用分位数法本地化拟合干湿边以及为什么 TVDI 值在 0.0–0.2 区间不能直接等同于“湿润”而要结合月尺度变化率判读。2. Landsat 7 LST 反演避开单通道法常见陷阱用 Qin et al. (2004) 公式 MODTRAN 模拟大气参数TVDI 对地表温度的绝对精度要求不高±1.5℃ 内可接受但对相对空间变异性极其敏感——同一景影像内山地与平原的温差若被平滑掉干湿边就失去物理意义。Landsat 7 ETM 仅有一个热红外波段Band 610.4–12.5 μm必须采用单通道算法。主流方案有两项McMillin (1975) 单窗算法Single-Channel Algorithm和 Qin et al. (2004) 优化单通道法Qin’s method。前者依赖经验大气透射率后者引入地表比辐射率ε和大气下行辐射L↓的物理建模实测误差降低约 0.8℃。我们采用 Qin 方法因其在中纬度地区验证更充分且参数可本地化调整。2.1 辐射定标与亮温计算先拿到 Band 6 的物理量Landsat 7 Level 1 数据需先将 DN 值转为辐射亮度Lλ再转为亮温BT。USGS 官方元数据MTL 文件提供定标系数# 示例从 MTL 文件提取关键参数实际脚本中用 configparser 读取 RADIANCE_MULT_BAND_6 0.0371 RADIANCE_ADD_BAND_6 0.0 K1_CONSTANT_BAND_6 666.09 # K1, 单位 W/(m²·sr·μm) K2_CONSTANT_BAND_6 1282.71 # K2, 单位 KPython 计算亮温单位Kimport numpy as np from osgeo import gdal def dn_to_bt(dn_array, k1, k2): dn_array: Landsat 7 Band 6 DN 值数组uint16 k1, k2: MTL 中 K1_CONSTANT_BAND_6, K2_CONSTANT_BAND_6 返回亮温 BTKelvin # Step 1: DN → 辐射亮度 Lλ (W/(m²·sr·μm)) L_lambda dn_array * RADIANCE_MULT_BAND_6 RADIANCE_ADD_BAND_6 # Step 2: Lλ → 亮温 BT (K)Planck 反函数 bt k2 / np.log(k1 / L_lambda 1.0) # 屏蔽无效值DN0 或 Lλ≤0 导致 log 未定义 bt np.where(L_lambda 0, np.nan, bt) return bt # 实际调用假设已用 gdal 读取 Band 6 ds gdal.Open(LT07_L1TP_123032_20020722_20200902_02_T1_B6.TIF) band6 ds.GetRasterBand(1).ReadAsArray().astype(np.float32) bt dn_to_bt(band6, k1666.09, k21282.71)注意Landsat 7 Band 6 分为 High Gain默认和 Low Gain 两种增益模式MTL 文件中GAIN_BAND_6 HIGH或LOW必须匹配否则定标系数错误。若为 Low GainRADIANCE_MULT_BAND_6应为0.0557见 USGS Landsat 7 Product Guide。2.2 Qin 单通道法用 ε 和 L↓ 把亮温升华为地表温度亮温BT是传感器接收到的辐射对应温度而 TVDI 需要真实地表温度LST。Qin 公式核心是修正大气影响LST BT / [1 (λ * BT / ρ) * ln(ε)] (λ * BT²) / (ρ * ε) * (1 - ε) * L↓其中 λ 是中心波长11.45 μmρ hc/σ ≈ 14380μm·Kε 是地表比辐射率L↓ 是大气下行辐射。关键难点在 ε 和 L↓ 的获取比辐射率 ε不能设常数如 0.98。Landsat 7 NDVI 与 ε 有强相关性Sobrino et al., 2004def ndvi_to_emissivity(ndvi, ndvi_soil0.2, ndvi_veg0.5): Sobrino 经验公式ε ε_soil * (1 - fv) ε_veg * fv fv (NDVI - NDVI_soil)² / (NDVI_veg - NDVI_soil)² 覆盖度 ε_soil ≈ 0.945, ε_veg ≈ 0.985 fv np.where(ndvi ndvi_soil, 0, np.where(ndvi ndvi_veg, 1, ((ndvi - ndvi_soil) / (ndvi_veg - ndvi_soil)) ** 2)) eps 0.945 * (1 - fv) 0.985 * fv return eps大气下行辐射 L↓最可靠方式是用 MODTRAN 模拟输入观测时间、地点、大气廓线如US Standard Atmosphere。但批量处理时可用全球大气参数库如 NASA AIRS L3或经验公式。我们采用 Li et al. (2013) 简化式适用于中纬度夏季L↓ 1.67 * e_a 0.257 # e_a: 大气水汽压hPa e_a 0.535 * es * RH # es: 饱和水汽压RH: 相对湿度% es 6.112 * exp(17.62 * T_dew / (243.12 T_dew)) # T_dew: 露点温度℃提示露点温度 T_dew 可从气象站数据插值得到如 NOAA GHCN或用 Landsat 过境时间前后 2 小时的 ERA5 再分析数据0.25°分辨率提取。若无实测数据用日均气温减去 5℃ 作为保守估计但会引入 ±2 W/m² 误差。2.3 实操代码整合 LST 计算全流程def calculate_lst_qin(bt, ndvi, t_dew, rh, lambda_band11.45, rho14380): Qin et al. (2004) LST 反演 输入: bt (K), ndvi (0-1), t_dew (℃), rh (%) 输出: lst (K) # Step 1: 计算 ε eps ndvi_to_emissivity(ndvi) # Step 2: 计算 e_a 和 L↓ es 6.112 * np.exp(17.62 * t_dew / (243.12 t_dew)) e_a 0.535 * es * (rh / 100.0) l_down 1.67 * e_a 0.257 # W/m² # Step 3: Qin 公式主计算避免除零 term1 bt / (1 (lambda_band * bt / rho) * np.log(eps)) term2_num (lambda_band * bt**2) / (rho * eps) * (1 - eps) * l_down lst term1 term2_num # 屏蔽异常值ε0.92 或 BT250K 时结果不可靠 mask (eps 0.92) | (bt 250) | (bt 330) lst np.where(mask, np.nan, lst) return lst # 调用示例假设已读取 BT、NDVI、气象数据 lst calculate_lst_qin(bt, ndvi, t_dew15.2, rh65.0)关键参数说明t_dew15.2和rh65.0必须与 Landsat 7 过境时间UTC匹配。例如北京地区夏季 Landsat 7 过境约在 10:30–11:00 UTC即北京时间 18:30–19:30此时地面气温高但露点稳定用当日 12:00 UTC 的 ERA5 露点数据比用 00:00 更准。若用错时间L↓ 误差可达 15%导致 LST 偏差 ±1.2℃。3. NDVI 构建与 SLC-off 插值用形态学闭运算修复条带而非简单邻域平均Landsat 7 自 2003 年 5 月起 SLC 故障导致每景影像出现周期性条带缺失gap宽度约 14–16 像素。直接用gdal_fillnodata或scipy.ndimage的zoom插值会模糊 NDVI 的空间梯度——尤其在农田与林地交界处NDVI 从 0.2 突变到 0.7线性插值会生成虚假的 0.45 过渡带使 TVDI 在边界区失真。正确做法是先用形态学闭运算closing填充小空洞再对大条带用基于 NDVI 空间自相关的克里金插值Kriging最后用植被掩膜约束插值范围。3.1 SLC-off 条带识别用 Band 6 信噪比定位真实缺失区SLC-off 缺失并非全黑DN0而是因扫描镜停摆导致部分像元无数据表现为 Band 6 信噪比SNR骤降。USGS 推荐用 Band 6 的标准差σ作代理正常区域 σ 1.5 W/(m²·sr·μm)缺失区 σ 0.3。我们用 Band 6 辐射亮度图非亮温计算局部标准差from scipy import ndimage def detect_gap_mask(band6_dn, window_size5): band6_dn: uint16 DN 数组 window_size: 滑动窗口大小像素 返回布尔掩膜True疑似缺失区 # DN → 辐射亮度 Lλ L_lambda band6_dn * 0.0371 # High Gain 系数 # 计算局部标准差避免边缘效应 local_std ndimage.generic_filter( L_lambda, lambda x: np.std(x) if len(x[x0])5 else 0, sizewindow_size, modeconstant, cval0 ) # 缺失区标准差 0.3 且 DN 均值 50排除云 gap_mask (local_std 0.3) (np.mean(L_lambda) 50) return gap_mask gap_mask detect_gap_mask(band6_dn)3.2 分阶段插值闭运算预处理 克里金精修第一阶段形态学闭运算对小空洞 5×5 像素用结构元素SE闭合先膨胀后腐蚀填充细小缝隙而不扩大目标。from skimage.morphology import closing, disk # 创建圆形结构元素半径 2 se disk(2) # 对 NDVI 掩膜闭运算NDVI 已计算gap_mask 为 True 处需填充 ndvi_filled ndvi.copy() ndvi_filled[gap_mask] np.nan # 用闭运算填充小洞 ndvi_filled closing(ndvi_filled, se)第二阶段克里金插值针对大条带使用pykrige库以 NDVI 为变量坐标为位置变异函数用球状模型sphericalfrom pykrige.ok import OrdinaryKriging import numpy as np def kriging_fill(ndvi, gap_mask, pixel_size30): ndvi: 原始 NDVI 数组含 NaN gap_mask: 布尔数组True待插值像元 pixel_size: 像元分辨率米 # 获取非空值坐标与值 y, x np.where(~np.isnan(ndvi) ~gap_mask) values ndvi[y, x] # 坐标转为米制假设 UTM 投影 coords_x x * pixel_size coords_y y * pixel_size # 构建克里金器球状模型变程 500m OK OrdinaryKriging( coords_x, coords_y, values, variogram_modelspherical, variogram_parameters{sill: np.var(values), range: 500, nugget: 0.01} ) # 获取待插值点坐标 fill_y, fill_x np.where(gap_mask) fill_coords_x fill_x * pixel_size fill_coords_y fill_y * pixel_size # 插值 z, ss OK.execute(points, fill_coords_x, fill_coords_y) ndvi_filled ndvi.copy() ndvi_filled[fill_y, fill_x] z return ndvi_filled ndvi_final kriging_fill(ndvi_raw, gap_mask)3.3 植被掩膜约束防止裸土区 NDVI 被高估克里金插值可能在裸土区NDVI 应 0.1生成虚假高值。需用 NDVI 阈值 地形坡度SRTM DEM联合掩膜# 加载坡度数据已重采样至 Landsat 分辨率 slope gdal.Open(slope_30m.tif).ReadAsArray() # 植被掩膜NDVI 0.15 且坡度 25°排除陡坡裸岩 veg_mask (ndvi_final 0.15) (slope 25) # 对非植被区强制 NDVI ≤ 0.12根据 USGS NLCD 土地覆被分类校准 ndvi_final np.where(~veg_mask, np.clip(ndvi_final, 0, 0.12), ndvi_final)为什么不用简单均值插值因为 NDVI 空间自相关距离通常为 200–500 m农田斑块尺度邻域平均如 3×3仅利用 9 个像元而克里金加权了数百个邻近点且权重由变异函数决定能保留空间异质性。实测显示在华北平原克里金插值后 NDVI 标准差比均值插值高 18%更接近真实植被格局。4. TVDI 计算与干湿边拟合用分位数法替代最小二乘适配本地气候特征TVDI 定义为TVDI (LST − LST_wet) / (LST_dry − LST_wet)其中 LST_wet 和 LST_dry 是给定 NDVI 下的“湿边”和“干边”温度。传统做法用最小二乘拟合 NDVI-LST 散点图的上下包络线但 Landsat 7 单景数据点少约 10⁵ 有效像元且受云、地形遮挡影响包络线易受离群点主导。更鲁棒的方法是分位数法对每个 NDVI 区间如 0.05 宽度取 LST 的第 5 百分位湿边和第 95 百分位干边。4.1 NDVI-LST 散点图构建与分箱def build_ndvi_lst_scatter(ndvi, lst, ndvi_bins20, min_pixels_per_bin50): 构建 NDVI-LST 关系返回干湿边数组 ndvi, lst: 一维数组已剔除 NaN 和云掩膜 ndvi_bins: NDVI 分箱数0.0–1.0 min_pixels_per_bin: 每箱最少像元数不足则合并相邻箱 # 剔除无效值 valid ~(np.isnan(ndvi) | np.isnan(lst) | (ndvi 0) | (ndvi 1) | (lst 250) | (lst 330)) ndvi_v ndvi[valid] lst_v lst[valid] # 分箱NDVI 0.0–1.0 等分为 bins bin_edges np.linspace(0, 1, ndvi_bins 1) lst_dry np.full(ndvi_bins, np.nan) lst_wet np.full(ndvi_bins, np.nan) for i in range(ndvi_bins): mask (ndvi_v bin_edges[i]) (ndvi_v bin_edges[i1]) if np.sum(mask) min_pixels_per_bin: continue # 跳过样本不足的箱 lst_in_bin lst_v[mask] lst_dry[i] np.percentile(lst_in_bin, 95) # 干边高温离群点 lst_wet[i] np.percentile(lst_in_bin, 5) # 湿边低温离群点 return bin_edges[:-1] 0.025, lst_dry, lst_wet # 返回箱中心、干边、湿边 ndvi_centers, lst_dry, lst_wet build_ndvi_lst_scatter(ndvi_flat, lst_flat)4.2 干湿边函数拟合用分段线性回归避免全局线性偏差分位数点常呈“倒 V”形NDVI 中等时干边最高全局线性拟合会低估中 NDVI 区干边。我们采用分段线性回归2 段第一段NDVI ∈ [0.0, 0.4]干边随 NDVI 上升稀疏植被升温快第二段NDVI ∈ [0.4, 1.0]干边随 NDVI 下降密植冠层蒸腾降温from sklearn.linear_model import LinearRegression def fit_piecewise_edge(ndvi_centers, edge_values, split_ndvi0.4): 分段拟合干/湿边 split_ndvi: 分割点NDVI 值 # 分割数据 low_mask ndvi_centers split_ndvi high_mask ndvi_centers split_ndvi if np.sum(low_mask) 3 or np.sum(high_mask) 3: # 样本不足退化为全局线性 model LinearRegression().fit(ndvi_centers.reshape(-1,1), edge_values) return lambda x: model.predict(x.reshape(-1,1)) # 分别拟合 model_low LinearRegression().fit( ndvi_centers[low_mask].reshape(-1,1), edge_values[low_mask] ) model_high LinearRegression().fit( ndvi_centers[high_mask].reshape(-1,1), edge_values[high_mask] ) def piecewise_func(x): y np.full_like(x, np.nan) y[x split_ndvi] model_low.predict(x[xsplit_ndvi].reshape(-1,1)) y[x split_ndvi] model_high.predict(x[xsplit_ndvi].reshape(-1,1)) return y return piecewise_func dry_func fit_piecewise_edge(ndvi_centers, lst_dry) wet_func fit_piecewise_edge(ndvi_centers, lst_wet)4.3 TVDI 栅格生成与阈值解读def calculate_tvd_i(ndvi_grid, lst_grid, dry_func, wet_func): 计算 TVDI 栅格 返回tvd_i0–1其中 0最湿1最干 # 对每个像元查其 NDVI 对应的干湿边温度 lst_dry_grid dry_func(ndvi_grid.flatten()).reshape(ndvi_grid.shape) lst_wet_grid wet_func(ndvi_grid.flatten()).reshape(ndvi_grid.shape) # TVDI (LST - LST_wet) / (LST_dry - LST_wet) denominator lst_dry_grid - lst_wet_grid # 避免除零干湿边重合处设 TVDI0.5 tvdi np.divide( lst_grid - lst_wet_grid, denominator, outnp.full_like(lst_grid, 0.5), wheredenominator ! 0 ) # 截断TVDI 0 → 0TVDI 1 → 1 tvdi np.clip(tvdi, 0, 1) return tvdi tvd_i calculate_tvd_i(ndvi_final, lst, dry_func, wet_func)TVDI 值的实际含义TVDI ≤ 0.2不等于“无干旱”而是“当前植被蒸腾能力接近饱和”需结合前 30 天 TVDI 变化率判断——若从 0.1 升至 0.25表明水分胁迫初现TVDI ∈ [0.4, 0.6]中度干旱作物气孔导度开始下降TVDI ≥ 0.8严重干旱但需排除火点干扰Landsat 7 Band 6 亮温 330K 时可能是火点应屏蔽关键技巧在同一区域用 2000–2005 年 Landsat 7 数据拟合的干湿边比用单景数据更稳定——因为多年数据能平滑年际气候噪声建议建立本地长期干湿边库。5. TVDI 结果验证与不确定性量化用站点土壤湿度反演残差定位算法失效区TVDI 是相对指数无法直接换算成体积含水量θv但可通过与地面实测 θv 的统计关系验证其干旱指示能力。然而全国土壤湿度站点稀疏如中国 CERN 站点间距 200 km单点对比易受尺度效应影响。更有效的方法是计算 TVDI 与 θv 的残差空间分布识别系统性偏差区并归因到算法环节。5.1 站点数据匹配时空窗口与尺度转换时间匹配Landsat 7 过境时间UTC与站点 θv 观测时间需在 ±2 小时内。若站点只有日均值用过境时刻前 1 小时的 ERA5 土壤湿度0–7 cm 层替代空间匹配站点坐标 1 km 缓冲区内取 TVDI 像元中值非平均值避免缓冲区跨土地覆被类型导致均值失真尺度转换Landsat 像元30 m→ 站点~1 m²用随机森林回归学习 TVDI、NDVI、坡度、土壤质地HWSD 数据库到 θv 的映射残差即为 TVDI 本身误差。# 示例用 10 个站点训练 RF 模型特征TVDI, NDVI, slope, clay_pct from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_absolute_error # X: 特征矩阵n_samples × 4, y: 实测 θvn_samples rf RandomForestRegressor(n_estimators100, random_state42) rf.fit(X_train, y_train) y_pred rf.predict(X_test) residuals y_test - y_pred # 残差空间化将残差插值回 Landsat 栅格 residual_raster interpolate_residuals(residuals, site_coords, tvd_i.shape)5.2 不确定性热力图三类失效区诊断表失效区类型残差特征主要成因修复动作高海拔区如青藏高原残差 0.05TVDI 系统性低估干旱LST 反演中大气水汽压e_a低估高原实际 e_a 仅为平原 1/3用站点实测露点重算 L↓或改用高原专用 ε-LST 关系城市建成区残差 -0.08TVDI 高估干旱NDVI 计算未剔除不透水面沥青反射率高伪 NDVI≈0.15加入夜间灯光数据VIIRS掩膜NDVI 0.1 且灯光强度 10 时强制 TVDI0.3新耕作区如退耕还林地残差空间自相关距离 5 km干湿边未反映植被演替——幼林 NDVI 低但蒸腾强LST_wet 偏高用 NDVI 时间序列趋势如 GEE 上 5 年 Slope识别新植被单独拟合干湿边5.3 最小可行验证用 NDVI-LST 散点图形状快速判别无需站点数据仅凭单景 NDVI-LST 散点图即可初步判断 TVDI 可靠性健康散点图呈清晰“倒三角”顶点在 NDVI≈0.3–0.4干边峰值底边平直湿边接近水平失效信号 1大气校正失败散点图整体右倾LST 随 NDVI 单调上升湿边斜率 0.5 K/NDVI —— 表明 L↓ 过低LST 被高估失效信号 2SLC-off 插值污染散点图在 NDVI∈[0.1,0.3] 出现垂直条带LST 值集中于某几行表明克里金插值未收敛需检查 gap_mask 是否漏判 Band 6 低 SNR 区。最后一句技术要点当 Landsat 7 数据用于 TVDI 计算时真正决定结果质量的不是算法复杂度而是对三个“隐性参数”的本地化处理——L↓ 中的露点温度、ε-LST 关系中的 NDVI 阈值、干湿边拟合中的分段点 NDVI0.4。这些值必须用本区域 3 年以上实测数据校准而非照搬文献一次校准可复用但每更换主栽作物类型如玉米改种大豆需重新验证 NDVI 阈值。本文还有配套的精品资源点击获取
返回列表