“天气晴朗时,见个面吧。我心里储存的,有关你的影像档,已经旧了,需要更新”
——林婉瑜
今天是七夕,让我们和代码相伴,邂逅一段新的故事。
前段时间,有读者私信小编,当我们在对一些研究区域进行预处理后会发现影像存在缺失问题,导致结果没办法用,这个问题应该如何解决,小编翻阅了一些大佬的文章,学到一点本事,今天来当一回女娲,看看如何补补天吧~~~。
打开咱们的伙伴:Google Earth Engine,诶,今天发现,在打印栏出现一行醒目的绿色大字。
从2024年11月13日起,如果在GEE上没有云端项目,将限制使用GEE,这个GEE的新闻头条部分读者已经在其他的文章或者是GEE开发官网得到消息了,还没有云端项目的伙伴,赶紧找到网址创建好属于自己的新项目,从项目进入即可!https://developers.google.com/earth-engine/cloud/earthengine_cloud_project_setup
配置好项目后,我们打开GEE的编辑器,开始上代码。
1 创建研究区域
var roi = ee.FeatureCollection("users/hesuixinya511/Province")
.filterMetadata("NAME","equals","重庆");
Map.centerObject(roi,7);
var styling = {color:"red",fillColor:"00000000"};
Map.addLayer(roi.style(styling),{},"CHONGQING");
代码解释:
第1~2行,从用户指定路径中加载一个要素集合(FeatureCollection)。这个集合包含中国各省的地理边界数据。利用filterMetadata命令从要素集合中过滤出名称为“重庆”的要素。“NAME”是要素集合中的一个属性字段,用来表示省份名称。
第3行,将地图视图的中心设置为重庆区域,并将缩放级别设置为7。这使得地图界面聚焦在指定区域,方便各位小伙伴查看。
第4行,定义了显示样式。color参数将边界线的颜色设置为红色,fillColor参数将填充颜色设置为透明(十六进制颜色代码一般为6位,此处8位,其中最后两位为透明度,00表示完全透明)。
第5行,将重庆区域的边界添加到地图中,并应用前面定义的样式。第三个参数“CHONGQING”是图层的名称,便于管理和识别。
上述代码,将得到重庆市的行政边界:
2 影像标准化处理
var img_normalize = function(img){
var minMax = img.reduceRegion({
reducer:ee.Reducer.minMax(),
geometry: roi,
scale: 30,
maxPixels: 10e13,
tileScale: 16 });
var year = img.get('year');
var normalize = ee.ImageCollection.fromImages(
img.bandNames().map(function(name){
name = ee.String(name);
var band = img.select(name);
return band.unitScale(ee.Number(minMax.get(name.cat('_min'))), ee.Number(minMax.get(name.cat('_max')))); })
).toBands().rename(img.bandNames());
return normalize;
};
代码解释:
第1行,定义一个名为img_normalize 的函数,接收一个影像img作为参数。该函数的目的是对影像中的各个波段进行标准化处理。
第2~7行,计算影像在指定区域(geometry:roi)内的每个波段的最小值和最大值。其中包括的基本参数为计算器、研究区域、分辨率、计算时的最大像素数以及瓦片缩放比例。
第8行,从影像的属性中获取年份信息。这一步在当前代码中没有被进一步使用,可以用于标记或其他数据处理。
第9~14行:遍历影像中的每个波段,进行标准化处理,将影像波段范围映射到[0,1],并将标准化后的各个波段合并为一个影像,重命名为原来的波段名称。
这种标准化处理通常用于遥感影像的时间序列分析和多影像比较,可以有效减少光照、传感器差异和其他非目标因素的影响。
3 影像去云与校正预处理
function maskL457sr(image) {//l57去云
// Bit 0 - Fill
// Bit 1 - Dilated Cloud
// Bit 2 - Unused
// Bit 3 - Cloud
// Bit 4 - Cloud Shadow
var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0);
var saturationMask = image.select('QA_RADSAT').eq(0);
// Apply the scaling factors to the appropriate bands.
var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2);
var thermalBand = image.select('ST_B6').multiply(0.00341802).add(149.0);
// Replace the original bands with the scaled ones and apply the masks.
return image.addBands(opticalBands, null, true)
.addBands(thermalBand, null, true)
.updateMask(qaMask)
.updateMask(saturationMask);
}
代码解释:
QA_PIXEL
波段:这是Landsat影像中用于质量评估的波段。该波段中的位(bits)用于标识影像中的各种质量问题,例如云、阴影、填充值等。
QA_RADSAT
波段:这是Landsat影像中用于指示饱和像素的波段。
上述波段通过位与操作和eq(0)即可达到目标效果。
第4行,光学波段校正,对光学波段应用缩放因子,将DN值转换为反射率。缩放因子和偏移量来源于Landsat影像的元数据。
第5行,热红外波段校正,对热红外波段应用缩放因子,将DN值转换为亮温(开尔文)。
第6~10行,更新影像,使用addBands用校正后的光学波段和热红外波段替换原始波段。null表示不设置新波段的名称,true 表示覆盖同名波段。使用updateMask,应用QA掩码和饱和掩码,去除有问题的像素。这一步确保输出影像仅包含有效数据。
此段代码对Landsat 4-5卫星影像进行预处理,以去除云、阴影和饱和像素,同时将影像值转换为物理意义的反射率和亮温。
Landsat8数据的预处理看下面:
function maskL8sr(image) {
// Bit 0 - Fill
// Bit 1 - Dilated Cloud
// Bit 2 - Cirrus
// Bit 3 - Cloud
// Bit 4 - Cloud Shadow
var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0);
var saturationMask = image.select('QA_RADSAT').eq(0);
// Apply the scaling factors to the appropriate bands.
var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2);
var thermalBands = image.select('ST_B.*').multiply(0.00341802).add(149.0);
// Replace the original bands with the scaled ones and apply the masks.
return image.addBands(opticalBands, null, true)
.addBands(thermalBands, null, true)
.updateMask(qaMask)
.updateMask(saturationMask);
}*/
4 影像筛选与中值合成
var imageCollection = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2').filterBounds(roi);//1111111
var monthCount = ee.List.sequence(0, 11);
// 通过图像收集,生成每月NDVI中值图像
var composites = ee.ImageCollection.fromImages(monthCount.map(function(m) {
var startMonth = 1; // 从1月开始
var startYear = ee.Number(2000); // 1993-1
var month = ee.Date.fromYMD(startYear, startMonth, 1).advance(m,'month').get('month');
var year = ee.Date.fromYMD(startYear, startMonth, 1).advance(m,'month').get('year')
// 按年筛选,然后按月筛选
var filtered = imageCollection.filter(ee.Filter.calendarRange({
start: year.subtract(1), // 过去两年的平均数
end: year,
field: 'year'
})).filter(ee.Filter.calendarRange({
start: month,
field: 'month'
}));
// mask for clouds and then take the median///
var composite = filtered.map(maskL457sr).median().clip(roi);
return composite.normalizedDifference(['SR_B4', 'SR_B3']).rename('NDVI')
.set('month', ee.Date.fromYMD(startYear, startMonth, 1).advance(m,'month'))
.set('system:time_start', ee.Date.fromYMD(startYear, startMonth, 1).advance(m,'month').millis());
}));
print(composites);
代码解释:
第1行:加载L5影像,并且按照研究区域筛选。
第2行:生成一个包含数字0到11的列表,用于表示每年的12个月。这将用于迭代每个月的处理。
第6-7行:根据基准日期(第五行定义的2000年1月1日)和m(月份偏移量)计算当前迭代的月份和年份。利用get函数提取当前迭代中的月份和年份。
第8-15行:在筛选过去两年的影像数据,筛选当前月份的影像数据。
第16行:应用之前定义的预处理函数maskL457sr,对影像进行去云和辐射校正。利用median方法计算当前月份的影像中值,以减少噪声和偶然变化的影响,最后使用clip将影像裁剪到roi。
第17行:计算NDVI。
第18行:设置元数据,为每张影像设置月份属性,方便后续的分析。
此段通过遍历一年中的每个月,计算Landsat 5影像在指定区域内的NDVI中值。敲黑板!!!这种方法可以用于时间序列分析,帮助研究区域内植被变化情况。通过使用中值和去云处理,能够有效减少影像中的噪声和误差,得到更加可靠的结果。
5 影像填补
// 用上个月和下个月的平均值替换被遮挡的像素
var replacedVals = composites.map(function(image){
var currentDate = ee.Date(image.get('system:time_start'));
var meanImage = composites.filterDate(
currentDate.advance(-2,'month'), currentDate.advance(2, 'month')).mean();//33333333333333333333333max min median
// 替换所有被屏蔽的值
return meanImage.where(image, image);
});
代码解释:
第1-6行,对composites中的每个图像进行逐一处理。map方法会将集合中的每个元素传递给函数,并返回一个新的集合。
第2行,获取当前的时间,将其转化为ee对象,方便后续的日期处理。
第3-4行,计算当前影像前后两个月的日期,过滤期间所有的影像,之后,计算其平均值,利用mean方法生成平均影像。
第5行,替换无效像素。where(condition,value):在条件为false的地方,用value替换原始影像的值.image作为条件:对于有效像素(即未被掩膜)的位置,条件为true,保留原始值。对于被掩膜的像素(即无效像素),条件为false,用meanImage中的值替换掉。
此代码在时间序列分析中用于填补由于云、阴影等原因导致的无效数据,以提高数据的完整性。
6 数据可视化
var palettes = require('users/gena/packages:palettes');
var Vis = {
min: -1,
max: 1.0,
palette: palettes.colorbrewer.RdYlGn[5]
};
Map.addLayer(compos.select(6), Vis, '插值前');
// .0-11 分别代表1-12个月
Map.addLayer(stacked.select(6), Vis, 'NDVI');
这里就不用过多解释,就是对处理前后的影像调调配色而已,我们来看最后的结果吧
填补前的影像
填补后的影像
效果还是挺不错的,只是在右小角有一小块还存在些差异,但是比起原始的影像就好多了。
好了,今天的GEE学习到这里就结束了。
“七”待已久,“夕”望是你,我是禾穗,祝正在学代码的朋友们早日遇见幸福噢~,不过单身的朋友也没关系啦,看看日历,今天没有早八,没有工作,是快乐周六呀!!