最大值_GEE上实现NDVI时间序列最大值合成

由于云雨等影响,使得遥感数据无法有效地观测地面,这种影响在NDVI上表现为低值噪声,为了降低这种影响,通常使用最大值合成的方法,得到相邻时间内最佳观测值作为填充值,从而消除低值噪声。这种方法简单实用,但是无法恢复地表真实情况,且会造成最大值对应的日期发生偏移,通常还要结合各种滤波算法对时间序列数据进行平滑,比如S-G滤波、谐波分析等。

为了实现最大值合成,需要将时间序列数据(ee.Image)转为更易处理的数组(ee.Array)。实现的过程比较简单,使用滑动窗口,在时间序列上取窗口内的最大值作为返回值,具体实现代码:

function MVC(inputNDVIcl , slideWindows)
 {
  var halfSize = (slideWindows-1)/2;
  var imageSize =inputNDVIcl.size();
  var list = ee.List.sequence(halfSize, imageSize.subtract(halfSize+1));
    //将影像集转为arrayimage
  var imagesArray = inputNDVIcl.toArray().arrayProject([0]);
  var date_start =ee.Date(inputNDVIcl.first().get('system:time_start'));
  
  var slide =ee.ImageCollection( 
    list.map(function(index){
      var date = ee.Number(index).add(1).multiply(8);
      var time = date_start.advance(date, 'day');
      var slicedarray  = imagesArray.arraySlice(0,ee.Number(index).subtract(halfSize).int(),ee.Number(index).add(halfSize+1).int());
      return slicedarray.arrayReduce(ee.Reducer.max(),[0]).arrayProject([0]).arrayGet([0][0]).rename("NDVI").set("system:time_start",time.millis());
  })
  );
  return slide;
 }

返回值的这段代码我本身有点疑惑

return slicedarray.arrayReduce(ee.Reducer.max(),[0]).arrayGet([0][0]).rename("NDVI").set("system:time_start",time.millis());

使用上面这段作为返回值时,在数据量小一点的时候可以正常运行(100景左右),在数据量比较大的时候就会报数组越界的错误。而加上arrayProject([0])之后,又可以正常运行了,不知道是为什么?

我做了几组对比实验,对比了原始数据(全年MODIS NDVI,364景)、八天最大值合成数据,还有这两组数据的sg滤波、谐波分析之后的效果。

0439c146e4d1e73ccd7fb92f20186224.png
原始NDVI时间序列

5b6424dc26da386d8a4fad0ed9f3c0c8.png
八天滑动最大值合成NDVI时间序列

84e7f9219b86ca5a9e6a427645a9f903.png
原始数据SG滤波

3096f98f4c999aef624e3404a9bed052.png
合成数据SG滤波

d8c79d8a8461bce0509812b272b07c42.png
原始数据谐波分析

bd3aad3e46b50a9255f122de480d725b.png
合成数据谐波分析

可以看到,由于原始数据较多由云雨造成的低值噪声,未做合成的数据直接做滤波会拉低整体的值,而使用合成之后的时候再进行滤波会与真实情况更接近。即便做了最大值合成,也无法完全消除密集云雨的影响。使用SG滤波对数据的细节有较好的保留,而使用谐波分析则消除了大部分细节,但使数据变得更平滑。