Zou_2018
Módulo de Google Earth Engine que clasifica el agua abierta con la regla de Zou et al. (2018): MNDWI mayor que NDVI o que EVI, y EVI menor que 0,1.
Qué hace #
Zou y sus colaboradores (2018) usaron esta regla para mapear los cuerpos de agua de Estados Unidos entre 1984 y 2016 con todo el archivo de Landsat. La idea es simple: en el agua, el MNDWI supera a los índices de vegetación, y el EVI casi no tiene señal. Un píxel es agua si su MNDWI es mayor que su NDVI o que su EVI, y además su EVI es menor que 0,1. Esa última condición evita confundir el agua con vegetación inundada o muy húmeda. Es más sencilla que DSWE y funciona bien en lagos, embalses y ríos anchos.
Cómo cargarlo #
El módulo es público. Pega esta línea al inicio de tu script en el Code Editor y usa sus funciones con zou. delante, por ejemplo zou.ClassifyWaterZou2018(image).
var zou = require('users/sigeduca/routines:Indexes/Zou_2018');
Funciones #
| Función | Recibe | Devuelve |
|---|---|---|
ClassifyWaterZou2018(image) | Imagen con las bandas Blue, Green, Red, Nir y Swir1, en reflectancia de 0 a 1. | Imagen de una banda, waterMask: 1 donde hay agua y 0 donde no. |
Escala antes de clasificar. El EVI usa una constante de 1 pensada para reflectancia de 0 a 1, y el umbral de 0,1 también. Con los valores digitales sin escalar, la regla no funciona.
Agua oscura en las costas. normalizedDifference() enmascara los píxeles con valores negativos, y en el mar o en lagos profundos la reflectancia escalada de la Colección 2 puede quedar un poco por debajo de 0. Si esas zonas te salen vacías, lleva las bandas a 0 antes con image.max(0), como hace Jones_2019R.
Ejemplo con una imagen #
Dibuja una geometría llamada AOI en el mapa y ejecuta este script. Toma una imagen de Landsat 9 con menos de 10 % de nubes sobre tu zona, la pasa a reflectancia y le aplica el módulo.
// Cargar el módulo var zou = require('users/sigeduca/routines:Indexes/Zou_2018'); // Una imagen de Landsat 9 con poca nubosidad sobre el AOI var img = ee.ImageCollection('LANDSAT/LC09/C02/T1_L2') .filterBounds(AOI) .filter(ee.Filter.lte('CLOUD_COVER', 10)) .first(); // Escalar a reflectancia y usar los nombres comunes de las bandas var bands = img.select('SR_B.').multiply(0.0000275).add(-0.2) .select(['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'], ['Blue', 'Green', 'Red', 'Nir', 'Swir1', 'Swir2']); // Máscara de agua var water = zou.ClassifyWaterZou2018(bands); Map.centerObject(AOI, 11); Map.addLayer(bands, {bands: ['Red', 'Green', 'Blue'], min: 0, max: 0.25}, 'Color verdadero'); Map.addLayer(water.selfMask(), {palette: ['00ffff']}, 'Agua (Zou, 2018)');
Ejemplo con una colección #
Para aplicar el módulo a muchas imágenes usamos map(): la función recibe cada imagen de la colección y devuelve el resultado. Dos detalles importan. Primero, cada imagen debe llegar escalada, con nombres comunes y sin nubes, y de eso se encarga prepare(). Segundo, las operaciones matemáticas borran las propiedades de la imagen, así que copiamos la fecha (system:time_start) con copyProperties() para poder graficar la serie en el tiempo.
// Cargar el módulo var zou = require('users/sigeduca/routines:Indexes/Zou_2018'); // Prepara cada imagen: máscara de nubes, reflectancia (0 a 1) y nombres comunes function prepare(img) { var qa = img.select('QA_PIXEL'); var clear = qa.bitwiseAnd(1 << 3).eq(0) // bit 3: nubes .and(qa.bitwiseAnd(1 << 4).eq(0)); // bit 4: sombras de nubes var bands = img.select(['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'], ['Blue', 'Green', 'Red', 'Nir', 'Swir1', 'Swir2']) .multiply(0.0000275).add(-0.2) .updateMask(clear); // Las operaciones matemáticas borran las propiedades: recuperamos la fecha return ee.Image(bands.copyProperties(img, ['system:time_start'])); } // Landsat 8 y 9 de dos años sobre el AOI var collection = ee.ImageCollection('LANDSAT/LC09/C02/T1_L2') .merge(ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')) .filterBounds(AOI) .filterDate('2023-01-01', '2025-01-01') .filter(ee.Filter.lte('CLOUD_COVER', 30)) .map(prepare); print('Imágenes', collection.size()); // Aplicar el módulo a cada imagen, conservando la fecha var water = collection.map(function(img) { return ee.Image(zou.ClassifyWaterZou2018(img).copyProperties(img, ['system:time_start'])); }); // Frecuencia de agua: porcentaje de observaciones en que cada píxel fue agua var frequency = water.mean().multiply(100).rename('frecuencia'); Map.centerObject(AOI, 11); Map.addLayer(frequency.selfMask(), {min: 0, max: 100, palette: ['c6dbef', '6baed6', '08306b']}, 'Frecuencia de agua (%)'); // Fracción del AOI cubierta por agua en cada fecha var chart = ui.Chart.image.series({ imageCollection: water, region: AOI, reducer: ee.Reducer.mean(), scale: 30 }).setOptions({title: 'Fracción de agua en el AOI (Zou, 2018)', vAxis: {title: 'Fracción (0 a 1)'}, pointSize: 3}); print(chart);
Código del módulo #
No necesitas copiarlo para usarlo. Si quieres modificarlo, créalo en tu propio repositorio y cambia la ruta de require().
// Máscara de agua según Zou et al. (2018) // https://www.pnas.org/content/pnas/suppl/2018/03/20/1719275115.DCSupplemental/pnas.1719275115.sapp.pdf var Ndvi = function(image) { // índice de vegetación de diferencia normalizada (NDVI) var ndvi = image.normalizedDifference(['Nir', 'Red']).rename('ndvi'); return(ndvi); }; var Evi = function(image) { // índice de vegetación mejorado (EVI) var evi = image.expression('2.5 * (Nir - Red) / (1 + Nir + 6 * Red - 7.5 * Blue)', { 'Nir': image.select(['Nir']), 'Red': image.select(['Red']), 'Blue': image.select(['Blue']) }); return(evi.rename(['evi'])); }; var Mndwi = function(image) { // índice de agua de diferencia normalizada modificado (MNDWI) var mndwi = image.normalizedDifference(['Green', 'Swir1']).rename('mndwi'); return(mndwi); }; // Agua: MNDWI mayor que NDVI o que EVI, y EVI menor que 0,1 exports.ClassifyWaterZou2018 = function(image) { var mndwi = Mndwi(image); var ndvi = Ndvi(image); var evi = Evi(image); var water = (mndwi.gt(ndvi).or(mndwi.gt(evi))).and(evi.lt(0.1)); return(water.rename(['waterMask'])); };
Referencias #
- Zou, Z., Xiao, X., Dong, J., Qin, Y., Doughty, R. B., Menarguez, M. A., Zhang, G. y Wang, J. (2018). Divergent trends of open-surface water body area in the contiguous United States from 1984 to 2016. Proceedings of the National Academy of Sciences, 115(15), 3810–3815.
- Yang, X., Pavelsky, T. M., Allen, G. H. y Donchyts, G. (2020). RivWidthCloud: An automated Google Earth Engine algorithm for river width extraction from remotely sensed imagery. IEEE Geoscience and Remote Sensing Letters, 17(2), 217–221.
