用Google Earth Engine (GEE) 批量计算 Sentinel-2 (哨兵2号)10米分辨率的夏季 NDVI
·
心思路
- 用 Sentinel-2 影像(10米分辨率,适合植被监测)
- 只取夏季(7-9月),植被生长茂盛,季相一致
- 做云掩膜,去掉云的干扰
- 计算每年夏季的 NDVI 中值(用中值比均值更稳健,减少残留云/阴影影响)
- 批量导出为 TIFF
代码分步解析
1. 导入研究区
首先得把你自己的行政区矢量文件上传到 GEE 的 Assets 里,然后替换下面的路径。
// =========================
// 1. 导入行政区
// =========================
var roi = ee.FeatureCollection("users/你的用户名/你的行政区"); // 这里改成你自己的矢量路径
Map.centerObject(roi, 8); // 地图缩放到研究区,级别8差不多是地级市大小
Map.addLayer(roi, {color: 'red'}, 'ROI'); // 把研究区用红色框显示出来
2. 云掩膜函数
Sentinel-2 的 QA60 波段是质量控制波段,专门用来标记云。这里用位运算把云和卷云都去掉。
// =========================
// 2. 云掩膜
// =========================
function maskS2Clouds(image) {
var qa = image.select('QA60'); // 提取质量控制波段
// 第10位是云,第11位是卷云,把这两位设为0(即无云)
var cloudBitMask = 1 << 10;
var cirrusBitMask = 1 << 11;
// 只有当这两位都为0时,像素才保留
var mask = qa.bitwiseAnd(cloudBitMask).eq(0)
.and(qa.bitwiseAnd(cirrusBitMask).eq(0));
// 应用掩膜,并把反射率从0-10000缩放到0-1(Sentinel-2原始值是放大了10000倍的)
return image.updateMask(mask).divide(10000);
}
3. NDVI 计算函数
NDVI 公式是 (近红外 - 红光) / (近红外 + 红光)。Sentinel-2 的 B8 是近红外,B4 是红光。
// =========================
// 3. NDVI函数
// =========================
function addNDVI(image) {
var ndvi = image.normalizedDifference(['B8', 'B4']).rename('NDVI'); // 计算NDVI并重命名波段
return image.addBands(ndvi); // 把NDVI作为新波段加回影像中
}
4. 设定时间范围
这里用了2019-2023,你可以根据需要改成2020-2024或者其他年份。
// =========================
// 4. 年份列表(近5年)
// =========================
var years = ee.List.sequence(2019, 2023);
// 👉 可以改成 2020–2024
5. 循环计算每年的 NDVI
这一步是核心:遍历每一年,筛选该年7-9月的影像,去云,计算NDVI,最后取中值合成一张图。
// =========================
// 5. 循环计算每年NDVI
// =========================
var yearlyNDVI = years.map(function(year) {
year = ee.Number(year); // 把年份转成GEE能识别的数字格式
// 定义夏季的起止时间(7月1日到9月30日)
var start = ee.Date.fromYMD(year, 7, 1);
var end = ee.Date.fromYMD(year, 9, 30);
// 筛选 Sentinel-2 影像
var collection = ee.ImageCollection('COPERNICUS/S2_SR_HARMONIZED')
.filterBounds(roi) // 只取研究区范围内的
.filterDate(start, end) // 只取该年夏季的
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 20)) // 只取云量小于20%的影像(减少计算量)
.map(maskS2Clouds) // 对每一张影像做云掩膜
.map(addNDVI); // 对每一张影像计算NDVI
// 提取NDVI波段,取中值,裁剪到研究区,并设置年份属性
var ndvi = collection.select('NDVI')
.median() // 用中值合成,避免极端值影响
.clip(roi) // 裁剪
.set('year', year); // 存一下年份,方便后面导出
return ndvi;
});
// 把计算结果转成 ImageCollection 格式,方便后续操作
var ndviCollection = ee.ImageCollection(yearlyNDVI);
6. 简单可视化一下
先看看第一年的效果,心里有个底。
// =========================
// 6. 可视化(示例显示第一年)
// =========================
var ndviVis = {
min: 0,
max: 1,
palette: ['white', 'green'] // 颜色从白(低NDVI)到绿(高NDVI)
};
var firstYear = ee.Image(ndviCollection.first()); // 取出第一年的影像
Map.addLayer(firstYear, ndviVis, 'NDVI First Year'); // 加到地图上
7. 批量导出到 Google Drive
这是最后一步,也是最爽的一步,点一下 Run,剩下的交给 GEE 服务器。
// =========================
// 7. 批量导出(关键)
// =========================
years.getInfo().forEach(function(year) {
// 从集合中筛选出对应年份的那张影像
var image = ndviCollection
.filter(ee.Filter.eq('year', year))
.first();
// 导出到 Google Drive
Export.image.toDrive({
image: image,
description: 'NDVI_' + year, // 任务名称
folder: 'GEE_NDVI', // Drive里的文件夹名(没有的话会自动创建)
fileNamePrefix: 'NDVI_' + year + '_Jul_Sep', // 文件名前缀
region: roi.geometry(), // 导出范围
scale: 10, // 分辨率10米(Sentinel-2原生分辨率)
maxPixels: 1e13 // 允许的最大像元数(防止区域太大报错)
});
});
注意事项
- 矢量文件:一定要先把你的 Shapefile 或者 GeoJSON 上传到 GEE 的
Assets,不然代码跑不了。 - 云量阈值:代码里设的是
CLOUDY_PIXEL_PERCENTAGE < 20,如果你研究区夏天云特别多,可以适当放宽到30,但掩膜后的效果可能会差点。 - 时间范围:如果是做冬季作物,记得把
start和end改成对应的月份。
更多推荐



所有评论(0)