1、代码
(1)Sentinel-2
function maskS2clouds(image) {
var qa = image.select('QA60');
var mask = qa.bitwiseAnd(1 << 10).eq(0).and(qa.bitwiseAnd(1 << 11).eq(0));
return image.updateMask(mask).divide(10000);}
Sentinel-2除云函数官方有提供。
(2)Landsat 5/7/8/9
function moveclouds(image) {
var qa = image.select('QA_PIXEL');
var cloudMask = qa.bitwiseAnd(1 << 3).eq(0).and(qa.bitwiseAnd(1 << 4).eq(0));
return image.updateMask(cloudMask);}
GEE上的Landsat数据集经历过一次更新,更新后的Landsat 5/7/8/9遥感数据的质量控制波段保持一致,因此可通用上述除云函数。
注:以前(更新前)Landsat的质量控制波段为“qa_pixel”,代表云和云影的Bit分别是Bit 5和Bit 3(图1)。目前的质量控制波段改为“QA_PIXEL”,代表云和云影的Bit分别是Bit 3和Bit 4(图2)。
图1 图2
!这里特别指出,有些资料中的除云函数使用的仍然是之前的Bit,将其用于目前的Landsat图像除云会出现一定错误,希望大家注意辨别。
2、如何理解
除云函数一般涉及到影像的质量控制波段,比如Landsat的“QA_PIXEL”波段、Sentinel的“QA60”波段。首先梳理影像的质量控制波段,以Landsat的“QA_PIXEL”波段为例进行说明:
(1)质量控制波段
Landsat的“QA_PIXEL”波段包括两种情况(图3、图4):
①一个Bit存储一个信息(图3):在这些Bit下,0表示无,1表示有。比如图像中某个像元的“QA_PIXEL”波段值(二进制)的第三个Bit上的数字是1,则表示该像元是有云像元。
②两个Bit存储一个信息(图4):有这种情况的存在是因为需要存储的信息不足以通过0、1来表示。比如Bits 8-9存储的是云量的等级信息,分为无、低、中、高四级,此时就需要0、1、2、3四个数字表示,而只有一位的二进制数字最多只能表示0和1两个十进制数字,那么就需要通过两个位(Bit)组合的方式才足以表示0、1、2、3。如果图像中某个像元的“QA_PIXEL”波段值(二进制)的第8、9个Bit上的数字是“00”,则表示该像元的云量等级为无云;同理,“01”表示低云;“10”表示中云;“11”表示高云。
图3 图4
(2)“bitwiseAnd”函数
var cloudMask = qa.bitwiseAnd(1 << 3).eq(0).and(qa.bitwiseAnd(1 << 4).eq(0));
这里面的“bitwiseAnd”函数可以理解为:“按位与操作符”,其功能通俗的说就是“按位与…对应”,“<< ”是移位符。“qa.bitwiseAnd(1 << 3)”的意思是,将二进制的数字1向左移动三位,得到一个二进制“1000”后,将这个二进制的Bit 3位(从右往左数第四个数)与质量波段的波段值(转为二进制后)的Bit 3位(从右往左数第四个数)相对应,如果二者相同,表示该像元有云,则将该像元的像元值赋值为“1000”的十进制,也就是8;若二者不同,则将该像元的像元值赋值为0。
那么,“qa.bitwiseAnd(1 << 3).eq(0)”是什么意思呢?在理解它之前,我们首先需要知道“Image.eq(number)”、“Image.gt(number)”、“Image.lt(number)”等语句的含义,这些语句返回的都是一个二值化图像(符合条件的返回1,不符合条件的返回0),并不是直接返回Image中符合条件的部分。
所以,当一个像元是有云像元时,按照前面的理解,“qa.bitwiseAnd(1 << 3)”会将该像元的像元值赋值为8,在此基础上,增加“.eq(0)”,这将把该像元的像元值赋值为0;当一个像元是无云像元时,“qa.bitwiseAnd(1 << 3)”会将该像元的像元值赋值为0,在此基础上,增加“.eq(0)”,这将把该像元的像元值赋值为1。因此,最终得到的是一个二值化的图像,像元值为1的像元表示无云像元,像元值为0的像元表示有云像元。
同理,如果还想除去云影等其他干扰数据质量的因素,可以使用存储相应信息的Bit来实现,例如,存储云影信息的Bit 4,在代码中增加一个限制条件即可,即“.add(qa.bitwiseAnd(1 << 4).eq(0))”。
根据上述操作,生成一个“cloudmask”,再利用“updateMask”函数,就可实现去云和去云影。