遥感影像中总是由于各种各样的原因会出现空缺值,包括云污染、传感器损坏呀之类的。最简单的方法当然还是利用线性插值的方法进行插补啦,就是利用缺失影像前后日期的数据进行线性插值,之后对缺失影像进行填补。今天我们就用GEE简单的实现一下这个方法。 这次我们对Sentinel-2的进行插补
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 s2 = ee.ImageCollection("COPERNICUS/S2_SR");
var filtered = s2
.filter(ee.Filter.date('2019-01-01', '2020-01-01'))
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30))
.filter(ee.Filter.bounds(geometry))
// 数据去云处理
function maskCloudAndShadowsSR(image) {
var cloudProb = image.select('MSK_CLDPRB');
var snowProb = image.select('MSK_SNWPRB');
var cloud = cloudProb.lt(5);
var snow = snowProb.lt(5);
var scl = image.select('SCL');
var shadow = scl.eq(3); // 3 = cloud shadow
var cirrus = scl.eq(10); // 10 = cirrus
var mask = (cloud.and(snow)).and(cirrus.neq(1)).and(shadow.neq(1));
return image.updateMask(mask).divide(10000)
.select("B.*")
.copyProperties(image, ["system:time_start"]);
}
var filtered = filtered.map(maskCloudAndShadowsSR)
var filtered = filtered.map(function(image) {
var timeImage = image.metadata('system:time_start').rename('timestamp')
var timeImageMasked = timeImage.updateMask(image.mask().select(0))
return image.addBands(timeImageMasked)
})
这只进行插值的核心步骤,我们对每个影像匹配其前几天的影像数据与后几天的影像数据,这个间隔天数可以自主设置。需要注意的是GEE里面使用Join进行匹配,匹配的时间单位是毫秒,这个我们需要把时间单位搞清楚。
//定义两个join,一个是距离目标影像30天范围内,并且是日期在目标影像之前,
//另一个是在目标影像之后的
var days = 30
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: filtered,
secondary: filtered,
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
})
插值公式 y = y1 + (y2-y1)*((t – t1) / (t2 – t1)) y = 需要插值的数据 y1 = 目标之前数据,>y2 = 目标之前数据 t 其所对应的时间信息
var interpolateImages = function(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(
join2Result.map(interpolateImages
function addNDVI(image) {
var ndvi = image.normalizedDifference(['B8', 'B4']).rename('ndvi');
return image.addBands(ndvi);
}
var ndviVis = {min:0, max: 0.9, palette: [
'FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718', '74A901',
'66A000', '529400', '3E8601', '207401', '056201', '004C00', '023B01',
'012E01', '011D01', '011301'
]}
var visualizeImage = function(image) {
return image.select('ndvi').visualize(ndviVis).clip(geometry)
}
var visCollectionOriginal = filtered
.map(addNDVI)
.map(visualizeImage)
var visCollectionInterpolated = interpolatedCol
.map(addNDVI)
.map(visualizeImage)
var videoArgs = {
dimensions: 400,
region: geometry,
framesPerSecond: 1,
crs: 'EPSG:3857',
};
print('Original NDVI Images', visCollectionOriginal.getVideoThumbURL(videoArgs))
print('Gap Filled NDVI Images', visCollectionInterpolated.getVideoThumbURL(videoArgs))
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有