GEEer成长日记五:Sentinel-2计算NDVI并逐月时间序列分析

  前几期我们介绍了MODIS和LANDSAT8遥感影像的MDVI时间序列,其他数据也与此类似,大家根据实际情况修改即可。本期我们介绍Sentinel-2   Level-2A数据在时间序列方面的研究。 

COPERNICUS/S2_SR

如果想深入了解这两个数据集,可以登录:

https://sentinel.esa.int/web/sentinel/user-guides/sentinel-2-msi/product-types/level-2a

European Union/ESA/Copernicus

https://sentinel.esa.int/web/sentinel/user-guides/sentinel-2-msi/resolutions/radiometric

辐射分辨率介绍

  GEE官方介绍:Sentinel-2 is a wide-swath, high-resolution, multi-spectral imaging mission supporting Copernicus Land Monitoring studies, including the monitoring of vegetation, soil and water cover, as well as observation of inland waterways and coastal areas.

  The Sentinel-2 L2 data are downloaded from scihub. They were computed by running sen2cor. WARNING: ESA did not produce L2 data for all L1 assets, and earlier L2 coverage is not global.

  The assets contain 12 UINT16 spectral bands representing SR scaled by 10000 (unlike in L1 data, there is no B10). There are also several more L2-specific bands (see band list for details). See the Sentinel-2 User Handbook for details. In addition, three QA bands are present where one (QA60) is a bitmask band with cloud mask information. For more details, see the full explanation of how cloud masks are computed.

  EE asset ids for Sentinel-2 L2 assets have the following format: COPERNICUS/S2_SR/20151128T002653_20151128T102149_T56MNN. Here the first numeric part represents the sensing date and time, the second numeric part represents the product generation date and time, and the final 6-character string is a unique granule identifier indicating its UTM grid reference (see MGRS).

  Clouds can be removed by using COPERNICUS/S2_CLOUD_PROBABILITY. See this tutorial explaining how to apply the cloud mask.

  分辨率:10m

  熟悉的朋友应该都熟悉

Landsat8的NDVI计算是通过4、5波段,而哨兵2号数据的NDVI计算是通过4、8波段。

继续引用大佬的总结:

  NDVI = (近红外波段 - 红波段) / (近红外波段 + 红波段)

  针对每种卫星的波段,选用的波段都有所不同,公式如下:

  Landsat8: NDVI = (band5 - band4) / (band5 + band4)

  Sentinel2: NDVI = (band8 - band4) / (band8 + band4)

  Modis: NDVI = (band2 - band1) / (band2 + band1)

  ETM/TM: NDVI = (band4 - band3) / (band4 + band3)

  AVHRR: NDVI = (CH2 - CH1) / (CH2 + CH1)

  因为哨兵系列数据分辨率高,我们在研究过程中考虑的分辨率还是500。话不多说,开始~


//还是老样子哈,以广东省2020年为目标
var geometry = ee.FeatureCollection('users/ZhengkunWang/guangdongsheng')
Map.centerObject(geometry,7)
//还是原来的配方,还是原来的调色板
var colorizedVis = {
  min: -0.8,
  max: 0.8,
  palette: ['blue', 'white', 'green'],
};

//使用QA波段去云
function maskS2clouds(image) {
  var qa = image.select('QA60');
  // Bits 10 and 11 are clouds and cirrus, respectively.
  var cloudBitMask = 1 << 10;
  var cirrusBitMask = 1 << 11;
  // Both flags should be set to zero, indicating clear conditions.
  var mask = qa.bitwiseAnd(cloudBitMask).eq(0)
      .and(qa.bitwiseAnd(cirrusBitMask).eq(0));
  return image.updateMask(mask).divide(10000).set(image.toDictionary(image.propertyNames()));
}
//特别注意的是,在数学变换之后,保持原始影像的属性,所以这里.set(image.toDictionary(image.propertyNames()));就是这个意思
//sentinel2 and geometry
var S2_COL = ee.ImageCollection("COPERNICUS/S2")
                       .filterDate("2020-01-01", "2020-12-31")
                       .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',20))
                       .filterBounds(geometry)
                       .map(maskS2clouds)
                       .map(function(image){
                         var ndvi = image.normalizedDifference(["B8","B4"]).rename('NDVI')
                         return image.addBands(ndvi)
                       })
                       .select('NDVI');
print(S2_COL)
Map.addLayer(S2_COL.mean().clip(geometry), colorizedVis, 'col');
var S2_chart = ui.Chart.image.series({
    imageCollection: S2_COL.select('NDVI'),
    region: geometry,
    reducer: ee.Reducer.mean(),
    scale: 500
    }).setOptions({
      interpolateNulls: true,
      lineWidth: 2,
      title: 'NDVI Time Seires',
      vAxis: {title: 'NDVI'},
      hAxis: {title: 'Date'},
      trendlines: { 0: {title: 'NDVI_trend',type:'linear', showR2: true,  color:'red', visibleInLegend: true}}
    });
print(S2_chart);

  这次我们一气呵成

 

   观察这个时间序列可以发现,同一天因为有好多轨道影像的原因,导致同一天有很多不同的值,所以我们需要进行日平均或月平均计算。今天我们先介绍月平均的时间序列分析。

var geometry = ee.FeatureCollection('users/ZhengkunWang/guangdongsheng')
Map.centerObject(geometry,6)

var colorizedVis = {
  min: -0.8,
  max: 0.8,
  palette: ['blue', 'white', 'green'],
};

//使用QA波段去云
function maskS2clouds(image) {
  var qa = image.select('QA60');
  // Bits 10 and 11 are clouds and cirrus, respectively.
  var cloudBitMask = 1 << 10;
  var cirrusBitMask = 1 << 11;
  // Both flags should be set to zero, indicating clear conditions.
  var mask = qa.bitwiseAnd(cloudBitMask).eq(0)
      .and(qa.bitwiseAnd(cirrusBitMask).eq(0));
  return image.updateMask(mask).divide(10000).set(image.toDictionary(image.propertyNames()));
}
var S2 = ee.ImageCollection('COPERNICUS/S2')
.filterDate('2020-01-01', '2020-12-31')
.filterBounds(geometry)
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 20))
.map(maskS2clouds);
var addNDVI = function(image) {
return image.addBands(image.normalizedDifference(['B8', 'B4']).rename('NDVI'));
};
// Add NDVI band to image collection
var S2 = S2.map(addNDVI);
var NDVI = S2.select(['NDVI']);
print(NDVI);
var NDVImed = NDVI.median();
Map.addLayer(NDVImed.clip(geometry), colorizedVis, 'NDVI image');


var years = ee.List.sequence(2020, 2020);
var months = ee.List.sequence(1, 12);
var S2_monthlymeanNDVI =  ee.ImageCollection.fromImages(
  years.map(function (y) {
    return months.map(function(m) {
    return NDVI.filter(ee.Filter.calendarRange(y,y, 'year')).filter(ee.Filter.calendarRange(m, m, 'month')).mean().set('year', y).set('month', m).set('system:time_start', ee.Date.fromYMD(y, m, 1));
    });
  }).flatten()
);
// Create a monthly time series chart.
var plotNDVI = ui.Chart.image.seriesByRegion(S2_monthlymeanNDVI, geometry,ee.Reducer.mean(),
'NDVI',500,'system:time_start')
              .setChartType('LineChart').setOptions({
                interpolateNulls: true,
                title: 'NDVI Monthly time series',
                hAxis: {title: 'Date'},
                vAxis: {title: 'NDVI',viewWindowMode: 'explicit', viewWindow: {max: 0.7,min: 0.3,},gridlines: {count: 10,}},
                trendlines: { 0: {title: 'NDVI_trend',type:'linear', showR2: true,  color:'red', visibleInLegend: true}}});
// Display.
print(plotNDVI);

可能是影像太多了,算了好几分钟,终于搞定:

结果如图:

 

   看完时间序列的话,拟合性还可以,但是全年一直增长?这合适吗?而且日期序号也有错误,小编还在找问题,如果有大神看出来的话,可以指点我一下下。

更多精彩内容请关注:

 

### 如何计算 NDVI 归一化差异植被指数 NDVI(Normalized Difference Vegetation Index)是用于评估植被覆盖度和健康状况的一种重要指标。其基本原理基于植物叶片对可见光和近红外光的不同吸收特性。NDVI计算公式如下: \[ \text{NDVI} = \frac{\text{(NIR - R)}}{\text{(NIR + R)}} \] 其中: - \( \text{NIR} \) 表示近红外波段的反射率[^1]。 - \( \text{R} \) 表示红光波段的反射率。 该公式的取值范围通常在 -1 到 1 之间,数值越接近于 1,则表明植被覆盖率越高;而负值则可能代表水体或其他无植被区域[^2]。 #### 使用 Python 批量计算 NDVI 如果需要通过编程方式计算 NDVI,可以采用以下代码片段作为参考。假设已知 NIR 和 R 数据存储为 NumPy 数组形式: ```python import numpy as np def calculate_ndvi(nir, red): """ 计算归一化植被指数 (NDVI) 参数: nir (numpy.ndarray): 近红外波段数据 red (numpy.ndarray): 红光波段数据 返回: numpy.ndarray: 计算得到的 NDVI 值矩阵 """ ndvi = (nir.astype(float) - red.astype(float)) / (nir + red) return ndvi ``` 此函数接受两个参数 `nir` 和 `red`,分别对应近红外波段与红光波段的数据返回计算后的 NDVI 结果数组[^4]。 #### 注意事项 当执行 NDVI 计算时需要注意一些常见问题,比如最终图像显示全黑或者结果超出了正常范围[-1, 1]的情况。这可能是由于输入数据未经过适当预处理所致,例如缺少辐射定标或大气校正步骤[^3]。
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值