GEE笔记:多日期滑动组件
前言
最近在进行土地覆被变化验证的相关研究,看到了Cohen等人为LandTrendr开发的 基于Landsat时间序列影像的验证工具:TimeSync。为了满足自己的需要(好像TimeSync在GEE上使用还要先将影像下载到本地???),本菜鸡参考大神们的代码,基于GEE平台弄了一个显示Landsat系列可以进行目视解译验证的工具(萌新求轻喷)。
一、GEE官方的日期滑动组件代码
代码如下(原文链接:https://developers.google.com/earth-engine/guides/ui_widgets)
// Use a DateSlider to create annual composites of this collection.
var collection = ee.ImageCollection('LANDSAT/LC08/C01/T1');
// Use the start of the collection and now to bound the slider.
var start = ee.Image(collection.first()).date().get('year').format();
var now = Date.now();
var end = ee.Date(now).format();
// Run this function on a change of the dateSlider.
var showMosaic = function(range) {
var mosaic = ee.Algorithms.Landsat.simpleComposite({
collection: collection.filterDate(range.start(), range.end())
});
// Asynchronously compute the name of the composite. Display it.
range.start().get('year').evaluate(function(name) {
var visParams = {bands: ['B4', 'B3', 'B2'], max: 100};
var layer = ui.Map.Layer(mosaic, visParams, name + ' composite');
Map.layers().set(0, layer);
});
};
// Asynchronously compute the date range and show the slider.
var dateRange = ee.DateRange(start, end).evaluate(function(range) {
var dateSlider = ui.DateSlider({
start: range['dates'][0],
end: range['dates'][1],
value: null,
period: 365,
onChange: showMosaic
});
Map.add(dateSlider.setValue(now));
});
二、多日期滑动组件
代码如下(示例):
代码看起来很长主要分为两部分:
- 对Landsat SR影像的一些预处理(云掩膜、波段计算等等)
- 通过日期滑动组件分别展示研究区的Lansat-5,7,8年度中值合成影像
var roi = ee.FeatureCollection("xxx");
//######################################################################################
//# Preparing #\\
//######################################################################################
//1.-------------------------------------------------------------------
// Define function to get and rename bands of interest from ETM+.
var renameETM =function(img) {
return img.select(
['B1', 'B2', 'B3', 'B4', 'B5', 'B7', 'pixel_qa', 'radsat_qa'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B7', 'pixel_qa', 'radsat_qa']
);
};
// Define function to get and rename bands of interest from OLI.
var renameOLI = function(img) {
return img.select(
['B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'pixel_qa'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B7', 'pixel_qa']
);
};
//2.-------------------------------------------------------------------.
//cloud mask------------------------------------------------
var cloudMaskL457 = function(image) {
var qa = image.select('pixel_qa');
// If the cloud bit (5) is set and the cloud confidence (7) is high
// or the cloud shadow bit is set (3), then it's a bad pixel.
var cloud = qa.bitwiseAnd(1 << 5)
.and(qa.bitwiseAnd(1 << 7))
.or(qa.bitwiseAnd(1 << 3))
// Remove edge pixels that don't occur in all bands
var mask2 = image.mask().reduce(ee.Reducer.min());
var maskObersaturation = image.select('radsat_qa').eq(0)
return image.updateMask(cloud.not()).updateMask(mask2.and(maskObersaturation));
};
var maskL8sr = function(image) {
// Bits 3 and 5 are cloud shadow and cloud, respectively.
var cloudShadowBitMask = 1 << 3;
var cloudsBitMask = 1 << 5;
// Get the pixel QA band.
var qa = image.select('pixel_qa');
// Both flags should be set to zero, indicating clear conditions.
var mask = qa.bitwiseAnd(cloudShadowBitMask).eq(0)
.and(qa.bitwiseAnd(cloudsBitMask).eq(0));
// Return the masked image, scaled to reflectance, without the QA bands.
return image.updateMask(mask);
}
//3.-------------------------------------------------------------------
//Add bands--------------------------------------------------
var addbands = function(img) {
var ndvi = img.normalizedDifference(["B4", "B3"]).rename(["NDVI"]);
var img1 = img.addBands(ndvi)
.set('system:time_start', img.get('system:time_start'));
return img1;
};
//4.-------------------------------------------------------------------
//divide-----------------------------------------------------
var divide = function(img){
img = img.select('B1', 'B2', 'B3', 'B4', 'B5','B7')
.divide(10000)
.set('system:time_start', img.get('system:time_start'));
return img;
};
//5.-------------------------------------------------------------------
// Define function to prepare OLI images.
var prepOLI = function(img) {
var orig = img;
img = renameOLI(img);
img = maskL8sr(img);
img = divide(img);
img = addbands(img);
return ee.Image(img.copyProperties(orig, orig.propertyNames()));
}
// Define function to prepare ETM+ images.
var prepETM = function(img) {
var orig = img;
img = renameETM(img);
img = cloudMaskL457(img);
//img = etm2oli(img);
img = divide(img);
img = addbands(img);
return ee.Image(img.copyProperties(orig, orig.propertyNames()));
}
//6.-------------------------------------------------------------------
var visParams = {
bands: ['B3', 'B2', 'B1'],
min: 0,
max: 0.3,
gamma: 1.4,
};
Map.centerObject(roi, 9);
var sidePanel = ui.Panel();
//######################################################################################
//# L5 part #\\
//######################################################################################
var L5 = ee.ImageCollection("LANDSAT/LT05/C01/T1_SR");
var start_1 = "1986-1-1";
var end_1 = "2011-12-31";
var showImage_1 = function(range){
print("---L5", range);
var colFilter = ee.Filter.and(
ee.Filter.bounds(roi),
ee.Filter.date(range.start(), range.end()),
//ee.Filter.lt('CLOUD_COVER', 50),
ee.Filter.lt('GEOMETRIC_RMSE_MODEL', 30),
ee.Filter.or(
ee.Filter.eq('IMAGE_QUALITY', 9),
ee.Filter.eq('IMAGE_QUALITY', 7)
)
);
// Filter collections and prepare them for merging.
var col_L5 = L5.filter(colFilter).map(prepETM).map(function(image){return image.clip(roi)});
var imgL5_med = col_L5.reduce(ee.Reducer.median())
.select(
['B1_median', 'B2_median', 'B3_median', 'B4_median','B5_median','B7_median', 'NDVI_median'],
['B1', 'B2', 'B3', 'B4', 'B5','B7', 'NDVI']);
range.start().get('year').evaluate(function(name) {
var layer_1 = ui.Map.Layer(imgL5_med, visParams, name + ' Landsat 5 composite');
Map.layers().set(0, layer_1);
});
};
showImage_1(ee.DateRange(start_1, ee.Date(start_1).advance(1, "year")));
ee.DateRange(start_1, end_1).evaluate(function(range) {
print("+++L5",range);
var dateSlider = ui.DateSlider({
start: range['dates'][0],
end: range['dates'][1],
value: start_1,
period: 365,
onChange: showImage_1,
style: {
width: "500px",
padding: "2px"
}
});
var main_panel_1 = ui.Panel({
widgets: [
ui.Label('Landsat 5 compsites 1986-2011', {fontWeight: 'bold'}),
dateSlider
],
style: {
width: "520px",
padding: "4px"
}
});
sidePanel.add(main_panel_1);
});
//######################################################################################
//# L7 part #\\
//######################################################################################
var L7 = ee.ImageCollection("LANDSAT/LE07/C01/T1_SR");
var start_2 = "1999-1-1";
var end_2 = "2019-12-31";
var showImage_2 = function(range){
print("---L7", range);
var colFilter_2 = ee.Filter.and(
ee.Filter.bounds(roi),
ee.Filter.date(range.start(), range.end()),
//ee.Filter.lt('CLOUD_COVER', 50),
ee.Filter.lt('GEOMETRIC_RMSE_MODEL', 30),
ee.Filter.or(
ee.Filter.eq('IMAGE_QUALITY', 9),
ee.Filter.eq('IMAGE_QUALITY', 7)
)
);
// Filter collections and prepare them for merging.
var col_L7 = L7.filter(colFilter_2).map(prepETM).map(function(image){return image.clip(roi)});
var imgL7_med = col_L7.reduce(ee.Reducer.median())
.select(
['B1_median', 'B2_median', 'B3_median', 'B4_median','B5_median','B7_median', 'NDVI_median'],
['B1', 'B2', 'B3', 'B4', 'B5','B7', 'NDVI']);
range.start().get('year').evaluate(function(name) {
var layer_2 = ui.Map.Layer(imgL7_med, visParams, name + ' Landsat 7 composite');
Map.layers().set(1, layer_2);
});
};
showImage_2(ee.DateRange(start_2, ee.Date(start_2).advance(1, "year")));
ee.DateRange(start_2, end_2).evaluate(function(range) {
print("+++L7",range);
var dateSlider = ui.DateSlider({
start: range['dates'][0],
end: range['dates'][1],
value: start_2,
period: 365,
onChange: showImage_2,
style: {
width: "500px",
padding: "2px"
}
});
var main_panel_2 = ui.Panel({
widgets: [
ui.Label('Landsat 7 compsites 2013-2019', {fontWeight: 'bold'}),
dateSlider
],
style: {
width: "520px",
padding: "4px"
}
});
sidePanel.add(main_panel_2);
});
//######################################################################################
//# L8 part #\\
//######################################################################################
var L8 = ee.ImageCollection("LANDSAT/LC08/C01/T1_SR");
var start_3 = "2013-1-1";
var end_3 = "2019-12-31";
var showImage_3 = function(range){
print("---L8", range);
var colFilter = ee.Filter.and(
ee.Filter.bounds(roi),
ee.Filter.date(range.start(), range.end()),
//ee.Filter.lt('CLOUD_COVER', 50),
ee.Filter.lt('GEOMETRIC_RMSE_MODEL', 30),
ee.Filter.or(
ee.Filter.eq('IMAGE_QUALITY', 9),
ee.Filter.eq('IMAGE_QUALITY_OLI', 9)
)
);
// Filter collections and prepare them for merging.
var col_L8 = L8.filter(colFilter).map(prepOLI).map(function(image){return image.clip(roi)});
var imgL8_med = col_L8.reduce(ee.Reducer.median())
.select(
['B1_median', 'B2_median', 'B3_median', 'B4_median','B5_median','B7_median', 'NDVI_median', ],
['B1', 'B2', 'B3', 'B4', 'B5','B7', 'NDVI']);
range.start().get('year').evaluate(function(name) {
var layer_3 = ui.Map.Layer(imgL8_med, visParams, name + ' Landsat 8 composite');
Map.layers().set(2, layer_3);
});
};
showImage_3(ee.DateRange(start_3, ee.Date(start_3).advance(1, "year")));
ee.DateRange(start_3, end_3).evaluate(function(range) {
print("+++L8",range);
var dateSlider = ui.DateSlider({
start: range['dates'][0],
end: range['dates'][1],
value: start_3,
period: 365,
onChange: showImage_3,
style: {
width: "300px",
padding: "2px"
}
});
var main_panel_3 = ui.Panel({
widgets: [
ui.Label('Landsat 8 compsites 2013-2019', {fontWeight: 'bold'}),
dateSlider
],
layout: "flow",
style: {
width: "520px",
padding: "4px"
}
});
sidePanel.add(main_panel_3);
});
ui.root.add(sidePanel);
最终的效果图:
总结
-
通过这个组件可以很方便的利用Landsat时间序列影像进行目视解译验证,未来希望可以加上验证点的某参数时间序列折线图(比如在GEE中导入一个FeatureCollection, 通过点击某个点就可以显示时间序列NDVI折线图)。
-
不知道大家除了TimeSync和GE之外还知道其他可以利用时间序列遥感影像验证的工具嘛?
最后,希望大家能够多与我交流指出错误,我会虚心接受!!!