Skip to content

PRISMA cloud detection

Run CloudSEN12 models in PRISMA

  • Authors: Gonzalo Mateo-García, Manuel Montesino Martin

This tutorial shows how to run CloudSEN12cloud detection models in a PRISMA image. It requires the cloudsen12_models package.

pip install cloudsen12_models georeader-spaceml
from georeader.readers import prisma
from cloudsen12_models import cloudsen12
from georeader import plot
/home/gonzalo/mambaforge/envs/marsmlpy312/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm

file = "rasters/PRS_L1_STD_OFFL_20241109073054_20241109073059_0001.he5"
prisma_reader = prisma.PRISMA(file)
prisma_reader

        File: rasters/PRS_L1_STD_OFFL_20241109073054_20241109073059_0001.he5
        Bounds: (47.82221221923828, 29.50290870666504, 48.19811248779297, 29.824541091918945)
        Time: 2024-11-09 07:30:54.783000+00:00
        VNIR Range: (406.9934, 977.3654) 63 bands
        SWIR Range: (943.3579, 2497.1155) 171 bands
        
from georeader.readers import S2_SAFE_reader

srf = S2_SAFE_reader.read_srf("S2A")
srf
/home/gonzalo/mambaforge/envs/marsmlpy312/lib/python3.12/site-packages/openpyxl/worksheet/_reader.py:329: UserWarning: Unknown extension is not supported and will be removed
  warn(msg)

B01 B02 B03 B04 B05 B06 B07 B08 B8A B09 B10 B11 B12
SR_WL
412 0.001776 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000
413 0.004073 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000
414 0.003626 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000
415 0.003515 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000
416 0.005729 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000
... ... ... ... ... ... ... ... ... ... ... ... ... ...
2316 0.000000 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.010984
2317 0.000000 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.007360
2318 0.000000 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.006491
2319 0.000000 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.004697
2320 0.000000 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.002059

877 rows × 13 columns

%%time
import numpy as np
# Load VNIR-SWIR in prisma units (i.e. radiance units)
vnir = prisma_reader.load_raw(swir_flag=False); print(vnir.shape)
swir = prisma_reader.load_raw(swir_flag=True); print(swir.shape)
vnir_swir = np.moveaxis(np.concatenate((vnir, swir), axis = 2), 2, 0)
# Load VNIR-SWIR central wavelengths
vnir_wvl = prisma_reader.wavelength_vnir[0]
swir_wvl = prisma_reader.wavelength_swir[0]
vnir_swir_wvl = np.concatenate((vnir_wvl, swir_wvl))
(1000, 1000, 63)
(1000, 1000, 171)
CPU times: user 7.46 s, sys: 1.39 s, total: 8.86 s
Wall time: 8.85 s

from georeader import reflectance
s2bands = reflectance.transform_to_srf(vnir_swir, 
                                           srf,
                                           wavelengths_hyperspectral=vnir_swir_wvl,
                                           as_reflectance=True,
                                           observation_date_corr_factor=prisma_reader.observation_date_correction_factor,
                                           verbose=True,
                                           units=prisma_reader.units)
type(s2bands)
2025-01-31 09:25:09(0/13) Processing band B01
2025-01-31 09:25:09  Loading 7 bands
2025-01-31 09:25:09  bands loaded, computing tensor
2025-01-31 09:25:09(1/13) Processing band B02
2025-01-31 09:25:09  Loading 12 bands
2025-01-31 09:25:09  bands loaded, computing tensor

/home/gonzalo/mambaforge/envs/marsmlpy312/lib/python3.12/site-packages/pysolar/solartime.py:113: UserWarning: I don't know about leap seconds after 2023
  warnings.warn \

2025-01-31 09:25:10(2/13) Processing band B03
2025-01-31 09:25:10  Loading 7 bands
2025-01-31 09:25:10  bands loaded, computing tensor
2025-01-31 09:25:10(3/13) Processing band B04
2025-01-31 09:25:10  Loading 5 bands
2025-01-31 09:25:10  bands loaded, computing tensor
2025-01-31 09:25:10(4/13) Processing band B05
2025-01-31 09:25:10  Loading 3 bands
2025-01-31 09:25:10  bands loaded, computing tensor
2025-01-31 09:25:10(5/13) Processing band B06
2025-01-31 09:25:10  Loading 3 bands
2025-01-31 09:25:10  bands loaded, computing tensor
2025-01-31 09:25:10(6/13) Processing band B07
2025-01-31 09:25:10  Loading 4 bands
2025-01-31 09:25:10  bands loaded, computing tensor
2025-01-31 09:25:10(7/13) Processing band B08
2025-01-31 09:25:10  Loading 14 bands
2025-01-31 09:25:10  bands loaded, computing tensor
2025-01-31 09:25:10(8/13) Processing band B8A
2025-01-31 09:25:10  Loading 5 bands
2025-01-31 09:25:10  bands loaded, computing tensor
2025-01-31 09:25:10(9/13) Processing band B09
2025-01-31 09:25:10  Loading 5 bands
2025-01-31 09:25:10  bands loaded, computing tensor
2025-01-31 09:25:10(10/13) Processing band B10
2025-01-31 09:25:10  Loading 8 bands
2025-01-31 09:25:10  bands loaded, computing tensor
2025-01-31 09:25:10(11/13) Processing band B11
2025-01-31 09:25:10  Loading 14 bands
2025-01-31 09:25:10  bands loaded, computing tensor
2025-01-31 09:25:10(12/13) Processing band B12
2025-01-31 09:25:10  Loading 32 bands
2025-01-31 09:25:10  bands loaded, computing tensor

numpy.ndarray
import matplotlib.pyplot as plt

bands_s2 = ["B01","B02","B03","B04","B05","B06","B07","B08","B8A", "B09","B10","B11","B12"]

fig, ax =plt.subplots(7,2,figsize=(10,10), tight_layout=True)
ax =ax.flatten()

for i,b in enumerate(bands_s2):
    ax[i].hist(s2bands[i].ravel())
    ax[i].set_title(b)
No description has been provided for this image
s2bands.shape
np.moveaxis(s2bands, 0, 2).astype(np.float32).shape
(1000, 1000, 13)
from georeader import griddata
from georeader.geotensor import GeoTensor
s2_image = griddata.read_to_crs(np.moveaxis(s2bands, 0, 2).astype(np.float32), 
                                lons=prisma_reader.lons, lats=prisma_reader.lats, 
                                resolution_dst=30)
s2_image
 
         Transform: | 30.00, 0.00, 192085.06|
| 0.00,-30.00, 3303421.30|
| 0.00, 0.00, 1.00|
         Shape: (13, 1211, 1235)
         Resolution: (30.0, 30.0)
         Bounds: (192085.06318415108, 3267091.300334674, 229135.06318415108, 3303421.300334674)
         CRS: EPSG:32639
         fill_value_default: -1
        
swir_nir_red = (s2_image.isel({"band": [S2_SAFE_reader.BANDS_S2_L1C.index(b) for b in ["B11", "B08", "B04"]]}) / .45).clip(0,1)

plot.show(swir_nir_red)
<Axes: >
No description has been provided for this image
model_4bands = cloudsen12.load_model_by_name(name="dtacs4bands", weights_folder="cloudsen12_models")
cloudmask = model_4bands.predict(s2bands[[S2_SAFE_reader.BANDS_S2_L1C.index(b) for b in model_4bands.bands]])

cloudmask_geotensor = griddata.read_to_crs(cloudmask,
                                           lons=prisma_reader.lons, lats=prisma_reader.lats, 
                                           resolution_dst=30, method="nearest")
invalids = np.all(swir_nir_red.values == 0,axis=0)
cloudmask_geotensor.values[invalids] = np.nan
# swir_nir_red.values[:, invalids] = np.nan
cloudsen12.plot_cloudSEN12mask(cloudmask_geotensor, ax=ax[1])

fig, ax = plt.subplots(1,2,figsize=(14,5),sharey=True, tight_layout=True)

plot.show(swir_nir_red,ax=ax[0])
cloudsen12.plot_cloudSEN12mask(cloudmask_geotensor, ax=ax[1])
<Axes: >
No description has been provided for this image

Licence

The cloudsen12_models package is published under a GNU Lesser GPL v3 licence

The CloudSEN12 database and all pre-trained models are released under a Creative Commons non-commercial licence. For using the models in comercial pipelines written consent by the authors must be provided.

This notebook is released under a Creative Commons non-commercial licence.

If you find this work useful please cite:

@article{aybar_cloudsen12_2024,
    title = {{CloudSEN12}+: {The} largest dataset of expert-labeled pixels for cloud and cloud shadow detection in {Sentinel}-2},
    issn = {2352-3409},
    url = {https://www.sciencedirect.com/science/article/pii/S2352340924008163},
    doi = {10.1016/j.dib.2024.110852},
    journal = {Data in Brief},
    author = {Aybar, Cesar and Bautista, Lesly and Montero, David and Contreras, Julio and Ayala, Daryl and Prudencio, Fernando and Loja, Jhomira and Ysuhuaylas, Luis and Herrera, Fernando and Gonzales, Karen and Valladares, Jeanett and Flores, Lucy A. and Mamani, Evelin and Quiñonez, Maria and Fajardo, Rai and Espinoza, Wendy and Limas, Antonio and Yali, Roy and Alcántara, Alejandro and Leyva, Martin and Loayza-Muro, Rau´l and Willems, Bram and Mateo-García, Gonzalo and Gómez-Chova, Luis},
    month = aug,
    year = {2024},
    pages = {110852},
}