GEE:Sentinel-2去云,cloudBitMask = 1 << 10,bitwiseAnd(1<<5)的含义,去云,位运算

本文将介绍在GEE中,如何理解和使用遥感数据的质量控制QA波段,以及介绍使用QA波段制作掩膜和去云的过程。



一、2024年10月31日答疑:

1.有粉丝问:L8是怎么用QA_PIXEL来掩膜掉云和噪声的吗,问了AI,还是没懂这些参数什么意思,为什么移位1<<5就是第六位,也不知道每一行什么意思。代码如下:

var cloudMaskL8=function(image){
  var qa=image.select('QA_PIXEL');
  var cloud=qa.bitwiseAnd(1<<2)
  .or(qa.bitwiseAnd(1<<5))
  .or(qa.bitwiseAnd(1<<7))
  .or(qa.bitwiseAnd(1<<4))
  .or(qa.bitwiseAnd(1<<3))
  .or(qa.bitwiseAnd(1<<8).and(qa.bitwiseAnd(1<<9)))
  .or(qa.bitwiseAnd(1<<10).and(qa.bitwiseAnd(1<<11)))
  .or(qa.bitwiseAnd(1<<12).and(qa.bitwiseAnd(1<<13)))
  .or(qa.bitwiseAnd(1<<14).and(qa.bitwiseAnd(1<<15)));
  return image.select([
    'SR_B2','SR_B3','SR_B4','SR_B5','SR_B6','SR_B7'],
    ['blue','green','red','nir','swir1','swir2']).updateMask(cloud.not());
};
 var cloudMaskL457=function(image){
   var qa=image.select('QA_PIXEL');
   var cloud=qa.bitwiseAnd(1<<5)
   .or(qa.bitwiseAnd(1<<7))
   .or(qa.bitwiseAnd(1<<3))
   .or(qa.bitwiseAnd(1<<4))
   .or(qa.bitwiseAnd(1<<8).and(qa.bitwiseAnd(1<<9)))
   .or(qa.bitwiseAnd(1<<10).and(qa.bitwiseAnd(1<<11)))
   .or(qa.bitwiseAnd(1<<12).and(qa.bitwiseAnd(1<<13)))
   .or(qa.bitwiseAnd(1<<14).and(qa.bitwiseAnd(1<<15)));
   return image.select([
     'SR_B1','SR_B2','SR_B3','SR_B4','SR_B5','SR_B7'],
     ['blue','green','red','nir','swir1','swir2']).updateMask(cloud.not());
 };

答:简单来说,就是数据是以二进制01这种格式保存的,以哨兵数据的QA60波段为例,假如有一个像素是111001111000,(bit10就是从右往左数第10个数字,从0开始数到10。10位相当于从1数第11个数字)。10位是1就是有云,0就是无云。例子的第10位数字是1,所以现在该像素是有云的。1<<10就是把0001左移10位,变成10000000000。现在将像素值111001111000和10000000000作比较,两个数字重叠一下,如果111001111000的第10位是1,那么就是有云,这个过程就是qa.bitwiseAnd(cloudBitMask)。And是布尔运算,如果第10位数字匹配返回1,不匹配返回0。就是说如果两数的布尔运算结果是1就是有云,0就是无云。.updateMask()是将无云的像素保留。

为什么这么做呢?是因为数据中的二进制数字中包含了很多信息,不光是云,卷云,可能还有其他信息(雪、阴影、水体、冰等)。比如该代码中有5,6,7,8,9,10,11,12,13,14,15。单独比较其中1位,不会造成误判,简化了判断流程。

二、粗浅理解

比如Sentinel-2数据的 ‘QA60’ 波段,包含Opaque clouds不透明的云和Cirrus clouds卷云
qa.bitwiseAnd(cloudBitMask).eq(0) 表示选择cloudBitMask
比特位为10的数据左移一位,并且让bit10位置的值等于0,这样就生成了云掩膜。
qa.bitwiseAnd(cirrusBitMask).eq(0) 表示选择 cirrusBitMask 比特位为11的数据左移一位,并且让bit11位置等于0,这样生成了卷云的掩膜。
③ 使用 and() 将两个掩膜合并加起来生成云和卷云的共同的大掩膜mask
④ 使用 .updateMask(mask) 更新掩膜,将无云的影像筛选出来。

符号描述运算规则
<<左移各二进位全部左移若干位,高位丢弃,低位补0
>>右移各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)
这里的1<<10或者1<<11要换算成二进制位运算,左移10位或者11位,右边用0补位

经过CFMASK算法处理后生成一个QA60,QA60在bit10和bit11是Cloud mask(二进制表示,存在Cloud mask即为1,不存在为0)


三、去云以前效果

去云以前

四、去云以后效果

去云以后


代码

//导入数据
var s2 = ee.ImageCollection("COPERNICUS/S2"),
 
point = ee.Geometry.Point([112.20553071765003, 26.404020061278715]);

S2去云

//s2去云
function maskS2clouds(image) {
  var qa = image.select('QA60');
  
// Bits 10 and 11 are clouds and cirrus, respectively.
//比特10和比特11分别是云和卷云。
  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).divide(10000);
}
var startDate = "2020-6-4";
 
  var endDate = "2020-6-30";
 
  Map.centerObject(point, 8);
 
  var s2Imgs = s2.filterDate(startDate, endDate)
 
                 .filterBounds(point);
 
  Map.addLayer(s2Imgs.first(), {min:0, max:3000, bands:["B4", "B3", "B2"]}, "raw", false);
  
 //影像集每幅影像去云
  s2Imgs = s2Imgs.map(maskS2clouds);
  
 //选择影像集第一幅影像去云,合成,显示
  Map.addLayer(s2Imgs.first(), {min:0, max:3000, bands:["B4", "B3", "B2"]}, "cloud");
 

在这里插入图片描述

这是我的原代码://Sentinel2数据制作经过量筛选后的时间序列NDVI function maskS2clouds(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).divide(10000).copyProperties(image).set('system:time_start', image.get('system:time_start')); } //定义感兴趣区 var shuidao = ee.Feature( ee.Geometry.Point([107.497, 30.2796]), {label: 'rice'}); var yumi = ee.Feature( ee.Geometry.Point([107.4673, 30.3475]), {label: 'corn'}); var youcai = ee.Feature( ee.Geometry.Point([107.4115, 30.17025]), {label: 'rape'}); var ganju = ee.Feature( ee.Geometry.Point([107.3455, 30.0034]), {label: 'citrus'}); //将wu种作物感兴趣区合并 var cropRegions = new ee.FeatureCollection([shuidao,yumi,youcai,ganju]); //筛选s2数据 var s2= ee.ImageCollection('COPERNICUS/S2_SR') .filterDate('2023-01-1', '2023-12-31') .filterBounds(cropRegions) .filterMetadata('CLOUDY_PIXEL_PERCENTAGE',"less_than",20) .map(maskS2clouds) //计算每副影像的NDVI并制作数据集 var ndvi = s2.map(function(image) { return image .select() .addBands(image.normalizedDifference(['B8', 'B4']).select([0], ['NDVI'])) }); //渲染NDVI显示颜色 var vis = {min: -0.2, max: 1, palette: [ 'FFFFFF', 'CE7E45', 'FCD163', '66A000', '207401', '056201', '004C00', '023B01', '012E01', '011301' ]}; Map.addLayer(ndvi, vis, 'NDVI'); //Map.addLayer(cropRegions, {color: COLOR.GAOLIANG},'ROI'); // Map.addLayer(gaoliang, {color: COLOR.GAOLIANG}); // Map.addLayer(yumi, {color: COLOR.YUMI}); // Map.addLayer(dadou, {color: COLOR.DADOU}); //定义图表及样式 var ndviTimeSeries = ui.Chart.image.seriesByRegion({ imageCollection: ndvi, regions: cropRegions, reducer: ee.Reducer.mean(), band: 'NDVI', scale: 10, xProperty: 'system:time_start', seriesProperty: 'label' }); ndviTimeSeries.setChartType('LineChart'); ndviTimeSeries.setOptions({ title: 'Sentinel-2数据作物时间序列NDVI变化', vAxi
最新发布
03-10
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_养乐多_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值