首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >遥感影像SG滤波(基于GEE)

遥感影像SG滤波(基于GEE)

作者头像
GIS与遥感开发平台
发布2022-12-03 09:56:38
发布2022-12-03 09:56:38
2.9K0
举报

SG滤波

为了填补数据、数据平滑,我们可以使用滤波的方法。前两天我们介绍了线性插值,今天我们来看一下更为高级的SG滤波。 SG滤波是使用每个像元及其时间维上前后各N个像元来拟合多项式,用多项式来重新计算某个时间上的像元值。

上面这个方程就是SG一般形式,t为时间,a为常数,我们把时间维上的像元带入方程就可以求解所有的a。然后我们把当前的时间t带进去就可以求解平滑后的像元值。

GEE实现SG滤波

第一步:选择研究区,对影像数据进行去云、计算NDVI。

代码语言:javascript
复制
var s2 = ee.ImageCollection("COPERNICUS/S2"); 
var geometry = ee.Geometry.Polygon([[
  [82.60642647743225, 27.16350437805251],
  [82.60984897613525, 27.1618529901377],
  [82.61088967323303, 27.163695288375266],
  [82.60757446289062, 27.16517483230927]
]]);
Map.addLayer(geometry, {color: 'red'}, 'Farm')
Map.centerObject(geometry)

var startDate = ee.Date('2017-01-01')
var endDate = startDate.advance(1, 'year')

var filtered = s2
  .filter(ee.Filter.date(startDate, endDate))
  .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30))
  .filter(ee.Filter.bounds(geometry))

// Write a function for Cloud masking
function maskS2clouds(image) {
  var qa = image.select('QA60')
  var cloudBitMask = 1 << 10;
  var cirrusBitMask = 1 << 11;
  var mask = qa.bitwiseAnd(cloudBitMask).eq(0).and(
             qa.bitwiseAnd(cirrusBitMask).eq(0))
  return image.updateMask(mask)
      .select("B.*")
      .copyProperties(image, ["system:time_start"])
}

var filtered = filtered.map(maskS2clouds)

function addNDVI(image) {
  var ndvi = image.normalizedDifference(['B8', 'B4']).toFloat().rename('ndvi');
  return image.addBands(ndvi);
}

var withNdvi = filtered.map(addNDVI);

var ndviCol = withNdvi.select('ndvi')
print('Original Collection', ndviCol)

第二步:设置好需要被插值的空影像,需要包含时间信息。这样方程计算出来以后我们就可以根据时间计算当时的像元值。这里我们每隔5天就设置一个空影像。我们把空影像标记为“interpolated”,之后把真实影像和需要被插值的影像结合到一起。

代码语言:javascript
复制
var n = 5;
var totalDays = endDate.difference(startDate, 'day');
var daysToInterpolate = ee.List.sequence(1, totalDays, n)

var initImages = daysToInterpolate.map(function(day) {
  var image = ee.Image().rename('ndvi').toFloat().set({
    'system:index': ee.Number(day).format('%d'),
    'system:time_start': startDate.advance(day, 'day').millis(),
    // Set a property so we can identify interpolated images
    'type': 'interpolated'
  })
  return image
})
var initCol = ee.ImageCollection.fromImages(initImages)
var mergedCol = ndviCol.merge(initCol)

var mergedCol = mergedCol.map(function(image) {
  var timeImage = image.metadata('system:time_start').rename('timestamp')
  var timeImageMasked = timeImage.updateMask(image.mask().select(0))
  return image.addBands(timeImageMasked)
})

第三步:利用Join函数把每个影像对应的之前和之后的影像链接起来。

代码语言:javascript
复制
var days = 60
var millis = ee.Number(days).multiply(1000*60*60*24)

var maxDiffFilter = ee.Filter.maxDifference({
  difference: millis,
  leftField: 'system:time_start',
  rightField: 'system:time_start'
})

var lessEqFilter = ee.Filter.lessThanOrEquals({
  leftField: 'system:time_start',
  rightField: 'system:time_start'
})


var greaterEqFilter = ee.Filter.greaterThanOrEquals({
  leftField: 'system:time_start',
  rightField: 'system:time_start'
})


var filter1 = ee.Filter.and(maxDiffFilter, lessEqFilter)
var join1 = ee.Join.saveAll({
  matchesKey: 'after',
  ordering: 'system:time_start',
  ascending: false})
  
var join1Result = join1.apply({
  primary: mergedCol,
  secondary: mergedCol,
  condition: filter1
})

var filter2 = ee.Filter.and(maxDiffFilter, greaterEqFilter)

var join2 = ee.Join.saveAll({
  matchesKey: 'before',
  ordering: 'system:time_start',
  ascending: true})
  
var join2Result = join2.apply({
  primary: join1Result,
  secondary: join1Result,
  condition: filter2
})

第四步:利用线性插值先把空数据插出来。

代码语言:javascript
复制
var filtered = join2Result.filter(ee.Filter.eq('type', 'interpolated'))

function interpolateImages(image) {
  var image = ee.Image(image)

  var beforeImages = ee.List(image.get('before'))
  var beforeMosaic = ee.ImageCollection.fromImages(beforeImages).mosaic()
  var afterImages = ee.List(image.get('after'))
  var afterMosaic = ee.ImageCollection.fromImages(afterImages).mosaic()

  var t1 = beforeMosaic.select('timestamp').rename('t1')
  var t2 = afterMosaic.select('timestamp').rename('t2')

  var t = image.metadata('system:time_start').rename('t')

  var timeImage = ee.Image.cat([t1, t2, t])

  var timeRatio = timeImage.expression('(t - t1) / (t2 - t1)', {
    't': timeImage.select('t'),
    't1': timeImage.select('t1'),
    't2': timeImage.select('t2'),
  })

  var interpolated = beforeMosaic
    .add((afterMosaic.subtract(beforeMosaic).multiply(timeRatio)))
  var result = image.unmask(interpolated)
  return result.copyProperties(image, ['system:time_start'])
}

var interpolatedCol = ee.ImageCollection(
  filtered.map(interpolateImages)).select('ndvi')
print('Interpolated Collection', interpolatedCol)

第五步:把插出来的数据进行SG滤波。

代码语言:javascript
复制
var oeel=require('users/OEEL/lib:loadAll');
// https://www.open-geocomputing.org/OpenEarthEngineLibrary/#.ImageCollection.SavatskyGolayFilter

// Use the same maxDiffFilter we used earlier
var maxDiffFilter = ee.Filter.maxDifference({
  difference: millis,
  leftField: 'system:time_start',
  rightField: 'system:time_start'
})

// Use the default distanceFunction
var distanceFunction = function(infromedImage, estimationImage) {
  return ee.Image.constant(
      ee.Number(infromedImage.get('system:time_start'))
      .subtract(
        ee.Number(estimationImage.get('system:time_start')))
        );
  }

// 把SG滤波函数设置为三次函数
var order = 3;
var smoothed = oeel.ImageCollection.SavatskyGolayFilter(
  interpolatedCol, 
  maxDiffFilter,
  distanceFunction,
  order)

//选择d_0_ndvi波段并重命名
var smoothed = smoothed.select(['d_0_ndvi'], ['smoothed'])

第六步:数据可视化

代码语言:javascript
复制
var title = 'Savitsky-Golay smoothing' +
  '(order = '+ order + ', window_size = ' + days + ')'

// 把原始的和经过SG滤波的数据NDVI曲线画出来
var chart = ui.Chart.image.series({
  imageCollection: ndviCol.merge(smoothed),
  region: geometry,
  reducer: ee.Reducer.mean(),
  scale: 20
}).setOptions({
      lineWidth: 1,
      title: title,
      interpolateNulls: true,
      vAxis: {title: 'NDVI'},
      hAxis: {title: '', format: 'YYYY-MMM'},
      series: {
        0: {color: 'blue', lineWidth: 1, 
          lineDashStyle: [1, 1], pointSize: 1,
          }, // Original NDVI
        1: {color: 'red', lineWidth: 2 }, // Smoothed NDVI
      },

    })
print(chart)


var ndviVis = {min:0, max: 0.7,  palette: [
    '#fdae61','#fee08b','#d9ef8b',
    '#a6d96a','#66bd63','#1a9850','#006837']
  }

var visualizeImage = function(image) {
  return image.visualize(ndviVis).clip(geometry)
}

var visCollectionOriginal = ndviCol
  .map(visualizeImage)
var visCollectionInterpolated = smoothed
  .map(visualizeImage)
  
var videoArgs = {
  dimensions: 400,
  region: geometry,
  framesPerSecond: 2,
  crs: 'EPSG:3857',
};

print('Original NDVI Images', visCollectionOriginal.getVideoThumbURL(videoArgs))

var videoArgs = {
  dimensions: 400,
  region: geometry,
  framesPerSecond: 5,
  crs: 'EPSG:3857',
};
print('SG Filtered NDVI Images', visCollectionInterpolated.getVideoThumbURL(videoArgs))
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-07-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 GIS与遥感开发平台 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SG滤波
    • GEE实现SG滤波
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档