用Google Earth Engine (GEE) 批量计算 Sentinel-2 (哨兵2号)10米分辨率的夏季 NDVI

📅 2026/7/2 3:15:54
用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-1Sentinel-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–20245. 循环计算每年的 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改成对应的月份。