authority: folia
slug: cloud-mask
name: Cloud Mask
domain: atmosphere
subdomain: processing
authority_id: folia:cloud-mask
external_ids:
  cf_standard_name: null
canonical_units: categorical
external_validations:
  library:
    name: s2cloudless
    id: sentinel-hub/sentinel2-cloud-detector
    docs_url: https://github.com/sentinel-hub/sentinel2-cloud-detector
  sentinel_hub:
    processor: SCL (Sentinel-2 L2A scene classification)
    docs_url: https://docs.sentinel-hub.com/api/latest/data/sentinel-2-l2a/#available-bands-and-data
  product:
    id: landsat-c2-qa-cmask-fmask
    docs_url: https://www.usgs.gov/landsat-missions/landsat-collection-2-quality-assessment-bands
  stac:
    extension: classification
    field: classification:classes
    docs_url: https://github.com/stac-extensions/classification
description: |
  Per-pixel indication of cloud presence in an optical scene. Three sources
  of truth differ subtly: s2cloudless is a single-class probability that is
  thresholded into a binary mask; the Sentinel-2 SCL gives discrete classes
  including thin cirrus (10) and cloud-shadow (3); Landsat Collection 2
  CMASK / Fmask packs cloud, cloud-shadow, and cirrus into separate bits of
  QA_PIXEL. Folia's canonical class codes for an interoperable cloud-mask:

  | code | class |
  |------|-------|
  | 0 | Clear |
  | 1 | Cloud |
  | 2 | Cirrus (thin / high) |
  | 3 | Cloud shadow |

  Recipes that only need a binary clear/cloud distinction collapse codes
  1-3 to "not clear". Consumed by every optical reflectance, index, and
  composite op.
theme: imagery
example_recipes:
  - title: "s2cloudless probability mask thresholded at 0.4"
    tool: python
    requires: [s2-l1c-reflectance]
    fixture: sentinel-2-l2a-iberia-2024-summer
    snippet: |
      from s2cloudless import S2PixelCloudDetector
      detector = S2PixelCloudDetector(threshold=0.4, average_over=4, dilation_size=2)
      cloud_mask = detector.get_cloud_masks(s2_l1c_bands)  # 0=clear, 1=cloud
    docs_url: https://github.com/sentinel-hub/sentinel2-cloud-detector
  - title: "Sentinel Hub evalscript: derive cloud mask from SCL"
    tool: sentinel-hub
    requires: [scl]
    fixture: sentinel-2-l2a-iberia-2024-summer
    snippet: |
      // SCL: 3=cloud-shadow, 8/9=cloud-medium/high, 10=cirrus
      function evaluatePixel(s) {
        var cloudy = (s.SCL == 8 || s.SCL == 9) ? 1
                   : (s.SCL == 10) ? 2
                   : (s.SCL == 3) ? 3 : 0;
        return [cloudy];
      }
    docs_url: https://docs.sentinel-hub.com/api/latest/data/sentinel-2-l2a/#available-bands-and-data
consumed_by: []
produced_by: []
demos: []
status: documented
sources:
  - https://github.com/sentinel-hub/sentinel2-cloud-detector
  - https://docs.sentinel-hub.com/api/latest/data/sentinel-2-l2a/#available-bands-and-data
  - https://www.usgs.gov/landsat-missions/landsat-collection-2-quality-assessment-bands
  - https://github.com/stac-extensions/classification
