From 3e79e38445b1f72a68830e980705d86ebcf1c67d Mon Sep 17 00:00:00 2001 From: Sirbatiano Date: Sat, 23 Mar 2024 08:26:58 +0000 Subject: [PATCH] test push readme, devcont, installer --- .devcontainer/Dockerfile | 20 ++ .devcontainer/devontainer.json | 22 ++ .devcontainer/docker-compose.yml | 20 ++ README.md | 481 +------------------------------ docs/GLOSSARY.md | 34 +++ pyraws_install.sh | 99 +++---- quickstart/README.md | 386 +++++++++++++++++++++++++ 7 files changed, 536 insertions(+), 526 deletions(-) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devontainer.json create mode 100644 .devcontainer/docker-compose.yml create mode 100644 docs/GLOSSARY.md create mode 100644 quickstart/README.md diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..bd966fe --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,20 @@ +############################################# INSTRUCTIONS ############################################# +# build image: docker build -t pyraws:latest --build-arg CACHEBUST=$(date +%s) -f dockerfile . +# run image: docker run -it --rm -p 8888:8888 pyraws:latest +############################################# END ############################################# + +# Use the official PyTorch base image +FROM pytorch/pytorch:1.11.0-cuda11.3-cudnn8-runtime + +# Set the working directory inside the container +WORKDIR /workspace + +# Install Python dependencies for pyraws: +RUN apt-get update && apt-get install -y git ffmpeg libsm6 libxext6 +# install pyraws + +RUN git clone -b main https://github.com/ESA-PhiLab/PyRawS.git + +RUN cd PyRawS && /bin/bash -c "source ./pyraws_install.sh" +RUN echo "source activate pyraws" > ~/.bashrc +ENV PATH /opt/conda/envs/pyraws/bin:$PATH diff --git a/.devcontainer/devontainer.json b/.devcontainer/devontainer.json new file mode 100644 index 0000000..1d0b2e0 --- /dev/null +++ b/.devcontainer/devontainer.json @@ -0,0 +1,22 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/anaconda + +{ + "name": "pyraws", + "dockerComposeFile": "docker-compose.yml", + "service": "pyraws", + "workspaceFolder": "/workspace", + "settings": { + "terminal.integrated.shell.linux": "/bin/bash" + }, + "extensions": [ + "ms-toolsai.jupyter", + "ms-toolsai.vscode-jupyter-cell-tags", + "ms-toolsai.jupyter-renderers", + "ms-toolsai.vscode-jupyter-powertoys", + "ms-toolsai.vscode-jupyter-slideshow", + "donjayamanne.python-extension-pack" + ], + // Use 'postCreateCommand' to run commands after the container is created. + //"postCreateCommand": "conda install -n simulator ipykernel --update-deps --force-reinstall" +} \ No newline at end of file diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml new file mode 100644 index 0000000..ed03ff0 --- /dev/null +++ b/.devcontainer/docker-compose.yml @@ -0,0 +1,20 @@ +version: "3.8" + +services: + pyraws: + image: pyraws:latest + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: 1 + capabilities: [gpu] + build: + context: . + dockerfile: Dockerfile + volumes: + - ../:/workspace/ + platform: linux/amd64 + + command: sleep infinity \ No newline at end of file diff --git a/README.md b/README.md index 41c782d..3f80b4e 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ ![GitHub pull requests](https://img.shields.io/github/issues-pr/ESA-PhiLab/PyRawS?style=flat-square) [![Tests](https://github.com/ESA-PhiLab/PyRawS/actions/workflows/run_tests.yml/badge.svg)](https://github.com/ESA-PhiLab/PyRawS/actions/workflows/run_tests.yml) +*(Disclaimer: This project is currently under development.)* + # PyRawS ![Alt Text](resources/images/PyRawS_logo.png) ## About the project @@ -15,60 +17,20 @@ The software is demonstrated on the first Sentinel-2 🛰️ Raw database for wa The package is written in Python and is open source💻, making it easy to use and modify for your specific needs. The systme is based on [pytorch]("https://pytorch.org/"), which be installed with `CUDA` support, to enable GPU acceleation. - +> [!IMPORTANT] > NB: What we call raw data in this project are Sentinel-2 data generated by the decompression and metadata addition of Sentinel-2 L0 data. Because of that, with the exception of the effects due to onboard equalization and lossy compression, they are the most similar version of the rawest form of data acquired by the satellite's sensors. Both the compression and equalization are applied onboard the satellite to reduce the amount of data transmitted to the ground station. For easy naming convention, this repo refer to the term "Raw" as the products decompressed with ancillary information appended. For further information browse our paper at https://arxiv.org/abs/2305.11891 -*(Disclaimer: This project is currently under development.)* +> [!NOTE] +> ### YouTube Tutorial ⭐️ +>A demo showcasing PyRawS capabilities is available on the YouTube channel of [Robin Cole](https://www.youtube.com/watch?v=aLe7Pw3DVmo) +>![Alt Text](resources/images/quicklook_yt.png) -### YouTube Tutorial ⭐️ - -A demo showcasing PyRawS capabilities is available on the YouTube channel of [Robin Cole](https://www.youtube.com/watch?v=aLe7Pw3DVmo) - - - -![Alt Text](resources/images/quicklook_yt.png) - - - -# Summary - - -
- Table of Contents -
    -
  1. About the Project
  2. -
  3. Content of the repository
  4. -
  5. Installation - -
  6. PyRawS databases
  7. -
  8. Raw events and Raw granules
  9. -
  10. Quickstart - -
  11. -
  12. Glossary
  13. -
  14. Contributing
  15. -
  16. License
  17. -
  18. Contacts
  19. -
-
-## Sentinel-2 Raw granules and events + +## Where I should I start? +Follow our [Quickstart](quickstart/README.md) section for tutorials and more. + ## Content of the repository The PyRawS repository includes the following directories: @@ -225,6 +187,8 @@ Now, you should be able to use your new database.
> [!TIP] > **N.B** The creation of a database is not mandatory. However, it is strongly advisable. Indeed, without creating a database you can still open `Raw data` as described in [Open a Raw event from path](#open-a-raw-event-from-path). However, some pieces of information such as the [Raw useful granules](#raw-useful-granule) associated to a specific event, the event bounding boxes or the image class can be retrieved only when the database is set-up. +## Sentinel-2 Raw granules and events + ## Raw events and Raw granules ![Alt Text](resources/images/etna_00_granules.png) @@ -233,425 +197,6 @@ since we use the bands [`B8A`, `B11`, `B12`] to detect wildfires and volcanic er Finally, for some [Raw useful granules](#raw-useful-granule) part of the eruptions or the wildfire could extend until the top or the bottom edge of the polygon. In this case, some of the bands could be missing for a portion of the area of interest. To be sure that this is not happening, in addition to the [Raw useful granules](#raw-useful-granule), it is important to consider [Raw complementary granules](#raw-complementary-granule), which fills the missing part of the interest bands of the [Raw useful granules](#raw-useful-granule).
For each [Sentinel-2 Raw event](#Sentinel-2-RAW-event), the `THRAWS` dataset clearly states those [Raw granules](#sentinel-2-raw-granule) that are [Raw useful granules](#raw-useful-granule) or [Raw complementary granules](#raw-complementary-granule). However, the entire [Raw granules](#sentinel-2-raw-granule) collection is provided for each [Raw event](#sentinel-2-raw-event) to permit users that wants to use other bands to detect warm temeprature anomalies to do it. -## Quickstart -The next examples (with the exception of [Open a Raw event from path](#open-a-raw-event-from-path)) will exploit the `THRAWS` database to showcase the use of PyRawS, but they are applicable to any [databases compatible with PyRawS](#PyRawS-databases). - -### Open a Raw event from path -The next code snipped will showcase how to use PyRawS to open a [Raw_event](#sentinel-2-raw-event) `My_Raw_data`, included in the `THRAWS` database by using its `PATH`. We assume to have the `My_RAW_data` directory in the same directory where you execute the code snippet below.
-To manipulate [Raw events](#sentinel-2-raw-event), `PyRawS` offer a class called `Raw_event`. To open an avent, we will use the [Raw_event](#sentinel-2-raw-event) class method `from_path(...)`, which parses the database specified, retrieves the event specified by `id_event` and opens it with the requested bands (`bands_list`). -When you open an event, you can specify which bands to use. If `bands_list` is not specified, the method `from_path(...)` will return all the bands. - -```py -from pyraws.raw.raw_event import Raw_event -#Instantiate an empty Raw_event -raw_event=Raw_event() - -#Bands to open. -bands_list=["B8A", "B11", "B12"] - -#Read "Etna_00" from THRAWS -raw_event.from_path(#Path to the Etna_00 event - raw_dir_path="Path_to_my_RAW_data", - #Bands to open. Leave to None to use all the bands. - bands_list=bands_list, - #If True, verbose mode is on. - verbose=True) -``` -The example above can be used directly, **even if you did not set up a** [PyRawS database](#PyRawS-databases). However, `PyRawS` offer some API to parse directly [Raw_event](#sentinel-2-raw-event) parsing a database. with no need to specify a path. Please, check [Open a Raw event from database](#open-a-raw-event-from-database). - -### Open a Raw event from database -The next code snipped will showcase how to use PyRawS to open the [Raw_event](#sentinel-2-raw-event) `Etna_00` included in the `THRAWS` database.
To do that, -To manipulate [Raw events](#sentinel-2-raw-event) objects, `PyRawS` will exploits the `Raw_event` class method `from_database(...)`, which parses the associated `.csv` file located in `PyRawS/database` with no need to specify the `PATH` from the user. To execute the next code snipped, we assume to you have already downloaded and set-up the `THRAWS` database as specificied in [databases compatible with PyRawS](#PyRawS-databases). -As for the method `from_path(...)` described in [Open a Raw event from path](#open-an-raw-event-from-path), you can specify which bands to use. If `bands_list` is not specified, the method `from_database(...)` will return all the bands. - -```py -from pyraws.raw.raw_event import Raw_event -#Instantiate an empty Raw_event -raw_event=Raw_event() - -#Bands to open. -bands_list=["B8A", "B11", "B12"] - -#Read "Etna_00" from THRAWS -raw_event.from_database(#Database ID_EVENT - id_event="Etna_00", - #Bands to open. Leave to None to use all the bands. - bands_list=bands_list, - #If True, verbose mode is on. - verbose=True, - #Database name - database="THRAWS") -``` -All the next examples will assume you already have downloaded and set-up the `THRAWS` database as specificied in [databases compatible with PyRawS](#PyRawS-databases). However, they can work by using `from_path(...)` instead of `from_database(...)` and specifying the `PATH` to the `Etna_00` event manually. - -### Show Raw granules information of a Raw event -As specified in [Raw events and Raw granules](#raw-events-and-raw-granules), an [Raw event](#sentinel-2-raw-event) is a collection of [Raw granules](#sentinel-2-raw-granule). As for [Raw_event](#sentinel-2-raw-event), [Raw granules](#sentinel-2-raw-granule) are modelled in PyRawS through a dedicated class `Raw_granule`.
-The next code snippet will show how to get the information about the [Raw granules](#sentinel-2-raw-granule) that compose the `Etna_00` [Raw_event](#sentinel-2-raw-event). The class method `show_granules_info()` will print the list of events and some metada for each event. To get the same information as a dictionary `{granule name : granule info}` for an easy manipulation, you can use the `Raw_event` class method `get_granules_info(...)`. - -```py -from pyraws.raw.raw_event import Raw_event -#Instantiate an empty Raw_event -raw_event=Raw_event() - -#Bands to open. -bands_list=["B8A", "B11", "B12"] - -#Read "Etna_00" from THRAWS database. -#You can also read it by using raw_event.from_path(...). -raw_event.from_database( #Database ID_EVENT - id_event="Etna_00", - #Bands to open. Leave to None to use all the bands. - bands_list=bands_list, - #If True, verbose mode is on. - verbose=True, - #Database name - database="THRAWS") -# Printing granules info -raw_event.show_granules_info() - -#Getting Raw granules info dictionary {granule name : granule info} -granules_info_dict=raw_event.get_granules_info() -``` - -### Get a single Raw\_granule from a Raw\_event -The class `Raw_event` contains a list of objects `Raw_granule`, each one modelling a specific [Raw granule](#sentinel-2-raw-granule) that belongs to that [Raw_event](#sentinel-2-raw-event) (please, check [Raw events and Raw granules](#raw-events-and-raw-granules) for more information).
-The different `Raw_granule` objects are sorted alphabetically and are accessible through indices. The next code snippet will show how to get a specific [Raw granule](#sentinel-2-raw-granule) by using the `Raw_event` class method `get_granule(granule_idx)`, where `granule_idx` is the granule indices. The function returns an `Raw_granule` object. As for `Raw_event` objects, it is possible to print or retrieve metadata information for a spefic `Raw_granule` by using the `Raw_granule` methods `get_granule_info()` and `show_granule_info()`. - -```py -from pyraws.raw.raw_event import Raw_event -#Instantiate an empty Raw_event -raw_event=Raw_event() - -#Bands to open. -bands_list=["B8A", "B11", "B12"] - -#Read "Etna_00" from THRAWS database. -#You can also read it by using raw_event.from_path(...). -raw_event.from_database( #Database ID_EVENT - id_event="Etna_00", - #Bands to open. Leave to None to use all the bands. - bands_list=bands_list, - #If True, verbose mode is on. - verbose=True, - #Database name - database="THRAWS") - -#Read the granule 0 of the Etna_00 event. -raw_granule_0 = raw_event.get_granule(0) - -# Printing the info of the granule 0 -raw_granule_0.show_granule_info() - -#Getting Raw granules info dictionary {granule name : granule info} -granule_0_info_dict=raw_granule_0.get_granule_info() -``` - -### Access a Raw\_granule pixels -To visualize the values of an `Raw_data` object, it is possible to return it as a [PyTorch](https://pytorch.org/) tensor. However, since the different bands have different resolutions, depending on the bands that we want to shape as a tensor, it is necessary to upsample/downsample some of them to adapt them to the band with higher/smaller resolution. The next code snippet will open the `Etna_00` with bands `B02` (10 m), `B8A` (20 m), `B11` (20 m), get the granule with index 1, and will return the first two bands in the collection as tensor by performing upsample. - -```py -from pyraws.raw.raw_event import Raw_event -#Instantiate an empty Raw_event -raw_event=Raw_event() - -#Bands to open. -bands_list=["B04", "B8A", "B11"] - -#Read "Etna_00" from THRAWS database. -#You can also read it by using raw_event.from_path(...). -raw_event.from_database( #Database ID_EVENT - id_event="Etna_00", - #Bands to open. Leave to None to use all the bands. - bands_list=bands_list, - #If True, verbose mode is on. - verbose=True, - #Database name - database="THRAWS") - -#Read the granule 1 of the Etna_00 event. -raw_granule_1 = raw_event.get_granule(1) - -#Returning the bands B04 and B8A of raw_granule_1 as tensor by upsampling. -raw_granule_1_tensor=raw_granule_1.as_tensor(#list of bands to transform as tensor - requested_bands=["B04", "B8A"], - #Set to True to perform downsampling (default) - downsampling=False) -``` - -### Superimpose Raw\_granule bands -It is possible to superimpose `Raw_granule` bands by using the class method `show_bands_superimposition(...)`. (N.B. it is possible to superimpose up to three bands). -In case bands have different resolution, you need to specify if you want to superimpose them by performing downsampling (default) or upsampling. The next code snippet will open the `Etna_00` with bands `B02`, `B8A`, `B11`, `B12`, get the granule with index 0, and will superimpose the last three bands. - -```py -from pyraws.raw.raw_event import Raw_event -import matplotlib.pyplot as plt - -#Instantiate an empty Raw_event -raw_event=Raw_event() - -#Bands to open. -bands_list=["B04", "B8A", "B11", "B12"] - -#Read "Etna_00" from THRAWS database. -#You can also read it by using raw_event.from_path(...). -raw_event.from_database( #Database ID_EVENT - id_event="Etna_00", - #Bands to open. Leave to None to use all the bands. - bands_list=bands_list, - #If True, verbose mode is on. - verbose=True, - #Database name - database="THRAWS") - -#Read the granule 0 of the Etna_00 event. -raw_granule_0 = raw_event.get_granule(0) - -#Returning the bands B04 and B8A of raw_granule_1 as tensor by upsampling. -raw_granule_0.show_bands_superimposition(#Bands to superimpose - requested_bands=["B04", "B11", "B12"], - #Set to True to perform downsampling - downsampling=True) -plt.show() -``` - -The previous code snippet will display the image below. As you can see, the various bands of the image lack of coregistration of the various bands. - -![Alt Text](resources/images/granule_superimposition.png) - -### How to perform the coarse coregisteration of Raw\_granules -PyRawS offers some utils to perform [coarse coregistration](#coarse-coregistration) on `Raw_granule` objects. You can coregister a specific `Raw_granule` object of the `Raw_event` collection by calling the `coarse_coregistration(...)` method of the `Raw_event` class by selecting the corresponding index through the `granules_idx` input.
- -```py -from pyraws.raw.raw_event import Raw_event - -#Instantiate an empty Raw_event -raw_event=Raw_event() - -#Bands to open. -bands_list=["B04", "B8A", "B11"] - -#Read "Etna_00" from THRAWS database. -#You can also read it by using raw_event.from_path(...). -raw_event.from_database( #Database ID_EVENT - id_event="Etna_00", - #Bands to open. Leave to None to use all the bands. - bands_list=bands_list, - #If True, verbose mode is on. - verbose=True, - #Database name - database="THRAWS") - -# Perform the corase coregistration of the "Etna_00" event. -# Missing pixels will be filled with zeros. -raw_coreg_granule_2=raw_event.coarse_coregistration( # granule index to coregister. - granules_idx=[2]) -``` - -The previous code snippet returns the coarse coregistration of the granule 2 of the "Etna_00" event. The coarse coregistration is performed by shifting the bands `B8A` and `B11` with respect to the band `B04`, which is the first in the collection. The missing pixels produced by the shift of the bands `B8A` and `B11` will be filled by zeros. The superimposition of the coregistered bands with zero-filling is shown in the image below ("coregistration") -It is possible to launch crop the missing values by setting the argument `crop_empty_pixels=True`, as in the snippet below. - -```py -from pyraws.raw.raw_event import Raw_event - -#Instantiate an empty Raw_event -raw_event=Raw_event() - -#Bands to open. -bands_list=["B04", "B8A", "B11"] - -#Read "Etna_00" from THRAWS database. -#You can also read it by using raw_event.from_path(...). -raw_event.from_database( #Database ID_EVENT - id_event="Etna_00", - #Bands to open. Leave to None to use all the bands. - bands_list=bands_list, - #If True, verbose mode is on. - verbose=True, - #Database name - database="THRAWS") - -# Perform the corase coregistration of the "Etna_00" event. -# Missing pixels will be cropped. -raw_coreg_granule_0_with_crop=raw_event.coarse_coregistration(# granule index to coregister. - granules_idx=[2], - # Cropping missing pixels. - crop_empty_pixels=True) -``` - -Alternatively, you can fill the pixing pixels with filler elements taken from other `Raw_granule` objects when available. This is done by setting the argument `use_complementary_granules=True`. In this case, the compatibility of adjacent `Raw_granule` objects will be checked by the `coarse_coregistration(...)` API and use it in case it is available. -When filling `Raw_granule` objects are not available, missing pixels will be cropped if `crop_empty_pixels` is set to True. The superimposition of the coregistered bands with crop is shown in the image below ("coregistration with crop). - -```py -from pyraws.raw.raw_event import Raw_event - -#Instantiate an empty Raw_event -raw_event=Raw_event() - -#Bands to open. -bands_list=["B04", "B8A", "B11"] - -#Read "Etna_00" from THRAWS database. -#You can also read it by using raw_event.from_path(...). -raw_event.from_database( #Database ID_EVENT - id_event="Etna_00", - #Bands to open. Leave to None to use all the bands. - bands_list=bands_list, - #If True, verbose mode is on. - verbose=True, - #Database name - database="THRAWS") - -# Perform the corase coregistration of the "Etna_00" event. -# Missing pixels will be cropped. -raw_coreg_granule_0_with_fill=raw_event.coarse_coregistration(# granule index to coregister. - granules_idx=[2], - # Search for filling elements - # among adjacent Raw granules - use_complementary_granules=True, - # Cropping missing pixels - # when compatible Raw granules - # are not available - crop_empty_pixels=True) -``` -The superimposition of the coregistered bands with filling elements is shown in the image below ("coregistration with fill). - -![Alt Text](resources/images/coregistration.png) - -### How to get the coordinates of a Raw granule band -It is possible to get coordinates of the vertices of a `Raw_granule` object. Georeferencing is performed by using the information of the bands shift used to perform the [coarse coregistration](#coarse-coregistration) with respect to the band `B02` and by exploiting the coordinates of the [Raw granule](#sentinel-2-raw-granule) footprint (please, refer to [Sentinel-2 Products Specification Document](https://sentinel.esa.int/documents/247904/685211/sentinel-2-products-specification-document)). The code snippet below shows ho to get the information of the differnet bands of an [Raw granule](#sentinel-2-raw-granule). - -```py -from pyraws.raw.raw_event import Raw_event - -#Instantiate an empty Raw_event -raw_event=Raw_event() - -#Bands to open. -bands_list=["B04", "B8A", "B11"] - -#Read "Etna_00" from THRAWS database. -#You can also read it by using raw_event.from_path(...). -raw_event.from_database( #Database ID_EVENT - id_event="Etna_00", - #Bands to open. Leave to None to use all the bands. - bands_list=bands_list, - #If True, verbose mode is on. - verbose=True, - #Database name - database="THRAWS") - -#Read the granule 1 of the Etna_00 event. -raw_granule_1 = raw_event.get_granule(1) - -#Get bands coordinates -bands_coordinates_dict=raw_granule_1.get_bands_coordinates() -``` -The code snipped above returns a `bands_coordinates_dict`, a dictionary structured as `{band_name : [BOTTOM-LEFT(lat, lon), BOTTOM-RIGHT(lat, lon), TOP-RIGHT(lat, lon), TOP-LEFT(lat, lon)]}`. - -### Raw_event: database metadata -This example will show you how to extract database metadata associated to an [Raw event](#sentinel-2-raw-event). To run the next example it is necessary to have set up database how described in [databases compatible with PyRawS](#PyRawS-databases).
-Database metadata include: -* Event class (e.g., `eruption`, `fire`, `not_event`) -* List of [Raw useful granules](#raw-useful-granule) -* {Useful granule : Bounding box} dictionary - -```py -from pyraws.raw.raw_event import Raw_event - -#Instantiate an empty Raw_event -raw_event=Raw_event() - -#Bands to open. -bands_list=["B04", "B8A", "B11"] - -#Read "Etna_00" from THRAWS database. -#raw_event.from_path(...) cannot be used. - -raw_event.from_database( #Database ID_EVENT - id_event="Etna_00", - #Bands to open. Leave to None to use all the bands. - bands_list=bands_list, - #If True, verbose mode is on. - verbose=True, - #Database name - database="THRAWS") - -#Extract event class. -raw_event.get_event_class() - -#Extract indices of Raw useful granules -raw_event.get_useful_granules_idx() - -#Get {Useful granule : Bounding box} dictionary -raw_event.get_bounding_box_dict() -``` -### Export a Raw_granule to TIF -This example will shows how to export an `Raw_granule` to [TIF](https://en.wikipedia.org/wiki/TIFF) files. To this aim, you need to provide the path to a target directory, which will contain a TIF file for each band. - -```py -from pyraws.raw.raw_event import Raw_event - -#Instantiate an empty Raw_event -raw_event=Raw_event() - -#Bands to open. -bands_list=["B04", "B8A", "B11"] - -#Read "Etna_00" from THRAWS database. -#raw_event.from_path(...) cannot be used. - -raw_event.from_database( #Database ID_EVENT - id_event="Etna_00", - #Bands to open. Leave to None to use all the bands. - bands_list=bands_list, - #If True, verbose mode is on. - verbose=True, - #Database name - database="THRAWS") - -#Apply coarse coregistration to the Raw granule with index 0 and return it -raw_granule_0=raw_event.coarse_coregistration([0]) - -#Save folder path -output_tif_folder="raw_target_folder" - -#Export a TIF file for each band. -raw_granule_0.export_to_tif(save_path=output_tif_folder) -``` - -## Glossary -* ### Coarse coregistration - Lightweight spatial coregistration method optimized for onboard-satellite applications. It simply shifts the various bands of a fixed factor that depends only on the bands, the satellite and detector number. - -* ### Sentinel-2 L0 data - Sentinel-2 data at `level-0` (`L0`) are data that are transmitted to Ground from Sentinel-2 satellites. The `L0` format is compressed to diminish downlink bandwidth requirements. For more information, refer to the [Sentinel-2 Products Specification Document](https://sentinel.esa.int/documents/247904/685211/sentinel-2-products-specification-document) - -* ### Sentinel-2 Raw data - In the frame of this project, the [Sentinel-2 Raw](#sentinel-2-raw-data) represents a particular product in the Sentinel-2 processing chain that matches a decompressed version of [Sentinel-2 L0 data](sentinel-2-l0-data) with additional metadata that are produced on ground. Once decompressed, `Sentinel-2 Raw data` are the data available on Ground that better emulate the one produced by Sentinel-2 detectors with the exception of the effects due to compression and onboard equalization, which are not compensated at this stage. Therefore, `Sentinel-2 raw data` are those exploited in this project. For more information, refer to the [Sentinel-2 Products Specification Document](https://sentinel.esa.int/documents/247904/685211/sentinel-2-products-specification-document).
-**N.B**: the nomenclature ```raw data``` and its location in the Sentinel-2 processing chain is specific for this project only. - -* ### Sentinel-2 Raw granule - A `granule` is the image acquired by a Sentinel-2 detector during a single acquisition lasting 3.6 s. Granules are defined at [L0](#sentinel-2-raw-data) level. However, since the processing perfomed on the ground between L0 and raw data does not alter the image content (with the exception of the decompression process) but just provide additional metadata, granules are defined also at [Sentinel-2 Raw](#sentinel-2-raw-data) level. - Given the pushbroom nature of the Sentinel-2 sensor, bands do not look at the same area at [Raw](#sentinel-2-raw-data) level. For more information, refer to the [Sentinel-2 Products Specification Document](https://sentinel.esa.int/documents/247904/685211/sentinel-2-products-specification-document) - -* ### Sentinel-2 Raw event - [Sentinel-2 Raw data](#sentinel-2-raw-data) are produced by decompressing [Sentinel-2 L0 data](sentinel-2-raw-data). To download L0 data, it is necessary to specify one polygon that surrounds a particular area-of-interest. This leads to download all those [Sentinel-2 Raw granules](#sentinel-2-raw-granule) whose reference band intersects the specified polygon. Such collection is a `Raw-event`. Each `Raw-event` matches one of the `ID_event` entry of the database.
- For each `Raw-event`, we do not provide all the collection of [Sentinel-2 Raw granules](#sentinel-2-Raw-granule), but only the set of [Raw data useful granules](#raw-data-useful-granule) and [Raw data complementary granules](#Raw-data-complementary-granule). For an intuitive example, please, check [Raw events and granules](#raw-events-and-raw-granules). - -* ### Sentinel-2 L1C data - The `Level 1-C` (`L1C`) is one format for `Sentinel-2` data. To convert [Sentinel-2 Raw data](#sentinel-2-raw-data) to `L1C` data, numerous processing steps are applied to correct defects, including bands coregistration, ortho-rectification, decompression, noise-suppression and other. For more information, refer to the [Sentinel-2 Products Specification Document](https://sentinel.esa.int/documents/247904/685211/sentinel-2-products-specification-document). - -* ### Sentinel-2 L1C event - Same concept for [Sentinel-2 Raw events](#sentinel-2-raw-event) but applied on [Sentinel-2 L1C data](#sentinel-2-l1c-data). - -* ### Sentinel-2 L1C tile - The `Sentinel-2 L1C tile` is the minimum `L1C` product that can be downloaded. - -* ### Raw complementary granule - Given a certain set of bands of interest `[Bx,By,...,Bz]`, `Raw complementarey granules` are the granules adjacents at [Raw-useful-granules](#raw-useful-granule) that that can be used to fill missing pixels of `[By,...,Bz]` bands due to their coregistration with respecto the band `Bx`. For an intuitive example, please, check [Raw events and granules](#raw-events-and-raw-granules). - -* ### Raw useful granule - Given a certain set of bands of interest `[Bx,By,...,Bz]`, where `Bx` is the first band in the set, an `Raw useful granule` is one of the collection of [Sentinel-2 Raw granules](#sentinel-2-raw-granule) that compose a [Sentinel-2 Raw event](#sentinel-2-raw-event) whose band `Bx` include (or intersects) a certain area of interest (e.g., an eruption or an area covered by a fire). For an intuitive example, please, check [Raw data events and granules](#raw-events-and-raw-granules). ## Contributing The ```PyRawS``` project is open to contributions. To discuss new ideas and applications, please, reach us via email (please, refer to [Contacts](#contacts)). To report a bug or request a new feature, please, open an [issue](https://github.com/ESA-PhiLab/PyRawS/issues) to report a bug or to request a new feature. diff --git a/docs/GLOSSARY.md b/docs/GLOSSARY.md new file mode 100644 index 0000000..95fa5b3 --- /dev/null +++ b/docs/GLOSSARY.md @@ -0,0 +1,34 @@ + +## Glossary +* ### Coarse coregistration + Lightweight spatial coregistration method optimized for onboard-satellite applications. It simply shifts the various bands of a fixed factor that depends only on the bands, the satellite and detector number. + +* ### Sentinel-2 L0 data + Sentinel-2 data at `level-0` (`L0`) are data that are transmitted to Ground from Sentinel-2 satellites. The `L0` format is compressed to diminish downlink bandwidth requirements. For more information, refer to the [Sentinel-2 Products Specification Document](https://sentinel.esa.int/documents/247904/685211/sentinel-2-products-specification-document) + +* ### Sentinel-2 Raw data + In the frame of this project, the [Sentinel-2 Raw](#sentinel-2-raw-data) represents a particular product in the Sentinel-2 processing chain that matches a decompressed version of [Sentinel-2 L0 data](sentinel-2-l0-data) with additional metadata that are produced on ground. Once decompressed, `Sentinel-2 Raw data` are the data available on Ground that better emulate the one produced by Sentinel-2 detectors with the exception of the effects due to compression and onboard equalization, which are not compensated at this stage. Therefore, `Sentinel-2 raw data` are those exploited in this project. For more information, refer to the [Sentinel-2 Products Specification Document](https://sentinel.esa.int/documents/247904/685211/sentinel-2-products-specification-document).
+**N.B**: the nomenclature ```raw data``` and its location in the Sentinel-2 processing chain is specific for this project only. + +* ### Sentinel-2 Raw granule + A `granule` is the image acquired by a Sentinel-2 detector during a single acquisition lasting 3.6 s. Granules are defined at [L0](#sentinel-2-raw-data) level. However, since the processing perfomed on the ground between L0 and raw data does not alter the image content (with the exception of the decompression process) but just provide additional metadata, granules are defined also at [Sentinel-2 Raw](#sentinel-2-raw-data) level. + Given the pushbroom nature of the Sentinel-2 sensor, bands do not look at the same area at [Raw](#sentinel-2-raw-data) level. For more information, refer to the [Sentinel-2 Products Specification Document](https://sentinel.esa.int/documents/247904/685211/sentinel-2-products-specification-document) + +* ### Sentinel-2 Raw event + [Sentinel-2 Raw data](#sentinel-2-raw-data) are produced by decompressing [Sentinel-2 L0 data](sentinel-2-raw-data). To download L0 data, it is necessary to specify one polygon that surrounds a particular area-of-interest. This leads to download all those [Sentinel-2 Raw granules](#sentinel-2-raw-granule) whose reference band intersects the specified polygon. Such collection is a `Raw-event`. Each `Raw-event` matches one of the `ID_event` entry of the database.
+ For each `Raw-event`, we do not provide all the collection of [Sentinel-2 Raw granules](#sentinel-2-Raw-granule), but only the set of [Raw data useful granules](#raw-data-useful-granule) and [Raw data complementary granules](#Raw-data-complementary-granule). For an intuitive example, please, check [Raw events and granules](#raw-events-and-raw-granules). + +* ### Sentinel-2 L1C data + The `Level 1-C` (`L1C`) is one format for `Sentinel-2` data. To convert [Sentinel-2 Raw data](#sentinel-2-raw-data) to `L1C` data, numerous processing steps are applied to correct defects, including bands coregistration, ortho-rectification, decompression, noise-suppression and other. For more information, refer to the [Sentinel-2 Products Specification Document](https://sentinel.esa.int/documents/247904/685211/sentinel-2-products-specification-document). + +* ### Sentinel-2 L1C event + Same concept for [Sentinel-2 Raw events](#sentinel-2-raw-event) but applied on [Sentinel-2 L1C data](#sentinel-2-l1c-data). + +* ### Sentinel-2 L1C tile + The `Sentinel-2 L1C tile` is the minimum `L1C` product that can be downloaded. + +* ### Raw complementary granule + Given a certain set of bands of interest `[Bx,By,...,Bz]`, `Raw complementarey granules` are the granules adjacents at [Raw-useful-granules](#raw-useful-granule) that that can be used to fill missing pixels of `[By,...,Bz]` bands due to their coregistration with respecto the band `Bx`. For an intuitive example, please, check [Raw events and granules](#raw-events-and-raw-granules). + +* ### Raw useful granule + Given a certain set of bands of interest `[Bx,By,...,Bz]`, where `Bx` is the first band in the set, an `Raw useful granule` is one of the collection of [Sentinel-2 Raw granules](#sentinel-2-raw-granule) that compose a [Sentinel-2 Raw event](#sentinel-2-raw-event) whose band `Bx` include (or intersects) a certain area of interest (e.g., an eruption or an area covered by a fire). For an intuitive example, please, check [Raw data events and granules](#raw-events-and-raw-granules). \ No newline at end of file diff --git a/pyraws_install.sh b/pyraws_install.sh index f257f52..f0532db 100644 --- a/pyraws_install.sh +++ b/pyraws_install.sh @@ -9,10 +9,10 @@ then exit 1 fi -# Create a new Conda environment called openmmlab +# Create a new Conda environment called pyraws conda create --name pyraws python=3.9 -y -# Activate the AINavi environment +# Activate the environment source $(conda info --base)/etc/profile.d/conda.sh if conda activate pyraws; then echo "pyraws environment activated" @@ -21,62 +21,45 @@ else exit 1 fi -#!/bin/bash -# Check the operating system and install pytorch accordingly -if [[ "$OSTYPE" == "darwin"* ]]; then - # macOS - echo "Detected macOS" - conda install -y pytorch==1.11.0 torchvision==0.12.0 torchaudio==0.11.0 -c pytorch -elif [[ "$OSTYPE" == "linux-gnu" ]]; then - # Linux - echo "Detected Linux" - if command -v nvcc >/dev/null 2>&1; then - # CUDA is available - if nvcc --version | grep "release 10\.2" >/dev/null 2>&1; then - # CUDA 10.2 - echo "Detected CUDA 10.2" - conda install -y pytorch==1.11.0 torchvision==0.12.0 torchaudio==0.11.0 cudatoolkit=10.2 -c pytorch - elif nvcc --version | grep "release 11\.3" >/dev/null 2>&1; then - # CUDA 11.3 - echo "Detected CUDA 11.3" - conda install -y pytorch==1.11.0 torchvision==0.12.0 torchaudio==0.11.0 cudatoolkit=11.3 -c pytorch - else - # CUDA version not supported, installing CPU version - echo "CUDA version not supported, installing CPU version" - conda install -y pytorch==1.11.0 torchvision==0.12.0 torchaudio==0.11.0 cpuonly -c pytorch - fi - else - # CUDA is not available, installing CPU version - echo "CUDA not detected, installing CPU version" - conda install -y pytorch==1.11.0 torchvision==0.12.0 torchaudio==0.11.0 cpuonly -c pytorch - fi -elif [[ "$OSTYPE" == "msys" ]]; then - # Windows - echo "Detected Windows" - if where nvcc >/dev/null 2>&1; then - # CUDA is available - if nvcc --version | grep "release 10\.2" >/dev/null 2>&1; then - # CUDA 10.2 - echo "Detected CUDA 10.2" - conda install -y pytorch==1.11.0 torchvision==0.12.0 torchaudio==0.11.0 cudatoolkit=10.2 -c pytorch - elif nvcc --version | grep "release 11\.3" >/dev/null 2>&1; then - # CUDA 11.3 - echo "Detected CUDA 11.3" - conda install -y pytorch==1.11.0 torchvision==0.12.0 torchaudio==0.11.0 cudatoolkit=11.3 -c pytorch - else - # CUDA version not supported, installing CPU version - echo "CUDA version not supported, installing CPU version" - conda install -y pytorch==1.11.0 torchvision==0.12.0 torchaudio==0.11.0 cpuonly -c pytorch - fi - else - # CUDA is not available, installing CPU version - echo "CUDA not detected, installing CPU version" - conda install -y pytorch==1.11.0 torchvision==0.12.0 torchaudio==0.11.0 cpuonly -c pytorch - fi -else - echo "Unsupported operating system" - exit 1 -fi + +# Define PyTorch version and components +pytorch_version="1.11.0" +torchvision_version="0.12.0" +torchaudio_version="0.11.0" + +# Function to install PyTorch +install_pytorch() { + conda install -y pytorch==$pytorch_version torchvision==$torchvision_version torchaudio==$torchaudio_version $1 -c pytorch +} + +# Install via pip: +# pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 torchaudio==0.12.1 --extra-index-url https://download.pytorch.org/whl/cu113 + +# Detect operating system +case "$OSTYPE" in + "darwin"*) + # macOS + echo "Detected macOS" + install_pytorch "cpuonly" + ;; + "linux-gnu"|"linux-gnueabihf") + # Linux + echo "Detected Linux" + # Install PyTorch with CUDA 11.3 support + install_pytorch "cudatoolkit=11.3" + ;; + "msys"|"win32") + # Windows + echo "Detected Windows" + # Install PyTorch with CUDA 11.3 support + install_pytorch "cudatoolkit=11.3" + ;; + *) + echo "Unsupported operating system" + exit 1 + ;; +esac + # get absolute path of current working directory # and setup the sys_cfg.py file diff --git a/quickstart/README.md b/quickstart/README.md new file mode 100644 index 0000000..a4504e1 --- /dev/null +++ b/quickstart/README.md @@ -0,0 +1,386 @@ + +# Quickstart +The next examples (with the exception of [Open a Raw event from path](#open-a-raw-event-from-path)) will exploit the `THRAWS` database to showcase the use of PyRawS, but they are applicable to any [databases compatible with PyRawS](#PyRawS-databases). + +### Open a Raw event from path +The next code snipped will showcase how to use PyRawS to open a [Raw_event](#sentinel-2-raw-event) `My_Raw_data`, included in the `THRAWS` database by using its `PATH`. We assume to have the `My_RAW_data` directory in the same directory where you execute the code snippet below.
+To manipulate [Raw events](#sentinel-2-raw-event), `PyRawS` offer a class called `Raw_event`. To open an avent, we will use the [Raw_event](#sentinel-2-raw-event) class method `from_path(...)`, which parses the database specified, retrieves the event specified by `id_event` and opens it with the requested bands (`bands_list`). +When you open an event, you can specify which bands to use. If `bands_list` is not specified, the method `from_path(...)` will return all the bands. + +```py +from pyraws.raw.raw_event import Raw_event +#Instantiate an empty Raw_event +raw_event=Raw_event() + +#Bands to open. +bands_list=["B8A", "B11", "B12"] + +#Read "Etna_00" from THRAWS +raw_event.from_path(#Path to the Etna_00 event + raw_dir_path="Path_to_my_RAW_data", + #Bands to open. Leave to None to use all the bands. + bands_list=bands_list, + #If True, verbose mode is on. + verbose=True) +``` +The example above can be used directly, **even if you did not set up a** [PyRawS database](#PyRawS-databases). However, `PyRawS` offer some API to parse directly [Raw_event](#sentinel-2-raw-event) parsing a database. with no need to specify a path. Please, check [Open a Raw event from database](#open-a-raw-event-from-database). + +### Open a Raw event from database +The next code snipped will showcase how to use PyRawS to open the [Raw_event](#sentinel-2-raw-event) `Etna_00` included in the `THRAWS` database.
To do that, +To manipulate [Raw events](#sentinel-2-raw-event) objects, `PyRawS` will exploits the `Raw_event` class method `from_database(...)`, which parses the associated `.csv` file located in `PyRawS/database` with no need to specify the `PATH` from the user. To execute the next code snipped, we assume to you have already downloaded and set-up the `THRAWS` database as specificied in [databases compatible with PyRawS](#PyRawS-databases). +As for the method `from_path(...)` described in [Open a Raw event from path](#open-an-raw-event-from-path), you can specify which bands to use. If `bands_list` is not specified, the method `from_database(...)` will return all the bands. + +```py +from pyraws.raw.raw_event import Raw_event +#Instantiate an empty Raw_event +raw_event=Raw_event() + +#Bands to open. +bands_list=["B8A", "B11", "B12"] + +#Read "Etna_00" from THRAWS +raw_event.from_database(#Database ID_EVENT + id_event="Etna_00", + #Bands to open. Leave to None to use all the bands. + bands_list=bands_list, + #If True, verbose mode is on. + verbose=True, + #Database name + database="THRAWS") +``` +All the next examples will assume you already have downloaded and set-up the `THRAWS` database as specificied in [databases compatible with PyRawS](#PyRawS-databases). However, they can work by using `from_path(...)` instead of `from_database(...)` and specifying the `PATH` to the `Etna_00` event manually. + +### Show Raw granules information of a Raw event +As specified in [Raw events and Raw granules](#raw-events-and-raw-granules), an [Raw event](#sentinel-2-raw-event) is a collection of [Raw granules](#sentinel-2-raw-granule). As for [Raw_event](#sentinel-2-raw-event), [Raw granules](#sentinel-2-raw-granule) are modelled in PyRawS through a dedicated class `Raw_granule`.
+The next code snippet will show how to get the information about the [Raw granules](#sentinel-2-raw-granule) that compose the `Etna_00` [Raw_event](#sentinel-2-raw-event). The class method `show_granules_info()` will print the list of events and some metada for each event. To get the same information as a dictionary `{granule name : granule info}` for an easy manipulation, you can use the `Raw_event` class method `get_granules_info(...)`. + +```py +from pyraws.raw.raw_event import Raw_event +#Instantiate an empty Raw_event +raw_event=Raw_event() + +#Bands to open. +bands_list=["B8A", "B11", "B12"] + +#Read "Etna_00" from THRAWS database. +#You can also read it by using raw_event.from_path(...). +raw_event.from_database( #Database ID_EVENT + id_event="Etna_00", + #Bands to open. Leave to None to use all the bands. + bands_list=bands_list, + #If True, verbose mode is on. + verbose=True, + #Database name + database="THRAWS") +# Printing granules info +raw_event.show_granules_info() + +#Getting Raw granules info dictionary {granule name : granule info} +granules_info_dict=raw_event.get_granules_info() +``` + +### Get a single Raw\_granule from a Raw\_event +The class `Raw_event` contains a list of objects `Raw_granule`, each one modelling a specific [Raw granule](#sentinel-2-raw-granule) that belongs to that [Raw_event](#sentinel-2-raw-event) (please, check [Raw events and Raw granules](#raw-events-and-raw-granules) for more information).
+The different `Raw_granule` objects are sorted alphabetically and are accessible through indices. The next code snippet will show how to get a specific [Raw granule](#sentinel-2-raw-granule) by using the `Raw_event` class method `get_granule(granule_idx)`, where `granule_idx` is the granule indices. The function returns an `Raw_granule` object. As for `Raw_event` objects, it is possible to print or retrieve metadata information for a spefic `Raw_granule` by using the `Raw_granule` methods `get_granule_info()` and `show_granule_info()`. + +```py +from pyraws.raw.raw_event import Raw_event +#Instantiate an empty Raw_event +raw_event=Raw_event() + +#Bands to open. +bands_list=["B8A", "B11", "B12"] + +#Read "Etna_00" from THRAWS database. +#You can also read it by using raw_event.from_path(...). +raw_event.from_database( #Database ID_EVENT + id_event="Etna_00", + #Bands to open. Leave to None to use all the bands. + bands_list=bands_list, + #If True, verbose mode is on. + verbose=True, + #Database name + database="THRAWS") + +#Read the granule 0 of the Etna_00 event. +raw_granule_0 = raw_event.get_granule(0) + +# Printing the info of the granule 0 +raw_granule_0.show_granule_info() + +#Getting Raw granules info dictionary {granule name : granule info} +granule_0_info_dict=raw_granule_0.get_granule_info() +``` + +### Access a Raw\_granule pixels +To visualize the values of an `Raw_data` object, it is possible to return it as a [PyTorch](https://pytorch.org/) tensor. However, since the different bands have different resolutions, depending on the bands that we want to shape as a tensor, it is necessary to upsample/downsample some of them to adapt them to the band with higher/smaller resolution. The next code snippet will open the `Etna_00` with bands `B02` (10 m), `B8A` (20 m), `B11` (20 m), get the granule with index 1, and will return the first two bands in the collection as tensor by performing upsample. + +```py +from pyraws.raw.raw_event import Raw_event +#Instantiate an empty Raw_event +raw_event=Raw_event() + +#Bands to open. +bands_list=["B04", "B8A", "B11"] + +#Read "Etna_00" from THRAWS database. +#You can also read it by using raw_event.from_path(...). +raw_event.from_database( #Database ID_EVENT + id_event="Etna_00", + #Bands to open. Leave to None to use all the bands. + bands_list=bands_list, + #If True, verbose mode is on. + verbose=True, + #Database name + database="THRAWS") + +#Read the granule 1 of the Etna_00 event. +raw_granule_1 = raw_event.get_granule(1) + +#Returning the bands B04 and B8A of raw_granule_1 as tensor by upsampling. +raw_granule_1_tensor=raw_granule_1.as_tensor(#list of bands to transform as tensor + requested_bands=["B04", "B8A"], + #Set to True to perform downsampling (default) + downsampling=False) +``` + +### Superimpose Raw\_granule bands +It is possible to superimpose `Raw_granule` bands by using the class method `show_bands_superimposition(...)`. (N.B. it is possible to superimpose up to three bands). +In case bands have different resolution, you need to specify if you want to superimpose them by performing downsampling (default) or upsampling. The next code snippet will open the `Etna_00` with bands `B02`, `B8A`, `B11`, `B12`, get the granule with index 0, and will superimpose the last three bands. + +```py +from pyraws.raw.raw_event import Raw_event +import matplotlib.pyplot as plt + +#Instantiate an empty Raw_event +raw_event=Raw_event() + +#Bands to open. +bands_list=["B04", "B8A", "B11", "B12"] + +#Read "Etna_00" from THRAWS database. +#You can also read it by using raw_event.from_path(...). +raw_event.from_database( #Database ID_EVENT + id_event="Etna_00", + #Bands to open. Leave to None to use all the bands. + bands_list=bands_list, + #If True, verbose mode is on. + verbose=True, + #Database name + database="THRAWS") + +#Read the granule 0 of the Etna_00 event. +raw_granule_0 = raw_event.get_granule(0) + +#Returning the bands B04 and B8A of raw_granule_1 as tensor by upsampling. +raw_granule_0.show_bands_superimposition(#Bands to superimpose + requested_bands=["B04", "B11", "B12"], + #Set to True to perform downsampling + downsampling=True) +plt.show() +``` + +The previous code snippet will display the image below. As you can see, the various bands of the image lack of coregistration of the various bands. + +![Alt Text](resources/images/granule_superimposition.png) + +### How to perform the coarse coregisteration of Raw\_granules +PyRawS offers some utils to perform [coarse coregistration](#coarse-coregistration) on `Raw_granule` objects. You can coregister a specific `Raw_granule` object of the `Raw_event` collection by calling the `coarse_coregistration(...)` method of the `Raw_event` class by selecting the corresponding index through the `granules_idx` input.
+ +```py +from pyraws.raw.raw_event import Raw_event + +#Instantiate an empty Raw_event +raw_event=Raw_event() + +#Bands to open. +bands_list=["B04", "B8A", "B11"] + +#Read "Etna_00" from THRAWS database. +#You can also read it by using raw_event.from_path(...). +raw_event.from_database( #Database ID_EVENT + id_event="Etna_00", + #Bands to open. Leave to None to use all the bands. + bands_list=bands_list, + #If True, verbose mode is on. + verbose=True, + #Database name + database="THRAWS") + +# Perform the corase coregistration of the "Etna_00" event. +# Missing pixels will be filled with zeros. +raw_coreg_granule_2=raw_event.coarse_coregistration( # granule index to coregister. + granules_idx=[2]) +``` + +The previous code snippet returns the coarse coregistration of the granule 2 of the "Etna_00" event. The coarse coregistration is performed by shifting the bands `B8A` and `B11` with respect to the band `B04`, which is the first in the collection. The missing pixels produced by the shift of the bands `B8A` and `B11` will be filled by zeros. The superimposition of the coregistered bands with zero-filling is shown in the image below ("coregistration") +It is possible to launch crop the missing values by setting the argument `crop_empty_pixels=True`, as in the snippet below. + +```py +from pyraws.raw.raw_event import Raw_event + +#Instantiate an empty Raw_event +raw_event=Raw_event() + +#Bands to open. +bands_list=["B04", "B8A", "B11"] + +#Read "Etna_00" from THRAWS database. +#You can also read it by using raw_event.from_path(...). +raw_event.from_database( #Database ID_EVENT + id_event="Etna_00", + #Bands to open. Leave to None to use all the bands. + bands_list=bands_list, + #If True, verbose mode is on. + verbose=True, + #Database name + database="THRAWS") + +# Perform the corase coregistration of the "Etna_00" event. +# Missing pixels will be cropped. +raw_coreg_granule_0_with_crop=raw_event.coarse_coregistration(# granule index to coregister. + granules_idx=[2], + # Cropping missing pixels. + crop_empty_pixels=True) +``` + +Alternatively, you can fill the pixing pixels with filler elements taken from other `Raw_granule` objects when available. This is done by setting the argument `use_complementary_granules=True`. In this case, the compatibility of adjacent `Raw_granule` objects will be checked by the `coarse_coregistration(...)` API and use it in case it is available. +When filling `Raw_granule` objects are not available, missing pixels will be cropped if `crop_empty_pixels` is set to True. The superimposition of the coregistered bands with crop is shown in the image below ("coregistration with crop). + +```py +from pyraws.raw.raw_event import Raw_event + +#Instantiate an empty Raw_event +raw_event=Raw_event() + +#Bands to open. +bands_list=["B04", "B8A", "B11"] + +#Read "Etna_00" from THRAWS database. +#You can also read it by using raw_event.from_path(...). +raw_event.from_database( #Database ID_EVENT + id_event="Etna_00", + #Bands to open. Leave to None to use all the bands. + bands_list=bands_list, + #If True, verbose mode is on. + verbose=True, + #Database name + database="THRAWS") + +# Perform the corase coregistration of the "Etna_00" event. +# Missing pixels will be cropped. +raw_coreg_granule_0_with_fill=raw_event.coarse_coregistration(# granule index to coregister. + granules_idx=[2], + # Search for filling elements + # among adjacent Raw granules + use_complementary_granules=True, + # Cropping missing pixels + # when compatible Raw granules + # are not available + crop_empty_pixels=True) +``` +The superimposition of the coregistered bands with filling elements is shown in the image below ("coregistration with fill). + +![Alt Text](resources/images/coregistration.png) + +### How to get the coordinates of a Raw granule band +It is possible to get coordinates of the vertices of a `Raw_granule` object. Georeferencing is performed by using the information of the bands shift used to perform the [coarse coregistration](#coarse-coregistration) with respect to the band `B02` and by exploiting the coordinates of the [Raw granule](#sentinel-2-raw-granule) footprint (please, refer to [Sentinel-2 Products Specification Document](https://sentinel.esa.int/documents/247904/685211/sentinel-2-products-specification-document)). The code snippet below shows ho to get the information of the differnet bands of an [Raw granule](#sentinel-2-raw-granule). + +```py +from pyraws.raw.raw_event import Raw_event + +#Instantiate an empty Raw_event +raw_event=Raw_event() + +#Bands to open. +bands_list=["B04", "B8A", "B11"] + +#Read "Etna_00" from THRAWS database. +#You can also read it by using raw_event.from_path(...). +raw_event.from_database( #Database ID_EVENT + id_event="Etna_00", + #Bands to open. Leave to None to use all the bands. + bands_list=bands_list, + #If True, verbose mode is on. + verbose=True, + #Database name + database="THRAWS") + +#Read the granule 1 of the Etna_00 event. +raw_granule_1 = raw_event.get_granule(1) + +#Get bands coordinates +bands_coordinates_dict=raw_granule_1.get_bands_coordinates() +``` +The code snipped above returns a `bands_coordinates_dict`, a dictionary structured as `{band_name : [BOTTOM-LEFT(lat, lon), BOTTOM-RIGHT(lat, lon), TOP-RIGHT(lat, lon), TOP-LEFT(lat, lon)]}`. + +### Raw_event: database metadata +This example will show you how to extract database metadata associated to an [Raw event](#sentinel-2-raw-event). To run the next example it is necessary to have set up database how described in [databases compatible with PyRawS](#PyRawS-databases).
+Database metadata include: +* Event class (e.g., `eruption`, `fire`, `not_event`) +* List of [Raw useful granules](#raw-useful-granule) +* {Useful granule : Bounding box} dictionary + +```py +from pyraws.raw.raw_event import Raw_event + +#Instantiate an empty Raw_event +raw_event=Raw_event() + +#Bands to open. +bands_list=["B04", "B8A", "B11"] + +#Read "Etna_00" from THRAWS database. +#raw_event.from_path(...) cannot be used. + +raw_event.from_database( #Database ID_EVENT + id_event="Etna_00", + #Bands to open. Leave to None to use all the bands. + bands_list=bands_list, + #If True, verbose mode is on. + verbose=True, + #Database name + database="THRAWS") + +#Extract event class. +raw_event.get_event_class() + +#Extract indices of Raw useful granules +raw_event.get_useful_granules_idx() + +#Get {Useful granule : Bounding box} dictionary +raw_event.get_bounding_box_dict() +``` +### Export a Raw_granule to TIF +This example will shows how to export an `Raw_granule` to [TIF](https://en.wikipedia.org/wiki/TIFF) files. To this aim, you need to provide the path to a target directory, which will contain a TIF file for each band. + +```py +from pyraws.raw.raw_event import Raw_event + +#Instantiate an empty Raw_event +raw_event=Raw_event() + +#Bands to open. +bands_list=["B04", "B8A", "B11"] + +#Read "Etna_00" from THRAWS database. +#raw_event.from_path(...) cannot be used. + +raw_event.from_database( #Database ID_EVENT + id_event="Etna_00", + #Bands to open. Leave to None to use all the bands. + bands_list=bands_list, + #If True, verbose mode is on. + verbose=True, + #Database name + database="THRAWS") + +#Apply coarse coregistration to the Raw granule with index 0 and return it +raw_granule_0=raw_event.coarse_coregistration([0]) + +#Save folder path +output_tif_folder="raw_target_folder" + +#Export a TIF file for each band. +raw_granule_0.export_to_tif(save_path=output_tif_folder) +```