点击上方蓝字关注我们
之前我们介绍了很多Sentinel-2的去云方法,包括(1)利用QA60波段进行位运算,去除云所在的位,采用的是F-Mask算法;(2)利用Sentinel-2: Cloud Probability数据进行云分数去云,采用的是欧空局的数据。今天,我们介绍一种最新的去云方法,(3)采用谷歌的Cloud Score+进行去云。文末,我们对比这三种去云方法的精度和局限性。
1 内容
在Google Earth Engine (GEE)中,Sentinel-2数据通过QA60波段(质量控制波段)实现云掩膜。其核心原理基于 质量信息位掩码(bitmask) 的技术,具体描述如下:
QA60的值为0:该像素无云。
QA60的值为1:该像素被云覆盖。
其代码可参考如下:
/***第一种方法,采用QA60进行Sentinel-2去云****/
function maskS2clouds_QA60(image) {
var qa = image.select('QA60');
// Bits 10 and 11 are clouds and cirrus, respectively.
var cloudBitMask = 1 << 10;
var cirrusBitMask = 1 << 11;
// Both flags should be set to zero, indicating clear conditions.
var mask = qa.bitwiseAnd(cloudBitMask).eq(0)
.and(qa.bitwiseAnd(cirrusBitMask).eq(0));
return image.updateMask(mask);
}
在Google Earth Engine (GEE) 中,Sentinel-2影像的 Cloud Probability 数据 是一种基于机器学习的云检测方法,提供了每个像素被云覆盖的概率。它依赖于光谱特征分析与训练模型生成的云概率波段,相比QA60波段的简单二值掩膜,这种方法具有更高的灵活性和精度。
Sentinel-2的Cloud Probability数据来源于 Sentinel-2 Cloud Probability 数据集 (COPERNICUS/S2_CLOUD_PROBABILITY
),每个像素的值为0到100,表示被云覆盖的概率(单位为百分比)。此数据通过机器学习模型结合Sentinel-2多光谱波段(如蓝、红、近红外和短波红外)以及大气信息生成。
低值(接近0):像素几乎不可能是云。
高值(接近100):像素高度可能是云。
这种概率评分为用户提供了细粒度的云检测能力,允许用户根据实际应用设定阈值进行去云处理。
其代码可参考如下:
/***第二种方法,采用CloudProbability进行Sentinel-2去云****/
// 建立去云函数,这里我们将去云的阈值设置为30
function CloudProbability(img,threshold){
var prob = img.select('probability')
return img.updateMask(prob.lte(threshold))
}
// 利用ee.Join.inner函数将cloud影像和Sentinel-2影像联合,以便后面去云时使用
function MergeImages(primary, secondary) {
var join = ee.Join.inner();
var filter = ee.Filter.equals({
leftField: 'system:index',
rightField: 'system:index'
});
var Col = join.apply(primary, secondary, filter)
.map(function(image) {
var img1 = ee.Image(image.get("primary"));
var img2 = ee.Image(image.get("secondary"));
return ee.Image.cat(img1,img2);
});
return ee.ImageCollection(Col);
}
Cloud Score+ 是一款用于中高分辨率光学卫星图像的质量评估 (QA) 处理器。Cloud Score+ S2_HARMONIZED 数据集由经过协调的 Sentinel-2 L1C 集合生成,Cloud Score+ 输出可用于识别相对清晰的像素,并有效地从 L1C(大气顶部)或 L2A(表面反射)图像中去除云和云阴影。Cloud Score+ S2_HARMONIZED 数据集包含两个 QA 波段,cs 和 cs_cdf,它们都以 0 到 1 之间的连续尺度对单个像素相对于表面可见性的可用性进行评级,其中 0 表示“不清晰”(被遮挡),而 1 表示“清晰”(未被遮挡)的观测结果。 cs 波段根据观测像素与(理论上的)清晰参考观测之间的光谱距离对 QA 进行评分,而 cs_cdf 波段则表示观测像素清晰的可能性,该可能性基于给定位置随时间变化的估计累积分数分布。换句话说,cs 可以被认为是更即时的大气相似性分数(即,该像素与我们期望在完全清晰的参考中看到的像素有多相似),而 cs_cdf 捕获随时间变化的估计分数的期望(即,如果我们拥有该像素随时间变化的所有分数,该分数将如何排名?)。Cloud Score+ S2_HARMONIZED 集合中的图像具有与生成它们的单个 Sentinel-2 L1C 资产相同的 id 和 system:index 属性,因此 Cloud Score+ 波段可以根据其共享的 system:index 链接到源图像。
其代码可参考如下:
/***第三种方法得到的去云影像结果**/
var S2A_img_rmCloudByCloudScore = S2A_img
.linkCollection(S2CS,'cs')
.map(function(img) {
return img.updateMask(img.select('cs').gte(0.6));
}).first();
2 讨论
var geometry =
/* color: #d63000 */
/* shown: false */
ee.Geometry.Point([103.82735541698865, 30.805600117293057]),
S2A = ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED"),
S2C = ee.ImageCollection("COPERNICUS/S2_HARMONIZED"),
S2CP = ee.ImageCollection("COPERNICUS/S2_CLOUD_PROBABILITY"),
S2CS = ee.ImageCollection("GOOGLE/CLOUD_SCORE_PLUS/V1/S2_HARMONIZED");
/***第一种方法,采用QA60进行Sentinel-2去云****/
function maskS2clouds_QA60(image) {
var qa = image.select('QA60');
// Bits 10 and 11 are clouds and cirrus, respectively.
var cloudBitMask = 1 << 10;
var cirrusBitMask = 1 << 11;
// Both flags should be set to zero, indicating clear conditions.
var mask = qa.bitwiseAnd(cloudBitMask).eq(0)
.and(qa.bitwiseAnd(cirrusBitMask).eq(0));
return image.updateMask(mask);
}
/***第二种方法,采用CloudProbability进行Sentinel-2去云****/
// 建立去云函数,这里我们将去云的阈值设置为30
function CloudProbability(img,threshold){
var prob = img.select('probability')
return img.updateMask(prob.lte(threshold))
}
// 利用ee.Join.inner函数将cloud影像和Sentinel-2影像联合,以便后面去云时使用
function MergeImages(primary, secondary) {
var join = ee.Join.inner();
var filter = ee.Filter.equals({
leftField: 'system:index',
rightField: 'system:index'
});
var Col = join.apply(primary, secondary, filter)
.map(function(image) {
var img1 = ee.Image(image.get("primary"));
var img2 = ee.Image(image.get("secondary"));
return ee.Image.cat(img1,img2);
});
return ee.ImageCollection(Col);
}
var S2A_img = S2A.filterDate('2020-10-1','2020-11-01')
.filterBounds(geometry)
// .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',50))
.sort('CLOUDY_PIXEL_PERCENTAGE')
// .map(maskS2clouds_QA60)
print('S2A_img',S2A_img)
var visualization = {
min: 0.0,
max: 3000,
bands: ['B4', 'B3', 'B2'],
};
Map.addLayer(S2A_img.first(), visualization, 'S2A_imgRGB',false);
/***第一种方法得到的去云影像结果**/
var S2A_img_rmCloudByQA60 = maskS2clouds_QA60(S2A_img.first())
/***第二种方法得到的去云影像结果**/
var S2CP_img = S2CP.filterDate('2020-10-1','2020-11-01')
.filterBounds(geometry);
var S2A_img_rmCloudByCloudProbability = MergeImages(S2A_img, S2CP_img).map(function(image){return CloudProbability(image,30)});//阈值为30
/***第三种方法得到的去云影像结果**/
var S2A_img_rmCloudByCloudScore = S2A_img
.linkCollection(S2CS,'cs')
.map(function(img) {
return img.updateMask(img.select('cs').gte(0.6));
}).first();
//设置空白处填充色系
var span = ee.Image(1).clip(S2A_img.first().geometry())
Map.addLayer(span,{palette:'blue'},'span')
//分别显示三种方法去云后的结果
Map.addLayer(S2A_img_rmCloudByQA60,visualization, 'S2A_img_rmCloudByQA60',false);
Map.addLayer(S2A_img_rmCloudByCloudProbability.first(),visualization, 'S2A_img_rmCloudByCloudProbability',false);
Map.addLayer(S2A_img_rmCloudByCloudScore,visualization, 'S2A_img_rmCloudByCloudScore',false);
3 参考文献
往期回顾