在GEE中,对单个Image进行可视化十分常见,但如何对ImageCollection进行可视化呢?
GEE给出了静态和动态的方法,因此你可以将可视化的参数赋予给ImageCollection中每一个Image,也可以更高级地利用GEE提供的函数将ImageCollection以一个动画或一系列幻灯片形式进行动态可视化,快速评估ImageCollection的内容,观测时空变化。
我将这一部分内容分为三块:
一、获取无云有序的影像集
二、可视化实现的方法
三、可视化的高级功能
当然,心急的朋友可以从第二块内容开始阅读~~~~
一、获取无云有序的影像集
我们需要根据遥感影像本身的特点和自身的需求,筛选出尽量无云且噪声较小的影像集作为可视化的素材,一般使用 filter(过滤)+ruduce(合成)的操作。
(1)按日期区间的合成
这里使用选择MODIS 16天的NDVI数据作为例子,这样操作后的集合产生的动画噪声较小,因为每个图像代表20多年数据中每16天的NDVI复合图像的中值:
//创建一个从1到365、步长为16(天)的数列,代表一年中的影像区间
var doyList = ee.List.sequence(1, 365, 16);
//导入MOSIS NDVI数据集
var ndviCol = ee.ImageCollection('MODIS/006/MOD13A2').select('NDVI');
//遍历数列,构建影像列表
var ndviComplist = doyList.map(function(startDoy){
startDoy = ee.Number(startDoy);
//按日期范围过滤图像,起始日期是当前日期startDoy,结束日期是当前日期的15天后
return ndviCol
.filter(ee.Filter.calendarRange(startDoy, startDoy.add(15),
'day_of_year'))
//将过滤得到的日期区间内的所有图像取中值,合成为一个图像
.reduce(ee.Reducer.median());
});
//将list格式的图像列表转换为ImageCollection格式
var ndviCompCol = ee.ImageCollection.fromImages(ndviCompList);
(2)按季节的年际合成
但是对于Landsat影像,每个传感器针对给定场景每16天收集一次Landsat数据,使得图像的某些部分经常被云遮盖。因此,可以考虑用遮盖云层并合成同一季节的几张年度图像可以产生更加无云的图像。下面的例子对每年7月和8月的Landsat 5图像取中值得到从1985年到2011年的每年的合成影像:
var lsCol = ee.ImageCollection('LANDSAT/LT05/C01/T1_SR')
.filterBounds(ee.Geometry.Point(-122.9, 43.6))
//得到每年7月-8月的影像
.filter(ee.Filter.dayOfYear(182, 243))
//给每个图像添加"year"属性
.map(function(img) {
return img.set('year', ee.Image(img).date().get('year'));
});
//定义一个函数以掩膜图像中云和阴影。
var cloudMask = function(img) {
var qa = img.select('pixel_qa');
var cloud = qa.bitwiseAnd(1 << 5).or(qa.bitwiseAnd(1 << 3));
return img.updateMask(cloud.not());
//获取有7月-8月图像的年份
var years = ee.List(lsCol.aggregate_array('year')).distinct().sort();
//生成年份列表以构建年度图像合成列表。
var lsCompList = years.map(function(year) {
return lsCol
// 按年份过滤图像集
.filterMetadata('year', 'equals', year)
//使用云层掩膜函数
.map(cloudMask)
//对同年内的所有影像取中值合成为一个图像
.reduce(ee.Reducer.median())
//将合成年份设置为图像属性。
.set('year', year);
});
//将list格式的图像列表转换为ImageCollection格式
var lsCompCol = ee.ImageCollection.fromImages(lsCompList);
(3)进阶——使用join方法
前两种方法是通过构建天和年的列表来逐步定义新日期以进行过滤和合成。使用join方法也可以实现这样的操作。下面的例子,首先得到了一个Unique年份集合并使用saveall
将属于相同年份的影像将被分到一个List对象中,在使用遍历的方法得到每年的合成影像。
var lsCol = ee.ImageCollection('LANDSAT/LT05/C01/T1_SR')
.filterBounds(ee.Geometry.Point(-122.9, 43.6))
.filter(ee.Filter.dayOfYear(182, 243))
// 给每个图像添加"year"属性
.map(function(img) { return img.set('year', ee.Image(img).date().get('year')); });
//得到不重复年份的影像集,里面每个影像代表一个年份
var distinctYears = lsCol.distinct('year').sort('year');
//定义一个联接过滤器;一对多加入“年份”属性。
var filter = ee.Filter.equals({leftField: 'year', rightField: 'year'});
// 定义一个连接.
var join = ee.Join.saveAll('year_match');
//应用join,将“year_match”属性添加到每个不重复年的代表图像。
//每个图像的“year_match”属性是包含属于相应年份的所有图像,是一个List格式
var joinCol = join.apply(distinctYears, lsCol, filter);
// 定义一个函数以掩膜图像中云和阴影。
var cloudMask = function(img) {
var qa = img.select('pixel_qa');
var cloud = qa.bitwiseAnd(1 << 5).or(qa.bitwiseAnd(1 << 3));
return img.updateMask(cloud.not()); };
//遍历每个不同年份的图像集
var lsCompList = joinCol.map(function(img) {
//获取属于给定年份的图像列表。
return ee.ImageCollection.fromImages(img.get('year_match'))
//使用云层掩膜
.map(cloudMask)
//取中值
.reduce(ee.Reducer.median())
//将合成年份设置为图像属性
.copyProperties(img, ['year']);
});
//将list格式的图像列表转换为ImageCollection格式
var lsCompCol = ee.ImageCollection(lsCompList);
下面的例子根据Landsat影像的行列信息对集合进行过滤后,将使用join操作对来自同一日期的Landsat图像进行镶嵌。
var lsCol = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR')
.filterDate('2017-01-01', '2019-01-01')
.filter('WRS_PATH == 38 && (WRS_ROW == 28 || WRS_ROW == 29)')
.map(function(img) {
var date = img.date().format('YYYY-MM-dd');
return img.set('date', date);
});
var distinctDates = lsCol.distinct('date').sort('date');
var filter = ee.Filter.equals({leftField: 'date', rightField: 'date'});
var join = ee.Join.saveAll('date_match');
var joinCol = join.apply(distinctDates, lsCol, filter);
var lsColMos = ee.ImageCollection(joinCol.map(function(col) {
return ee.ImageCollection.fromImages(col.get('date_match')).mosaic();
}));
(4)排序
按时间对集合进行排序,以确保按正确的时间顺序排列,或者按您选择的属性排序。默认情况下,集合是按照自然顺序排序,也可以使用sort方法根据影像的属性进行排序。
//按观察时间排序,使用system:time_start属性
var s2col = ee.ImageCollection('COPERNICUS/S2_SR')
.filterBounds(ee.Geometry.Point(-122.1, 37.2))
.sort('system:time_start');
//或者通过云量来定义顺序
var s2col = ee.ImageCollection('COPERNICUS/S2_SR')
.filterBounds(ee.Geometry.Point(-122.1, 37.2))
.sort('CLOUDY_PIXEL_PERCENTAGE');
//也可以通过派生的属性来定义,例如NDVI均值。
var aoi = ee.Geometry.Point(-122.1, 37.2).buffer(1e4);
var ndviCol = ee.ImageCollection('MODIS/006/MOD13A1')
.filterDate('2018-01-01', '2019-01-01')
.select('NDVI')
// 遍历图像集合以计算区域内的平均NDVI并将其作为属性
.map(function(img) {
var meanNdvi = img.reduceRegion({
reducer: ee.Reducer.mean(),
geometry: aoi,
scale: 500});
return img.set('meanNdvi', meanNdvi.get('NDVI'));
})
// 根据NDVI均值倒叙排列
.sort('meanNdvi', false);