From 74e323eda225ff6a715e72abfa51e96d28d0f8c2 Mon Sep 17 00:00:00 2001 From: Remi Cresson <remi.cresson@irstea.fr> Date: Tue, 17 May 2022 14:56:20 +0200 Subject: [PATCH] DOC: update doc --- mkdocs.yml | 7 +-- scenes/dates.py | 9 ++-- scenes/deepnets.py | 6 +-- scenes/download.py | 17 ++++--- scenes/indexation.py | 17 ++++--- scenes/sentinel.py | 107 +++++++++++++++++++++++++++++++++++++------ scenes/spot.py | 71 ++++++++++++++++++++++++---- 7 files changed, 182 insertions(+), 52 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index 8d63f45..cc806fd 100755 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -2,7 +2,7 @@ theme: name: "material" icon: - repo: material/github + repo: fontawesome/brands/gitlab features: - content.code.annotate - navigation.tabs @@ -30,7 +30,7 @@ extra: feature: tabs: true social: - - icon: material/gitlab + - icon: fontawesome/brands/gitlab link: https://gitlab.irstea.fr/umr-tetis/scenes markdown_extensions: @@ -50,5 +50,6 @@ markdown_extensions: # rest of the navigation.. site_name: Scenes - +repo_url: https://gitlab.irstea.fr/umr-tetis/scenes +repo_name: umr-tetis/scenes docs_dir: doc/ diff --git a/scenes/dates.py b/scenes/dates.py index 0e2fe86..c65972c 100644 --- a/scenes/dates.py +++ b/scenes/dates.py @@ -5,12 +5,11 @@ This module aims to deal with dates. --- The `datetime.datetime` class is used as internal date type. -``` -#!python +``` py dt = datetime.datetime(year=2020, month=12, day=2) ``` Is equivalent to: -``` +``` py dt = str2datetime("02-12-2020") dt = str2datetime("2020-12-02") dt = str2datetime("02/12/2020") @@ -18,7 +17,7 @@ dt = str2datetime("02/12/2020") The `any2datetime` method returns a `datetime.datetime` instance, whatever the input is (`str` or `datetime.datetime`). -``` +``` py dt1 = datetime.datetime(year=2020, month=12, day=2) dt2 = str2datetime("02-12-2020") dt1_2 = any2datetime(dt1) # same @@ -26,7 +25,7 @@ dt2_2 = any2datetime("02-12-2020") # same ``` The `get_timestamp` method converts a `datetime.datetime` instance into a number of seconds (int). -``` +``` py ts = get_timestamp(dt) # 1606780800.0 ``` """ diff --git a/scenes/deepnets.py b/scenes/deepnets.py index eabfc8a..ee02abf 100644 --- a/scenes/deepnets.py +++ b/scenes/deepnets.py @@ -1,17 +1,17 @@ """ + This module provides tools to easily interact with deep learning models. OTBTF is needed to use this module. --- -# Super-resolution +## Super-resolution The SR4RS model can be applied over any `scenes.core.Source` instance. We recall that this model is intended to be used over Sentinel-2 optical images. For example, here is how we perform the super-resolution of a Theia S2 product. -``` -#!python +``` py import scenes archive = "SENTINEL2B_..._T31TEJ_D_V1-8.zip" s2_scene = scenes.sentinel.Sentinel22AScene(archive) diff --git a/scenes/download.py b/scenes/download.py index 89f74e4..5bf9f3f 100644 --- a/scenes/download.py +++ b/scenes/download.py @@ -14,45 +14,44 @@ password_theia = thisisnotmyrealpassword ``` To instantiate the `scenes.download.TheiaDownloader`: -``` -#!python +``` py import scenes cfg_file = "config.txt" # Theia config file theia = scenes.download.TheiaDownloader(cfg_file) ``` -# Bounding box + temporal range +## Bounding box + temporal range The following example shows how to use the `scenes.download.TheiaDownloader` to search or download all Sentinel-2 images in a bounding box within a temporal range. -## Search +### Search When the `download_dir` is not set, the download is not performed, and only the search results are returned from the function. -``` +``` py bbox = scenes.spatial.BoundingBox(43.706, 43.708, 4.317, 4.420) trange = ("01/01/2020", "O1/O1/2022") results = theia.download_in_range(bbox, trange, level="LEVEL2A") print(results) ``` -## Download +### Download To download the files, the `download_dir` must be specified: -``` +``` py theia.download_in_range(bbox, trange, "/tmp/download/", "LEVEL2A") ``` When files already exist, the md5sum is computed and compared with the one in the catalog, in order to determine if it has to be downloaded again. If the file is already downloaded and is complete according to the md5sum, its download is skipped. -# Bounding box + single date +## Bounding box + single date In the same manner, the downloader can search or download the closest images from a specific date. The returned dict from the function is updated with a "delta" key storing the value of the number of days from the specific date. -``` +``` py # For searching only results = theia.download_in_range(bbox, trange, "LEVEL2A") diff --git a/scenes/indexation.py b/scenes/indexation.py index c656e84..ebfc76d 100644 --- a/scenes/indexation.py +++ b/scenes/indexation.py @@ -7,37 +7,36 @@ The `scenes.indexation.Index` uses an R-Tree to perform the indexation of object Example: spatio-temporal indexation of multiple `scenes.core.Scene` instances. -# Build a spatio temporal index +## Build a spatio temporal index -``` -#!python +``` py import scenes scenes_list = [...] # a list of various `scenes.core.Scene` instances. index = scenes.indexation.Index(scenes_list) # build the index ``` -# Search from a `BoundingBox` +## Search from a `BoundingBox` The `find_indices()` method returns the indices of the indexed `scenes.core.Scene` instances matching the query. The `find()` method returns the indexed `scenes.core.Scene` instances matching the query. -``` +``` py bbox = BoundingBox(43.706, 43.708, 4.317, 4.420) indices_results = index.find_indices(bbox) # spatial query returning scenes indices scenes_results = index.find(bbox) # spatial query returning scenes instances ``` -# Spatio-temporal search +## Spatio-temporal search A date min and/or a date max can be added in the query. -``` +``` py scenes_results = index.find(bbox, "01/01/2020" "01/01/2022") ``` -# Search from a vector data file +## Search from a vector data file The search can also be performed with a vector data file. -``` +``` py vec = "/path/to/vector.gpkg" scenes_results = index.find(vec, "01/01/2020" "01/01/2022") ``` diff --git a/scenes/sentinel.py b/scenes/sentinel.py index 5e266cf..8194aab 100644 --- a/scenes/sentinel.py +++ b/scenes/sentinel.py @@ -3,34 +3,115 @@ This module contains Sentinel-2 classes (sources and scenes). Right now everything is ready to use THEIA L2A and L3A products. -# Scene +## `Scene` based classes The `Sentinel22AScene` and `Sentinel23AScene` classes carry metadata and sources respectively for Sentinel-2 Level 2A and Level 3A products. They both inherit from -the generic abstract `Sentinel2SceneBase` class. +the generic abstract `Sentinel2SceneBase` class, which itself inherits from `Scene`. + +``` mermaid +classDiagram + + Scene <|-- Sentinel2SceneBase + Sentinel2SceneBase <|-- Sentinel22AScene + Sentinel2SceneBase <|-- Sentinel23AScene + + class Scene{ + +datetime acquisition_date + +int epsg + +bbox_wgs84 + +get_metadata() + +__repr__() + } + + class Sentinel2SceneBase{ + +__init__(archive, tag) + +get_file() + +get_band() + +get_metadata() + +Sentinel2Source get_10m_bands() + +Sentinel2Source get_20m_bands() + + } + + class Sentinel22AScene{ + +__init__(archive) + +str clm_r1_msk_file + +str clm_r2_msk_file + +str edg_r1_msk_file + +str edg_r2_msk_file + +get_metadata() + } + + class Sentinel23AScene{ + +__init__(archive) + +str flg_r1_msk_file + +str flg_r2_msk_file + +get_metadata() + } +``` -## Instantiation +### Instantiation `Sentinel22AScene` and `Sentinel23AScene` are instantiated from the archive (.zip file) or the product folder. -``` -#!python +``` py import scenes sc_2a = scenes.sentinel.Sentinel22AScene("SENTINEL2B_..._T31TEJ_D_V1-8.zip") sc_3a = scenes.sentinel.Sentinel23AScene("SENTINEL2X_...L3A_T31TEJ_D_V1-0.zip") ``` -## Metadata +### Metadata The scene metadata can be accessed with the `get_metadata()` method, like any `scenes.core.Scene` instance. -``` +``` py md_dict = sc_2a.get_metadata() for key, value in md_dict.items(): print(f"{key}: {value}") ``` -## Sources +## `Source` based classes + +The `Sentinel22ASource` and `Sentinel23ASource` classes carry imagery sources +respectively for Sentinel-2 Level 2A and Level 3A products. They both inherit from +the generic `Sentinel2Source` class, which itself inherits from `Source`. + +``` mermaid +classDiagram + + Source <|-- Sentinel2Source + Sentinel2Source <|-- Sentinel22ASource + Sentinel2Source <|-- Sentinel23ASource + + class Source{ + +__init__(root_scene, out, parent=None) + +Scene root_scene + +Source parent + +Source drilled(msk_vec_file, nodata=0) + +Source cld_msk_drilled(nodata=0) + +Source resample_over(ref_img, interpolator="nn", nodata=0) + +Source clip_over_img(ref_img) + +Source clip_over_vec(ref_vec) + +Source new_source(*args) + } + + class Sentinel2Source{ + +R1_SIZE + +R2_SIZE + +Sentinel2Source msk_drilled(msk_dict, exp, nodata=0) + } + + class Sentinel22ASource{ + +Sentinel22ASource cld_msk_drilled(nodata=0) + } + + class Sentinel23ASource{ + +Sentinel23ASource flg_msk_drilled(keep_flags_values=(3, 4), nodata=0) + } +``` + +The sources carry the following images for Level 2 and Level 3 products: - The 10m spacing channels, in the following order: 4, 3, 2, 8 - The 20m spacing channels, in the following order: 5, 6, 7, 8a, 11, 12 @@ -48,14 +129,14 @@ no-data value (default is 0). The following example show how to derive a child source replacing the pixels that are in the clouds with pixels at -10000 (which is the no-data value in Theia products): -``` +``` py drilled = bands_10m_2a.cld_msk_drilled() ``` The `Sentinel23ASource` implements the `Sentinel23ASource.flg_msk_drilled` method, that enable to mask the pixels on a selection of labels of the quality mask. The following example shows how to mask pixels of anything other that land with -10000: -``` +``` py drilled = bands_10m_3a.flg_msk_drilled(keep_flags_values=(4,)) ``` @@ -63,7 +144,7 @@ drilled = bands_10m_3a.flg_msk_drilled(keep_flags_values=(4,)) hence implemented sources transformations (e.g. `scenes.core.Source.masked`, `scenes.core.Source.clip_over_img`, `scenes.core.Source.resample_over`, `scenes.core.Source.reproject`, etc. -``` +``` py clipped = drilled.clip_over_img(roi) reprojected = clipped.reproject(epsg=4328) ``` @@ -71,11 +152,11 @@ Note that the resulting transformed `Sentinel22ASource` and `Sentinel23ASource` instances of `Sentinel22ASource` and `Sentinel23ASource` even after generic operations implemented in `scenes.core.Source`. -# Usage with pyotb +## Usage with pyotb As `scenes.core.Source`, it also can be used like any `pyotb.core.otbObject`. The following example show how to use an OTB application with a source at input. -``` +``` py rgb_nice = pyotb.DynamicConvert(reprojected) rgb_nice.write("image.tif", pixel_type="uint8") ``` diff --git a/scenes/spot.py b/scenes/spot.py index 427b366..bf96495 100644 --- a/scenes/spot.py +++ b/scenes/spot.py @@ -5,15 +5,41 @@ for Spot 6/7 products. --- -# Scene +# `Scene` based class The `Spot67Scene` class carries metadata and image sources for Spot-6/7 sensors. +``` mermaid +classDiagram + + Scene <|-- Spot67Scene + + class Scene{ + +datetime acquisition_date + +int epsg + +bbox_wgs84 + +get_metadata() + +__repr__() + } + + class Spot67Scene{ + +float azimuth_angle + +float azimuth_angle_across + +float azimuth_angle_along + +float incidence_angle + +float sun_azimuth_angle + +float sun_elev_angle + +get_metadata() + +Spot67Source get_xs() + +Spot67Source get_pan() + +Spot67Source get_pxs() + } +``` + ## Instantiation A `Spot67Scene` is instantiated from the .XML DIMAP files of PAN and XS: -``` -#!python +``` py import scenes sc = scenes.spot.Spot67Scene(dimap_file_xs="DIM_SPOT6_MS..._1.XML", dimap_file_pan="DIM_SPOT6_P..._1.XML") @@ -23,7 +49,7 @@ sc = scenes.spot.Spot67Scene(dimap_file_xs="DIM_SPOT6_MS..._1.XML", The scene metadata can be accessed with the `get_metadata()` method, like any `scenes.core.Scene` instance. -``` +``` py md_dict = sc.get_metadata() for key, value in md_dict.items(): print(f"{key}: {value}") @@ -31,14 +57,39 @@ for key, value in md_dict.items(): ## Sources +The `Spot67Source` is the class for the different Spot-6/7 sources. + +``` mermaid +classDiagram + + Source <|-- Spot67Source + + class Source{ + +__init__(root_scene, out, parent=None) + +Scene root_scene + +Source parent + +Source drilled(msk_vec_file, nodata=0) + +Source cld_msk_drilled(nodata=0) + +Source resample_over(ref_img, interpolator="nn", nodata=0) + +Source clip_over_img(ref_img) + +Source clip_over_vec(ref_vec) + +Source new_source(*args) + } + + class Spot67Source{ + +Spot67Source cld_msk_drilled(nodata=0) + } + +``` + ### Different sources -The `Spot67Scene` delivers three kind of `Spot67Source` instances: +The `Spot67Scene` delivers three `Spot67Source` instances: - The multispectral image (xs) - The Panchromatic image (pan) - The pansharpenend image (pxs) -``` +``` py xs = sc.get_xs() pan = sc.get_pan() pxs = sc.get_pxs(method="bayes") @@ -53,7 +104,7 @@ Three level of radiometry are available for Spot-6/7 images: - TOA (Top Of Atmosphere) - TOC (Top Of Canopy) -``` +``` py p_dn = sc.get_pan() xs_toa = sc.get_xs(reflectance="toa") pxs_toc = sc.get_pxs(reflectance="toc") @@ -64,14 +115,14 @@ enable to mask the cloud masks over the root source, with the specified no-data value (default is 0). The following example show how to derive a child source replacing the pixels that are in the clouds with zero-valued pixels: -``` +``` py pxs_drilled = pxs.cld_msk_drilled() ``` The `Spot67Source` inherits from `scenes.core.Source`, hence implemented sources transformations (e.g. `scenes.core.Source.masked()`, `scenes.core.Source.clip_over_img()`, `scenes.core.Source.resample_over()`, `scenes.core.Source.reproject()`, etc. -``` +``` py clipped = pxs_drilled.clip_over_img(roi) reprojected = clipped.reproject(epsg=4328) ``` @@ -82,7 +133,7 @@ Note that the resulting transformed `Spot67Source` is still an instance of As `scenes.core.Source`, it also can be used like any `pyotb.core.otbObject`. The following example show how to use an OTB application with a source at input. -``` +``` py rgb_nice = pyotb.DynamicConvert(reprojected) rgb_nice.write("image.tif", pixel_type="uint8") ``` -- GitLab