閾值處理、掩膜和重新映射圖像
????????本章前一節討論了如何使用波段運算來操作圖像,?這些方法通過組合圖像內的波段來創建新的連續值。 本期內容使用邏輯運算符對波段或索引值進行分類,以創建分類圖像。
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