下一章 上一章 目录 设置
5、五识 第 1节E ...
-
第 1节Earth Engine 中的算法
NDVI的算术计算
由于植被在这些波长下的高反射率,红色和近红外波段提供了大量有关植被的信息。特别注意植被曲线(以绿色表示)在 NIR 范围(大约750-900 nm)内具有相对较高的反射率。另请注意,植被在红色范围(约630-690 nm)的反射率较低,此时阳光被叶绿素吸收。这表明,如果可以将红光和近红外波段结合起来,它们将提供有关植被的大量信息。
1972年Landsat 1发射后不久,分析师们就致力于设计一个强大的单一值,以-1到1的范围来反映植被的健康状况。
其中NIR和红色指的是这两个波段各自的亮度。正如在章节中所见。该亮度可以以反射率、辐射率或数字(DN)为单位来表达;NDVI 旨在在使用这些波长的平台上提供几乎相同的值。该方程的一般形式称为“归一化差值”——分子是“差值”,分母是“归一化”值。NDVI 的输出在 -1 和 1之间变化。大量绿色植被的值约为0.8–0.9。没有绿叶的值接近 0,水的值接近 -1。
为了计算NDVI,我们将介绍Earth Engine的波段运算实现。
基于云的频带算法是 Earth Engine 最强大的方面之一,因为该平台的计算机针对这种类型的繁重处理进行了优化。即使在行星尺度上,波段的计算也可以非常快地完成——这个想法在基于云的遥感出现之前是遥不可及的。Earth Engine 根据需要自动在大量计算机之间进行计算分区,并组合结果进行显示。
作为示例,让我们检查旧金山的图像。
// Calculate NDVI using Sentinel 2
// Import and filter imagery by location and date.
var sfoPoint=ee.Geometry.Point(-122.3774, 37.6194);
var sfoImage=ee.ImageCollection(\'COPERNICUS/S2\')
.filterBounds(sfoPoint)
.filterDate(\'2020-02-01\', \'2020-04-01\')
.first();
// Display the image as a false color composite.
Map.centerObject(sfoImage, 11);
Map.addLayer(sfoImage,{
bands: [\'B8\', \'B4\', \'B3\'],
min: 0,
max: 2000
}, \'False color\');
Earth Engine 中最简单的数□□算是加法、减法、乘法和除法。让我们选择近红外和红光波段,并使用这些操作来计算图像的 NDVI。
// Extract the near infrared and red bands.
var nir=sfoImage.select(\'B8\');
var red=sfoImage.select(\'B4\');
// Calculate the numerator and the denominator using subtraction and addition respectively.
var numerator=nir.subtract(red);
var denominator=nir.add(red);
// Now calculate NDVI.
var ndvi=numerator.divide(denominator);
// Add the layer to our map with a palette.
var vegPalette=[\'red\', \'white\', \'green\'];
Map.addLayer(ndvi,{
min: -1,
max: 1,
palette: vegPalette
}, \'NDVI Manual\');
检查生成的索引,如果需要,使用检查器挑选植被和非植被区域中的像素值。
使用Sentinel-2计算的NDVI。请记住,NDVI 的输出在-1和1之间变化。大量绿色植被的值约为0.8–0.9。没有绿叶的值接近0,水的值接近-1。
使用这些简单的算术工具,你可以构建几乎任何索引,或开发和可视化你自己的索引。
NDVI归一化差值的单次运算计算
像 NDVI 这样的归一化差异在遥感中非常常见,因此 Earth Engine 提供了使用归一化差异方法在单个步骤中执行特定序列的减法、加法和除法的能力。此方法采用输入图像以及你指定的波段,并创建这两个波段的标准化差异。之前使用波段算法创建的 NDVI 计算可以用一行代码替换:
// Now use the built-in normalizedDifference function to achieve the same outcome.
var ndviND=sfoImage.normalizedDifference([\'B8\', \'B4\']);
Map.addLayer(ndviND,{
min: -1,
max: 1,
palette: vegPalette
}, \'NDVI normalizedDiff\');
请注意,向normalizedDifference提供两个波段的顺序很重要。我们使用近红外波段 B8 作为第一个参数,使用红波段 B4 作为第二个参数。如果你的两次 NDVI 计算在绘制到屏幕上时看起来不相同,请检查以确保 NIR 和红色波段的顺序正确。
使用 NDWI 的归一化差值
如前所述,归一化差异法用于许多不同的指数。让我们将相同的normalizedDifference方法应用于另一个索引。
归一化水分指数(NDWI)是由Gao(1996)提出的,作为植被水分含量的指数。该指数对植被冠层液体含量的变化敏感。这意味着该指数可用于检测经历干旱条件的植被或区分作物灌溉水平。在干旱地区,灌溉作物可以与自然植被区分开来。有时也称为归一化差异水分指数 (NDMI)。
其中 NIR 是近红外,中心在860 nm (0.86 μm) 附近,SWIR 是短波红外,中心在1,240 nm (1.24 μm) 附近。
使用归一化差异方法在 Earth Engine 中计算并显示 NDWI。对于 Sentinel-2,B8 是 NIR 波段,B11 是 SWIR 波段。
// Use normalizedDifference to calculate NDWI
var ndwi=sfoImage.normalizedDifference([\'B8\', \'B11\']);
var waterPalette=[\'white\', \'blue\'];
Map.addLayer(ndwi,{
min: -0.5,
max: 1,
palette: waterPalette
}, \'NDWI\');
检查 NDVI 识别为拥有大量植被的地图区域。注意哪些颜色更蓝。这是含水量较高的植被。
第2节:图像阈值处理、掩模和重新映射
本章前一节讨论了如何使用波段运算来操作图像。这些方法通过组合图像内的波段来创建新的连续值。本部分使用逻辑运算符对波段或索引值进行分类,以创建分类图像。
实施阈值
实现阈值使用数字(阈值)和逻辑运算符来帮助我们将图像的可变性划分为类别。例如,回想一下我们的 NDVI 地图。大量植被的 NDVI 值接近1,无植被区域接近0。如果我们想查看地图上哪些区域有植被,我们可以使用阈值将每个像素中的 NDVI 值概括为“无植被””或“植被”。诚然,这是一个很大的简化,但可以帮助我们更好地理解地球表面的丰富变化。
例如,如果我们想要查看城市植被覆盖的比例,这种类型的分类可能很有用。让我们创建美国华盛顿州西雅图附近的 Sentinel-2 NDVI 地图。
// Create an NDVI image using Sentinel 2.
var seaPoint=ee.Geometry.Point(-122.2040, 47.6221);
var seaImage=ee.ImageCollection(\'COPERNICUS/S2\')
.filterBounds(seaPoint)
.filterDate(\'2020-08-15\', \'2020-10-01\')
.first();
var seaNDVI=seaImage.normalizedDifference([\'B8\', \'B4\']);
// And map it.
Map.centerObject(seaPoint, 10);
var vegPalette=[\'red\', \'white\', \'green\'];
Map.addLayer(seaNDVI,
{
min: -1,
max: 1,
palette: vegPalette
},
\'NDVI Seattle\');
检查图像。我们可以看到,植被区域呈深绿色,无植被区域呈白色,水呈粉红色。如果我们使用Inspector 查询图像,我们可以看到公园和其他森林地区的 NDVI 大约超过0.5。
因此,将 NDVI 值大于0.5 的区域定义为森林覆盖区域,将低于该阈值的区域定义为非森林覆盖区域是有意义的。
现在,我们将该值定义为阈值,并使用它来确定植被区域的阈值。
// Implement a threshold.
var seaVeg=seaNDVI.gt(0.5);
// Map the threshold.
Map.addLayer(seaVeg,
{
min: 0,
max: 1,
palette: [\'white\', \'green\']
},
\'Non-forest vs. Forest\');
gt方法来自布尔运算符系列,也就是说,gt 是一个在每个像素中执行测试的函数,如果测试结果为 true,则返回值1,否则返回0。这里,对于图像中的每个像素,它测试NDVI值是否大于0.5。当满足此条件时,seaVeg层将获得值1。当条件不成立时,它会获得值0。
使用检查器工具探索这个新层。如果单击绿色位置,则 NDVI 应大于0.5。如果单击白色像素,NDVI 值应等于或小于0.5。
该布尔系列中的其他运算符包括小于 (lt)、小于或等于 (lte)、等于 (eq)、不等于 (neq) 和大于或等于 (gte) 等。
使用构建复杂的分类。
对 NDVI 进行分类的二值图非常有用。但是,在某些情况下,你可能希望将图像拆分为两个以上的容器。Earth Engine 提供了一个工具,即where 方法,可以根据测试结果有条件地评估每个像素内的 true 或 false。这类似于其他语言中常见的if语句。然而,为了在 Earth Engine 编程时执行此逻辑,我们避免使用 JavaScript if 语句。
重要的是,JavaScript如果命令不是在 Google 的服务器上计算的,并且在运行代码时可能会产生严重的问题-实际上,服务器会尝试将所有要执行的信息发送到你自己计算机的浏览器,而浏览器对于如此庞大的任务来说能力不足。相反,我们使用where 子句来实现条件逻辑。
假设我们不只是将 NDVI 中的森林区域与非森林区域分开,而是希望将图像分为可能的水域、非森林区域和森林区域。我们可以使用where 和阈值-0.1和0.5。我们将首先使用ee创建图像。图像。然后,我们剪辑新图像,使其覆盖与seaNDVI 图层相同的区域。
// Implement .where.
// Create a starting image with all values=1.
var seaWhere=ee.Image(1)
// Use clip to constrain the size of the new image.
.clip(seaNDVI.geometry());
// Make all NDVI values less than -0.1 equal 0.
seaWhere=seaWhere.where(seaNDVI.lte(-0.1), 0);
// Make all NDVI values greater than 0.5 equal 2.
seaWhere=seaWhere.where(seaNDVI.gte(0.5), 2);
// Map our layer that has been divided into three classes.
Map.addLayer(seaWhere,
{
min: 0,
max: 2,
palette: [\'blue\', \'white\', \'green\']
},
\'Water, Non-forest, Forest\');
关于这段代码,有一些你以前可能没有见过的有趣的事情需要注意。首先,我们没有为每个where调用定义一个新变量。因此,我们可以执行许多where 调用,而无需每次都创建新变量并需要跟踪它们。其次,当我们创建起始图像时,我们将值设置为1。这意味着我们可以轻松地分别使用一个where 子句设置底部和顶部值。最后,虽然我们在这里没有这样做,但我们可以使用and 和or组合多个where 子句。例如,我们可以使用seaNDVI 识别具有中等水平 NDVI 的像素。gte (-0.1)。和(seaNDVI.lt (0.5) )。
屏蔽图像中的特定值
遮罩图像是一种删除图像的特定区域(被遮罩覆盖的区域)以防止显示或分析的技术。Earth Engine 允许你查看当前蒙版并更新蒙版。
// Implement masking.
// View the seaVeg layer\'s current mask.
Map.centerObject(seaPoint, 9);
Map.addLayer(seaVeg.mask(),{}, \'seaVeg Mask\');
你可以使用检查器来查看黑色区域被遮盖,而白色区域的常量值为1。这意味着数据值仅在白色区域内被映射并可用于分析。
现在假设我们只想在森林地区进行显示和分析。让我们从图像中屏蔽掉非森林区域。首先,我们使用 equals (eq ) 方法创建一个二进制掩码。
// Create a binary mask of non-forest.
var vegMask=seaVeg.eq(1);
在制作遮罩时,你将想要查看和分析的值设置为大于0的数字。其想法是设置不需要的值以获得 0 值。具有0值的像素被遮盖掉(实际上,它们一旦我们使用updateMask 方法将这些值添加到现有掩码中,就根本不会出现在屏幕上。
// Update the seaVeg mask with the non-forest mask.
var maskedVeg=seaVeg.updateMask(vegMask);
// Map the updated Veg layer
Map.addLayer(maskedVeg,
{
min: 0,
max: 1,
palette: [\'green\']
},
\'Masked Forest Layer\');
关闭所有其他层。你可以看到maskedVeg图层现在如何遮盖所有非森林区域。
映射图层的更新蒙版,你可以看到这是为什么。
// Map the updated mask
Map.addLayer(maskedVeg.mask(),{},\'maskedVeg Mask\');
非森林区域现在也被遮盖了(图像的黑色区域)。
重新映射图像中的值
重新映射采用图像中的特定值并为它们分配不同的值。
让我们使用remap方法来更改seaWhere图层的值。请注意,由于我们将中间值更改为最大,因此我们还需要调整调色板。
// Implement remapping.
// Remap the values from the seaWhere layer.
var seaRemap=seaWhere.remap([0,1, 2],// Existing values.
[9, 11, 10]); // Remapped values.
Map.addLayer(seaRemap,
{
min: 9,
max: 11,
palette: [\'blue\', \'green\', \'white\']
},
\'Remapped Values\');
使用检查器比较原始的seaWhere (显示为Water、Non-Forest、Forest)和seaRemap之间的值,标记为“R emapped Values”。单击森林区域,你应该看到重新映射值应为10,而不是2。
对于森林区域,重新映射的图层的值为10,而原始图层的值为2。你的检查器中可能有更多图层。