From ad8ed3717eb8c78f21199226084d7386e3d3ee49 Mon Sep 17 00:00:00 2001 From: Remi Cresson <remi.cresson@inrae.fr> Date: Tue, 6 Jun 2023 19:45:36 +0200 Subject: [PATCH] Doc: fix reflectance --- doc/index.md | 188 +++++++++++++++------------------------------------ 1 file changed, 53 insertions(+), 135 deletions(-) diff --git a/doc/index.md b/doc/index.md index 7a16c5c..cdc584c 100644 --- a/doc/index.md +++ b/doc/index.md @@ -20,6 +20,9 @@ pip install https://gitlab.irstea.fr/umr-tetis/scenes/-/archive/develop/scenes-d `Scene` instances have generic methods and attributes. +- **Imagery sources**: imagery sources can be accessed using `get_xxx()` +methods, where `xxx` is the name of the source to get. Any source can be used +in OTB, PyOTB pipelines, or with numpy directly. - **Metadata**: metadata access with the `get_metadata()` method. ``` py for key, value in sc.get_metadata(): @@ -37,29 +40,36 @@ Spot 6/7 scenes are instantiated from XS and PAN XML files of DIMAPS products. ``` py from scenes.spot import Spot67Scene -sc = Spot67Scene(dimap_file_xs="/path/to/DIM_SPOT7_MS_..._1.XML", - dimap_file_pan="/path/to/DIM_SPOT7_P_..._1.XML") +sc = Spot67Scene( + dimap_file_xs="/path/to/DIM_SPOT7_MS_..._1.XML", + dimap_file_pan="/path/to/DIM_SPOT7_P_..._1.XML" +) ``` ### Image sources -Spot-6/7 scenes have 3 images sources. +Spot-6/7 scenes have 3 images sources: `xs`, `pan` and `pxs`. | Source | `Scene` method | Description | |--------|----------------|--------------------------------------------------------------------| | XS | `get_xs()` | 4 channels (Red, Green, Blue, Near Infrared), ~6m physical spacing | | Pan | `get_pan()` | 1 channel (visible domain), ~1.5m physical spacing | -| PXS | `get_pxs(method=...)` | 4 channels (same as XS), ~1.5m physical spacing | +| PXS | `get_pxs()` | 4 channels (same as XS), ~1.5m physical spacing | Each source can be computed in DN/TOA/TOC reflectance. ``` py xs_raw = sc.get_xs() # DN -xs_raw = sc.get_xs(reflectance="dn") # DN -xs_toa = sc.get_xs(reflectance="toa") # TOA -xs_toc = sc.get_xs(reflectance="toc") # TOC +xs_toa = sc.get_xs().reflectance(level="toa") # TOA +xs_toc = sc.get_xs().reflectance(level="toc") # TOC ``` +!!! Warning + + OTB version must be >= 8.1.0 to support optical calibration using source + `reflectance()` method. + kwargs of `reflectance()` are the same as `pyotb.OpticalCalibration`. + Each source can be masked with the cloud masks of the original product. The no-data value can be chosen. @@ -67,21 +77,22 @@ The no-data value can be chosen. xs_toa_cld = xs_toa.cld_msk_drilled() # (1) ``` -1. To change the no-data inside the clouds mask: `masked_src = src.cld_msk_drilled(nodata=-999)` +1. To change the no-data inside the clouds mask: +`masked_src = src.cld_msk_drilled(nodata=-999)` ### Examples Computing NDVI from XS image in TOA reflectance: ``` py -xs = toa.get_xs(reflectance="toa") # (1) +xs = toa.get_xs().reflectance(level="toa") # (1) exp = "(im1b4-im1b1)/(im1b4+im1b1)" -ndvi = pyotb.bandmath(exp=exp, il=[xs]) # (2) +ndvi = pyotb.bandmath(exp=exp, il=[xs]) # (2) ndvi.write("ndvi.tif") ``` 1. `xs` is a `scenes.spot.Spot67Source` instance -2. `ndvi` is a `pyotb.app` that inputs `xs` +2. `ndvi` is a `pyotb.App` object that inputs `xs` The next example is a set of preprocessing operations on a Spot-6/7 XS image: @@ -91,10 +102,10 @@ The next example is a set of preprocessing operations on a Spot-6/7 XS image: 4. clip the result over a reference raster ``` py -pxs = sc.get_pxs(reflectance="toa") # (1) -drilled = pxs.cld_msk_drilled() # (2) +pxs = sc.get_pxs().reflectance(level="toa") # (1) +drilled = pxs.cld_msk_drilled() # (2) ref_img = "/tmp/S2A_2020...._FRE_10m.tif" -subset = drilled.clip_over_img(ref_img) # (3) +subset = drilled.clip_over_img(ref_img) # (3) subset.write("subset.tif") ``` @@ -112,14 +123,16 @@ Superimpose an image over a reference image. In the example below, `ref_img` is another `scenes.core.Source` instance. ``` py -toa = sc.get_pxs(reflectance="toa") +toa = sc.get_pxs().reflectance(level="toa") superimposed = toa.resample_over(ref_img) superimposed.write("superimposed.tif") ``` ## Sentinel-2 -Currently, Level-2 and Level-3 products from the [Theia land data center](https://www.theia-land.fr/en/product/sentinel-2-surface-reflectance/) are supported. +Currently, Level-2 and Level-3 products from the +[Theia land data center](https://www.theia-land.fr/en/product/sentinel-2-surface-reflectance/) +and Level-2 products from Microsoft Planetary Computer are supported ### Instantiation @@ -131,9 +144,16 @@ sc_level2 = Sentinel22AScene("/path/to/SENTINEL2A_..._V1-8/.zip") sc_level3 = Sentinel23AScene("/path/to/SENTINEL2X_...L3A_T31TEJ_D/.zip") ``` +Note that you can also instanciate uncomplete products, e.g. only 10m spacing +bands. In this case, a warning will be displayed. + ### Sources -Sentinel-2 images include 2 sources. +Sentinel-2 images include the following sources: +- single band, 10m spacing: `b4`, `b3`, `b2`, `b8` +- single band, 20m spacing: `b5`, `b6`, `b7`, `b8a`, `b11`, `b12` +- concatenated bands: `10m_bands`, `20m_bands` +- for Theia products, quality masks: `clm_r1`, `clm_r2`, `edg_r1`, `edg_r2` | Source | `Scene` method | Description | |-----------|-------------------|-----------------------------------------------------------| @@ -149,7 +169,8 @@ src = sc_level2.get_10m_bands() masked_src = src.cld_msk_drilled() # (1) ``` -1. To change the no-data inside the clouds mask: `masked_src = src.cld_msk_drilled(nodata=-999)` +1. To change the no-data inside the clouds mask: +`masked_src = src.cld_msk_drilled(nodata=-999)` For Level 3 products, using the quality mask: @@ -158,16 +179,21 @@ src = sc_level3.get_10m_bands() masked_src = src.flg_msk_drilled() # (1) ``` -1. To change the no-data inside the clouds mask: `masked_src = src.flg_msk_drilled(nodata=-999)`. -Also, the `keep_flags_values` can be used to select the pixels to keep from a list of values in the quality mask (land, water, snow, ...). +1. To change the no-data inside the clouds mask: +`masked_src = src.flg_msk_drilled(nodata=-999)`. +Also, the `keep_flags_values` can be used to select the pixels to keep from a +list of values in the quality mask (land, water, snow, ...). ## Spatial and temporal indexation -Scenes includes a module to perform spatial and temporal indexation of `Scene` instances. +Scenes includes a module to perform spatial and temporal indexation of `Scene` +instances. ### Query in space -Perform a query in space (WGS84 bounding box) and time (optional) with an indexation structure. +Perform a query in space (WGS84 bounding box) and time (optional) with an +indexation structure. + ``` py from scenes import spot, indexation scs = spot.get_spot67_scenes(root_dir) # (1) @@ -184,127 +210,19 @@ for sc in matches: ### Query in space and time To perform searches in time: + ``` py matches1 = idx.find(bbox_wgs84=bbox, "01/02/2019", "01-12-2020") # (1) matches2 = idx.find(bbox_wgs84=bbox, "01/02/2019") # (2) matches3 = idx.find(bbox_wgs84=bbox, date_max="01/02/2019") # (3) ``` -1. A few date formats are supported: "dd/mm/yyyy", "dd-mm-yyyy", and "yyyy-mm-dd" +1. A few date formats are supported: "dd/mm/yyyy", "dd-mm-yyyy", and +"yyyy-mm-dd" 2. Here we don't have upper bound -3. You can also specify only an upper bound, without lower bound (use the keywords `date_min` and `date_max` - - -## Architecture - -### Scene class - -The scene class handles all the metadata and the image sources. - - -``` mermaid -classDiagram - - Scene <|-- Spot67Scene - Scene <|-- Sentinel2SceneBase - Sentinel2SceneBase <|-- Sentinel22AScene - Sentinel2SceneBase <|-- Sentinel23AScene - - Scene --* Source: root_scene - - 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() - - } - - 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() - } - -``` - -### Source class - -The source stores the image pipeline that delivers the pixels. +3. You can also specify only an upper bound, without lower bound (use the +keywords `date_min` and `date_max` -``` mermaid -classDiagram - - Source <|-- Spot67Source - 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 Spot67Source{ - +Spot67Source cld_msk_drilled(nodata=0) - } - - 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) - } - -``` ### Implement a new sensor from scratch -- GitLab