目录
一、联合多源遥感影像的意义
联合多源遥感影像意味着将来自不同传感器、不同时间或不同空间分辨率的遥感数据融合在一起,来获取完整、准确的地表信息。这种融合可以提供比单一数据源更多、更丰富的信息,同时还能降低遥感数据中的噪声、缺失数据和歧义等因素的影响,从而提高地表信息的质量和可靠性。联合多源遥感影像的意义主要体现在以下几个方面:
1. 提高信息质量
利用多源遥感数据的互补性,可以提高地表信息的准确性、全面性和时效性,从而更好地满足决策和研究的需要。
2. 丰富数据内容
联合多源遥感影像可以提供更多的地表特征信息,如高程、植被、水体、土壤类型、岩石等,这样可以帮助更好地理解自然环境和人类活动。
3. 降低数据噪声
联合多源遥感影像还可以通过对不同数据源的重叠区域进行一些处理,去除重复信息和不一致信息,从而减少噪声和错误。
联合多源遥感影像的技术在生态环境监测、资源调查、城市规划、农业生产、灾害管理、国土安全等领域均有广泛的应用前景。接下来以Landsat-8和Sentinel-2的数据融合为例,详细讲解其处理过程的GEE实现。
二、GEE实现
本例以Sentinel-2数据为主,Landsat-8做为Sentinel-2没有数据区域的补充,GEE下载代码如下:
1、研究区域和下载年份的选择
// 指定研究区域
var geometry = 自己导入的FeatureCollection对象;
// 区域筛选,有需要就加上
geometry = geometry.filterMetadata(列名, 筛选条件, 筛选对象名称);
// 研究区域显示
Map.centerObject(geometry, 8);
// 选择下载年份,每次下载一年的数据,后面需要用前后两年数据补充
var the_year = ee.Number(2020);
var startYear = the_year.subtract(1);
var endYear = the_year.add(1);
2、定义数值转换函数
接下来先写好Landsat-8地表反射率产品和Sentinel-2 2A产品的数值转化函数,参考GEE相关产品的示例代码。虽然GEE上的这两个产品已经做好了大气校正,但数值不是地表反射率,还需做一个简单的线性变换:
// L8辐射定标 DN-->反射率
function L8_applyScaleFactors(image) {
image = ee.Image(image);
var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2);
return image.addBands(opticalBands, null, true);
}
// S2辐射定标 DN-->反射率
function S2_applyScaleFactors(image) {
image = ee.Image(image);
var opticalBands = image.select('B.').divide(10000);
return image.addBands(opticalBands, null, true);
}
3、定义影像去云函数
再是去云函数的定义,可根据需求调整,具体数值含义参考产品中相应波段说明。其中Sentinel-2去云参考了‘SCL’和‘QA60'两个波段,因为经过尝试后笔者认为联合这两个波段去除效果最好,单独使用其中一个都有较严重的去不干净的问题。Sentinel-2的去云方法大家也多多参考其他博主的见解:
// L8去云、去雪
function maskL8sr(image){
var DilatedCloud = 1 << 1; //云层边缘
var Cloud = 1 << 3; //云层
var CloudShadowBitMask = 1 << 4; //云影
var SnowBitMask = 1 << 5; //积雪
var qa = image.select('QA_PIXEL');
var mask = qa.bitwiseAnd(DilatedCloud).eq(0)
.and(qa.bitwiseAnd(Cloud).eq(0))
.and(qa.bitwiseAnd(CloudShadowBitMask).eq(0))
.and(qa.bitwiseAnd(SnowBitMask).eq(0));
return image.updateMask(mask);
}
// S2去云、去雪
function maskS2clouds(image) {
var scl = image.select('SCL');
var Cloud_Shadows = 1 << 3;
var Clouds_Low_Probability = 1 << 7;
var Clouds_Medium_Probability = 1 << 8;
var Clouds_High_Probability = 1 << 9;
var Cirrus = 1 << 10;
var Snow_Ice = 1 << 11;
var qa = image.select('QA60');
var cloudBitMask = 1 << 10;
var cirrusBitMask = 1 << 11;
var mask = scl.bitwiseAnd(Cloud_Shadows).eq(0)
.and(scl.bitwiseAnd(Clouds_Low_Probability).eq(0))
.and(scl.bitwiseAnd(Clouds_Medium_Probability).eq(0))
.and(scl.bitwiseAnd(Clouds_High_Probability).eq(0))
.and(scl.bitwiseAnd(Cirrus).eq(0))
.and(scl.bitwiseAnd(Snow_Ice).eq(0))
.and(qa.bitwiseAnd(cloudBitMask).eq(0))
.and(qa.bitwiseAnd(cirrusBitMask).eq(0));
return image.updateMask(mask);
}
4、筛选研究需要的Landsat-8数据
说明:
<1> 若研究区域为平原,T1、T2产品均达到质量标准。其它情况要慎重选择符合要求的产品
<2> 筛除了云量高于75%的影像,大家可以根据需求调整
<3> 部分影像存在去云波段的错误,导致去除不彻底,这类影像需要识别并删除
<4> 本例的联合多源时序遥感数据主要用于后续计算几种传统植被指数,故只选择了nir、red、green、blue四个波段,实际应用中,应当根据自身需求选择合适的波段
<5> 若想在GEE上直接计算进一步的结果,如植被指数,并下载,可参考以下文章:
使用GEE计算多种时序植被指数/建筑指数/水体指数https://blog.csdn.net/m0_71243797/article/details/129132868
// 初始化L8遥感数据
var Landsat_8 = ee.ImageCollection("LANDSAT/LC08/C02/T1_L2")
.merge(ee.ImageCollection("LANDSAT/LC08/C02/T2_L2"))
.filterDate(
ee.Date.fromYMD(startYear, 1, 1),
ee.Date.fromYMD(endYear.add(1), 1, 1)
)
.filterBounds(geometry)
.filter(ee.Filter.lt("CLOUD_COVER", 75))
.map(maskL8sr)
.map(L8_applyScaleFactors)
// 识别删除去云错误影像
.map(function(image){
var image_mean = ee.Image(image)
.select(['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5'])
.reduce(ee.Reducer.mean());
return image.addBands(image_mean.rename("ref_mean"));
})
.map(function(image){
var mean = image.select('ref_mean').reduceRegion({
reducer: ee.Reducer.mean(),
scale: 90,
});
return image.set("ref_mean", mean.get('ref_mean'));
})
.filter(ee.Filter.lt("ref_mean", 0.2))
// 波段选择和重命名
.select(['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5'])
.map(function(image){
return ee.Image(image).rename(['blue', 'green', 'red', 'nir']);
});
print("Landsat_8:", Landsat_8);
补充:去云异常影像的识别和删除流程
上文提到的去云不彻底问题在Sentinel-2中也存在,本例提供一种较为有效的方法:云栅格在nir、red、green、blue波段的反射率明显高于其它栅格,去云异常的影像由于大量云栅格的存在,上述四波段的平均值的全图均值明显高于正常影像,将该结果保存至新的属性‘ref_mean’中,找到合适的阈值,就可以筛除这部分影像了。
我们可以输出一个包含所有所选影像的‘ref_mean’属性的条形图,人工选阈值(下面这段代码只为绘制条形图,阈值笔者已经调试好了,为0.2,在下载使用时可以不添加这一步):
// ref_mean条形图
var refMeanList = Landsat_8.aggregate_array('ref_mean');
var chart = ui.Chart.array.values(refMeanList, 0)
.setChartType('ColumnChart')
.setOptions({
title: '属性 ref_mean 的条形图',
hAxis: {title: 'ref_mean'},
vAxis: {title: '影像序号'},
colors: ['red']
});
print(chart);
结果如下图所示,可以很明显的看到,正常影像的‘ref_mean’属性至较为一致,在0.11左右波动,而去云异常影像显著偏高,可选择0.2做为阈值:
任举一例,去除效果如下(左图:去除前;右图:去除后):
5、筛选研究需要的Sentinel-2数据
过程与Landsat-8数据筛选类似:
// 初始化S2遥感数据
var Sentinel_2 = ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED")
.filterDate(
ee.Date.fromYMD(startYear, 1, 1),
ee.Date.fromYMD(endYear.add(1), 1, 1)
)
.filterBounds(geometry)
.filter(ee.Filter.lt("CLOUDY_PIXEL_PERCENTAGE", 75))
.map(maskS2clouds)
.map(S2_applyScaleFactors)
// 识别删除去云错误影像
.map(function(image){
var image_mean = ee.Image(image)
.select(['B2', 'B3', 'B4', 'B8'])
.reduce(ee.Reducer.mean());
return image.addBands(image_mean.rename("ref_mean"));
})
.map(function(image){
var mean = image.select('ref_mean').reduceRegion({
reducer: ee.Reducer.mean(),
scale: 90,
});
return image.set("ref_mean", mean.get('ref_mean'));
})
.filter(ee.Filter.lt("ref_mean", 0.2))
// 波段选择和重命名
.select(['B2', 'B3', 'B4', 'B8'])
.map(function(image){
return ee.Image(image).rename(['blue', 'green', 'red', 'nir']);
});
print("Sentinel_2:", Sentinel_2);
6、时序遥感影像的合成
按照研究所需,分别合成Landsat-8和Sentinel-2的时间序列影像。本例为每半月一张:
// 时间序列影像合成
var yearList = ee.List.sequence(startYear, endYear, 1);
var monthList = ee.List.sequence(1, 12, 1);
var dayList = ee.List([[1, 15], [16, 31]]);
// L8
var L8_imageList = yearList.map(function(year_1){
year_1 = ee.Number(year_1);
var year_2 = year_1;
return monthList.map(function(month_1){
month_1 = ee.Number(month_1);
var month_2 = month_1;
return dayList.map(function(days){
days = ee.List(days);
var day_1 = ee.Number(days.get(0));
var day_2 = ee.Number(days.get(1));
var images = Landsat_8
.filter(ee.Filter.calendarRange(year_1, year_2, "year"))
.filter(ee.Filter.calendarRange(month_1 ,month_2, "month"))
.filter(ee.Filter.calendarRange(day_1, day_2, "day_of_month"))
.median()
.clip(geometry)
.clamp(0, 1);
return images;
});
});
}).flatten();
print("L8_imageList:", L8_imageList);
// S2
var S2_imageList = yearList.map(function(year_1){
year_1 = ee.Number(year_1);
var year_2 = year_1;
return monthList.map(function(month_1){
month_1 = ee.Number(month_1);
var month_2 = month_1;
return dayList.map(function(days){
days = ee.List(days);
var day_1 = ee.Number(days.get(0));
var day_2 = ee.Number(days.get(1));
var images = Sentinel_2
.filter(ee.Filter.calendarRange(year_1, year_2, "year"))
.filter(ee.Filter.calendarRange(month_1 ,month_2, "month"))
.filter(ee.Filter.calendarRange(day_1, day_2, "day_of_month"))
.median()
.clip(geometry)
.clamp(0, 1);
return images;
});
});
}).flatten();
print("S2_imageList:", S2_imageList);
7、多源遥感影像的合成
联合Sentinel-2、Landsat-8数据,用相同时间序列的Landsat-8填补Sentinel-2的空白:
// S2叠到L8上
var S2L8_imageList = S2_imageList.zip(L8_imageList);
var S2_and_L8 = S2L8_imageList.map(function(imageList){
imageList = ee.List(imageList);
var S2_image = ee.Image(imageList.get(0));
var L8_image = ee.Image(imageList.get(1));
var S2L8_image = ee.Algorithms.If(
S2_image.bandNames().length().eq(0),
L8_image,
ee.Algorithms.If(
L8_image.bandNames().length().eq(0),
S2_image,
L8_image.blend(S2_image)
)
);
return S2L8_image;
});
8、遥感影像空白区域的填补
最后,使用相邻两年的平均数据补充还可能存在的空白区域。注意,不同年份数据的划分切片取决于研究选择的时间序列长度,需根据实际情况修改:
去云代码涉及到叠置分析的知识,可参考下面这篇文章,笔者也参考了这篇文章:GEE学习笔记 九十一:栅格影像叠置分析https://blog.csdn.net/shi_weihappy/article/details/105972787
// 按年分组 前后年均值填补
var last_year_image = S2_and_L8.slice(0, 24);
var this_year_image = S2_and_L8.slice(24, 48);
var next_year_image = S2_and_L8.slice(48, 72);
var three_years_image = last_year_image
.zip(next_year_image)
.zip(this_year_image);
var image_to_drive = three_years_image.map(function(imageList){
imageList = ee.List(imageList);
var last_and_next = ee.List(imageList.get(0));
var this_image = ee.Image(imageList.get(1));
var last_image = ee.Image(last_and_next.get(0));
var next_image = ee.Image(last_and_next.get(1));
var fill_image = ee.ImageCollection.fromImages(
[last_image, next_image]
).mean();
var new_image = ee.Algorithms.If(
this_image.bandNames().length().eq(0),
fill_image,
ee.Algorithms.If(
fill_image.bandNames().length().eq(0),
this_image,
fill_image.blend(this_image)
)
);
return new_image;
});
print("image_to_drive", image_to_drive);
9、遥感影像的批量显示和批量下载
// 数据展示
var visualization = {
min: 0.0,
max: 0.3,
bands: ['red', 'green', 'blue'],
};
for (var i = 0; i < 24; i++)
{
Map.addLayer(ee.Image(image_to_drive.get(i)), visualization);
}
Map.addLayer(geometry, null, "geometry");
// 数据下载
var name_image = ee.List(
['01-1','01-2','02-1','02-2','03-1','03-2',
'04-1','04-2','05-1','05-2','06-1','06-2',
'07-1','07-2','08-1','08-2','09-1','09-2',
'10-1','10-2','11-1','11-2','12-1','12-2']
);
for (var i = 0; i < 24; i++)
{
var f_name = name_image.get(i).getInfo();
Export.image.toDrive({
image: ee.Image(image_to_drive.get(i)),
folder: 'my_folder',
fileNamePrefix: f_name,
description: f_name,
region: geometry.geometry().bounds(),
scale: 30, //重采样使空间分辨率为30m
crs: "EPSG:4326", //使用WGS84坐标系
maxPixels: 1e13
});
}