心思路

  1. 用 Sentinel-2 影像(10米分辨率,适合植被监测)
  2. 只取夏季(7-9月),植被生长茂盛,季相一致
  3. 做云掩膜,去掉云的干扰
  4. 计算每年夏季的 NDVI 中值(用中值比均值更稳健,减少残留云/阴影影响)
  5. 批量导出为 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 // 允许的最大像元数(防止区域太大报错)
  });
});

注意事项

  1. 矢量文件:一定要先把你的 Shapefile 或者 GeoJSON 上传到 GEE 的 Assets,不然代码跑不了。
  2. 云量阈值:代码里设的是 CLOUDY_PIXEL_PERCENTAGE < 20,如果你研究区夏天云特别多,可以适当放宽到30,但掩膜后的效果可能会差点。
  3. 时间范围:如果是做冬季作物,记得把 start 和 end 改成对应的月份。
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐