在前面的内容中,我们计算了增强植被指数 (EVI),以说明卫星图像上的波段运算,代码在单个图像上被调用一次。 如果我们想以相同的方式计算整个 ImageCollection 中的每个图像的 EVI,该怎么办?在这里,我们使用 Earth Engine 工作流程第二部分的关键工具,即 .map 命令。
在开始编写 EVI 功能之前,值得注意的是,在基于云的遥感过程中,在多种设置中都会遇到“Map”一词,能够区分用途非常重要。 “Map”在 Earth Engine 中可以充当动词或名词,“地图”作为名词有两种用法。 我们可能会随意提及“Map”,或更准确地说是“Map panel”; 这些术语指的是图像在代码界面中显示的位置。 第二种方式“Map”用作名词,指代地球引擎对象,该对象具有可以调用的函数。 这方面的例子是熟悉的 Map.addLayer 和 Map.setCenter。 如果打算使用该词,它将以紫色文本显示并在代码编辑器中大写。 我们在这里讨论的是使用 .map 作为动词,代表在一组上重复执行一组动作的想法。 这通常称为“mapping over the set”。
为了在整个 ImageCollection 上有效地映射一组给定的操作,需要以特定的方式设置处理。
熟悉其他编程语言的用户可能希望看到“loop”代码来执行此操作,但 Earth Engine 中的处理并不完全按照这种方式完成。 相反,我们将创建一个函数,然后将其映射到 ImageCollection。 首先,设想创建一个只接受一个参数(ee.Image)的函数。 然后,该函数被设计为对输入 ee.Image 执行一组指定的操作,然后,重要的是,返回 ee.Image 作为函数的最后一步。 当我们将该函数映射到 ImageCollection 时,如下所示,效果是我们从 ImageCollection 开始,对每个图像执行操作,并接收处理后的 ImageCollection,如下所示输出。
我们可以创建什么类型的函数? 例如,您可以想象一个函数获取图像并返回一个图像,当给定波段的值低于某个阈值时,该图像的像素值为 1,否则返回 0。 映射此函数的效果将是图像的整个 ImageCollection,其中的零和一代表每个图像上的测试结果。 或者,您可以想象一个函数计算复杂的自定义索引并发送回在每个像素中计算的该索引的图像。 在这里,我们将创建函数来计算任何输入 Landsat 5 图像的 EVI,并返回为每个像素计算索引的单波段图像。 将下面的函数定义复制并粘贴到代码编辑器中,将其添加到上一节脚本的末尾(上一期过滤图像的脚本)。
var makeLandsat5EVI = function(oneL5Image) {
// compute the EVI for any Landsat 5 image. Note it's specific to
// Landsat 5 images due to the band numbers. Don't run this exact
// function for images from sensors other than Landsat 5.
// Extract the bands and divide by 1e4 to account for scaling done.
var nirScaled = oneL5Image.select('SR_B4').divide(10000);
var redScaled = oneL5Image.select('SR_B3').divide(10000);
var blueScaled = oneL5Image.select('SR_B1').divide(10000);
// Calculate the numerator, note that order goes from left to right.
var numeratorEVI = (nirScaled.subtract(redScaled)).multiply(2.5);
// Calculate the denominator
var denomClause1 = redScaled.multiply(6);
var denomClause2 = blueScaled.multiply(7.5);
var denominatorEVI = nirScaled.add(denomClause1).subtract(
denomClause2).add(1);
// Calculate EVI and name it.
var landsat5EVI =
numeratorEVI.divide(denominatorEVI).rename(
'EVI');
return (landsat5EVI);
};
值得强调的是,一般来说,带名称是特定于每个 ImageCollection 的。 因此,例如,如果该函数在没有带“SR_B4”的图像上运行,则函数调用将失败。 在这里,我们在函数名称中强调了它是专门为 Landsat 5 创建 EVI 的。
函数 makeLandsat5EVI 用于接收单个图像,选择适当的波段来计算 EVI,进行计算并返回单波段图像。 如果我们知道组成 ImageCollection 的每张图像的名称,我们可以将名称输入到代码编辑器中,并为每张图像一次调用一个函数,将图像组装成变量,然后将它们组合成ImageCollection。 这将非常乏味并且很容易出错:项目列表可能会输入错误,图像可能会丢失等。相反,如上所述,我们将使用 .map。 使用下面的代码,让我们打印有关云过滤的集合的信息并显示它,执行 .map 命令,并探索生成的 ImageCollection。
var L5EVIimages = efficientFilteredSet.map(makeLandsat5EVI);
print('Verifying that the .map gives back the same number of
images: ',
L5EVIimages.size());
print(L5EVIimages);
Map.addLayer(L5EVIimages, {}, 'L5EVIimages', 1, 1);
输入并执行此代码后,您将看到一个灰度图像(图1)。 如果仔细观察图像的边缘,您可能会发现其后面绘制的其他图像,看起来有点像桌子上的一叠纸。 这是由 makeLandsat5EVI 函数绘制的 ImageCollection 的图。 您可以选择“检查器”面板并单击其中一个灰度像素来查看整个 ImageCollection 的值。 单击像素后,通过打开和关闭项目列表来查找系列标签。 当您打开该标签时,您将看到该像素处的 EVI 值图表(图2),该图表是通过将 makeLandsat5EVI 函数映射到过滤后的 ImageCollection 上而创建的。
图1
图2