174 lines
5.8 KiB
JavaScript

/**
* Landsat 系列地表温度 (LST) 数据下载 —— 以年平均温度处理下载为例
*
* @author CVEO Team
* @date 2026-01-15
*
* 1. 加载 Landsat-8, Landsat-9 SR 数据
* 2. 合并 Landsat-8, Landsat-9 LST 数据
* 3. 合成年度平均 Landsat LST 数据
* 4. 导出 COG 云优化并填补缺失值的 GeoTIFF 影像 (大区域 GEE 自动分块下载)
*/
// 加载研究区域和影像
var region_name = "应城市";
var region_name_en = "Yingcheng";
var region = Yingcheng;
var crs = "EPSG:4526";
// var region_name = "保康县";
// var region_name_en = "Baokang";
// var region = Baokang;
// var crs = "EPSG:4525";
var start_year = 2021;
var end_year = 2025;
var start_date = start_year + "-01-01";
var end_date = end_year + "-12-31";
var cloud_threshold = 90; // 最大云量阈值
var LansatBands = ["ST_B10"];
var commonBands = ["LST"];
var region_geo = region.geometry();
var bounds = region_geo.bounds();
var common_filter = ee.Filter.and(
ee.Filter.bounds(bounds),
ee.Filter.date(start_date, end_date)
);
/**
* Applies scaling factors.
* @param {ee.Image} image Landsat SR image
* @returns {ee.Image} Landsat SR image with scaled bands
*/
function applyScaleFactors(image) {
var opticalBands = image.select("SR_B.").multiply(0.0000275).add(-0.2);
var thermalBands = image.select("ST_B.*").multiply(0.00341802).add(149.0);
return image
.addBands(opticalBands, null, true)
.addBands(thermalBands, null, true);
}
/**
* 开尔文转摄氏度
* @param {ee.Image} image Landsat LST image
* @returns {ee.Image} Landsat LST image in Celsius
*/
function kelvinToCelsius(image) {
return ee.Image(image.expression("B1 - 273.15", { B1: image.select(0) }))
.rename("LST")
.copyProperties(image)
.copyProperties(image, ["system:time_start", "system:index", "system:id"]);
}
/**
* Function to mask clouds using the Landsat QA_PIXEL and QA_RADSAT bands
* @param {ee.Image} image Landsat SR image
* @return {ee.Image} cloud masked and saturated Landsat SR image
*/
function maskLandsatclouds(image) {
var qa = image.select("QA_PIXEL");
var qa_radsat = image.select("QA_RADSAT");
// Bits 3 and 4 are cloud and cloud shadow, respectively.
var cloudBitMask = 1 << 3;
var shadowBitMask = 1 << 4;
// Both flags should be set to zero, indicating clear conditions.
var mask = qa.bitwiseAnd(cloudBitMask).eq(0)
.and(qa.bitwiseAnd(shadowBitMask).eq(0))
.and(qa_radsat.eq(0));
image = image.updateMask(mask);
return image
.copyProperties(image)
.copyProperties(image, ["system:time_start", "system:index", "system:id"]);
}
// 加载 Landsat-8, Landsat-9 SR 数据
var L8dataset = ee.ImageCollection("LANDSAT/LC08/C02/T1_L2")
.filter(common_filter)
.filter(ee.Filter.lt("CLOUD_COVER", cloud_threshold));
print(start_date + " - " + end_date + " Landsat-8 SR dataset", L8dataset);
var L9dataset = ee.ImageCollection("LANDSAT/LC09/C02/T1_L2")
.filter(common_filter)
.filter(ee.Filter.lt("CLOUD_COVER", cloud_threshold));
print(start_date + " - " + end_date + " Landsat-9 SR dataset", L9dataset);
// 合并 Landsat-8, Landsat-9 LST 数据
var LSTdataset = L8dataset.merge(L9dataset)
.map(applyScaleFactors)
.map(maskLandsatclouds)
.select(LansatBands, commonBands)
.map(kelvinToCelsius);
print(start_date + " - " + end_date + " Landsat-8,9 LST dataset", LSTdataset);
// 合成年度平均 Landsat LST 数据
var years = ee.List.sequence(start_year, end_year);
var months = ee.List.sequence(1, 12);
var yearlyLST = ee.ImageCollection.fromImages(
years.map(function (y) {
return ee.ImageCollection.fromImages(
months.map(function (m) {
return LSTdataset
.filter(ee.Filter.calendarRange(y, y, "year"))
.filter(ee.Filter.calendarRange(m, m, "month"))
.mean()
.clip(bounds)
.set("month", m)
.set("year", y);
})
).mean().set("year", y);
})
);
if (start_year == end_year) {
var year_str = start_year;
} else {
var year_str = start_year + "-" + end_year;
}
print(year_str + " Annual Mean Landsat LST dataset", yearlyLST);
var total_mean_LST = LSTdataset.select("LST").mean();
print(year_str + " Total Year Mean Landsat LST Histogram", ui.Chart.image.histogram(total_mean_LST, region, 100, 258));
var annual_mean_LST = yearlyLST.select("LST").mean();
print(year_str + " Annual Mean Landsat LST Histogram", ui.Chart.image.histogram(annual_mean_LST, region, 100, 258));
var lst_vis = {
min: 2,
max: 40,
palette: [
'040274', '040281', '0502a3', '0502b8', '0502ce', '0502e6',
'0602ff', '235cb1', '307ef3', '269db1', '30c8e2', '32d3ef',
'3be285', '3ff38f', '86e26f', '3ae237', 'b5e22e', 'd6e21f',
'fff705', 'ffd611', 'ffb613', 'ff8b13', 'ff6e08', 'ff500d',
'ff0000', 'de0101', 'c21301', 'a71001', '911003'
],
};
var styling = {
color: "blue",
fillColor: "00000000",
};
Map.centerObject(region, 10);
Map.addLayer(total_mean_LST, lst_vis, year_str + " Landsat Total Year Mean LST");
Map.addLayer(annual_mean_LST, lst_vis, year_str + " Landsat Annual Mean LST");
Map.addLayer(region.style(styling), {}, region_name);
// 导出合并后的影像
// 明确设置数据类型为Float32, 否则默认类型为Float64, 会占用更多内存
// 并对缺失值进行填充, 否则默认为nan不便于后续本地处理
var processed_img = annual_mean_LST.toFloat().unmask(-9999.0);
print("Start exporting " + year_str + "Yearly Mean LST image (" + crs + ")", processed_img);
Export.image.toDrive({
image: processed_img,
description: region_name_en + "_LST_" + year_str,
folder: "LST",
region: region, // 添加后会自动裁剪
scale: 30,
crs: crs,
maxPixels: 1e13, // GEE 最多支持 1e8 像素, 当超过时会自动分块
fileFormat: "GeoTIFF",
// 导出COG云优化的GeoTIFF影像, 并明确设置缺失值为-9999.0
formatOptions: {
cloudOptimized: true,
noData: -9999.0,
},
});