Skip to main content

Cloud Masking

Per-pixel cloud classification based on Fmask (Zhu & Woodcock, 2012) and the MODIS cloud mask (Ackerman et al., 1998). This is a simplified implementation using 7 spectral/thermal tests; it does not include cloud shadow detection or temporal consistency.

Input​

Each pixel is represented as a PixelBands struct with top-of-atmosphere (TOA) reflectances in [0, 1] and optional brightness temperature in Kelvin.

FieldWavelengthRequired
blue~0.48 umYes
green~0.56 umYes
red~0.66 umYes
nir~0.86 umYes
swir1~1.6 umYes
swir2~2.2 umOptional (0 if absent)
cirrus~1.38 umOptional (0 if absent)
btThermal BT (K)Optional (0 if absent)

Classification Output​

Each pixel is classified as one of four CloudClass values:

ClassMeaning
ClearUsable for analysis
CloudCloud detected with high confidence
UncertainThin cloud, haze, or cloud shadow
SnowSnow or ice

Test Cascade​

Tests are applied in order. The first test that triggers determines the classification; remaining tests are skipped.

Test 1: Cirrus Band​

If cirrus > cirrus_threshold (default 0.02), classify as Cloud. The 1.38 um band is absorbed by water vapor in the lower atmosphere, so high reflectance indicates high-altitude ice clouds.

Test 2: NDSI Snow​

Compute NDSI = ND(green, SWIR1). If NDSI > ndsi_snow (default 0.15) and NIR > 0.11 and SWIR1 < 0.15, classify as Snow. The SWIR1 < 0.15 condition discriminates snow (low SWIR) from cloud (high SWIR).

Test 3: Brightness Temperature​

If bt is available (> 0):

  • BT < bt_cold (default 240 K): Cloud (cold cloud tops)
  • BT < bt_warm (default 270 K): Uncertain (possible thin cloud)

Test 4: Brightness​

Compute mean visible reflectance = (blue + green + red) / 3. If mean_vis > brightness_high (default 0.35), proceed to the whiteness test.

Test 5: Whiteness​

Whiteness is the mean absolute deviation of visible bands from their mean, normalized by the mean. Clouds are spectrally flat (white), so whiteness < whiteness_max (default 0.7) combined with high brightness triggers Cloud.

Test 6: HOT (Haze Optimized Transformation)​

HOT = blue - 0.5 * red - hot_threshold (default 0.08). Positive HOT with mean_vis > 0.15 indicates haze or thin cloud: Uncertain. Based on Zhang et al. (2002).

Test 7: NDVI Vegetation​

NDVI = ND(NIR, red). If NDVI > ndvi_veg (default 0.5), classify as Clear (dense vegetation is not cloud).

Pixels that do not trigger any test default to Clear.

Thresholds​

All thresholds are configurable via CloudThresholds. Defaults:

ParameterDefaultUnit
brightness_high0.35reflectance
whiteness_max0.70ratio
hot_threshold0.08reflectance
ndsi_snow0.15index
bt_cold240K
bt_warm270K
cirrus_threshold0.02reflectance
ndvi_veg0.50index

Batch Processing​

classify_image applies the cascade to a slice of PixelBands, filling a parallel &mut [CloudClass] mask. class_counts summarizes the mask, and ClassCounts::cloud_fraction() returns the combined cloud + uncertain fraction.