Commit 6f5832f0 authored by Cresson Remi's avatar Cresson Remi
Browse files

Merge branch '14-codes_examples' into 'develop'

DOC: add examples

Closes #10, #8, and #14

See merge request !33
parents a3ee5f87 5120ae72
Pipeline #35125 passed with stages
in 4 minutes and 47 seconds
......@@ -78,7 +78,7 @@ class Source(pyotb.Output):
"""
for new_app in args:
self._app_stack.append(new_app)
return Source(root_imagery=self.root_imagery, out=self._app_stack[-1], parent=self)
return self.__class__(root_imagery=self.root_imagery, out=self._app_stack[-1], parent=self)
def drilled(self, msk_vec_file, inside=True, nodata=0):
"""
......
# -*- coding: utf-8 -*-
"""
This module aims to deal with dates
This module aims to deal with dates.
---
The `datetime.datetime` class is used as internal date type.
```
#!python
dt = datetime.datetime(year=2020, month=12, day=2)
```
Is equivalent to:
```
dt = str2datetime("02-12-2020")
dt = str2datetime("2020-12-02")
dt = str2datetime("02/12/2020")
```
The `any2datetime` method returns a `datetime.datetime` instance, whatever the input is (`str` or
`datetime.datetime`).
```
dt1 = datetime.datetime(year=2020, month=12, day=2)
dt2 = str2datetime("02-12-2020")
dt1_2 = any2datetime(dt1) # same
dt2_2 = any2datetime("02-12-2020") # same
```
The `get_timestamp` method converts a `datetime.datetime` instance into a number of seconds (int).
```
ts = get_timestamp(dt) # 1606780800.0
```
"""
import datetime
......
"""
This module provides tools to easily interact with deep learning models.
It is based on OTBTF.
OTBTF is needed to use this module.
---
# 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
import scenes
archive = "SENTINEL2B_..._T31TEJ_D_V1-8.zip"
s2_scene = scenes.sentinel.Sentinel22AScene(archive)
s2_image = s2_scene.get_imagery().get_10m_bands()
sr = scenes.deepnets.sr4rs(s2_image) # pyotb.core.otbObject
sr.write("sr.tif")
```
"""
import os
import zipfile
......
# -*- coding: utf-8 -*-
"""
This module handles the download of Sentinel-2 images from Theia (L2A or L3A).
The `scenes.download.TheiaDownloader` uses Theia credentials.
Those must be stored in a file looking like this:
```
serveur = https://theia.cnes.fr/atdistrib
resto = resto2
token_type = text
login_theia = remi.cresson@irstea.fr
password_theia = thisisnotmyrealpassword
```
To instantiate the `scenes.download.TheiaDownloader`:
```
#!python
import scenes
cfg_file = "config.txt" # Theia config file
theia = scenes.download.TheiaDownloader(cfg_file)
```
# 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
When the `download_dir` is not set, the download is not performed, and only the search results
are returned from the function.
```
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
To download the files, the `download_dir` must be specified:
```
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
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.
```
# For searching only
results = theia.download_in_range(bbox, trange, "LEVEL2A")
# For downloading
theia.download_in_range(bbox, trange, "/tmp/download/", "LEVEL2A")
```
"""
import datetime
import hashlib
......
"""
This module contains stuff for the spatio-temporal indexation of scenes
This module contains stuff for the spatio-temporal indexation of scenes.
The `scenes.indexation.Index` uses an R-Tree to perform the indexation of objects in the (x, y, t) domain.
---
Example: spatio-temporal indexation of multiple `scenes.core.Scene` instances.
# Build a spatio temporal index
```
#!python
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`
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.
```
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
A date min and/or a date max can be added in the query.
```
scenes_results = index.find(bbox, "01/01/2020" "01/01/2022")
```
# Search from a vector data file
The search can also be performed with a vector data file.
```
vec = "/path/to/vector.gpkg"
scenes_results = index.find(vec, "01/01/2020" "01/01/2022")
```
"""
import datetime
import rtree
......@@ -27,7 +69,8 @@ def _bbox(bbox_wgs84, date_min, date_max):
class Index:
"""
Stores an indexation structures for a list of Scenes"""
Stores an indexation structure for a list of Scenes
"""
def __init__(self, scenes_list):
"""
Args:
......
......@@ -2,6 +2,97 @@
This module contains Sentinel-2 classes (sources, imagery, and scenes).
Right now everything is ready to use THEIA L2A and L3A products.
# Scene
The `Sentinel22AScene` and `Sentinel23AScene` classes carry metadata and imagery
respectively for Sentinel-2 Level 2A and Level 3A products. They both inherit from
the generic abstract `Sentinel2SceneBase` class.
## Instantiation
`Sentinel22AScene` and `Sentinel23AScene` are instantiated from the archive (.zip file)
or the product folder.
```
#!python
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
The scene metadata can be accessed with the `get_metadata()` method, like any
`scenes.core.Scene` instance.
```
md_dict = sc_2a.get_metadata()
for key, value in md_dict.items():
print(f"{key}: {value}")
```
## Imagery
The imagery can be accessed with the `get_imagery()` method, which returns a
`Sentinel22AImagery` or a `Sentinel23AImagery` instance.
There is a single kind of imagery in `Sentinel22AScene` and `Sentinel23AScene`.
```
imagery_2a = sc_2a.get_imagery()
imagery_3a = sc_3a.get_imagery()
```
## Sources
The `Sentinel22AImagery` (and `Sentinel23AImagery`) both deliver two kind of `Sentinel22ASource`
(and `Sentinel23ASource`) instances:
- 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
```
bands_10m_2a = imagery_2a.get_10m_bands()
bands_20m_2a = imagery_2a.get_20m_bands()
bands_10m_3a = imagery_3a.get_10m_bands()
bands_20m_3a = imagery_3a.get_20m_bands()
```
The `Sentinel22ASource` implements the `Sentinel22ASource.cld_msk_drilled` method, that
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 pixels at -10000 (which is the no-data
value in Theia products):
```
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:
```
drilled = bands_10m_3a.flg_msk_drilled(keep_flags_values=(4,))
```
`Sentinel22ASource` and `Sentinel23ASource` inherit 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.
```
clipped = drilled.clip_over_img(roi)
reprojected = clipped.reproject(epsg=4328)
```
Note that the resulting transformed `Sentinel22ASource` and `Sentinel23ASource` are still
instances of `Sentinel22ASource` and `Sentinel23ASource` even after generic operations
implemented in `scenes.core.Source`.
# 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.
```
rgb_nice = pyotb.DynamicConvert(reprojected)
rgb_nice.write("image.tif", pixel_type="uint8")
```
"""
import datetime
from abc import abstractmethod
......@@ -60,12 +151,13 @@ class Sentinel23ASource(Sentinel2Source):
Args:
keep_flags_values: flags values to keep (Default value = (3, 4)). Can be:
0 = No data
1 = Cloud
2 = Snow
3 = Water
4 = Land
(source: https://labo.obs-mip.fr/multitemp/theias-l3a-product-format/)
- 0 = No data
- 1 = Cloud
- 2 = Snow
- 3 = Water
- 4 = Land
(source: https://labo.obs-mip.fr/multitemp/theias-l3a-product-format/)
nodata: nodata value inside holes (Default value = -10000)
Returns:
......
"""
This module provides classes and functions to help with light geospatial objects (projections, bounding boxes, etc)
This module provides classes and functions to help with light geospatial objects
(projections, bounding boxes, etc).
"""
import math
from osgeo import osr, ogr
......
"""
This module contains Spot 6/7 classes. It implements sources, imagery and scene.
This module contains classes to work with Spot 6/7 products.
In particular, it specializes `scenes.core.Source`, `scenes.core.Imagery`
and `scenes.core.Scene` for Spot 6/7 products.
---
# Scene
The `Spot67Scene` class carries metadata and imagery for Spot-6/7 sensors.
## Instantiation
A `Spot67Scene` is instantiated from the .XML DIMAP files of PAN and XS:
```
#!python
import scenes
sc = scenes.spot.Spot67Scene(dimap_file_xs="DIM_SPOT6_MS..._1.XML",
dimap_file_pan="DIM_SPOT6_P..._1.XML")
```
## Metadata
The scene metadata can be accessed with the `get_metadata()` method, like any
`scenes.core.Scene` instance.
```
md_dict = sc.get_metadata()
for key, value in md_dict.items():
print(f"{key}: {value}")
```
## Imagery
The imagery can be accessed with the `get_imagery()` method, which returns a
`Spot67Imagery` instance.
Two kind of imagery exist:
- DN (Digital Number): raw sensor values
- TOA (Top Of Atmosphere): calibrated reflectance
```
imagery_dn = sc.get_imagery(reflectance="dn") # uncalibrated
imagery_toa = sc.get_imagery(reflectance="toa") # TOA reflectance
```
## Sources
The `Spot67Imagery` delivers three kind of `Spot67Source` instances:
- The multispectral image
- The Panchromatic image
- The pansharpenend image
```
xs = imagery.get_xs() # Multispectral image Source
pan = imagery.get_pan() # Panchromatic image Source
pxs = imagery.get_pxs(method="bayes") # Pansharpened Source
```
The `Spot67Source` implements the `Spot67Source.cld_msk_drilled` method, that
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:
```
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.
```
clipped = pxs_drilled.clip_over_img(roi)
reprojected = clipped.reproject(epsg=4328)
```
Note that the resulting transformed `Spot67Source` is still an instance of
`Spot67Source` even after generic operations implemented in `scenes.core.Source`.
# 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.
```
rgb_nice = pyotb.DynamicConvert(reprojected)
rgb_nice.write("image.tif", pixel_type="uint8")
```
"""
import datetime
import xml.etree.ElementTree as ET
......@@ -13,13 +96,13 @@ from scenes.spatial import extent_overlap
def find_all_dimaps(pth):
"""
Return the list of DIMAPS that are inside all subdirectories of the root directory
Return the list of DIMAPS XML files that are inside all subdirectories of the root directory.
Args:
pth: root directory
Returns:
list of DIMAPS
list of DIMAPS XML files
"""
return utils.find_files_in_all_subdirs(pth=pth, pattern="DIM_*.XML")
......@@ -27,7 +110,8 @@ def find_all_dimaps(pth):
def get_spot67_scenes(root_dir):
"""
Return the list of pairs of PAN/XS DIMAPS
Return the list of scenes that can be instantiated from a root directory containing
a "PAN" and a "MS" subdirectories.
Args:
root_dir: directory containing "MS" and "PAN" subdirectories
......@@ -100,7 +184,11 @@ class Spot67Imagery(Imagery):
"""
Spot 6/7 imagery class.
This class carry the base image source, which can be radiometrically or geometrically corrected.
A `Spot67Imagery` instance carries the following `Spot67Source` instances:
- xs: the multispectral channels (Red, Gree, Blue, Near infrared @ 6.0 meters spacing)
- pan: the panchromatic channel (Visible domain @ 1.5 meters spacing)
- pxs: the pansharpened channels (Red, Gree, Blue, Near infrared @ 1.5 meters spacing)
"""
......@@ -126,20 +214,34 @@ class Spot67Imagery(Imagery):
self.pan = _toa(self.pan)
def get_xs(self):
"""Returns XS source"""
"""
Returns the MS source
Returns:
A Spot67Source instance for the MS image
"""
return Spot67Source(self, self.xs)
def get_pan(self):
"""Returns PAN source"""
"""
Returns PAN source
Returns:
A Spot67Source instance for the PAN image
"""
return Spot67Source(self, self.pan)
def get_pxs(self, method="bayes"):
"""
Returns the pansharpened source
Args:
method: one of rcs, lmvm, bayes (Default value = "bayes")
Returns:
Pansharpened XS source
A Spot67Source instance for the pansharpened image
"""
xs = self.get_xs()
......@@ -153,7 +255,8 @@ class Spot67Scene(Scene):
"""
Spot 6/7 root_scene class.
The class carries all the metadata from the root_scene, and can be used to retrieve its imagery.
The Spot67Scene class carries all metadata and imagery from the scene.
A Spot67Scene object can be instantiated from the XS and PAN DIMAPS (.XML) file.
"""
PXS_OVERLAP_THRESH = 0.995
......@@ -161,8 +264,9 @@ class Spot67Scene(Scene):
def __init__(self, dimap_file_xs, dimap_file_pan):
"""
Args:
dimap_file_xs: DIMAP file for XS
dimap_file_pan: DIMAP file for PAN
dimap_file_xs: XML DIMAP file for the XS product
dimap_file_pan: XML DIMAP file for the PAN product
"""
# DIMAP files
......@@ -298,7 +402,9 @@ class Spot67Scene(Scene):
def get_metadata(self):
"""
Get metadata
Get metadata.
The metadata is stored in a dict().
Returns:
metadata: dict
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment