Source code for eoreader.bands

# -*- coding: utf-8 -*-
# Copyright 2024, SERTIT-ICube - France, https://sertit.unistra.fr/
# This file is part of eoreader project
#     https://github.com/sertit/eoreader
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Band module containing:

- wrapper for SAR and optical bands
- Index definitions
- Aliases for all these useful variables

To use it, simply type:

.. code-block:: python

    >>> from eoreader.bands import *
    >>> GREEN
    <SpectralBandNames.GREEN: 'GREEN'>
    >>> HH
    <SarBandNames.HH: 'HH'>
    >>> NDVI
    <function NDVI at 0x00000261F6FFA950>
"""
# flake8: noqa
from eoreader.bands.bands import Band, BandMap

__all__ = ["Band", "BandMap"]

from eoreader.bands.band_names import BandNames

__all__ += ["BandNames"]

from eoreader.bands.band_names import (
    ALL_CLOUDS,
    CIRRUS,
    CLOUDS,
    RAW_CLOUDS,
    SHADOWS,
    CloudsBandNames,
)

__all__ += [
    "CloudsBandNames",
    "RAW_CLOUDS",
    "CLOUDS",
    "SHADOWS",
    "CIRRUS",
    "ALL_CLOUDS",
]

from eoreader.bands.band_names import DEM, HILLSHADE, SLOPE, DemBandNames

__all__ += ["DemBandNames", "DEM", "SLOPE", "HILLSHADE"]

from eoreader.bands.indices import (
    get_all_index_names,
    get_all_needed_bands,
    get_needed_bands,
    is_index,
)

__all__ += [
    "get_all_index_names",
    "get_needed_bands",
    "get_all_needed_bands",
    "is_index",
]

# Spyndex indices
__all__ += get_all_index_names()
from eoreader.bands.band_names import (
    HH,
    HH_DSPK,
    HV,
    HV_DSPK,
    RH,
    RH_DSPK,
    RV,
    RV_DSPK,
    VH,
    VH_DSPK,
    VV,
    VV_DSPK,
    SarBandNames,
)
from eoreader.bands.indices import *
from eoreader.bands.sar_bands import SarBand, SarBandMap

__all__ += [
    "SarBand",
    "SarBandMap",
    "SarBandNames",
    "VV",
    "VV_DSPK",
    "HH",
    "HH_DSPK",
    "VH",
    "VH_DSPK",
    "HV",
    "HV_DSPK",
    "RH",
    "RH_DSPK",
    "RV",
    "RV_DSPK",
]

from eoreader.bands.band_names import GREEN1  # To be deprecated
from eoreader.bands.band_names import (
    BLUE,
    CA,
    F1,
    F2,
    GREEN,
    GREEN_1,
    NARROW_NIR,
    NIR,
    PAN,
    RED,
    S7,
    SWIR_1,
    SWIR_2,
    SWIR_CIRRUS,
    TIR_1,
    TIR_2,
    VRE_1,
    VRE_2,
    VRE_3,
    WV,
    YELLOW,
    Oa01,
    Oa02,
    Oa09,
    Oa10,
    Oa13,
    Oa14,
    Oa15,
    Oa18,
    Oa19,
    Oa21,
    SpectralBandNames,
)
from eoreader.bands.spectral_bands import SpectralBand, SpectralBandMap

__all__ += [
    "SpectralBand",
    "SpectralBandMap",
    "SpectralBandNames",
    "CA",
    "BLUE",
    "GREEN",
    "GREEN_1",
    "GREEN1",  # To be deprecated
    "YELLOW",
    "RED",
    "VRE_1",
    "VRE_2",
    "VRE_3",
    "NIR",
    "NARROW_NIR",
    "WV",
    "SWIR_CIRRUS",
    "SWIR_1",
    "SWIR_2",
    "TIR_1",
    "TIR_2",
    "PAN",
    "S7",
    "F1",
    "F2",
    "Oa01",
    "Oa02",
    "Oa09",
    "Oa10",
    "Oa13",
    "Oa14",
    "Oa15",
    "Oa18",
    "Oa19",
    "Oa21",
]

from eoreader.bands.mappings import (
    EOREADER_STAC_MAP,
    EOREADER_TO_SPYNDEX_DICT,
    SPYNDEX_TO_EOREADER_DICT,
)

__all__ += ["EOREADER_TO_SPYNDEX_DICT", "SPYNDEX_TO_EOREADER_DICT", "EOREADER_STAC_MAP"]

__all__ += [
    "is_spectral_band",
    "is_thermal_band",
    "is_sar_band",
    "is_sat_band",
    "is_clouds",
    "is_dem",
    "to_band",
    "to_str",
]

from typing import Union

from eoreader.exceptions import InvalidTypeError as _ite

BandType = Union[
    str, SpectralBandNames, SarBandNames, CloudsBandNames, DemBandNames, BandNames
]
""" EOReader band type, either a string, a BandName or its children: Spectral, SAR, DEM or Cloud band names """

BandsType = Union[list, BandType]
""" EOReader bands type, either a list or a BandType. """


[docs] def is_spectral_band(band: BandType) -> bool: """ Returns True if is a spectral band (from :code:`SpectralBandNames`) Args: band (BandType): Anything that could be an optical band Returns: bool: True if the band asked is an optical band Examples: >>> from eoreader.bands import NDVI, HH, GREEN, SLOPE, CLOUDS >>> >>> is_spectral_band(NDVI) False >>> is_spectral_band(HH) False >>> is_spectral_band(GREEN) True >>> is_spectral_band(SLOPE) False >>> is_spectral_band(CLOUDS) False """ is_valid = True try: SpectralBandNames(band) except ValueError: is_valid = False return is_valid
[docs] def is_thermal_band(band: BandType) -> bool: """ Returns True if is a spectral and a thermal band (from :code:`SpectralBandNames`) Args: band (BandType): Anything that could be an optical band Returns: bool: True if the band asked is an optical band Examples: >>> from eoreader.bands import SWIR_1, NDVI, HH, GREEN, SLOPE, CLOUDS >>> >>> is_thermal_band(SWIR_1) True >>> is_thermal_band(NDVI) False >>> is_thermal_band(HH) False >>> is_thermal_band(GREEN) False >>> is_thermal_band(SLOPE) False >>> is_thermal_band(CLOUDS) False """ return is_spectral_band(band) and band in [TIR_1, TIR_2, F1, F2, S7]
[docs] def is_sar_band(band: BandType) -> bool: """ Returns True if is a SAR band (from :code:`SarBandNames`) Args: band (BandType): Anything that could be a SAR band Returns: bool: True if the band asked is a SAR band Examples: >>> from eoreader.bands import NDVI, HH, GREEN, SLOPE, CLOUDS >>> >>> is_sar_band(NDVI) False >>> is_sar_band(HH) True >>> is_sar_band(GREEN) False >>> is_sar_band(SLOPE) False >>> is_sar_band(CLOUDS) False """ is_valid = True try: SarBandNames(band) except ValueError: is_valid = False return is_valid
[docs] def is_sat_band(band: BandType) -> bool: """ Returns True if is a satellite band (from both :code:`SarBandNames` or :code:`SpectralBandNames`) Args: band (BandType): Anything that could be a band Returns: bool: True if the band asked is a satellite band (Spectral or SAR) Examples: >>> from eoreader.bands import NDVI, HH, GREEN, SLOPE, CLOUDS >>> >>> is_sat_band(NDVI) False >>> is_sat_band(HH) True >>> is_sat_band(GREEN) True >>> is_sat_band(SLOPE) False >>> is_sat_band(CLOUDS) False """ return is_sar_band(band) or is_spectral_band(band)
[docs] def is_clouds(clouds: BandType) -> bool: """ Returns True if is a cloud band (from :code:`CloudBandNames`) Args: clouds (BandType): Anything that could be a cloud band Returns: bool: True if the band asked is a cloud band Examples: >>> from eoreader.bands import NDVI, HH, GREEN, SLOPE, CLOUDS >>> >>> is_clouds(NDVI) False >>> is_clouds(HH) False >>> is_clouds(GREEN) False >>> is_clouds(SLOPE) False >>> is_clouds(CLOUDS) True """ is_valid = True try: CloudsBandNames(clouds) except ValueError: is_valid = False return is_valid
[docs] def is_dem(dem: BandType) -> bool: """ Returns True if is a DEM band (from :code:`DemBandNames`) Args: clouds (BandType): Anything that could be a DEM band Returns: bool: True if the band asked is a DEM band Examples: >>> from eoreader.bands import NDVI, HH, GREEN, SLOPE, CLOUDS >>> >>> is_dem(NDVI) False >>> is_dem(HH) False >>> is_dem(GREEN) False >>> is_dem(SLOPE) True >>> is_dem(CLOUDS) False """ is_valid = True try: DemBandNames(dem) except ValueError: is_valid = False return is_valid
[docs] def to_band( to_convert: Union[list[BandType], BandType], as_list: bool = True ) -> Union[list, BandNames]: """ Convert a string (or real value) to any alias, band or index. You can pass the name or the value of the bands. Args: to_convert (Union[list, BandNames, str]): Values to convert into band objects as_list (bool): Return the result as a list Returns: list: Bands as BandNames Examples: >>> from eoreader.bands import RED, DEM, CLOUDS >>> >>> to_band(["NDVI", "GREEN", RED, "VH_DSPK", "SLOPE", DEM, "CLOUDS", CLOUDS]) [<function NDVI at 0x00000154DDB12488>, <SpectralBandNames.GREEN: 'GREEN'>, <SpectralBandNames.RED: 'RED'>, <SarBandNames.VH_DSPK: 'VH_DSPK'>, <DemBandNames.SLOPE: 'SLOPE'>, <DemBandNames.DEM: 'DEM'>, <ClassifBandNames.CLOUDS: 'CLOUDS'>, <ClassifBandNames.CLOUDS: 'CLOUDS'>] """ from sertit import types def convert_to_band(tc) -> BandNames: band_or_idx = None # Try legit types if isinstance(tc, str): # Try index if tc in get_all_index_names(): from eoreader.bands import indices band_or_idx = getattr(indices, tc) else: try: band_or_idx = SarBandNames.convert_from(tc)[0] except TypeError: try: band_or_idx = SpectralBandNames.convert_from(tc)[0] except TypeError: try: band_or_idx = DemBandNames.convert_from(tc)[0] except TypeError: try: band_or_idx = CloudsBandNames.convert_from(tc)[0] except TypeError: pass elif is_index(tc) or is_sat_band(tc) or is_dem(tc) or is_clouds(tc): band_or_idx = tc # Store it if band_or_idx: return band_or_idx else: if tc == "GREEN1": from sertit import logs logs.deprecation_warning( "`GREEN1` is deprecated in favor of `GREEN_1`. `GREEN1` will be removed in a future release." ) return GREEN1 else: raise _ite(f"Unknown band or index: {tc}") if as_list: band_list = [] to_convert = types.make_iterable(to_convert) for tc in to_convert: tc_band = convert_to_band(tc=tc) band_list.append(tc_band) return band_list else: if types.is_iterable(to_convert): raise _ite(f"Set as_list=True(default) for list arguments") return convert_to_band(to_convert)
[docs] def to_str( to_convert: Union[list[BandType], BandType], as_list: bool = True ) -> Union[list, str]: """ Convert a string (or real value) to any alias, band or index. You can pass the name or the value of the bands. Args: to_convert (Union[list, BandNames, str]): Values to convert into str as_list (bool): Return the result as a list Returns: list: Bands as strings Examples: >>> from eoreader.bands import RED, DEM, CLOUDS >>> >>> to_str(["NDVI", "GREEN", RED, "VH_DSPK", "SLOPE", DEM, "CLOUDS", CLOUDS]) ['NDVI', 'GREEN', 'RED', 'VH_DSPK', 'SLOPE', 'DEM', 'CLOUDS', 'CLOUDS'] """ from sertit import types if as_list: to_convert = types.make_iterable(to_convert) bands_str = [] for tc in to_convert: if isinstance(tc, str): band_str = tc else: try: band_str = tc.name except AttributeError: band_str = tc.__name__ bands_str.append(band_str) return bands_str else: if types.is_iterable(to_convert): raise _ite(f"Set as_list=True(default) for list arguments") try: band_str = tc.name except AttributeError: band_str = tc.__name__ return band_str