mask_with_scl¶
- mask_with_scl(data, scl, mask_codes=None, fill_value=None)[source]¶
Apply SCL-based masking to a data array.
This function masks pixels in the data array based on the Scene Classification Layer (SCL) values. Unlike
mask_sclwhich only returns a masked SCL array, this function applies the mask to actual data (e.g., spectral bands).Supported array shapes: - 2D data (y, x) with 2D SCL (y, x) - 3D data (time, y, x) with 3D SCL (time, y, x) - 4D data (time, band, y, x) with 3D SCL (time, y, x) - SCL broadcast across bands
- Parameters:
data (
numpy.ndarray) – The data array to mask (2D, 3D, or 4D).scl (
numpy.ndarray) – The SCL array (2D or 3D). For 4D data, SCL should be 3D (time, y, x).mask_codes (
sequenceoffloat, optional) – SCL codes to mask (set to fill_value). Defaults to clouds/shadows/etc: [0, 1, 2, 3, 8, 9, 10] (no data, saturated, dark, shadow, cloud med/high, cirrus).fill_value (
float, optional) – Value to assign to masked pixels. Defaults to NaN.
- Returns:
Data array with masked pixels replaced by fill_value.
- Return type:
Examples
>>> import numpy as np >>> from eo_processor import mask_with_scl >>> # 3D example: (time=2, y=3, x=3) >>> data = np.ones((2, 3, 3), dtype=np.float64) >>> scl = np.array([[[4, 4, 9], [4, 8, 4], [4, 4, 4]], ... [[4, 4, 4], [3, 4, 4], [4, 4, 10]]], dtype=np.float64) >>> result = mask_with_scl(data, scl) >>> # Pixels with SCL codes 9, 8, 3, 10 are now NaN >>> np.isnan(result[0, 0, 2]) # SCL=9 (cloud high) True
Overview¶
mask_with_scl applies SCL-based masking directly to a data array (e.g., spectral bands).
Unlike mask_scl which only filters the SCL array itself, this function uses the SCL
as a classification layer to mask corresponding pixels in the actual data.
This is particularly useful when:
Processing multi-band imagery where clouds/shadows need to be removed
Working with time-series data where the SCL mask should be applied consistently
Building composites that require pre-masking of invalid pixels
Supported Array Shapes¶
The function supports the following combinations:
Data Shape |
SCL Shape |
|---|---|
2D: (y, x) |
2D: (y, x) |
3D: (time, y, x) |
3D: (time, y, x) |
4D: (time, band, y, x) |
3D: (time, y, x) |
For 4D data with 3D SCL, the mask is broadcast across all bands, ensuring that if a pixel is cloudy at time t, it is masked in all spectral bands at that time step.
Default Mask Codes¶
If mask_codes is not provided, the function masks the following SCL classes:
0: No Data
1: Saturated / Defective
2: Dark Area Pixels
3: Cloud Shadows
8: Cloud (Medium Probability)
9: Cloud (High Probability)
10: Thin Cirrus
This leaves valid surface pixels (vegetation, bare soil, water, snow/ice) intact.
Typical Sentinel-2 SCL Codes¶
For reference:
Code |
Meaning |
Action |
0 1 2 3 4 5 6 7 8 9 10 11 |
No Data Saturated / Defective Dark Area Pixels Cloud Shadows Vegetation Not Vegetated Water Unclassified Cloud (Medium Probability) Cloud (High Probability) Thin Cirrus Snow / Ice |
Mask Mask Mask Mask Keep Keep Keep Keep Mask Mask Mask Keep |
Parameters¶
data(numpy.ndarray): The data array to mask (2D, 3D, or 4D).scl(numpy.ndarray): The SCL classification layer (2D or 3D).mask_codes(Sequence[float] | None): SCL codes to mask. Defaults to[0, 1, 2, 3, 8, 9, 10].fill_value(float | None): Value for masked pixels. Defaults toNaN.
Returns¶
numpy.ndarray (float64): Data array with masked pixels replaced.
Examples¶
Basic 3D Usage¶
import numpy as np
from eo_processor import mask_with_scl
# Sentinel-2 bands: shape (time=10, y=100, x=100)
red_band = np.random.rand(10, 100, 100)
scl = np.random.choice([4, 5, 6, 8, 9], size=(10, 100, 100))
# Mask cloud pixels (8, 9) in the red band
masked_red = mask_with_scl(red_band, scl)
4D Multi-Band Usage¶
import numpy as np
from eo_processor import mask_with_scl
# Multi-band data: shape (time=10, band=4, y=100, x=100)
# Bands: B02 (Blue), B03 (Green), B04 (Red), B08 (NIR)
data = np.random.rand(10, 4, 100, 100)
scl = np.random.choice([4, 5, 6, 8, 9], size=(10, 100, 100))
# Mask clouds across all bands
masked_data = mask_with_scl(data, scl)
Custom Mask Codes¶
# Only mask high-probability clouds and shadows
masked = mask_with_scl(data, scl, mask_codes=[3, 9])
Custom Fill Value¶
# Use -9999 as nodata instead of NaN
masked = mask_with_scl(data, scl, fill_value=-9999.0)
Integration with XArray/Dask¶
import xarray as xr
from eo_processor import mask_with_scl
# Apply via xr.apply_ufunc for chunked processing
masked_data = xr.apply_ufunc(
mask_with_scl,
data_array, # 4D: (time, band, y, x)
scl_array, # 3D: (time, y, x)
dask="parallelized",
output_dtypes=[float],
)
See Also¶
mask_scl()- Filter the SCL array itselfmask_vals()- Mask specific values in any arrayreplace_nans()- Replace NaN values after masking