rslearn 0.0.26__tar.gz → 0.0.27__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rslearn-0.0.26/rslearn.egg-info → rslearn-0.0.27}/PKG-INFO +6 -3
- {rslearn-0.0.26 → rslearn-0.0.27}/README.md +2 -2
- {rslearn-0.0.26 → rslearn-0.0.27}/pyproject.toml +4 -1
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/__init__.py +2 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/aws_landsat.py +44 -161
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/aws_open_data.py +2 -4
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/aws_sentinel1.py +1 -3
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/aws_sentinel2_element84.py +54 -165
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/climate_data_store.py +1 -3
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/copernicus.py +1 -2
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/data_source.py +1 -1
- rslearn-0.0.27/rslearn/data_sources/direct_materialize_data_source.py +336 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/earthdaily.py +52 -155
- rslearn-0.0.27/rslearn/data_sources/earthdatahub.py +425 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/eurocrops.py +1 -2
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/gcp_public_data.py +1 -2
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/google_earth_engine.py +1 -2
- rslearn-0.0.27/rslearn/data_sources/hf_srtm.py +595 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/local_files.py +1 -1
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/openstreetmap.py +1 -1
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/planet.py +1 -2
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/planet_basemap.py +1 -2
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/planetary_computer.py +183 -186
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/soilgrids.py +3 -3
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/stac.py +1 -2
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/usda_cdl.py +1 -3
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/usgs_landsat.py +7 -254
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/worldcereal.py +1 -1
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/worldcover.py +1 -1
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/worldpop.py +1 -1
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/xyz_tiles.py +5 -9
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/concatenate_features.py +6 -1
- rslearn-0.0.26/rslearn/train/all_patches_dataset.py → rslearn-0.0.27/rslearn/train/all_crops_dataset.py +120 -117
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/data_module.py +27 -27
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/dataset.py +109 -62
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/lightning_module.py +1 -1
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/model_context.py +3 -3
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/prediction_writer.py +69 -41
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/tasks/classification.py +1 -1
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/tasks/detection.py +5 -5
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/tasks/regression.py +1 -1
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/utils/__init__.py +2 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/utils/geometry.py +21 -0
- rslearn-0.0.27/rslearn/utils/m2m_api.py +251 -0
- rslearn-0.0.27/rslearn/utils/retry_session.py +43 -0
- {rslearn-0.0.26 → rslearn-0.0.27/rslearn.egg-info}/PKG-INFO +6 -3
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn.egg-info/SOURCES.txt +6 -2
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn.egg-info/requires.txt +3 -0
- rslearn-0.0.26/rslearn/data_sources/earthdata_srtm.py +0 -282
- {rslearn-0.0.26 → rslearn-0.0.27}/LICENSE +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/NOTICE +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/__init__.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/arg_parser.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/config/__init__.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/config/dataset.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/const.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/utils.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/data_sources/vector_source.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/dataset/__init__.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/dataset/add_windows.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/dataset/dataset.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/dataset/handler_summaries.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/dataset/manage.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/dataset/materialize.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/dataset/remap.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/dataset/storage/__init__.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/dataset/storage/file.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/dataset/storage/storage.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/dataset/window.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/lightning_cli.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/log_utils.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/main.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/__init__.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/anysat.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/attention_pooling.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/clay/clay.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/clay/configs/metadata.yaml +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/clip.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/component.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/conv.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/croma.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/detr/__init__.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/detr/box_ops.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/detr/detr.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/detr/matcher.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/detr/position_encoding.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/detr/transformer.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/detr/util.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/dinov3.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/faster_rcnn.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/feature_center_crop.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/fpn.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/galileo/__init__.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/galileo/galileo.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/galileo/single_file_galileo.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/module_wrapper.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/molmo.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/multitask.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/olmoearth_pretrain/__init__.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/olmoearth_pretrain/model.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/olmoearth_pretrain/norm.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/panopticon.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/panopticon_data/sensors/drone.yaml +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/panopticon_data/sensors/enmap.yaml +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/panopticon_data/sensors/goes.yaml +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/panopticon_data/sensors/himawari.yaml +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/panopticon_data/sensors/intuition.yaml +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/panopticon_data/sensors/landsat8.yaml +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/panopticon_data/sensors/modis_terra.yaml +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/panopticon_data/sensors/qb2_ge1.yaml +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/panopticon_data/sensors/sentinel1.yaml +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/panopticon_data/sensors/sentinel2.yaml +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/panopticon_data/sensors/superdove.yaml +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/panopticon_data/sensors/wv23.yaml +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/pick_features.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/pooling_decoder.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/presto/__init__.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/presto/presto.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/presto/single_file_presto.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/prithvi.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/resize_features.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/sam2_enc.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/satlaspretrain.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/simple_time_series.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/singletask.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/ssl4eo_s12.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/swin.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/task_embedding.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/terramind.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/trunk.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/unet.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/upsample.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/models/use_croma.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/py.typed +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/template_params.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/tile_stores/__init__.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/tile_stores/default.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/tile_stores/tile_store.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/__init__.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/callbacks/__init__.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/callbacks/adapters.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/callbacks/freeze_unfreeze.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/callbacks/gradients.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/callbacks/peft.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/dataset_index.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/optimizer.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/scheduler.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/tasks/__init__.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/tasks/embedding.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/tasks/multi_task.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/tasks/per_pixel_regression.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/tasks/segmentation.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/tasks/task.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/transforms/__init__.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/transforms/concatenate.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/transforms/crop.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/transforms/flip.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/transforms/mask.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/transforms/normalize.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/transforms/pad.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/transforms/resize.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/transforms/select_bands.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/transforms/sentinel1.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/train/transforms/transform.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/utils/array.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/utils/colors.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/utils/feature.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/utils/fsspec.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/utils/get_utm_ups_crs.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/utils/grid_index.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/utils/jsonargparse.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/utils/mp.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/utils/raster_format.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/utils/rtree_index.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/utils/spatial_index.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/utils/sqlite_index.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/utils/stac.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/utils/time.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/utils/vector_format.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/vis/__init__.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/vis/normalization.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/vis/render_raster_label.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/vis/render_sensor_image.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/vis/render_vector_label.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/vis/utils.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn/vis/vis_server.py +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn.egg-info/dependency_links.txt +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn.egg-info/entry_points.txt +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/rslearn.egg-info/top_level.txt +0 -0
- {rslearn-0.0.26 → rslearn-0.0.27}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rslearn
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.27
|
|
4
4
|
Summary: A library for developing remote sensing datasets and models
|
|
5
5
|
Author: OlmoEarth Team
|
|
6
6
|
License: Apache License
|
|
@@ -248,6 +248,9 @@ Requires-Dist: pycocotools>=2.0; extra == "extra"
|
|
|
248
248
|
Requires-Dist: pystac_client>=0.9; extra == "extra"
|
|
249
249
|
Requires-Dist: rtree>=1.4; extra == "extra"
|
|
250
250
|
Requires-Dist: termcolor>=3.0; extra == "extra"
|
|
251
|
+
Requires-Dist: xarray>=2024.1; extra == "extra"
|
|
252
|
+
Requires-Dist: zarr>=3.1.2; extra == "extra"
|
|
253
|
+
Requires-Dist: numcodecs>=0.16; extra == "extra"
|
|
251
254
|
Requires-Dist: satlaspretrain_models>=0.3; extra == "extra"
|
|
252
255
|
Requires-Dist: scipy>=1.16; extra == "extra"
|
|
253
256
|
Requires-Dist: terratorch>=1.0.2; extra == "extra"
|
|
@@ -587,7 +590,7 @@ data:
|
|
|
587
590
|
groups: ["default"]
|
|
588
591
|
predict_config:
|
|
589
592
|
groups: ["predict"]
|
|
590
|
-
|
|
593
|
+
load_all_crops: true
|
|
591
594
|
skip_targets: true
|
|
592
595
|
patch_size: 512
|
|
593
596
|
trainer:
|
|
@@ -750,7 +753,7 @@ test_config:
|
|
|
750
753
|
split: val
|
|
751
754
|
predict_config:
|
|
752
755
|
groups: ["predict"]
|
|
753
|
-
|
|
756
|
+
load_all_crops: true
|
|
754
757
|
skip_targets: true
|
|
755
758
|
patch_size: 512
|
|
756
759
|
```
|
|
@@ -320,7 +320,7 @@ data:
|
|
|
320
320
|
groups: ["default"]
|
|
321
321
|
predict_config:
|
|
322
322
|
groups: ["predict"]
|
|
323
|
-
|
|
323
|
+
load_all_crops: true
|
|
324
324
|
skip_targets: true
|
|
325
325
|
patch_size: 512
|
|
326
326
|
trainer:
|
|
@@ -483,7 +483,7 @@ test_config:
|
|
|
483
483
|
split: val
|
|
484
484
|
predict_config:
|
|
485
485
|
groups: ["predict"]
|
|
486
|
-
|
|
486
|
+
load_all_crops: true
|
|
487
487
|
skip_targets: true
|
|
488
488
|
patch_size: 512
|
|
489
489
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "rslearn"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.27"
|
|
4
4
|
description = "A library for developing remote sensing datasets and models"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "OlmoEarth Team" },
|
|
@@ -52,6 +52,9 @@ extra = [
|
|
|
52
52
|
"rtree>=1.4",
|
|
53
53
|
# Needed by DINOv3.
|
|
54
54
|
"termcolor>=3.0",
|
|
55
|
+
"xarray>=2024.1",
|
|
56
|
+
"zarr>=3.1.2",
|
|
57
|
+
"numcodecs>=0.16",
|
|
55
58
|
"satlaspretrain_models>=0.3",
|
|
56
59
|
"scipy>=1.16",
|
|
57
60
|
"terratorch>=1.0.2",
|
|
@@ -17,6 +17,7 @@ from .data_source import (
|
|
|
17
17
|
ItemLookupDataSource,
|
|
18
18
|
RetrieveItemDataSource,
|
|
19
19
|
)
|
|
20
|
+
from .direct_materialize_data_source import DirectMaterializeDataSource
|
|
20
21
|
|
|
21
22
|
__all__ = (
|
|
22
23
|
"DataSource",
|
|
@@ -24,5 +25,6 @@ __all__ = (
|
|
|
24
25
|
"Item",
|
|
25
26
|
"ItemLookupDataSource",
|
|
26
27
|
"RetrieveItemDataSource",
|
|
28
|
+
"DirectMaterializeDataSource",
|
|
27
29
|
"data_source_from_config",
|
|
28
30
|
)
|
|
@@ -9,32 +9,28 @@ import urllib.request
|
|
|
9
9
|
import zipfile
|
|
10
10
|
from collections.abc import Generator
|
|
11
11
|
from datetime import datetime
|
|
12
|
-
from typing import
|
|
12
|
+
from typing import BinaryIO
|
|
13
13
|
|
|
14
|
-
import affine
|
|
15
14
|
import boto3
|
|
16
15
|
import dateutil.parser
|
|
17
16
|
import fiona
|
|
18
17
|
import fiona.transform
|
|
19
|
-
import numpy.typing as npt
|
|
20
|
-
import rasterio
|
|
21
18
|
import shapely
|
|
22
19
|
import shapely.geometry
|
|
23
20
|
import tqdm
|
|
24
|
-
from rasterio.enums import Resampling
|
|
25
21
|
from upath import UPath
|
|
26
22
|
|
|
27
23
|
import rslearn.data_sources.utils
|
|
28
|
-
from rslearn.config import LayerConfig
|
|
29
24
|
from rslearn.const import SHAPEFILE_AUX_EXTENSIONS, WGS84_PROJECTION
|
|
30
|
-
from rslearn.
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
from rslearn.data_sources.direct_materialize_data_source import (
|
|
26
|
+
DirectMaterializeDataSource,
|
|
27
|
+
)
|
|
28
|
+
from rslearn.tile_stores import TileStoreWithLayer
|
|
33
29
|
from rslearn.utils.fsspec import get_upath_local, join_upath, open_atomic
|
|
34
|
-
from rslearn.utils.geometry import
|
|
30
|
+
from rslearn.utils.geometry import STGeometry
|
|
35
31
|
from rslearn.utils.grid_index import GridIndex
|
|
36
32
|
|
|
37
|
-
from .data_source import
|
|
33
|
+
from .data_source import DataSourceContext, Item, QueryConfig
|
|
38
34
|
|
|
39
35
|
WRS2_GRID_SIZE = 1.0
|
|
40
36
|
|
|
@@ -79,7 +75,7 @@ class LandsatOliTirsItem(Item):
|
|
|
79
75
|
)
|
|
80
76
|
|
|
81
77
|
|
|
82
|
-
class LandsatOliTirs(
|
|
78
|
+
class LandsatOliTirs(DirectMaterializeDataSource[LandsatOliTirsItem]):
|
|
83
79
|
"""A data source for Landsat 8/9 OLI-TIRS imagery on AWS.
|
|
84
80
|
|
|
85
81
|
Specifically, uses the usgs-landsat S3 bucket maintained by USGS. The data includes
|
|
@@ -91,7 +87,7 @@ class LandsatOliTirs(DataSource, TileStore):
|
|
|
91
87
|
|
|
92
88
|
bucket_name = "usgs-landsat"
|
|
93
89
|
bucket_prefix = "collection02/level-1/standard/oli-tirs"
|
|
94
|
-
|
|
90
|
+
BANDS = ["B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "B10", "B11"]
|
|
95
91
|
|
|
96
92
|
wrs2_url = "https://d9-wret.s3.us-west-2.amazonaws.com/assets/palladium/production/s3fs-public/atoms/files/WRS2_descending_0.zip" # noqa
|
|
97
93
|
"""URL to download shapefile specifying polygon of each (path, row)."""
|
|
@@ -110,6 +106,10 @@ class LandsatOliTirs(DataSource, TileStore):
|
|
|
110
106
|
SpaceMode.WITHIN.
|
|
111
107
|
context: the data source context.
|
|
112
108
|
"""
|
|
109
|
+
# Each band is a separate single-band asset.
|
|
110
|
+
asset_bands = {band: [band] for band in self.BANDS}
|
|
111
|
+
super().__init__(asset_bands=asset_bands)
|
|
112
|
+
|
|
113
113
|
# If context is provided, we join the directory with the dataset path,
|
|
114
114
|
# otherwise we treat it directly as UPath.
|
|
115
115
|
if context.ds_path is not None:
|
|
@@ -342,16 +342,43 @@ class LandsatOliTirs(DataSource, TileStore):
|
|
|
342
342
|
return item
|
|
343
343
|
raise ValueError(f"item {name} not found")
|
|
344
344
|
|
|
345
|
-
|
|
345
|
+
# --- DirectMaterializeDataSource implementation ---
|
|
346
|
+
|
|
347
|
+
def get_asset_url(self, item_name: str, asset_key: str) -> str:
|
|
348
|
+
"""Get the presigned URL to read the asset for the given item and asset key.
|
|
349
|
+
|
|
350
|
+
Args:
|
|
351
|
+
item_name: the name of the item.
|
|
352
|
+
asset_key: the key identifying which asset to get (the band name).
|
|
353
|
+
|
|
354
|
+
Returns:
|
|
355
|
+
the presigned URL to read the asset from.
|
|
356
|
+
"""
|
|
357
|
+
# Get the item since it has the blob path.
|
|
358
|
+
item = self.get_item_by_name(item_name)
|
|
359
|
+
|
|
360
|
+
# For Landsat, the asset_key is the band name (e.g., "B1", "B2", etc.).
|
|
361
|
+
blob_key = item.blob_path + f"{asset_key}.TIF"
|
|
362
|
+
return self.client.generate_presigned_url(
|
|
363
|
+
"get_object",
|
|
364
|
+
Params={
|
|
365
|
+
"Bucket": self.bucket_name,
|
|
366
|
+
"Key": blob_key,
|
|
367
|
+
"RequestPayer": "requester",
|
|
368
|
+
},
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
# --- DataSource implementation ---
|
|
372
|
+
|
|
373
|
+
def deserialize_item(self, serialized_item: dict) -> LandsatOliTirsItem:
|
|
346
374
|
"""Deserializes an item from JSON-decoded data."""
|
|
347
|
-
assert isinstance(serialized_item, dict)
|
|
348
375
|
return LandsatOliTirsItem.deserialize(serialized_item)
|
|
349
376
|
|
|
350
377
|
def retrieve_item(
|
|
351
378
|
self, item: LandsatOliTirsItem
|
|
352
379
|
) -> Generator[tuple[str, BinaryIO], None, None]:
|
|
353
380
|
"""Retrieves the rasters corresponding to an item as file streams."""
|
|
354
|
-
for band in self.
|
|
381
|
+
for band in self.BANDS:
|
|
355
382
|
buf = io.BytesIO()
|
|
356
383
|
self.bucket.download_fileobj(
|
|
357
384
|
item.blob_path + f"{band}.TIF",
|
|
@@ -376,7 +403,7 @@ class LandsatOliTirs(DataSource, TileStore):
|
|
|
376
403
|
geometries: a list of geometries needed for each item
|
|
377
404
|
"""
|
|
378
405
|
for item, cur_geometries in zip(items, geometries):
|
|
379
|
-
for band in self.
|
|
406
|
+
for band in self.BANDS:
|
|
380
407
|
band_names = [band]
|
|
381
408
|
if tile_store.is_raster_ready(item.name, band_names):
|
|
382
409
|
continue
|
|
@@ -389,147 +416,3 @@ class LandsatOliTirs(DataSource, TileStore):
|
|
|
389
416
|
ExtraArgs={"RequestPayer": "requester"},
|
|
390
417
|
)
|
|
391
418
|
tile_store.write_raster_file(item.name, band_names, UPath(fname))
|
|
392
|
-
|
|
393
|
-
# The functions below are to emulate TileStore functionality so we can easily
|
|
394
|
-
# support materialization directly from the COGs.
|
|
395
|
-
def is_raster_ready(
|
|
396
|
-
self, layer_name: str, item_name: str, bands: list[str]
|
|
397
|
-
) -> bool:
|
|
398
|
-
"""Checks if this raster has been written to the store.
|
|
399
|
-
|
|
400
|
-
Args:
|
|
401
|
-
layer_name: the layer name or alias.
|
|
402
|
-
item_name: the item.
|
|
403
|
-
bands: the list of bands identifying which specific raster to read.
|
|
404
|
-
|
|
405
|
-
Returns:
|
|
406
|
-
whether there is a raster in the store matching the source, item, and
|
|
407
|
-
bands.
|
|
408
|
-
"""
|
|
409
|
-
# Always ready since we access it on AWS bucket.
|
|
410
|
-
return True
|
|
411
|
-
|
|
412
|
-
def get_raster_bands(self, layer_name: str, item_name: str) -> list[list[str]]:
|
|
413
|
-
"""Get the sets of bands that have been stored for the specified item.
|
|
414
|
-
|
|
415
|
-
Args:
|
|
416
|
-
layer_name: the layer name or alias.
|
|
417
|
-
item_name: the item.
|
|
418
|
-
|
|
419
|
-
Returns:
|
|
420
|
-
a list of lists of bands that are in the tile store (with one raster
|
|
421
|
-
stored corresponding to each inner list). If no rasters are ready for
|
|
422
|
-
this item, returns empty list.
|
|
423
|
-
"""
|
|
424
|
-
return [[band] for band in self.bands]
|
|
425
|
-
|
|
426
|
-
def get_raster_bounds(
|
|
427
|
-
self, layer_name: str, item_name: str, bands: list[str], projection: Projection
|
|
428
|
-
) -> PixelBounds:
|
|
429
|
-
"""Get the bounds of the raster in the specified projection.
|
|
430
|
-
|
|
431
|
-
Args:
|
|
432
|
-
layer_name: the layer name or alias.
|
|
433
|
-
item_name: the item to check.
|
|
434
|
-
bands: the list of bands identifying which specific raster to read. These
|
|
435
|
-
bands must match the bands of a stored raster.
|
|
436
|
-
projection: the projection to get the raster's bounds in.
|
|
437
|
-
|
|
438
|
-
Returns:
|
|
439
|
-
the bounds of the raster in the projection.
|
|
440
|
-
"""
|
|
441
|
-
item = self.get_item_by_name(item_name)
|
|
442
|
-
geom = item.geometry.to_projection(projection)
|
|
443
|
-
return (
|
|
444
|
-
int(geom.shp.bounds[0]),
|
|
445
|
-
int(geom.shp.bounds[1]),
|
|
446
|
-
int(geom.shp.bounds[2]),
|
|
447
|
-
int(geom.shp.bounds[3]),
|
|
448
|
-
)
|
|
449
|
-
|
|
450
|
-
def read_raster(
|
|
451
|
-
self,
|
|
452
|
-
layer_name: str,
|
|
453
|
-
item_name: str,
|
|
454
|
-
bands: list[str],
|
|
455
|
-
projection: Projection,
|
|
456
|
-
bounds: PixelBounds,
|
|
457
|
-
resampling: Resampling = Resampling.bilinear,
|
|
458
|
-
) -> npt.NDArray[Any]:
|
|
459
|
-
"""Read raster data from the store.
|
|
460
|
-
|
|
461
|
-
Args:
|
|
462
|
-
layer_name: the layer name or alias.
|
|
463
|
-
item_name: the item to read.
|
|
464
|
-
bands: the list of bands identifying which specific raster to read. These
|
|
465
|
-
bands must match the bands of a stored raster.
|
|
466
|
-
projection: the projection to read in.
|
|
467
|
-
bounds: the bounds to read.
|
|
468
|
-
resampling: the resampling method to use in case reprojection is needed.
|
|
469
|
-
|
|
470
|
-
Returns:
|
|
471
|
-
the raster data
|
|
472
|
-
"""
|
|
473
|
-
# Landsat assets have single band per asset.
|
|
474
|
-
assert len(bands) == 1
|
|
475
|
-
band = bands[0]
|
|
476
|
-
|
|
477
|
-
# Get the item since it has the blob path.
|
|
478
|
-
item = self.get_item_by_name(item_name)
|
|
479
|
-
|
|
480
|
-
# Create pre-signed URL for rasterio access.
|
|
481
|
-
# We do this because accessing via URL is much faster since rasterio can use
|
|
482
|
-
# the URL directly.
|
|
483
|
-
blob_key = item.blob_path + f"{band}.TIF"
|
|
484
|
-
url = self.client.generate_presigned_url(
|
|
485
|
-
"get_object",
|
|
486
|
-
Params={
|
|
487
|
-
"Bucket": self.bucket_name,
|
|
488
|
-
"Key": blob_key,
|
|
489
|
-
"RequestPayer": "requester",
|
|
490
|
-
},
|
|
491
|
-
)
|
|
492
|
-
|
|
493
|
-
# Construct the transform to use for the warped dataset.
|
|
494
|
-
wanted_transform = affine.Affine(
|
|
495
|
-
projection.x_resolution,
|
|
496
|
-
0,
|
|
497
|
-
bounds[0] * projection.x_resolution,
|
|
498
|
-
0,
|
|
499
|
-
projection.y_resolution,
|
|
500
|
-
bounds[1] * projection.y_resolution,
|
|
501
|
-
)
|
|
502
|
-
|
|
503
|
-
with rasterio.open(url) as src:
|
|
504
|
-
with rasterio.vrt.WarpedVRT(
|
|
505
|
-
src,
|
|
506
|
-
crs=projection.crs,
|
|
507
|
-
transform=wanted_transform,
|
|
508
|
-
width=bounds[2] - bounds[0],
|
|
509
|
-
height=bounds[3] - bounds[1],
|
|
510
|
-
resampling=resampling,
|
|
511
|
-
) as vrt:
|
|
512
|
-
return vrt.read()
|
|
513
|
-
|
|
514
|
-
def materialize(
|
|
515
|
-
self,
|
|
516
|
-
window: Window,
|
|
517
|
-
item_groups: list[list[LandsatOliTirsItem]],
|
|
518
|
-
layer_name: str,
|
|
519
|
-
layer_cfg: LayerConfig,
|
|
520
|
-
) -> None:
|
|
521
|
-
"""Materialize data for the window.
|
|
522
|
-
|
|
523
|
-
Args:
|
|
524
|
-
window: the window to materialize
|
|
525
|
-
item_groups: the items from get_items
|
|
526
|
-
layer_name: the name of this layer
|
|
527
|
-
layer_cfg: the config of this layer
|
|
528
|
-
"""
|
|
529
|
-
RasterMaterializer().materialize(
|
|
530
|
-
TileStoreWithLayer(self, layer_name),
|
|
531
|
-
window,
|
|
532
|
-
layer_name,
|
|
533
|
-
layer_cfg,
|
|
534
|
-
item_groups,
|
|
535
|
-
)
|
|
@@ -318,9 +318,8 @@ class Naip(DataSource):
|
|
|
318
318
|
groups.append(cur_groups)
|
|
319
319
|
return groups
|
|
320
320
|
|
|
321
|
-
def deserialize_item(self, serialized_item:
|
|
321
|
+
def deserialize_item(self, serialized_item: dict) -> NaipItem:
|
|
322
322
|
"""Deserializes an item from JSON-decoded data."""
|
|
323
|
-
assert isinstance(serialized_item, dict)
|
|
324
323
|
return NaipItem.deserialize(serialized_item)
|
|
325
324
|
|
|
326
325
|
def ingest(
|
|
@@ -639,9 +638,8 @@ class Sentinel2(
|
|
|
639
638
|
return item
|
|
640
639
|
raise ValueError(f"item {name} not found")
|
|
641
640
|
|
|
642
|
-
def deserialize_item(self, serialized_item:
|
|
641
|
+
def deserialize_item(self, serialized_item: dict) -> Sentinel2Item:
|
|
643
642
|
"""Deserializes an item from JSON-decoded data."""
|
|
644
|
-
assert isinstance(serialized_item, dict)
|
|
645
643
|
return Sentinel2Item.deserialize(serialized_item)
|
|
646
644
|
|
|
647
645
|
def retrieve_item(
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
import tempfile
|
|
5
|
-
from typing import Any
|
|
6
5
|
|
|
7
6
|
import boto3
|
|
8
7
|
from upath import UPath
|
|
@@ -78,9 +77,8 @@ class Sentinel1(DataSource, TileStore):
|
|
|
78
77
|
"""Gets an item by name."""
|
|
79
78
|
return self.sentinel1.get_item_by_name(name)
|
|
80
79
|
|
|
81
|
-
def deserialize_item(self, serialized_item:
|
|
80
|
+
def deserialize_item(self, serialized_item: dict) -> CopernicusItem:
|
|
82
81
|
"""Deserializes an item from JSON-decoded data."""
|
|
83
|
-
assert isinstance(serialized_item, dict)
|
|
84
82
|
return CopernicusItem.deserialize(serialized_item)
|
|
85
83
|
|
|
86
84
|
def ingest(
|
|
@@ -6,23 +6,20 @@ from collections.abc import Callable
|
|
|
6
6
|
from datetime import timedelta
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
9
|
-
import affine
|
|
10
9
|
import numpy as np
|
|
11
10
|
import numpy.typing as npt
|
|
12
11
|
import rasterio
|
|
13
12
|
import requests
|
|
14
|
-
from rasterio.enums import Resampling
|
|
15
13
|
from upath import UPath
|
|
16
14
|
|
|
17
|
-
from rslearn.
|
|
15
|
+
from rslearn.data_sources.direct_materialize_data_source import (
|
|
16
|
+
DirectMaterializeDataSource,
|
|
17
|
+
)
|
|
18
18
|
from rslearn.data_sources.stac import SourceItem, StacDataSource
|
|
19
|
-
from rslearn.dataset import Window
|
|
20
|
-
from rslearn.dataset.manage import RasterMaterializer
|
|
21
19
|
from rslearn.log_utils import get_logger
|
|
22
|
-
from rslearn.tile_stores import
|
|
23
|
-
from rslearn.utils import
|
|
20
|
+
from rslearn.tile_stores import TileStoreWithLayer
|
|
21
|
+
from rslearn.utils import STGeometry
|
|
24
22
|
from rslearn.utils.fsspec import join_upath
|
|
25
|
-
from rslearn.utils.geometry import PixelBounds
|
|
26
23
|
from rslearn.utils.raster_format import get_raster_projection_and_bounds
|
|
27
24
|
|
|
28
25
|
from .data_source import (
|
|
@@ -32,7 +29,7 @@ from .data_source import (
|
|
|
32
29
|
logger = get_logger(__name__)
|
|
33
30
|
|
|
34
31
|
|
|
35
|
-
class Sentinel2(
|
|
32
|
+
class Sentinel2(DirectMaterializeDataSource[SourceItem], StacDataSource):
|
|
36
33
|
"""A data source for Sentinel-2 L2A imagery on AWS from s3://sentinel-cogs.
|
|
37
34
|
|
|
38
35
|
The S3 bucket has COGs so this data source supports direct materialization. It also
|
|
@@ -97,31 +94,36 @@ class Sentinel2(StacDataSource, TileStore):
|
|
|
97
94
|
cache_upath.mkdir(parents=True, exist_ok=True)
|
|
98
95
|
|
|
99
96
|
# Determine which assets we need based on the bands in the layer config.
|
|
100
|
-
|
|
97
|
+
asset_bands: dict[str, list[str]]
|
|
101
98
|
if context.layer_config is not None:
|
|
102
|
-
|
|
99
|
+
asset_bands = {}
|
|
103
100
|
for asset_key, band_names in self.ASSET_BANDS.items():
|
|
104
101
|
# See if the bands provided by this asset intersect with the bands in
|
|
105
102
|
# at least one configured band set.
|
|
106
103
|
for band_set in context.layer_config.band_sets:
|
|
107
104
|
if not set(band_set.bands).intersection(set(band_names)):
|
|
108
105
|
continue
|
|
109
|
-
|
|
106
|
+
asset_bands[asset_key] = band_names
|
|
110
107
|
break
|
|
111
108
|
elif assets is not None:
|
|
112
|
-
|
|
109
|
+
asset_bands = {
|
|
113
110
|
asset_key: self.ASSET_BANDS[asset_key] for asset_key in assets
|
|
114
111
|
}
|
|
115
112
|
else:
|
|
116
|
-
|
|
113
|
+
asset_bands = dict(self.ASSET_BANDS)
|
|
114
|
+
|
|
115
|
+
# Initialize DirectMaterializeDataSource with asset_bands
|
|
116
|
+
DirectMaterializeDataSource.__init__(self, asset_bands=asset_bands)
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
# Initialize StacDataSource
|
|
119
|
+
StacDataSource.__init__(
|
|
120
|
+
self,
|
|
119
121
|
endpoint=self.STAC_ENDPOINT,
|
|
120
122
|
collection_name=self.COLLECTION_NAME,
|
|
121
123
|
query=query,
|
|
122
124
|
sort_by=sort_by,
|
|
123
125
|
sort_ascending=sort_ascending,
|
|
124
|
-
required_assets=list(
|
|
126
|
+
required_assets=list(asset_bands.keys()),
|
|
125
127
|
cache_dir=cache_upath,
|
|
126
128
|
properties_to_record=[self.HARMONIZE_PROPERTY_NAME],
|
|
127
129
|
)
|
|
@@ -129,6 +131,42 @@ class Sentinel2(StacDataSource, TileStore):
|
|
|
129
131
|
self.harmonize = harmonize
|
|
130
132
|
self.timeout = timeout
|
|
131
133
|
|
|
134
|
+
# --- DirectMaterializeDataSource implementation ---
|
|
135
|
+
|
|
136
|
+
def get_asset_url(self, item_name: str, asset_key: str) -> str:
|
|
137
|
+
"""Get the URL to read the asset for the given item and asset key.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
item_name: the name of the item.
|
|
141
|
+
asset_key: the key identifying which asset to get.
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
the URL to read the asset from.
|
|
145
|
+
"""
|
|
146
|
+
item = self.get_item_by_name(item_name)
|
|
147
|
+
return item.asset_urls[asset_key]
|
|
148
|
+
|
|
149
|
+
def get_read_callback(
|
|
150
|
+
self, item_name: str, asset_key: str
|
|
151
|
+
) -> Callable[[npt.NDArray[Any]], npt.NDArray[Any]] | None:
|
|
152
|
+
"""Return a callback to harmonize Sentinel-2 data if needed.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
item_name: the name of the item being read.
|
|
156
|
+
asset_key: the key identifying which asset is being read.
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
A callback function for harmonization, or None if not needed.
|
|
160
|
+
"""
|
|
161
|
+
# Visual bands do not need harmonization.
|
|
162
|
+
if not self.harmonize or asset_key == "visual":
|
|
163
|
+
return None
|
|
164
|
+
|
|
165
|
+
item = self.get_item_by_name(item_name)
|
|
166
|
+
return self._get_harmonize_callback(item)
|
|
167
|
+
|
|
168
|
+
# --- Harmonization helpers ---
|
|
169
|
+
|
|
132
170
|
def _get_harmonize_callback(
|
|
133
171
|
self, item: SourceItem
|
|
134
172
|
) -> Callable[[npt.NDArray], npt.NDArray] | None:
|
|
@@ -223,152 +261,3 @@ class Sentinel2(StacDataSource, TileStore):
|
|
|
223
261
|
item.name,
|
|
224
262
|
asset_key,
|
|
225
263
|
)
|
|
226
|
-
|
|
227
|
-
def is_raster_ready(
|
|
228
|
-
self, layer_name: str, item_name: str, bands: list[str]
|
|
229
|
-
) -> bool:
|
|
230
|
-
"""Checks if this raster has been written to the store.
|
|
231
|
-
|
|
232
|
-
Args:
|
|
233
|
-
layer_name: the layer name or alias.
|
|
234
|
-
item_name: the item.
|
|
235
|
-
bands: the list of bands identifying which specific raster to read.
|
|
236
|
-
|
|
237
|
-
Returns:
|
|
238
|
-
whether there is a raster in the store matching the source, item, and
|
|
239
|
-
bands.
|
|
240
|
-
"""
|
|
241
|
-
# Always ready since we wrap accesses to underlying API.
|
|
242
|
-
return True
|
|
243
|
-
|
|
244
|
-
def get_raster_bands(self, layer_name: str, item_name: str) -> list[list[str]]:
|
|
245
|
-
"""Get the sets of bands that have been stored for the specified item.
|
|
246
|
-
|
|
247
|
-
Args:
|
|
248
|
-
layer_name: the layer name or alias.
|
|
249
|
-
item_name: the item.
|
|
250
|
-
|
|
251
|
-
Returns:
|
|
252
|
-
a list of lists of bands that are in the tile store (with one raster
|
|
253
|
-
stored corresponding to each inner list). If no rasters are ready for
|
|
254
|
-
this item, returns empty list.
|
|
255
|
-
"""
|
|
256
|
-
return list(self.asset_bands.values())
|
|
257
|
-
|
|
258
|
-
def _get_asset_by_band(self, bands: list[str]) -> str:
|
|
259
|
-
"""Get the name of the asset based on the band names."""
|
|
260
|
-
for asset_key, asset_bands in self.asset_bands.items():
|
|
261
|
-
if bands == asset_bands:
|
|
262
|
-
return asset_key
|
|
263
|
-
|
|
264
|
-
raise ValueError(f"no known asset with bands {bands}")
|
|
265
|
-
|
|
266
|
-
def get_raster_bounds(
|
|
267
|
-
self, layer_name: str, item_name: str, bands: list[str], projection: Projection
|
|
268
|
-
) -> PixelBounds:
|
|
269
|
-
"""Get the bounds of the raster in the specified projection.
|
|
270
|
-
|
|
271
|
-
Args:
|
|
272
|
-
layer_name: the layer name or alias.
|
|
273
|
-
item_name: the item to check.
|
|
274
|
-
bands: the list of bands identifying which specific raster to read. These
|
|
275
|
-
bands must match the bands of a stored raster.
|
|
276
|
-
projection: the projection to get the raster's bounds in.
|
|
277
|
-
|
|
278
|
-
Returns:
|
|
279
|
-
the bounds of the raster in the projection.
|
|
280
|
-
"""
|
|
281
|
-
item = self.get_item_by_name(item_name)
|
|
282
|
-
geom = item.geometry.to_projection(projection)
|
|
283
|
-
return (
|
|
284
|
-
int(geom.shp.bounds[0]),
|
|
285
|
-
int(geom.shp.bounds[1]),
|
|
286
|
-
int(geom.shp.bounds[2]),
|
|
287
|
-
int(geom.shp.bounds[3]),
|
|
288
|
-
)
|
|
289
|
-
|
|
290
|
-
def read_raster(
|
|
291
|
-
self,
|
|
292
|
-
layer_name: str,
|
|
293
|
-
item_name: str,
|
|
294
|
-
bands: list[str],
|
|
295
|
-
projection: Projection,
|
|
296
|
-
bounds: PixelBounds,
|
|
297
|
-
resampling: Resampling = Resampling.bilinear,
|
|
298
|
-
) -> npt.NDArray[Any]:
|
|
299
|
-
"""Read raster data from the store.
|
|
300
|
-
|
|
301
|
-
Args:
|
|
302
|
-
layer_name: the layer name or alias.
|
|
303
|
-
item_name: the item to read.
|
|
304
|
-
bands: the list of bands identifying which specific raster to read. These
|
|
305
|
-
bands must match the bands of a stored raster.
|
|
306
|
-
projection: the projection to read in.
|
|
307
|
-
bounds: the bounds to read.
|
|
308
|
-
resampling: the resampling method to use in case reprojection is needed.
|
|
309
|
-
|
|
310
|
-
Returns:
|
|
311
|
-
the raster data
|
|
312
|
-
"""
|
|
313
|
-
asset_key = self._get_asset_by_band(bands)
|
|
314
|
-
item = self.get_item_by_name(item_name)
|
|
315
|
-
asset_url = item.asset_urls[asset_key]
|
|
316
|
-
|
|
317
|
-
# Construct the transform to use for the warped dataset.
|
|
318
|
-
wanted_transform = affine.Affine(
|
|
319
|
-
projection.x_resolution,
|
|
320
|
-
0,
|
|
321
|
-
bounds[0] * projection.x_resolution,
|
|
322
|
-
0,
|
|
323
|
-
projection.y_resolution,
|
|
324
|
-
bounds[1] * projection.y_resolution,
|
|
325
|
-
)
|
|
326
|
-
|
|
327
|
-
# Read from the raster under the specified projection/bounds.
|
|
328
|
-
with rasterio.open(asset_url) as src:
|
|
329
|
-
with rasterio.vrt.WarpedVRT(
|
|
330
|
-
src,
|
|
331
|
-
crs=projection.crs,
|
|
332
|
-
transform=wanted_transform,
|
|
333
|
-
width=bounds[2] - bounds[0],
|
|
334
|
-
height=bounds[3] - bounds[1],
|
|
335
|
-
resampling=resampling,
|
|
336
|
-
) as vrt:
|
|
337
|
-
raw_data = vrt.read()
|
|
338
|
-
|
|
339
|
-
# We can return the data now if harmonization is not needed.
|
|
340
|
-
if not self.harmonize or bands == self.ASSET_BANDS["visual"]:
|
|
341
|
-
return raw_data
|
|
342
|
-
|
|
343
|
-
# Otherwise we apply the harmonize_callback.
|
|
344
|
-
item = self.get_item_by_name(item_name)
|
|
345
|
-
harmonize_callback = self._get_harmonize_callback(item)
|
|
346
|
-
|
|
347
|
-
if harmonize_callback is None:
|
|
348
|
-
return raw_data
|
|
349
|
-
|
|
350
|
-
array = harmonize_callback(raw_data)
|
|
351
|
-
return array
|
|
352
|
-
|
|
353
|
-
def materialize(
|
|
354
|
-
self,
|
|
355
|
-
window: Window,
|
|
356
|
-
item_groups: list[list[SourceItem]],
|
|
357
|
-
layer_name: str,
|
|
358
|
-
layer_cfg: LayerConfig,
|
|
359
|
-
) -> None:
|
|
360
|
-
"""Materialize data for the window.
|
|
361
|
-
|
|
362
|
-
Args:
|
|
363
|
-
window: the window to materialize
|
|
364
|
-
item_groups: the items from get_items
|
|
365
|
-
layer_name: the name of this layer
|
|
366
|
-
layer_cfg: the config of this layer
|
|
367
|
-
"""
|
|
368
|
-
RasterMaterializer().materialize(
|
|
369
|
-
TileStoreWithLayer(self, layer_name),
|
|
370
|
-
window,
|
|
371
|
-
layer_name,
|
|
372
|
-
layer_cfg,
|
|
373
|
-
item_groups,
|
|
374
|
-
)
|