当前位置: 首页 > news >正文

【Python实例】读取/处理 Landsat LST数据

目录

  • 数据准备
    • 💡 QA 掩码如何工作:
  • 基于Python读取Landsat LST数据
    • 1_LST信息读取及可视化
    • 2_QA信息读取及可视化
    • 3_基于云层/阴影掩膜图层 (ST_QA.TIF)得到去云温度图
  • 参考

下载Landsat LST数据的详细过程可参见另一博客-【数据集】EarthExplore下载Landsat LST 数据。本博客提供详细Python代码进行LST数据的可视化以及处理。

数据准备

以 Landsat 8 的地表温度波段(ST_B10.TIF)为例,实现以下两个功能:
一、读取并可视化地表温度(ST_B10)图像+云层覆盖信息(QA)图像
二、提取影像详细信息(包括元数据、云层、空间信息等)

地表温度单位说明:
Landsat 8 ST_B10 是以 数字数值(DN) 存储的,转换为 开尔文(K) 的公式为:

ST = DN * 0.00341802 + 149.0

💡 QA 掩码如何工作:

Landsat 地表温度 QA 波段是一个 位掩码(bitmask),每个像素的值是一个整数,具体位代表不同特征:

位段含义
0–1填充值标记(无效像素)
2–3云层
4–5云影
6–7雪/冰

基于Python读取Landsat LST数据

1_LST信息读取及可视化

绘制的地块 LST 数据如下:
在这里插入图片描述此图像出现了一条 垂直白色带状区域,表示该区域的像素值为 缺失值或无效值(NaN),所以在绘图时显示为白色。

🔍 可能原因分析(按优先级排序)

编号原因说明
🟡 1卫星扫描缝隙 / 数据缺失(缺口)Landsat 卫星扫描为“摆扫式”,在某些路径行可能会出现写入失败、断带或缺失
🟠 2云层遮挡被掩膜掉了如果 QA 掩膜将该区域标记为云或云影,温度图就被设置为 NaN
🔵 3卫星姿态调整或角度问题有些场景在极端角度下成像,边缘存在畸变或数据空白
⚫ 4数据产品问题 / 处理失败处理过程中某波段损坏、投影失败,也可能导致区域为空

完整Python实现代码如下:

import rasterio
import numpy as np
import matplotlib.pyplot as plt
from rasterio.plot import show
from rasterio.plot import show_hist
from rasterio.plot import plotting_extent
from mpl_toolkits.axes_grid1 import make_axes_locatable
from matplotlib.patches import Rectangle
import os# 设置字体为 Times New Roman
plt.rcParams['font.family'] = 'Times New Roman'# === 1. 设置路径 ===
lst_path = r"D:\0 DataBase\13_EarthExplore_LC08_L2SP\LC08_L2SP_127039_20190117_20200829_02_T1_ST_B10.TIF"
qa_path = r"D:\0 DataBase\13_EarthExplore_LC08_L2SP\LC08_L2SP_127039_20190117_20200829_02_T1_ST_QA.TIF"save_dir = r"D:\0 DataBase\13_EarthExplore_LC08_L2SP\Figures"if not os.path.exists(save_dir):os.makedirs(save_dir)# === 读取 LST 波段 ===
with rasterio.open(lst_path) as src:band = src.read(1)metadata = src.metabounds = src.boundscrs = src.crstransform = src.transformnodata = src.nodataextent = plotting_extent(src)# 打印元信息
print("📄 File metadata:")
print(f" - Data type: {metadata['dtype']}")
print(f" - Resolution: {src.res}")
print(f" - CRS: {crs}")
print(f" - Bounds: {bounds}")
print(f" - NoData value: {nodata}")
print("\n🌡 Pixel value range (DN):")
print(f" - Min: {np.nanmin(band)}")
print(f" - Max: {np.nanmax(band)}")# 转换为温度(摄氏度)
lst_kelvin = band * 0.00341802 + 149.0
lst_kelvin = np.where(band == nodata, np.nan, lst_kelvin)
lst_celsius = lst_kelvin - 273.15# === 3. 可视化地表温度 + 经纬度 ===
fig, ax = plt.subplots(figsize=(10, 8))
im = ax.imshow(lst_celsius, cmap='plasma', extent=extent)
ax.set_title("Landsat 8 Surface Temperature (°C)", fontsize=15)
ax.set_xlabel("Longitude", fontsize=14)
ax.set_ylabel("Latitude", fontsize=14)
ax.grid(True, linestyle='--', linewidth=0.5)# ✅ 设置 colorbar 与主图高度相同
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.1)
cbar = plt.colorbar(im, cax=cax)
cbar.set_label("Temperature (°C)", fontsize=14)# 保存图像
output_path_lst = os.path.join(save_dir, "Landsat8_Surface_Temperature.png")
plt.tight_layout()
plt.savefig(output_path_lst, dpi=300)
plt.show()

输出信息如下:

📄 File metadata:- Data type: uint16- Resolution: (30.0, 30.0)- CRS: EPSG:32648- Bounds: BoundingBox(left=642885.0, bottom=3239685.0, right=869415.0, top=3470715.0)- NoData value: 0.0🌡 Pixel value range (DN):- Min: 0- Max: 47143

2_QA信息读取及可视化

在这里插入图片描述

这幅图是根据 TIF 文件 ST_QA.TIF 中的 “位掩码(bitmask)” 生成的,所显示的是:

区域含义在图中颜色
黑色区域被标记为云层或云影的像素黑色(值为 True)
白色区域被标记为清晰无云的像素白色(值为 False)
灰色区域(若有)可能是图像压缩造成混色或边缘过渡视觉效果

完整Python实现代码如下:

# === 4. 读取 QA 波段并解析云掩膜 ===
with rasterio.open(qa_path) as qa_src:qa_band = qa_src.read(1)qa_extent = plotting_extent(qa_src)# Landsat 8 ST_QA 位掩码含义(示例:常用位段)
# Bit 0-1: Designated Fill
# Bit 2-3: Cloud
# Bit 4-5: Cloud shadow
# Bit 6-7: Snow/Ice
# Bit 8-9+: Cirrus, etc.# 提取云层 & 云影掩膜(以下是简化示例,具体可根据官方文档调整)
cloud_mask = np.bitwise_and(qa_band, 0b00001100) > 0
shadow_mask = np.bitwise_and(qa_band, 0b00110000) > 0# 创建综合掩膜
cloud_and_shadow = np.logical_or(cloud_mask, shadow_mask)# 可视化掩膜
plt.figure(figsize=(8, 6))
plt.imshow(cloud_and_shadow, cmap='gray', extent=extent)
plt.title("Cloud and Shadow Mask (QA Band)", fontsize=15)
plt.xlabel("Longitude", fontsize=14)
plt.ylabel("Latitude", fontsize=14)
plt.grid(True, linestyle='--', linewidth=0.5)"""
# ✅ 添加图像边框(外框)
rect = Rectangle((qa_extent[0], qa_extent[2]),  # 左下角 (minX, minY)qa_extent[1] - qa_extent[0],   # 宽度 (maxX - minX)qa_extent[3] - qa_extent[2],   # 高度 (maxY - minY)linewidth=1.5,edgecolor='black',facecolor='none'
)
ax.add_patch(rect)
"""# ✅ 方法:手动用 plot 画边框
x_min, x_max, y_min, y_max = qa_extent[0], qa_extent[1], qa_extent[2], qa_extent[3]# 画4条边线
ax.plot([x_min, x_max], [y_min, y_min], color='black', linewidth=1.5)  # 下边
ax.plot([x_min, x_max], [y_max, y_max], color='black', linewidth=1.5)  # 上边
ax.plot([x_min, x_min], [y_min, y_max], color='black', linewidth=1.5)  # 左边
ax.plot([x_max, x_max], [y_min, y_max], color='black', linewidth=1.5)  # 右边# 保存图像
output_path_qa = os.path.join(save_dir, "Landsat8_QA_Cloud_Mask.png")
plt.tight_layout()
plt.savefig(output_path_qa, dpi=300)
plt.show()# 输出云像素统计
total_pixels = cloud_and_shadow.size
cloud_pixels = np.sum(cloud_and_shadow)
print(f"\n☁️ Cloud/Shadow Pixels: {cloud_pixels} ({cloud_pixels / total_pixels * 100:.2f}%)")print(f"✅ QA mask image saved to: {output_path_qa}")
print(f"✅ LST image saved to: {output_path_lst}")

输出信息如下:

☁️ Cloud/Shadow Pixels: 55351269 (95.19%)

3_基于云层/阴影掩膜图层 (ST_QA.TIF)得到去云温度图

目标任务

  1. 使用 cloud_and_shadow 掩膜,将受影响像素设为 NaN
  2. 绘制“去云”后的地表温度图(单位:°C)
  3. 导出处理后的图像为 .png 图像(可视化图)和 .tif(GeoTIFF)

绘制的去云温度图如下:
在这里插入图片描述

完整实现代码如下(Python):

import rasterio
import numpy as np
import matplotlib.pyplot as plt
from rasterio.plot import plotting_extent
from mpl_toolkits.axes_grid1 import make_axes_locatable
from rasterio.transform import Affine
from rasterio.crs import CRS
import os
import numpy.ma as ma# 设置字体
plt.rcParams['font.family'] = 'Times New Roman'# === 文件路径 ===
lst_path = r"D:\0 DataBase\13_EarthExplore_LC08_L2SP\LC08_L2SP_127039_20190117_20200829_02_T1_ST_B10.TIF"
qa_path = r"D:\0 DataBase\13_EarthExplore_LC08_L2SP\LC08_L2SP_127039_20190117_20200829_02_T1_ST_QA.TIF"
save_dir = r"D:\0 DataBase\13_EarthExplore_LC08_L2SP\Figures"if not os.path.exists(save_dir):os.makedirs(save_dir)# === 读取 LST 波段 ===
with rasterio.open(lst_path) as src:lst_dn = src.read(1)lst_meta = src.meta.copy()lst_extent = plotting_extent(src)lst_crs = src.crslst_transform = src.transformnodata = src.nodata# 转换为摄氏度
lst_kelvin = lst_dn * 0.00341802 + 149.0
lst_kelvin = np.where(lst_dn == nodata, np.nan, lst_kelvin)
lst_celsius = lst_kelvin - 273.15# === 读取 QA 波段并创建掩膜 ===
with rasterio.open(qa_path) as qa_src:qa_band = qa_src.read(1)cloud_mask = np.bitwise_and(qa_band, 0b00001100) > 0
shadow_mask = np.bitwise_and(qa_band, 0b00110000) > 0
cloud_and_shadow = np.logical_or(cloud_mask, shadow_mask)# === 应用掩膜:将云层和阴影区域设为 NaN ===
lst_masked = np.where(cloud_and_shadow, np.nan, lst_celsius)# 使用掩膜数组隐藏 NaN
masked_array = ma.masked_invalid(lst_masked)# === 可视化去云后的地表温度图 ===
fig, ax = plt.subplots(figsize=(10, 8))
im = ax.imshow(masked_array, cmap='plasma', extent=lst_extent)
ax.set_title("Cloud-masked Surface Temperature (°C)", fontsize=15)
ax.set_xlabel("Longitude", fontsize=14)
ax.set_ylabel("Latitude", fontsize=14)
ax.grid(True, linestyle='--', linewidth=0.5)from mpl_toolkits.axes_grid1 import make_axes_locatable
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.1)
cbar = plt.colorbar(im, cax=cax)
cbar.set_label("Temperature (°C)")plt.tight_layout()
plt.savefig(os.path.join(save_dir, "LST_Masked_by_QA_fixed.png"), dpi=300)
plt.show()png_path = os.path.join(save_dir, "LST_Masked_by_QA.png")
print(f"✅ Cloud-masked temperature PNG saved to:\n{png_path}")# === 导出 GeoTIFF(去云地表温度)===
tif_path = os.path.join(save_dir, "LST_Masked_by_QA.tif")# 更新元数据
lst_meta.update({"dtype": "float32","nodata": np.nan,"count": 1,"crs": lst_crs,"transform": lst_transform
})with rasterio.open(tif_path, "w", **lst_meta) as dst:dst.write(lst_masked.astype(np.float32), 1)print(f"✅ Cloud-masked temperature GeoTIFF saved to:\n{tif_path}")

参考

http://www.xdnf.cn/news/699085.html

相关文章:

  • Three.js引擎基础
  • HIS系统——药库管理模块功能解析
  • 【操作系统】内存管理知识点深度解析
  • 直播框架:基础知识点
  • 【基础题库回复四则】2022-1-26
  • git提交更改
  • 三强联合!Attention+LSTM,结合特征融合,起手二区!
  • 从“被动养老”到“主动健康管理”:平台如何重构代际关系?
  • Linux上给SD卡创建分区
  • 光谱相机在生态修复监测中的应用
  • LeetCode 463. 岛屿的周长 java题解
  • 软件测试之黑盒测试与白盒测试详解
  • python 小工具,获取 github 仓库信息
  • ORDER BY子句在一个 SQL 查询中只能出现一次
  • 全球轨道铺设设备市场发展现状与未来趋势分析
  • HDFS:解锁大数据存储的奥秘
  • 54、C# 委托 (Delegate)
  • Maven 项目中集成数据库文档生成工具
  • leetcode hot100刷题日记——23.数组中的第K个最大元素
  • 磁光电流互感器行业2025数据分析报告
  • UE5 编辑器工具蓝图
  • 2025年AEJ SCI2区,动态反向排序教与学优化算法DSTLBO+光伏系统参数辨识,深度解析+性能实测
  • java课堂笔记10
  • ubuntu创建指定版本python虚拟环境
  • emu8086 v4.08安装教程
  • Python基础语法(下)
  • 打破认知壁垒重构科技驱动美好生活 大模型义务传播计划
  • 数据科学入门
  • CS144 - Lecture 1 记录
  • js中common.js和ECMAScript.js区别