planetary_computer_Sentinel2.md

April 23, 2026 ยท View on GitHub

rslearn.data_sources.planetary_computer.Sentinel2

Sentinel-2 L2A data on Microsoft Planetary Computer. This data source obtains Sentinel-2 satellite images from https://planetarycomputer.microsoft.com/dataset/sentinel-2-l2a.

Configuration

{
  "class_path": "rslearn.data_sources.planetary_computer.Sentinel2",
  "init_args": {
    // Flag (default false) to harmonize pixel values across different processing
    // baselines (recommended), see
    // https://developers.google.com/earth-engine/datasets/catalog/COPERNICUS_S2_SR_HARMONIZED
    "harmonize": false,
    // Optional STAC query filter. Below are examples of filtering by commonly
    // used attributes.
    "query": null,
    "sort_by": null,
    "sort_ascending": true,
    "timeout_seconds": 10
  }
}

This data source supports direct materialization ("ingest": false).

Available Bands

These uint16 bands are available:

  • B01
  • B02
  • B03
  • B04
  • B05
  • B06
  • B07
  • B08
  • B09
  • B11
  • B12
  • B8A

Note that B10 is not present in L2A.

The following uint8 bands are also available:

  • SCL (scene classification layer)
  • R
  • G
  • B

R/G/B are from the TCI (visual) product. These are processed from B04, B03, and B02.

Example

Here is an example data source configuration to obtain 8-bit RGB imagery. We set sort_by to get the least cloudy scene based on the overall scene metadata.

{
  "layers": {
    "sentinel2": {
      "band_sets": [{
          "bands": ["R", "G", "B"],
          "dtype": "uint8"
      }],
      "data_source": {
        "class_path": "rslearn.data_sources.planetary_computer.Sentinel2",
        "init_args": {
          "cache_dir": "cache/planetary_computer",
          "harmonize": true,
          "sort_by": "eo:cloud_cover"
        },
        "ingest": false,
        "query_config": {
          "max_matches": 1,
          "space_mode": "MOSAIC"
        }
      },
      "type": "raster"
    }
  }
}

Cloud-Aware Ranking

For Sentinel-2, rslearn supports cloud-aware ranking compositors that reorder overlapping items inside each materialized group and then apply FIRST_VALID.

OmniCloudMask

To rank with OmniCloudMask, configure:

{
  "layers": {
    "sentinel2": {
      "type": "raster",
      "band_sets": [
        {"bands": ["R", "G", "B"], "dtype": "uint8"},
        {"bands": ["B04", "B03", "B8A"], "dtype": "uint16"}
      ],
      "data_source": {
        "class_path": "rslearn.data_sources.planetary_computer.Sentinel2",
        "init_args": {
          "harmonize": true,
          "query": {"eo:cloud_cover": {"lt": 80}}
        },
        "ingest": false,
        "query_config": {
          "max_matches": 1,
          "space_mode": "MOSAIC"
        }
      },
      "compositing_method": {
        "class_path": "rslearn.dataset.omni_cloud_mask.OmniCloudMaskFirstValid",
        "init_args": {
          "red_band": "B04",
          "green_band": "B03",
          "nir_band": "B8A",
          "scoring_resolution": 20.0
        }
      }
    }
  }
}

For reliable ranking quality with OmniCloudMask, create windows with at least 96x96 pixels (per dimension). Smaller windows can run, but accuracy may be lower even when inference padding is enabled.

For Sentinel-2 with nir_band="B8A", scoring_resolution: 20.0 is a good speed-focused choice because it scores once on a 20 m window-level grid and reuses that ordering across the layer's band sets.

That setting is not always optimal for accuracy. If you want the most direct ranking on the output grid, leave scoring_resolution unset so scoring runs on each materialization grid instead.

This same API can be used for other sensors. A good explicit choice for finer-than-10 m imagery is often scoring_resolution: 10.0, while coarser imagery usually works best at its native resolution.

Requires omnicloudmask (pip install .[extra] in this repo). See OmniCloudMaskFirstValid for details.

When using this compositor with context.layer_config, include the scoring bands in a configured band_sets entry (for example, B04, B03, B8A). These are not automatically inferred from compositing_method.

Sentinel-2 SCL

To rank with Sentinel-2 Scene Classification Layer (SCL) classes, configure:

{
  "layers": {
    "sentinel2": {
      "type": "raster",
      "band_sets": [
        {"bands": ["R", "G", "B"], "dtype": "uint8"},
        {"bands": ["SCL"], "dtype": "uint8"}
      ],
      "data_source": {
        "class_path": "rslearn.data_sources.planetary_computer.Sentinel2",
        "init_args": {
          "harmonize": true,
          "query": {"eo:cloud_cover": {"lt": 80}}
        },
        "ingest": false,
        "query_config": {
          "max_matches": 1,
          "space_mode": "MOSAIC"
        }
      },
      "compositing_method": {
        "class_path": "rslearn.dataset.sentinel2_scl.Sentinel2SCLFirstValid",
        "init_args": {
          "scl_band": "SCL"
        }
      }
    }
  }
}

See Sentinel2SCLFirstValid for scoring details and available weights.

When using this compositor with context.layer_config, include scl_band (default SCL) in a configured band_sets entry. It is not automatically inferred from compositing_method.

Save this to a dataset folder like /path/to/dataset/config.json. Then we can create a sample window, and then run prepare and materialize (skipping ingest since we disabled it above in favor of directly materializing from the Planetary Computer COGs):

export DATASET_PATH=/path/to/dataset
# This will create one 1024x1024 window at 10 m/pixel, which matches the Sentinel-2
# resolution.
rslearn dataset add_windows --root $DATASET_PATH --group default --name seattle --box=-122.337,47.616,-122.337,47.616 --src_crs EPSG:4326 --window_size 1024 --utm --resolution 10 --start 2025-07-01T00:00:00Z --end 2025-08-01T00:00:00Z
rslearn dataset prepare --root $DATASET_PATH
rslearn dataset materialize --root $DATASET_PATH

You can then visualize the image in qgis:

qgis $DATASET_PATH/windows/default/seattle/layers/sentinel2/R_G_B/geotiff.tif

A Sentinel-2 image of Seattle from July 2025.

Harmonization

Scenes at or after processing baseline 04.00 have pixel values that are 1000 higher so that there is more contrast between dark pixels. Harmonization undoes this by subtracting 1000 from the pixel values in these scenes. Note that, while we enabled harmonization above, the TCI (8-bit visual) image is unaffected by harmonization.

We recommend enabling harmonization whenever you are using any scenes captured before 2022-01-25. If you are only using newer scenes, and want to leverage the added contrast, then include a filter on the processing baseline to ensure no older scenes got included, e.g.:

{
  "class_path": "rslearn.data_sources.planetary_computer.Sentinel2",
  "init_args": {
    "cache_dir": "cache/planetary_computer",
    "harmonize": false,
    "query": {
      "s2:processing_baseline": {"gte": "04.00"}
    }
  }
}

Common STAC Query Filters

Planetary Computer supports many STAC metadata filters. Here is an example combining filters for several commonly used attributes: cloud cover, processing baseline, platform (S2A/S2B/S2C), and MGRS tile:

{
  "class_path": "rslearn.data_sources.planetary_computer.Sentinel2",
  "init_args": {
    "query": {
      "eo:cloud_cover": {"lt": 20},
      "platform": {"in": ["sentinel-2a", "sentinel-2b", "sentinel-2c"]},
      "s2:mgrs_tile": {"eq": "10TET"},
      "s2:processing_baseline": {"eq": "05.10"}
    }
  }
}