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.