阈值处理、掩膜和重新映射图像
本章前一节讨论了如何使用波段运算来操作图像, 这些方法通过组合图像内的波段来创建新的连续值。 本期内容使用逻辑运算符对波段或索引值进行分类,以创建分类图像。
1.实现阈值
实现阈值使用数字(阈值)和逻辑运算符来帮助我们将图像的可变性划分为类别。 例如,回想一下我们的 NDVI 地图。 大量植被的 NDVI 值接近 1,而非植被区域接近 0。如果我们想查看地图上哪些区域有植被,我们可以使用阈值将每个像素中的 NDVI 值概括为“无植被” ”或“植被”。 可以肯定的是,这是一个很大的简化,但可以帮助我们更好地理解地球表面的丰富变化。 例如,如果我们想要查看城市植被覆盖的比例,这种类型的分类可能很有用。 让我们创建美国华盛顿州西雅图附近的 Sentinel-2 地图, 在新脚本中输入以下代码(图 1)。
// 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');
图1 美国华盛顿州西雅图上空 Sentinel-2 图像的 NDVI 图像
检查图像, 我们可以看到,植被区域呈深绿色,无植被区域呈白色,水呈粉红色。 如果我们使用 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。当条件为 false 时,它将获得值 0(图 2)。使用 Inspector 工具探索这个新层。 如果单击绿色位置,则 NDVI 应大于 0.5。 如果单击白色像素,则 NDVI 值应等于或小于 0.5。该布尔族中的其他运算符包括小于 (lt)、小于或等于 (lte)、等于 (eq)、不等于 至 (neq),并且大于或等于 (gte) 及以上。
图2 美国华盛顿州西雅图基于NDVI的阈值森林和非森林图像
2.使用 .where 构建复杂的分类
对 NDVI 进行分类的二值图非常有用,但是,在某些情况下,您可能希望将图像拆分为两个以上类别。 Earth Engine 提供了一个工具,即 where 方法,可以根据测试结果有条件地评估每个像素内的 true 或 false。 这类似于其他语言中常见的 if 语句。 然而,为了在 Earth Engine 编程时执行此逻辑,我们避免使用 JavaScript if 语句。 重要的是,JavaScript 如果命令不是在 Google 的服务器上计算的,并且在运行代码时可能会产生严重的问题,实际上,服务器会尝试将所有要执行的信息发送到您自己计算机的浏览器,而浏览器对于如此庞大的数据量来说是非常不足的。 任务。 相反,我们使用 where 子句来实现条件逻辑。
假设我们不只是将 NDVI 中的森林区域与非森林区域分开,而是希望将图像分为可能的水域、非森林区域和森林区域。 我们可以使用 where 和阈值 -0.1 和 0.5。 我们将首先使用 ee.Image 创建图像。 然后,我们裁剪新图像,使其覆盖与 seaNDVI 图层相同的区域(图 3)。
// 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.gte(−0.1).and(seaNDVI.lt(0.5))来识别具有中等水平的NDVI的像素。
图3 美国华盛顿州西雅图基于NDVI阈值的水、森林和非森林图像
3.屏蔽图像中的特定值
屏蔽图像是一种将图像的特定区域(被掩膜覆盖的区域)从显示或分析中删除的技术。Earth Engine允许您查看当前掩码和更新掩膜(图4)。
// Implement masking.
// View the seaVeg layer's current mask.
Map.centerObject(seaPoint, 9);
Map.addLayer(seaVeg.mask(), {}, 'seaVeg Mask');
您可以使用Inspector来查看黑色区域被遮盖,而白色区域的常量值为 1。这意味着数据值仅在白色区域内被映射并可用于分析。 现在假设我们只想在森林中显示和进行分析地区。 让我们从图像中屏蔽掉非森林区域,首先,我们使用 equals (eq) 方法创建一个二进制掩膜。
// Create a binary mask of non-forest.
var vegMask = seaVeg.eq(1);
在制作掩膜时,您将想要查看和分析的值设置为大于 0 的数字。其想法是设置不需要的值以获得 0 的值。具有 0 值的像素被遮盖掉(实际上,它们 一旦我们使用 updateMask 方法将这些值添加到现有掩膜中,就根本不会出现在屏幕上。
图 4 我们之前创建的 seaVeg 层的现有掩模
// 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 图层现在如何遮盖所有非森林区域(图 5)。映射该图层的更新蒙版,您可以看到这是为什么(图 6)。
图 5 更新后的掩膜现在仅显示森林区域, 非森林地区是被遮蔽和透明的
图 6 更新后的掩模,非森林区域现在也被遮盖(图像的黑色区域)
// Map the updated mask
Map.addLayer(maskedVeg.mask(), {}, 'maskedVeg Mask');
3.重新映射图像中的值
重新映射采用图像中的特定值并为它们分配不同的值。这对于分类数据集特别有用,让我们使用 remap 方法来更改 seaWhere 图层的值。请注意,由于我们将中间值更改为最大,因此我们还需要调整调色板。
// 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(标记为“Remapped Values”)之间的值。 单击森林区域,您应该看到重新映射值应为 10,而不是 2(图 7)。
图 7 对于森林区域,重新映射的图层的值为 10,而原始图层的值为 2,您的Inspector中可能有更多图层
【代码链接】https://code.earthengine.google.com/496370d6752d56e39dbfe6ea10ac718b