Sentinel-2影像分析:NDVI计算与分区
在本博客中,我们将使用Google Earth Engine(GEE)进行Sentinel-2影像的分析,重点是归一化植被指数(NDVI)的计算与分区。通过以下步骤,我们将实现对特定区域的NDVI计算、分区可视化以及时间序列分析。
1. 定义感兴趣区域(AOI)
首先,我们需要定义一个感兴趣区域(AOI),这将是我们分析的基础。我们从指定的资产加载矢量特征集合,以下是代码示例:
var aoi = ee.FeatureCollection('projects/gee-trial2/assets/Shapfile/WMH_Distric');
Map.centerObject(aoi, 8); // 将地图中心移动到AOI,并设置缩放级别为8
2. 加载和处理Sentinel-2影像
接下来,我们将加载Sentinel-2影像数据,并进行一系列的过滤操作,以确保我们获得高质量的影像。我们将过滤出2023年10月1日至2023年12月31日之间的影像,并且云量小于10%。同时,我们将计算每幅影像的NDVI,并将其作为新波段添加到影像中:
var s2 = ee.ImageCollection("COPERNICUS/S2_SR")
.filterBounds(aoi) // 过滤出在AOI范围内的影像
.filterDate('2023-10-01', '2023-12-31') // 过滤出指定日期的影像
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 10)) // 过滤出云量小于10%的影像
.map(function(img) {
var ndvi = img.normalizedDifference(['B8', 'B4']).rename('NDVI'); // 计算NDVI
return img.addBands(ndvi); // 将NDVI作为新波段添加到影像中
});
// 获取AOI内的中位数NDVI影像
var ndvi = s2.select('NDVI').median().clip(aoi); // 选择NDVI波段,计算中位数并裁剪到AOI
3. NDVI分区
在计算完NDVI后,我们可以使用表达式对NDVI进行分区,定义不同的NDVI范围。以下是分区的代码示例:
var ndviZoned = ndvi.expression(
"(b('NDVI') < 0.2) ? 1" + // NDVI < 0.2 为 1(非常低)
": (b('NDVI') < 0.4) ? 2" + // 0.2 ≤ NDVI < 0.4 为 2(低)
": (b('NDVI') < 0.6) ? 3" + // 0.4 ≤ NDVI < 0.6 为 3(中)
": (b('NDVI') < 0.8) ? 4" + // 0.6 ≤ NDVI < 0.8 为 4(高)
": 5" // NDVI ≥ 0.8 为 5(非常高)
).rename('NDVI_Zones'); // 重命名分区结果
为了可视化分区结果,我们为不同的分区设置颜色:
var zoneVis = {
min: 1, // 最小值
max: 5, // 最大值
palette: ['red', 'orange', 'yellow', 'lightgreen', 'green'], // 分区颜色
};
// 将NDVI和分区结果添加到地图中
Map.addLayer(ndvi, {min: -1, max: 1, palette: ['white', 'blue', 'green']}, 'NDVI'); // 添加NDVI影像
Map.addLayer(ndviZoned.clip(aoi), zoneVis, 'NDVI Zonation'); // 添加NDVI分区结果,裁剪到AOI
4. NDVI时间序列图
为了分析NDVI随时间的变化,我们将创建NDVI的时间序列图。我们将计算每幅影像在AOI内的均值NDVI,并生成图表:
var ndviTimeSeries = s2.select('NDVI').map(function(image) {
var meanDict = image.reduceRegion({
reducer: ee.Reducer.mean(), // 使用均值计算
geometry: aoi, // 计算区域为AOI
scale: 10, // 设置像素分辨率为10米
maxPixels: 1e9 // 最大像素数
});
var meanNDVI = ee.Number(meanDict.get('NDVI')); // 获取均值NDVI
var date = ee.Date(image.get('system:time_start')); // 获取影像的时间
return ee.Feature(null, { // 创建一个特征对象
'NDVI': meanNDVI, // 设置NDVI属性
'system:time_start': date // 设置时间属性
});
});
// 创建并打印NDVI时间序列图
var chart = ui.Chart.feature.byFeature({
features: ndviTimeSeries, // 使用的特征集合
xProperty: 'system:time_start', // X轴属性为时间
yProperties: ['NDVI'] // Y轴属性为NDVI
}).setChartType('LineChart') // 设置图表类型为折线图
.setOptions({
title: 'NDVI Time Series (Mean NDVI in AOI)', // 图表标题
hAxis: {title: 'Date'}, // X轴标题
vAxis: {title: 'NDVI'}, // Y轴标题
lineWidth: 2, // 线宽
pointSize: 4, // 点大小
curveType: 'function', // 曲线类型
legend: {position: 'none'} // 隐藏图例
});
print(chart); // 打印图表
5. 图例UI
最后,我们将创建一个图例面板,以便更好地理解NDVI分区的颜色与标签。以下是图例的代码示例:
var legend = ui.Panel({
style: {
position: 'bottom-left', // 图例位置为左下角
padding: '8px 15px' // 图例内边距
}
});
// 添加图例标题
var legendTitle = ui.Label({
value: 'NDVI Zonation', // 标题内容
style: {fontWeight: 'bold', fontSize: '16px', margin: '0 0 4px 0'} // 样式设置
});
legend.add(legendTitle); // 将标题添加到图例面板
// 定义分区标签和对应颜色
var zonationLabels = ['Very Low', 'Low', 'Medium', 'High', 'Very High'];
var zonationColors = ['red', 'orange', 'yellow', 'lightgreen', 'green'];
// 循环创建每个分区的颜色框和描述
for (var i = 0; i < 5; i++) {
var colorBox = ui.Label('', { // 创建颜色框
backgroundColor: zonationColors[i], // 设置背景颜色
padding: '8px', // 设置内边距
margin: '0 0 4px 0' // 设置外边距
});
var description = ui.Label(zonationLabels[i], { // 创建描述标签
margin: '0 0 4px 6px' // 设置外边距
});
var row = ui.Panel({ // 创建一行面板,包含颜色框和描述
widgets: [colorBox, description], // 添加颜色框和描述
layout: ui.Panel.Layout.Flow('horizontal') // 设置水平布局
});
legend.add(row); // 将行添加到图例面板
}
// 将图例面板添加到地图中
Map.add(legend);
结果
总结
通过以上步骤,我们成功地定义了感兴趣区域,加载了Sentinel-2影像数据,计算了NDVI,进行了分区分析,并生成了NDVI的时间序列图。同时,我们还创建了图例面板,以便更好地理解分析结果。这些分析为我们提供了深入了解植被状况的重要工具,希望这篇博客能帮助您更好地利用Google Earth Engine进行环境监测与分析!
// ------------------ 1. 定义感兴趣区域(AOI) ------------------ //
// 从指定的资产加载感兴趣区域(AOI),这里是一个矢量特征集合
var aoi = ee.FeatureCollection('projects/gee-trial2/assets/Shapfile/WMH_Distric');
// 将地图中心移动到感兴趣区域,并设置缩放级别为8
Map.centerObject(aoi, 8);
// ------------------ 2. 加载和处理Sentinel-2影像 ------------------ //
// 加载Sentinel-2影像集合
var s2 = ee.ImageCollection("COPERNICUS/S2_SR")
// 过滤出在感兴趣区域内的影像
.filterBounds(aoi)
// 过滤出在2023年10月1日至2023年12月31日之间的影像
.filterDate('2023-10-01', '2023-12-31')
// 过滤出云量小于10%的影像
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 10))
// 对每幅影像进行处理,计算NDVI并将其添加为新波段
.map(function(img) {
var ndvi = img.normalizedDifference(['B8', 'B4']).rename('NDVI'); // 计算NDVI
return img.addBands(ndvi); // 将NDVI作为新波段添加到影像中
});
// 获取感兴趣区域内的中位数NDVI影像,用于空间分析
var ndvi = s2.select('NDVI').median().clip(aoi); // 选择NDVI波段,计算中位数并裁剪到AOI
// ------------------ 3. NDVI分区 ------------------ //
// 使用表达式对NDVI进行分区,定义不同的NDVI范围
var ndviZoned = ndvi.expression(
"(b('NDVI') < 0.2) ? 1" + // NDVI < 0.2 为 1(非常低)
": (b('NDVI') < 0.4) ? 2" + // 0.2 ≤ NDVI < 0.4 为 2(低)
": (b('NDVI') < 0.6) ? 3" + // 0.4 ≤ NDVI < 0.6 为 3(中)
": (b('NDVI') < 0.8) ? 4" + // 0.6 ≤ NDVI < 0.8 为 4(高)
": 5" // NDVI ≥ 0.8 为 5(非常高)
).rename('NDVI_Zones'); // 重命名分区结果
// 可视化分区的样式设置
var zoneVis = {
min: 1, // 最小值
max: 5, // 最大值
palette: ['red', 'orange', 'yellow', 'lightgreen', 'green'], // 分区颜色
};
// 将NDVI和分区结果添加到地图中
Map.addLayer(ndvi, {min: -1, max: 1, palette: ['white', 'blue', 'green']}, 'NDVI'); // 添加NDVI影像
Map.addLayer(ndviZoned.clip(aoi), zoneVis, 'NDVI Zonation'); // 添加NDVI分区结果,裁剪到AOI
// ------------------ 4. NDVI时间序列图 ------------------ //
// 创建NDVI时间序列,用于分析NDVI随时间的变化
var ndviTimeSeries = s2.select('NDVI').map(function(image) {
// 计算每幅影像在AOI内的NDVI均值
var meanDict = image.reduceRegion({
reducer: ee.Reducer.mean(), // 使用均值计算
geometry: aoi, // 计算区域为AOI
scale: 10, // 设置像素分辨率为10米
maxPixels: 1e9 // 最大像素数
});
var meanNDVI = ee.Number(meanDict.get('NDVI')); // 获取均值NDVI
var date = ee.Date(image.get('system:time_start')); // 获取影像的时间
return ee.Feature(null, { // 创建一个特征对象
'NDVI': meanNDVI, // 设置NDVI属性
'system:time_start': date // 设置时间属性
});
});
// 创建并打印NDVI时间序列图
var chart = ui.Chart.feature.byFeature({
features: ndviTimeSeries, // 使用的特征集合
xProperty: 'system:time_start', // X轴属性为时间
yProperties: ['NDVI'] // Y轴属性为NDVI
}).setChartType('LineChart') // 设置图表类型为折线图
.setOptions({
title: 'NDVI Time Series (Mean NDVI in AOI)', // 图表标题
hAxis: {title: 'Date'}, // X轴标题
vAxis: {title: 'NDVI'}, // Y轴标题
lineWidth: 2, // 线宽
pointSize: 4, // 点大小
curveType: 'function', // 曲线类型
legend: {position: 'none'} // 隐藏图例
});
print(chart); // 打印图表
// ------------------ 5. 图例UI ------------------ //
// 创建图例面板,显示NDVI分区的颜色与标签
var legend = ui.Panel({
style: {
position: 'bottom-left', // 图例位置为左下角
padding: '8px 15px' // 图例内边距
}
});
// 添加图例标题
var legendTitle = ui.Label({
value: 'NDVI Zonation', // 标题内容
style: {fontWeight: 'bold', fontSize: '16px', margin: '0 0 4px 0'} // 样式设置
});
legend.add(legendTitle); // 将标题添加到图例面板
// 定义分区标签和对应颜色
var zonationLabels = ['Very Low', 'Low', 'Medium', 'High', 'Very High'];
var zonationColors = ['red', 'orange', 'yellow', 'lightgreen', 'green'];
// 循环创建每个分区的颜色框和描述
for (var i = 0; i < 5; i++) {
var colorBox = ui.Label('', { // 创建颜色框
backgroundColor: zonationColors[i], // 设置背景颜色
padding: '8px', // 设置内边距
margin: '0 0 4px 0' // 设置外边距
});
var description = ui.Label(zonationLabels[i], { // 创建描述标签
margin: '0 0 4px 6px' // 设置外边距
});
var row = ui.Panel({ // 创建一行面板,包含颜色框和描述
widgets: [colorBox, description], // 添加颜色框和描述
layout: ui.Panel.Layout.Flow('horizontal') // 设置水平布局
});
legend.add(row); // 将行添加到图例面板
}
// 将图例面板添加到地图中
Map.add(legend);
代码功能总结
该代码实现了以下功能:
- 定义感兴趣区域(AOI):从指定的资产中加载地理区域。
- 加载和处理Sentinel-2影像:过滤影像并计算NDVI。
- NDVI分区:根据NDVI值将区域分为不同的等级,并进行可视化。
- NDVI时间序列图:分析NDVI随时间的变化,并生成折线图。
- 图例UI:创建一个图例面板,展示NDVI分区的颜色与标签。