合成、遮盖和镶嵌

Landsat 8 TOA 反射率集合加载到名为 l8 的变量中后,您会发现以下代码会生成一个最新值合成影像:

代码编辑器 (JavaScript)

var l8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA');
var landsat2016 = l8.filterDate('2016-01-01', '2016-12-31');
Map.addLayer(landsat2016, visParams, 'l8 collection');

此合成图像存在的一个问题是,其中布满了云。您不必只获取集合中的最后一个像素(当您将集合添加到地图时,Earth Engine 会隐式对其调用 mosaic()),而是可以缩减 ImageCollection详细了解如何缩减影像集合)。

使用 Reducer 进行合成

您最初接触到 reducer 是为了获取图像区域中的统计信息。这是空间缩减。将一个影像集合缩减为一个影像时,如果该集合表示一段时间内的影像,则为时间缩减。您使用的 Reducer 类型决定了 Earth Engine 如何处理重叠的像素。Landsat 8 每 16 天会访问地球上的同一地点。这意味着在 6 个月的时间内,大约会有 12 张图片(如果场景重叠,则会更多)。地图上的每个像素都源自一组像素,即所显示集合中每张图片的一个像素。

只需将集合添加到地图中,即可选择最新的像素,即堆栈中最新影像的像素。可以使用 Earth Engine 精简器来改变此行为。例如,可以指示 Earth Engine 选择堆栈中的中位数值,而不是从堆栈中获取最新的像素。这样做的好处是可移除云(值较高)和阴影(值较低)。使用中位数缩减器缩减影像集合时,合成值是每个波段在一段时间内的中位数。例如,使用 2016 年的 Landsat 场景:

代码编辑器 (JavaScript)

// Get the median over time, in each band, in each pixel.
var median = l8.filterDate('2016-01-01', '2016-12-31').median();

// Make a handy variable of visualization parameters.
var visParams = {bands: ['B4', 'B3', 'B2'], max: 0.3};

// Display the median composite.
Map.addLayer(median, visParams, 'median');

此代码中的新内容是应用于图片集合的 median() 方法。 与过滤方法类似,此方法是图片集合上更通用的 reduce() 方法的快捷方式,该方法将 ee.Reducer() 作为实参。在代码编辑器的文档标签页中查看 ee.Reducer 软件包,即可查看所有 Earth Engine 归约器的列表。在为图片集合选择化简器时,请注意输出是图片,因此输出为非数值的化简器(例如 histogramtoList 化简器)不适用于图片集合。

Tutorial_api_06_median_composite
图 6. Landsat 8 中值合成。

缩小中值合成图后,您应该会看到类似图 6 的内容。这应该比您之前制作的近期价值复合值看起来好得多。此时,不妨退一步,考虑一下为了获得该中值复合值,我们做了哪些工作。Earth Engine 已加载美国大陆的整个 Landsat 8 集合,并计算了每个像素的中位数。这可是大量数据!当然,您可以先过滤集合,然后计算年度中位数, 就像您之前所做的那样。重点是,如果您必须下载所有这些影像并制作此合成影像,那将是一项大工程。借助 Earth Engine,您可以在几秒钟内获得结果!

如需详细了解合成和镶嵌,请点击此处

遮盖

虽然中值合成比近值合成有所改进,但您可能仍需要遮盖图像的某些部分。遮盖图片中的像素会使这些像素变为透明,并将其从分析中排除。图像中每个波段的每个像素都有一个掩码。遮罩值为 0 或更低值的像素将是透明的。掩码值大于 0 的对象将进行渲染。可以使用类似 image1.mask(image2) 的调用来设置图片的遮罩。此调用会获取 image2 的值,并将其作为 image1 的掩码。image2 中值为 0 的任何像素在 image1 中都将变为透明。

例如,假设您想遮盖中值合成中的所有水像素。可以使用 Hansen 等人 (2013) 描述的数据集(位于 Earth Engine 数据目录中)创建水体掩码。(如需详细了解 Hansen 等人的数据集,请参阅本教程。)在此数据集中,水的值为 2,陆地的值为 1,“无数据”的值为 0。使用一些逻辑来创建在没有陆地的地方具有零值的遮罩图片:

代码编辑器 (JavaScript)

// Load or import the Hansen et al. forest change dataset.
var hansenImage = ee.Image('UMD/hansen/global_forest_change_2015');

// Select the land/water mask.
var datamask = hansenImage.select('datamask');

// Create a binary mask.
var mask = datamask.eq(1);

// Update the composite mask with the water mask.
var maskedComposite = median.updateMask(mask);
Map.addLayer(maskedComposite, visParams, 'masked');

此代码中有几项新内容值得详细介绍。首先,select() 函数可用于从图像中提取感兴趣的波段。在此,我们仅选择我们关心的频段:datamask。下一个新事物是逻辑运算符 eq(),表示“等于”。我们使用 eq(1) 创建一个二元图像,其中 datamask 波段中所有值不为 1 的像素(即水或无数据)在生成的图像中都获得值 0。

通过这种遮盖,中值合成影像中所有位于陆地上的像素(根据 Hansen 等人的数据集)都可见,但位于水上(或无数据)的像素是透明的,并且不会纳入您对 maskedComposite 影像进行的任何分析中。

镶嵌

通过结合使用图像集合、逻辑运算符、遮罩和合成的概念,您可以获得有趣的效果。例如,假设您希望图像中的陆地像素以真彩色显示,而所有其他像素以蓝色显示,您可以执行以下操作:

代码编辑器 (JavaScript)

// Make a water image out of the mask.
var water = mask.not();

// Mask water with itself to mask all the zeros (non-water).
water = water.mask(water);

// Make an image collection of visualization images.
var mosaic = ee.ImageCollection([
  median.visualize(visParams),
  water.visualize({palette: '000044'}),
]).mosaic();

// Display the mosaic.
Map.addLayer(mosaic, {}, 'custom mosaic');

这段代码包含许多操作,下面我们来详细说明一下。首先,我们使用 not() 逻辑运算符反转之前创建的遮罩。具体来说,not() 会将所有零转换为 1,并将所有非零值转换为零。将该变量称为 water 并不完全正确,因为它还包含一些无数据像素,但在当前的制图背景下是可以的。接下来,使用“水”本身来遮盖“水”。这样会生成一个图像,其中所有水像素均为 1,其他所有内容都被遮盖。最后一步是使用 mosaic() 合并图片。由于 mosaic() 适用于图片集合,因此我们将要合并的图片列表传递给图片集合构造函数,然后在最后一步调用 mosaic()。该列表中的图片顺序非常重要。具体而言,输出图片将包含输入集合中图片堆栈的最后一个未被遮盖的像素。在这种情况下,这是可行的,因为水层是集合中的最后一张(最上层)图片,并且仅包含出现水的位置的未遮盖像素。

请注意,集合中的图片是可视化图片。当您对图片调用 visualize() 时,系统会根据您传入的可视化参数将图片转换为 3 波段 8 位图片。默认的可视化参数适用于 3 波段 8 位图像,因此在向地图添加图像时,您无需提供可视化参数。结果应如图 7 所示。

Tutorial_api_07_mosaic.png
图 7. 可将水域统一着色的自定义马赛克。

至此,您已了解如何将影像集合直观呈现为近期值合成影像、如何使用化简器合成影像集合,以及如何通过遮盖和镶嵌影像集合来制作自定义合成影像。在下一页中,了解如何向集合中的每张图片添加植被指数,以及如何使用该指数制作“最绿像素”合成图。