authority: folia
slug: water-mask
name: Water Mask
domain: land
subdomain: processing
authority_id: folia:water-mask
external_ids:
  cf_standard_name: null
canonical_units: categorical
external_validations:
  product:
    id: jrc-global-surface-water
    docs_url: https://global-surface-water.appspot.com/
  library:
    name: awesome-spectral-indices
    id: NDWI,MNDWI
    docs_url: https://github.com/awesome-spectral-indices/awesome-spectral-indices
  sentinel_hub:
    processor: SCL class 6 (water)
    docs_url: https://docs.sentinel-hub.com/api/latest/data/sentinel-2-l2a/
  gee:
    op: ESA WorldCover class 80 (Permanent water bodies)
    docs_url: https://esa-worldcover.org/
description: |
  Per-pixel indication of surface water presence. Canonical binary classes:

  | code | class |
  |------|-------|
  | 0 | Non-water |
  | 1 | Water |

  Sources differ in temporal scope. JRC Global Surface Water (Pekel et al.
  2016) summarises transition and permanence across the full Landsat record
  (1984-present); ESA WorldCover and the Sentinel-2 SCL (class 6 = water)
  are instantaneous scene-level products. The most common recipe is an
  MNDWI or NDWI threshold over a single optical scene: MNDWI > 0 reliably
  separates open water from soil and vegetation at 20 m, and Sentinel-1
  backscatter thresholding extends the recipe through cloud cover. Consumed
  by hydrology, flood-extent, shoreline, and water-quality ops.
theme: hydrology
example_recipes:
  - title: "One-call water mask (Folia)"
    tool: folia
    requires: [s2-l2a-reflectance]
    snippet: |
      # imagery_water_mask wraps MNDWI + threshold in a single op.
      water = imagery_water_mask(
          image=sentinel2_scene,
          mode="from-scene",
          threshold=0.0,       # use 0.3 for sediment-laden waters
          green_band="B3",
          swir1_band="B11",
      )
    docs_url: folia/domains/geo/operations/imagery/water_mask.yaml
  - title: "Two-op recipe: MNDWI then threshold (Folia)"
    tool: folia
    requires: [s2-l2a-reflectance]
    snippet: |
      # Explicit two-op form: useful when you want to inspect or reuse MNDWI.
      mndwi = imagery_radiometric_indices(
          image=sentinel2_scene,
          indices=["Water:MNDWI"],
          channels_green=3,
          channels_mir=11,
      )
      water = raster_calc(raster=mndwi, expression="where(b1 > 0, 1, 0)")
    docs_url: folia/domains/geo/operations/imagery/radiometric_indices.yaml
  - title: "MNDWI threshold on Sentinel-2 (GEE)"
    tool: gee
    requires: [s2-l2a-reflectance]
    snippet: |
      var s2 = ee.Image('COPERNICUS/S2_SR_HARMONIZED/...');
      var mndwi = s2.normalizedDifference(['B3', 'B11']);  // (Green - SWIR1) / (Green + SWIR1)
      var water = mndwi.gt(0).rename('water');             // 0=non-water, 1=water
    docs_url: https://developers.google.com/earth-engine/apidocs/ee-image-normalizeddifference
  - title: "JRC GSW permanent-water mask (occurrence > 90%)"
    tool: gee
    requires: []
    snippet: |
      var gsw = ee.Image('JRC/GSW1_4/GlobalSurfaceWater');
      var permanent = gsw.select('occurrence').gt(90).unmask(0);
    docs_url: https://global-surface-water.appspot.com/
consumed_by: []
produced_by: [imagery_water_mask]
demos: []
status: documented
sources:
  - https://global-surface-water.appspot.com/
  - https://github.com/awesome-spectral-indices/awesome-spectral-indices
  - https://esa-worldcover.org/
  - https://docs.sentinel-hub.com/api/latest/data/sentinel-2-l2a/
