Quality Masks¶
Utilities for creating quality masks and filtering Sentinel-2 scenes.
Overview¶
The gee_acolite.utils.masks module provides functions to create the masks used in quality control of satellite imagery, including:
- Water / land classification
- Cirrus cloud detection
- TOA reflectance cloud threshold
- Cloud probability and shadow detection
- Negative reflectance filtering
Mask Pipeline¶
Functions¶
mask_negative_reflectance
¶
Mask out negative reflectance values.
Removes pixels with negative reflectance, which are physically impossible and indicate processing errors or noise.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
image
|
Image
|
Image with reflectance band. |
required |
band
|
str
|
Band name to check for negative values. |
required |
Returns:
| Type | Description |
|---|---|
Image
|
Masked image with only non-negative values. |
Source code in gee_acolite/utils/masks.py
toa_mask
¶
Create mask based on TOA reflectance threshold.
Masks pixels with high TOA reflectance, typically indicating clouds, bright surfaces, or other anomalies.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
image
|
Image
|
Image with TOA reflectance bands. |
required |
band
|
str
|
Band name to check (default: 'rhot_B11' - SWIR). |
'rhot_B11'
|
threshold
|
float
|
Maximum reflectance threshold (default: 0.03). |
0.03
|
Returns:
| Type | Description |
|---|---|
Image
|
Binary mask (1 = valid, 0 = masked). |
Source code in gee_acolite/utils/masks.py
cirrus_mask
¶
Create cirrus cloud mask.
Uses cirrus band (1375nm) to detect high-altitude cirrus clouds.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
image
|
Image
|
Image with cirrus band. |
required |
band
|
str
|
Cirrus band name (default: 'rhot_B10'). |
'rhot_B10'
|
threshold
|
float
|
Maximum cirrus reflectance (default: 0.005). |
0.005
|
Returns:
| Type | Description |
|---|---|
Image
|
Binary mask (1 = no cirrus, 0 = cirrus detected). |
Source code in gee_acolite/utils/masks.py
non_water
¶
Create water/land classification mask.
Uses SWIR reflectance to distinguish water from land. Water has low SWIR reflectance due to strong absorption.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
image
|
Image
|
Image with SWIR band. |
required |
band
|
str
|
SWIR band name (default: 'rhot_B11'). |
'rhot_B11'
|
threshold
|
float
|
Maximum reflectance for water (default: 0.05). |
0.05
|
Returns:
| Type | Description |
|---|---|
Image
|
Binary mask (1 = water, 0 = land). |
Source code in gee_acolite/utils/masks.py
add_cloud_bands
¶
Add cloud mask band based on cloud probability.
Uses Sentinel-2 Cloud Probability dataset to identify cloudy pixels.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
img
|
Image
|
Image with 'cloud_prob' property containing Cloud Probability image. |
required |
cloud_prob_threshold
|
float
|
Cloud probability threshold 0-100 (default: 50). |
50
|
Returns:
| Type | Description |
|---|---|
Image
|
Input image with 'clouds' band added (1 = cloud, 0 = clear). |
Source code in gee_acolite/utils/masks.py
add_shadow_bands
¶
add_shadow_bands(img: Image, nir_dark_threshold: float = 0.15, cloud_proj_distance: float = 1) -> Image
Add cloud shadow mask bands to L1C image.
Identifies cloud shadows by projecting cloud locations in the direction of solar illumination and intersecting with dark NIR pixels.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
img
|
Image
|
Image with 'clouds' band and solar geometry metadata. |
required |
nir_dark_threshold
|
float
|
Threshold for dark pixels in NIR (0-1, default: 0.15). |
0.15
|
cloud_proj_distance
|
float
|
Maximum shadow projection distance in km (default: 1). |
1
|
Returns:
| Type | Description |
|---|---|
Image
|
Input image with 'dark_pixels', 'cloud_transform', and 'shadows' bands. |
Source code in gee_acolite/utils/masks.py
add_cld_shdw_mask
¶
add_cld_shdw_mask(img: Image, cloud_prob_threshold: float = 50, nir_dark_threshold: float = 0.15, cloud_proj_distance: float = 1, buffer: int = 50) -> Image
Add combined cloud and shadow mask with buffer.
Creates comprehensive cloud and shadow mask by combining: 1. Cloud probability mask 2. Cloud shadow detection 3. Buffer around masked areas
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
img
|
Image
|
Image with 'cloud_prob' property containing Cloud Probability data. |
required |
cloud_prob_threshold
|
float
|
Cloud probability threshold 0-100 (default: 50). |
50
|
nir_dark_threshold
|
float
|
Threshold for dark NIR pixels 0-1 (default: 0.15). |
0.15
|
cloud_proj_distance
|
float
|
Shadow projection distance in km (default: 1). |
1
|
buffer
|
int
|
Buffer distance around clouds/shadows in meters (default: 50). |
50
|
Returns:
| Type | Description |
|---|---|
Image
|
Input image with 'cloudmask' band (1 = cloud/shadow, 0 = clear). |
Source code in gee_acolite/utils/masks.py
Masking Sequence¶
Usage Examples¶
Basic Water Mask¶
import ee
from gee_acolite.utils.masks import non_water
image = corrected_images.first()
# Keep pixels where B11 < 0.05 (water)
water_mask = non_water(image, band='B11', threshold=0.05)
image_water = image.updateMask(water_mask)
Cirrus Mask¶
from gee_acolite.utils.masks import cirrus_mask
# Detect cirrus using B10 (1375 nm)
no_cirrus = cirrus_mask(image, band='B10', threshold=0.005)
image_no_cirrus = image.updateMask(no_cirrus)
Full Combined Mask (as used internally by compute_water_mask)¶
from gee_acolite.utils import masks
settings = {
'l2w_mask_threshold': 0.05,
'l2w_mask_cirrus_threshold': 0.005,
'l2w_mask_high_toa_threshold': 0.3,
}
# Water / land
mask = masks.non_water(image, 'B11', settings['l2w_mask_threshold'])
# Cirrus
mask = mask.And(masks.cirrus_mask(image, 'B10', settings['l2w_mask_cirrus_threshold']))
# Bright clouds (TOA threshold)
mask = mask.And(masks.toa_mask(image, 'rhot_B4', settings['l2w_mask_high_toa_threshold']))
clean_image = image.updateMask(mask)
Cloud and Shadow Masking (requires search_with_cloud_proba)¶
from gee_acolite.utils.masks import add_cld_shdw_mask, cld_shdw_mask
from gee_acolite.utils.search import search_with_cloud_proba
images = search_with_cloud_proba(roi, '2023-06-01', '2023-06-30')
def apply_cloud_mask(img):
img = add_cld_shdw_mask(
img,
cloud_prob_threshold=50,
nir_dark_threshold=0.15,
cloud_proj_distance=10,
buffer=50,
)
return img.updateMask(cld_shdw_mask(img))
masked = images.map(apply_cloud_mask)
Cloud Detection Decision Tree¶
Threshold Reference¶
| Parameter | Threshold | Description | Mode |
|---|---|---|---|
l2w_mask_threshold |
> 0.05 | SWIR B11 water/land split | Conservative |
l2w_mask_threshold |
> 0.0 | SWIR B11 — permissive | Turbid waters |
l2w_mask_cirrus_threshold |
< 0.005 | B10 cirrus detection | Standard |
l2w_mask_cirrus_threshold |
< 0.003 | B10 cirrus detection | Strict |
l2w_mask_high_toa_threshold |
< 0.3 | TOA cloud threshold | Conservative |
l2w_mask_high_toa_threshold |
< 0.2 | TOA cloud threshold | Strict |
| Cloud probability | < 50 | S2 Cloud Probability | Standard |
| Cloud probability | < 30 | S2 Cloud Probability | Strict |
NDWI — Water Index¶
The water/land mask is based on SWIR reflectance (B11). Internally, non_water keeps pixels where B11 < threshold. For reference, the NDWI index used in some contexts is:
- NDWI > 0: likely water
- NDWI < 0: likely land/vegetation
References¶
- McFeeters, S. K. (1996). The use of the Normalized Difference Water Index (NDWI) in the delineation of open water features. IJRS, 17(7), 1425–1432.
- Martins, V. S., et al. (2017). Assessment of atmospheric correction methods for Sentinel-2 MSI images applied to Amazon floodplain lakes. Remote Sensing, 9(4), 322.