Export and cloud mask Google Earth Engine imagery with automated composite creation and filtering capabilities.
—
Specialized cloud and shadow masking for Landsat and Sentinel-2 imagery with configurable algorithms and thresholds. Geedim provides automatic detection of image collection types and applies appropriate masking methods.
Enumeration of available cloud masking methods for Sentinel-2 imagery.
class CloudMaskMethod(Enum):
"""Enumeration for Sentinel-2 cloud masking methods."""
cloud_prob = 'cloud-prob'
"""
Threshold the Sentinel-2 Cloud Probability.
Deprecated since version 1.9.0: Please use the cloud_score method.
"""
qa = 'qa'
"""
Bit mask the QA60 quality assessment band.
Deprecated since version 1.9.0: Please use the cloud_score method.
"""
cloud_score = 'cloud-score'
"""
Threshold the Sentinel-2 Cloud Score+.
Uses the GOOGLE_CLOUD_SCORE_PLUS_V1_S2_HARMONIZED dataset.
"""Enumeration for Sentinel-2 Cloud Score+ bands used with the cloud_score method.
class CloudScoreBand(Enum):
"""Enumeration for Sentinel-2 Cloud Score+ bands."""
cs = 'cs'
"""
Pixel quality score based on spectral distance from a clear reference.
"""
cs_cdf = 'cs_cdf'
"""
Cumulative distribution function value of possible cs values.
"""Cloud masking parameters vary by image collection type:
def addMaskBands(
mask_cirrus: bool = True,
mask_shadows: bool = True,
**kwargs
) -> ee.Image:
"""
Add mask bands for Landsat imagery.
Parameters:
- mask_cirrus (bool): Whether to mask cirrus clouds (valid for Landsat 8-9)
- mask_shadows (bool): Whether to mask cloud shadows
- **kwargs: Additional masking parameters
"""def addMaskBands(
method: CloudMaskMethod = CloudMaskMethod.cloud_score,
prob: float = 0.6,
cloud_dist: float = 1000.0,
band: CloudScoreBand = CloudScoreBand.cs_cdf,
**kwargs
) -> ee.Image:
"""
Add mask bands for Sentinel-2 imagery.
Parameters:
- method (CloudMaskMethod): Cloud masking method
- prob (float): Cloud probability threshold (0.0-1.0)
- cloud_dist (float): Maximum cloud distance in meters
- band (CloudScoreBand): Cloud Score+ band to use
- **kwargs: Additional masking parameters
"""Different mask bands are automatically added based on image type:
# Common mask bands
FILL_MASK: ee.Image # Valid data mask
CLOUDLESS_MASK: ee.Image # Cloud-free pixels mask
CLOUD_DIST: ee.Image # Distance to nearest cloud (meters)
# Landsat-specific bands
QA_MASK: ee.Image # Quality assessment mask
SHADOW_MASK: ee.Image # Cloud shadow mask
CIRRUS_MASK: ee.Image # Cirrus cloud mask
# Sentinel-2 specific bands
CLOUD_PROB: ee.Image # Cloud probability (0-100)
CLOUD_SCORE: ee.Image # Cloud Score+ valueCalculate cloud coverage and fill statistics for regions:
def set_mask_portions(
ee_image: ee.Image,
region: dict | ee.Geometry = None,
scale: float = None
) -> ee.Image:
"""
Set FILL_PORTION and CLOUDLESS_PORTION properties.
Parameters:
- ee_image (ee.Image): Image to analyze
- region (dict | ee.Geometry, optional): Analysis region
- scale (float, optional): Analysis scale in meters
Returns:
ee.Image: Image with portion properties set
"""import ee
import geedim
geedim.Initialize()
# Load Landsat 8 image
image = ee.Image('LANDSAT/LC08/C02/T1_L2/LC08_173083_20200601')
# Add mask bands with custom parameters
masked_image = image.gd.addMaskBands(
mask_cirrus=True, # Mask cirrus clouds
mask_shadows=True # Mask cloud shadows
)
# Apply cloud masking
cloud_free = masked_image.maskClouds()
# Check cloud coverage
region = ee.Geometry.Point(-122.4194, 37.7749).buffer(10000)
coverage_image = masked_image.gd.set_mask_portions(region=region, scale=30)
# Get coverage statistics from image properties
fill_portion = coverage_image.get('FILL_PORTION').getInfo()
cloudless_portion = coverage_image.get('CLOUDLESS_PORTION').getInfo()
print(f"Fill portion: {fill_portion}%")
print(f"Cloudless portion: {cloudless_portion}%")# Load Sentinel-2 image
s2_image = ee.Image('COPERNICUS/S2_SR_HARMONIZED/20200601T185751_20200601T185931_T10SEG')
# Add mask bands using Cloud Score+ method
masked_s2 = s2_image.gd.addMaskBands(
method=geedim.CloudMaskMethod.cloud_score,
prob=0.65, # 65% cloud probability threshold
cloud_dist=2000, # 2km maximum cloud distance
band=geedim.CloudScoreBand.cs_cdf # Use CDF band
)
# Apply cloud masking
cloud_free_s2 = masked_s2.maskClouds()
# Alternative: Use legacy methods (deprecated)
legacy_masked = s2_image.gd.addMaskBands(
method=geedim.CloudMaskMethod.qa, # QA60 band method
prob=0.6
)# Load image collection
collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \
.filterDate('2020-01-01', '2020-12-31') \
.filterBounds(region)
# Add mask bands to entire collection
masked_collection = collection.gd.addMaskBands(
mask_cirrus=True,
mask_shadows=True
)
# Apply cloud masking to all images
cloud_free_collection = masked_collection.maskClouds()
# Filter by cloud coverage
low_cloud_collection = collection.gd.search(
start_date='2020-06-01',
end_date='2020-09-30',
cloudless_portion=80, # Minimum 80% cloud-free
fill_portion=95 # Minimum 95% valid data
)# Custom cloud distance calculation
def custom_cloud_masking(image):
# Add mask bands with custom parameters
masked = image.gd.addMaskBands(
method=geedim.CloudMaskMethod.cloud_score,
prob=0.5, # Lower threshold for more aggressive masking
cloud_dist=5000, # 5km cloud buffer
band=geedim.CloudScoreBand.cs # Use raw cloud score
)
# Get cloud distance band for analysis
cloud_dist = masked.select('CLOUD_DIST')
# Apply masking
return masked.maskClouds()
# Apply to collection
custom_masked = collection.map(custom_cloud_masking)# Analyze mask quality for a region
def assess_mask_quality(image, region, scale=30):
# Add mask bands and calculate portions
masked = image.gd.addMaskBands().gd.set_mask_portions(
region=region,
scale=scale
)
# Extract mask statistics
stats = {
'image_id': image.get('system:id').getInfo(),
'fill_portion': masked.get('FILL_PORTION').getInfo(),
'cloudless_portion': masked.get('CLOUDLESS_PORTION').getInfo(),
'date': image.date().format('YYYY-MM-dd').getInfo()
}
return stats
# Assess collection
region = ee.Geometry.Rectangle([-122.5, 37.7, -122.3, 37.8])
collection_list = collection.limit(10).getInfo()['features']
quality_stats = []
for img_info in collection_list:
img = ee.Image(img_info['id'])
stats = assess_mask_quality(img, region)
quality_stats.append(stats)
# Print results
for stats in quality_stats:
print(f"{stats['date']}: {stats['cloudless_portion']:.1f}% cloud-free")Install with Tessl CLI
npx tessl i tessl/pypi-geedim