目录
1 前言
2 代码解析
2.1 定义感兴趣区域并居中显示
2.2 加载数据集并过滤
2.3 定义 kNDVI 计算函数
2.4 生成年度影像集合
2.5 计算 NDVI 和 kNDVI 的时间序列
2.6 可视化时间序列
2.7 导出影像到 Google Drive
3 完整代码
4 运行结果
1 前言
在遥感领域,归一化植被指数(NDVI)是一个广泛使用的指标,用于评估植被覆盖和健康状况。然而,随着研究的深入,基于 NDVI 的改进指标,如核归一化植被指数(kNDVI),逐渐受到关注。本篇博客将详细介绍如何使用 Google Earth Engine (GEE) 的 JavaScript API,通过一段代码实现 NDVI 和 kNDVI 的计算、可视化以及数据导出。我们将逐步解析代码,帮助读者理解其逻辑和应用场景。
NDVI 是基于红光和近红外波段反射率计算的植被指数,其值范围在 -1 到 1 之间,反映了植被的生长状态。kNDVI 是 NDVI 的非线性变体,通过引入双曲正切函数(tanh)对 NDVI 进行变换,使其对高植被覆盖区域的敏感性更强。这在研究长期植被动态或高密度植被区时尤为有用。
主要内容:
- 定义一个感兴趣区域(ROI)。
- 从 Landsat 数据集中提取 2010-2020 年的 NDVI 数据。
- 计算 kNDVI。
- 生成 NDVI 和 kNDVI 的年度时间序列图。
- 将结果导出到 Google Drive。
2 代码解析
2.1 定义感兴趣区域并居中显示
var roi = geometry;
Map.centerObject(roi, 6);
- roi:用户定义的几何区域,通常在 GEE 编辑器中通过绘图工具手动指定。
- Map.centerObject(roi, 6):将地图视图居中于 roi,缩放级别为 6。这一步确保我们能在 GEE 的交互式地图上直观查看研究区域。
2.2 加载数据集并过滤
var dataset = ee.ImageCollection('LANDSAT/COMPOSITES/C02/T1_L2_ANNUAL_NDVI').filterBounds(roi).filterDate('2010-01-01', '2020-12-31');
- ee.ImageCollection:加载 Landsat 的年度 NDVI 合成数据集(LANDSAT/COMPOSITES/C02/T1_L2_ANNUAL_NDVI)。该数据集基于 Landsat Tier 1 Level 2 数据预计算了 NDVI。
- .filterBounds(roi):过滤出与 roi 空间相交的影像。
- .filterDate('2010-01-01', '2020-12-31'):限定时间范围为 2010 年至 2020 年。
2.3 定义 kNDVI 计算函数
function calculateKNDVI(NDVI) {return NDVI.pow(2).tanh().rename('kNDVI');
}
- calculateKNDVI:一个自定义函数,用于计算 kNDVI。
- NDVI.pow(2):将 NDVI 值平方。
- .tanh():应用双曲正切函数,输出范围为 (-1, 1),增强高 NDVI 值的区分度。
- .rename('kNDVI'):将结果波段重命名为 kNDVI。
2.4 生成年度影像集合
var years = ee.List.sequence(2010, 2020);var annualData = years.map(function(year) {var yearStr = ee.Number(year).format('%d');var image = dataset.filterDate(yearStr.cat('-01-01'), yearStr.cat('-12-31')).mean().clip(roi);var NDVI = image.select('NDVI').rename('NDVI');var kNDVI = calculateKNDVI(NDVI);return NDVI.addBands(kNDVI).set('year', year);
});var annualCollection = ee.ImageCollection(annualData);
- ee.List.sequence(2010, 2020):生成 2010-2020 的年份列表。
- .map(function(year) {...}):对每个年份执行操作:
- yearStr.cat('-01-01') 和 yearStr.cat('-12-31'):构造每年的起止日期。
- .filterDate().mean():过滤该年份数据并计算均值。
- .clip(roi):裁剪到感兴趣区域。
- NDVI.addBands(kNDVI):将 NDVI 和 kNDVI 合并为多波段影像。
- .set('year', year):为影像添加年份属性。
- ee.ImageCollection(annualData):将结果转为影像集合。
2.5 计算 NDVI 和 kNDVI 的时间序列
var ndviSeries = annualCollection.map(function(img) {var mean = img.select('NDVI').reduceRegion({reducer: ee.Reducer.mean(),geometry: roi,scale: 500,maxPixels: 1e13}).get('NDVI');return ee.Feature(null, {'year': img.get('year'), 'NDVI': mean});
});var kndviSeries = annualCollection.map(function(img) {var mean = img.select('kNDVI').reduceRegion({reducer: ee.Reducer.mean(),geometry: roi,scale: 500,maxPixels: 1e13}).get('kNDVI');return ee.Feature(null, {'year': img.get('year'), 'kNDVI': mean});
});
- .reduceRegion():对指定波段(NDVI 或 kNDVI)在 roi 内计算均值。
- reducer: ee.Reducer.mean():使用均值缩减器。
- scale: 500:计算分辨率为 500 米。
- maxPixels: 1e13:设置最大像素数,避免超出计算限制。
- ee.Feature(null, {...}):将年份和均值封装为无几何信息的要素,用于后续绘图。
2.6 可视化时间序列
var ndviChart = ui.Chart.feature.byFeature(ndviSeries, 'year', ['NDVI']).setOptions({title: 'NDVI trend',hAxis: {title: 'Year'},vAxis: {title: 'NDVI'},lineWidth: 2,pointSize: 4,colors: ['green']});
print(ndviChart);var kndviChart = ui.Chart.feature.byFeature(kndviSeries, 'year', ['kNDVI']).setOptions({title: 'kNDVI trend',hAxis: {title: 'Year'},vAxis: {title: 'kNDVI'},lineWidth: 2,pointSize: 4,colors: ['blue']});
print(kndviChart);
- ui.Chart.feature.byFeature:根据要素集合绘制折线图。
- X 轴为 year,Y 轴为 NDVI 或 kNDVI。
- .setOptions({...}):设置图表样式,包括标题、轴标签、线条宽度、点大小和颜色。
- print():将图表输出到 GEE 控制台。
2.7 导出影像到 Google Drive
years.evaluate(function(yearList) {yearList.forEach(function(year) {var image = annualCollection.filter(ee.Filter.eq('year', year)).first();Export.image.toDrive({image: image.select('NDVI'),description: "NDVI_" + year,fileNamePrefix: "NDVI_" + year,scale: 500,region: roi,crs: "EPSG:4326",maxPixels: 1e13,folder: 'Annual_NDVI'});Export.image.toDrive({image: image.select('kNDVI'),description: "kNDVI_" + year,fileNamePrefix: "kNDVI_" + year,scale: 500,region: roi,crs: "EPSG:4326",maxPixels: 1e13,folder: 'Annual_kNDVI'});});
});
- years.evaluate():将服务器端的年份列表转为客户端可用的 JavaScript 数组。
- .forEach():对每个年份执行导出:
- .filter().first():从集合中提取该年份的影像。
- Export.image.toDrive():将 NDVI 和 kNDVI 影像分别导出。
- scale: 500:分辨率为 500 米。
- crs: "EPSG:4326":使用 WGS84 坐标系。
- folder:分别存储在 Annual_NDVI 和 Annual_kNDVI 文件夹中。
3 完整代码
var roi = geometry;
Map.centerObject(roi, 6);var dataset = ee.ImageCollection('LANDSAT/COMPOSITES/C02/T1_L2_ANNUAL_NDVI').filterBounds(roi).filterDate('2010-01-01', '2020-12-31');function calculateKNDVI(NDVI) {return NDVI.pow(2).tanh().rename('kNDVI');
}var years = ee.List.sequence(2010, 2020);var annualData = years.map(function(year) {var yearStr = ee.Number(year).format('%d');var image = dataset.filterDate(yearStr.cat('-01-01'), yearStr.cat('-12-31')).mean().clip(roi);var NDVI = image.select('NDVI').rename('NDVI');var kNDVI = calculateKNDVI(NDVI);return NDVI.addBands(kNDVI).set('year', year);
});var annualCollection = ee.ImageCollection(annualData);var ndviSeries = annualCollection.map(function(img) {var mean = img.select('NDVI').reduceRegion({reducer: ee.Reducer.mean(),geometry: roi,scale: 500,maxPixels: 1e13}).get('NDVI');return ee.Feature(null, {'year': img.get('year'), 'NDVI': mean});
});var kndviSeries = annualCollection.map(function(img) {var mean = img.select('kNDVI').reduceRegion({reducer: ee.Reducer.mean(),geometry: roi,scale: 500,maxPixels: 1e13}).get('kNDVI');return ee.Feature(null, {'year': img.get('year'), 'kNDVI': mean});
});var ndviChart = ui.Chart.feature.byFeature(ndviSeries, 'year', ['NDVI']).setOptions({title: 'NDVI trend',hAxis: {title: 'Year'},vAxis: {title: 'NDVI'},lineWidth: 2,pointSize: 4,colors: ['green']});
print(ndviChart);var kndviChart = ui.Chart.feature.byFeature(kndviSeries, 'year', ['kNDVI']).setOptions({title: 'kNDVI trend',hAxis: {title: 'Year'},vAxis: {title: 'kNDVI'},lineWidth: 2,pointSize: 4,colors: ['blue']});
print(kndviChart);years.evaluate(function(yearList) {yearList.forEach(function(year) {var image = annualCollection.filter(ee.Filter.eq('year', year)).first();Export.image.toDrive({image: image.select('NDVI'),description: "NDVI_" + year,fileNamePrefix: "NDVI_" + year,scale: 500,region: roi,crs: "EPSG:4326",maxPixels: 1e13,folder: 'Annual_NDVI'});Export.image.toDrive({image: image.select('kNDVI'),description: "kNDVI_" + year,fileNamePrefix: "kNDVI_" + year,scale: 500,region: roi,crs: "EPSG:4326",maxPixels: 1e13,folder: 'Annual_kNDVI'});});
});
4 运行结果


