GEE, Sentinel 2 cloud and shadow

GEE在2021年8月30日左右甘邀,發(fā)布了Sentinel 2 去云的新教程琅坡,利用Probability產(chǎn)品和 CDI指數(shù)來(lái)去云逗物。官方教程代碼如下:
https://code.earthengine.google.com/a7d6d6defee0ae0d0fdfe4d4c5011306
或者在Examples中也可以找到

image.png

以下內(nèi)容是自己的筆記

目錄

  • 知識(shí)點(diǎn)
  • 官方代碼講解
  • 實(shí)際應(yīng)用

一跌前、知識(shí)點(diǎn)

  • CDI
    CDI是David Frantz在2018年創(chuàng)造的指數(shù)钮糖,這個(gè)指數(shù)是用來(lái)探測(cè)Sentinel 2中的云,并且還可以區(qū)分高亮云和建筑物枢析,在GEE中的調(diào)用是ee.Algorithms.Sentinel2.CDI 玉掸。由于CDI指數(shù)是使用Sentinel 2 Level 1C 產(chǎn)品生成的,所以用這個(gè)算法計(jì)算CDI時(shí)醒叁,要用到Sentinel 2 Level 1C 司浪。想要更加了解這個(gè)指數(shù)的可以看David Frantz在RSE上發(fā)表的文章Improvement of the Fmask algorithm for Sentinel-2 images: Separating clouds from bright surfaces based on parallax effects

  • ee.Join函數(shù)
    關(guān)于這部分內(nèi)容泊业,推薦去看知乎上的一個(gè)作者,想要了解Join函數(shù)就必須先了解Filter断傲,更加推薦大家去看視頻版脱吱,也就12分鐘。
    第10節(jié) GEE的參數(shù)類(lèi)型 (Filter认罩,Join) - 知乎 (zhihu.com)

二、官方代碼講解

1. 調(diào)用三個(gè)數(shù)據(jù)集

// 調(diào)用 Sentinel 2 L1C產(chǎn)品续捂,來(lái)計(jì)算CDI
var s2 = ee.ImageCollection('COPERNICUS/S2');
// 調(diào)用 Probability產(chǎn)品
var s2c = ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY');
// 調(diào)用 Sentine 2 L2A產(chǎn)品
var s2Sr = ee.ImageCollection('COPERNICUS/S2_SR');

2. 篩選

// ROI
var roi = ee.Geometry.Point([-122.4431, 37.7498]);
Map.centerObject(roi, 11);

// 定義時(shí)間范圍
var start = ee.Date('2019-03-01');
var end = ee.Date('2019-09-01');

// 選出CDI計(jì)算中要用到的波段
s2 = s2.filterBounds(roi).filterDate(start, end)
    .select(['B7', 'B8', 'B8A', 'B10']);

s2c = s2c.filterDate(start, end).filterBounds(roi);
// 這里對(duì)Sentinel 2 L2A產(chǎn)品的波段選擇沒(méi)有要求垦垂,也可以選擇其他波段,或者全選牙瓢,但注意和L1C區(qū)分
s2Sr = s2Sr.filterDate(start, end).filterBounds(roi)
    .select(['B2', 'B3', 'B4', 'B5']);

3. 定義函數(shù):將兩個(gè)數(shù)據(jù)集合并
下面這個(gè)函數(shù)劫拗,實(shí)際上是將collectionB 按照時(shí)間屬性,加入到collectionA中矾克。比如:有2個(gè)數(shù)據(jù)集页慷,一個(gè)是EVI,一個(gè)是NDVI胁附,它們都有一年的時(shí)間序列酒繁,我想按照時(shí)間整合兩個(gè)數(shù)據(jù)集到一個(gè)數(shù)據(jù)集當(dāng)中,以便于分析控妻。
注意:ee.Join.saveFirst 返回的是左邊數(shù)據(jù)集collectionA州袒,只是將 collectionB當(dāng)作一個(gè)屬性添加到collectionA中的屬性當(dāng)中而已

// propertyName 是一個(gè)MatchKey,由用戶(hù)自定義弓候,可以是任何字符串
//為了后面的map函數(shù)郎哭,ee.ImageCollection 一定要加,因?yàn)閑e.Join函數(shù)返回的是Join對(duì)象
function indexJoin(collectionA, collectionB, propertyName) {
  var joined = ee.ImageCollection(ee.Join.saveFirst(propertyName).apply({
    primary: collectionA,
    secondary: collectionB,
    condition: ee.Filter.equals({
      leftField: 'system:index',
      rightField: 'system:index'})
  }));
  // 通過(guò)get函數(shù)獲取右邊數(shù)據(jù)集的影像菇存,再通過(guò)addBands合并成一個(gè)ImageCol
  return joined.map(function(image) {
    return image.addBands(ee.Image(image.get(propertyName)));
  });
}

4. 定義函數(shù):去云
這一步才是真正的開(kāi)始去云以及去掉陰影夸研,前面都是數(shù)據(jù)集的準(zhǔn)備

function maskImage(image) {
  // 計(jì)算CDI,下面的B10是Sentinel2 L1C的波段
  var cdi = ee.Algorithms.Sentinel2.CDI(image);
  var s2c = image.select('probability');
  var cirrus = image.select('B10').multiply(0.0001);

 // 閾值設(shè)定依鸥,滿(mǎn)足下列條件的都是云亥至,這里的閾值是官方給的
  var isCloud = s2c.gt(65).and(cdi.lt(-0.5)).or(cirrus.gt(0.01));

  // 以下代碼似乎是通過(guò)面積來(lái)判斷,有知道的可以評(píng)論一下
  // Reproject is required to perform spatial operations at 20m scale.
  // 20m scale is for speed, and assumes clouds don't require 10m precision.
  isCloud = isCloud.focal_min(3).focal_max(16);
  isCloud = isCloud.reproject({crs: cdi.projection(), scale: 20});

  // Project shadows from clouds we found in the last step. This assumes we're working in
  // a UTM projection.
  var shadowAzimuth = ee.Number(90)
      .subtract(ee.Number(image.get('MEAN_SOLAR_AZIMUTH_ANGLE')));

  // With the following reproject, the shadows are projected 5km.
  isCloud = isCloud.directionalDistanceTransform(shadowAzimuth, 50);
  isCloud = isCloud.reproject({crs: cdi.projection(), scale: 100});

  isCloud = isCloud.select('distance').mask();
  return image.select('B2', 'B3', 'B4').updateMask(isCloud.not());
}

5. 合并與去云
官方這里給的是無(wú)云中值合成案例

// 將Probability 加入到 Sentinel2 L2A中
var withCloudProbability = indexJoin(s2Sr, s2c, 'cloud_probability');

// 將Sentinel2 L1C 加入到 withCloudProbability 中
var withS2L1C = indexJoin(withCloudProbability, s2, 'l1c');

// 對(duì)最后合并的數(shù)據(jù)集進(jìn)行去云
var masked = ee.ImageCollection(withS2L1C.map(maskImage));

// 中值合成毕籽,下面設(shè)置8是為了避免memory errors
var median = masked.reduce(ee.Reducer.median(), 8);

三抬闯、實(shí)際應(yīng)用

生成云掩膜的過(guò)程實(shí)際上只用到L1C產(chǎn)品和Probability產(chǎn)品,如果按照官方的步驟关筒,把L2A產(chǎn)品和Probability產(chǎn)品先合并溶握,那么L2A產(chǎn)品中的波段不能含有 ['B7', 'B8', 'B8A', 'B10'],因?yàn)楹竺孢€會(huì)和L1C產(chǎn)品合并蒸播,CDI只用到了L1C產(chǎn)品中的 ['B7', 'B8', 'B8A', 'B10']來(lái)計(jì)算睡榆。如果將L2A和L1C的['B7', 'B8', 'B8A', 'B10']都合并在一起,會(huì)出現(xiàn)波段命名不一樣的情況萍肆,如下圖所示,此時(shí)如果用maskImage,CDI計(jì)算用到的波段可能是L2A的胀屿。

image.png

而我們?cè)谑褂眠^(guò)程中塘揣,B8這個(gè)波段對(duì)我們很重要,不能丟掉B8宿崭。因此亲铡,可以先生成掩膜文件,再通過(guò)Map循環(huán)來(lái)掩膜葡兑。
代碼如下:

// 數(shù)據(jù)集
var s2 = ee.ImageCollection('COPERNICUS/S2');
var s2c = ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY');
var s2Sr = ee.ImageCollection('COPERNICUS/S2_SR');

var roi = ee.Geometry.Point([-122.4431, 37.7498]);
Map.centerObject(roi, 11);

var start = ee.Date('2020-01-01');
var end = ee.Date('2021-01-01');

//篩選
s2 = s2.filterBounds(roi).filterDate(start, end)
    .select(['B7', 'B8', 'B8A', 'B10']);
s2c = s2c.filterDate(start, end).filterBounds(roi);

var s2Sr = s2Sr
            .filterBounds(roi)
            .filterDate(start,end)
            .filter(ee.Filter.lte('CLOUDY_PIXEL_PERCENTAGE',50))

// Join two collections on their 'system:index' property.
function indexJoin(collectionA, collectionB, propertyName) {
  var joined = ee.ImageCollection(ee.Join.saveFirst(propertyName).apply({
    primary: collectionA,
    secondary: collectionB,
    condition: ee.Filter.equals({
      leftField: 'system:index',
      rightField: 'system:index'})
  }));
  // Merge the bands of the joined image.
  return joined.map(function(image) {
    return image.addBands(ee.Image(image.get(propertyName)));
  });
}

// 生成一個(gè)云掩膜波段奖蔓,并將這個(gè)掩膜波段命名為 CloudMask
function maskImage(image) {
  // Compute the cloud displacement index from the L1C bands.
  var cdi = ee.Algorithms.Sentinel2.CDI(image);
  var prob = image.select('probability');
  var cirrus = image.select('B10').multiply(0.0001);
  var isCloud = prob.gt(65).and(cdi.lt(-0.5)).or(cirrus.gt(0.01));

  isCloud = isCloud.focal_min(3).focal_max(16);
  isCloud = isCloud.reproject({crs: cdi.projection(), scale: 20});

  var shadowAzimuth = ee.Number(90)
      .subtract(ee.Number(image.get('MEAN_SOLAR_AZIMUTH_ANGLE')));

  isCloud = isCloud.directionalDistanceTransform(shadowAzimuth, 50);
  isCloud = isCloud.reproject({crs: cdi.projection(), scale: 100});

  isCloud = isCloud.select('distance').mask().rename('CloudMask');
  return isCloud.not();
}

// 將probability產(chǎn)品合并到s2中
var withCloudProbability = indexJoin(s2, s2c, 'cloud_probability');
// 生成掩膜文件
var masked = ee.ImageCollection(withCloudProbability.map(maskImage));
//將掩膜文件合并到L2A產(chǎn)品中
var s2SrWithMask = indexJoin(s2Sr,masked,'could_mask');

// 使用Map函數(shù),開(kāi)始掩膜
var S2_cloudMask = s2SrWithMask.map(function(img){
    var mask = img.select('CloudMask')
    return img.updateMask(mask)
              .divide(10000)
              .select('B.*')
              .toFloat()
              .copyProperties(img, ["system:time_start"])
})

print('S2_cloudMask:',S2_cloudMask)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末讹堤,一起剝皮案震驚了整個(gè)濱河市吆鹤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌洲守,老刑警劉巖疑务,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異梗醇,居然都是意外死亡知允,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)婴削,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)廊镜,“玉大人,你說(shuō)我怎么就攤上這事唉俗∴推樱” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵虫溜,是天一觀的道長(zhǎng)雹姊。 經(jīng)常有香客問(wèn)我,道長(zhǎng)衡楞,這世上最難降的妖魔是什么吱雏? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮瘾境,結(jié)果婚禮上歧杏,老公的妹妹穿的比我還像新娘。我一直安慰自己迷守,他們只是感情好犬绒,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著兑凿,像睡著了一般凯力。 火紅的嫁衣襯著肌膚如雪茵瘾。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,821評(píng)論 1 290
  • 那天咐鹤,我揣著相機(jī)與錄音拗秘,去河邊找鬼。 笑死祈惶,一個(gè)胖子當(dāng)著我的面吹牛雕旨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播捧请,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼奸腺,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了血久?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤帮非,失蹤者是張志新(化名)和其女友劉穎氧吐,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體末盔,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡筑舅,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了陨舱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片翠拣。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖游盲,靈堂內(nèi)的尸體忽然破棺而出误墓,到底是詐尸還是另有隱情,我是刑警寧澤益缎,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布谜慌,位于F島的核電站,受9級(jí)特大地震影響莺奔,放射性物質(zhì)發(fā)生泄漏欣范。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一令哟、第九天 我趴在偏房一處隱蔽的房頂上張望恼琼。 院中可真熱鬧,春花似錦屏富、人聲如沸晴竞。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)颓鲜。三九已至表窘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間甜滨,已是汗流浹背乐严。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留衣摩,地道東北人昂验。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像艾扮,于是被迫代替她去往敵國(guó)和親既琴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容