Shortcuts

Source code for torchgeo.datasets.enmap

# Copyright (c) TorchGeo Contributors. All rights reserved.
# Licensed under the MIT License.

"""EnMAP dataset."""

from collections.abc import Callable, Iterable, Sequence
from typing import Any, ClassVar

import matplotlib.pyplot as plt
import numpy as np
from einops import rearrange
from matplotlib.figure import Figure
from pyproj import CRS

from .errors import RGBBandsMissingError
from .geo import RasterDataset
from .utils import Path, percentile_normalization

ALL_BANDS = list(range(1, 225))
# Remove bands strongly affected by water vapor absorption due to presence of nodata:
# * https://arxiv.org/abs/2306.00385
# * https://arxiv.org/abs/2408.08447
DEFAULT_BANDS = list(range(1, 127)) + list(range(142, 161)) + list(range(168, 225))


[docs]class EnMAP(RasterDataset): """`EnMAP <https://www.enmap.org/>`__ dataset. The Environmental Mapping and Analysis Program (EnMAP) is a German hyperspectral satellite mission that monitors and characterizes Earth's environment on a global scale. EnMAP measures geochemical, biochemical and biophysical variables providing information on the status and evolution of terrestrial and aquatic ecosystems. Mission Outline: * Dedicated pushbroom hyperspectral imager mainly based on modified existing or pre-developed technology * Broad spectral range from 420 nm to 1000 nm (VNIR) and from 900 nm to 2450 nm (SWIR) with high radiometric resolution and stability in both spectral ranges * 30 km swath width at a spatial resolution of 30 x 30 m, nadir revisit time of 27 days and off-nadir (30°) pointing feature for fast target revisit (4 days) * Sufficient on-board memory to acquire 1,000 km swath length per orbit and a total of 5,000 km per day. If you use this dataset in your research, please cite the following papers: * https://doi.org/10.1016/j.rse.2024.114379 * https://doi.org/10.1016/j.rse.2023.113632 .. versionadded:: 0.7 """ # https://www.enmap.org/data/doc/EN-PCV-ICD-2009-2_HSI_Product_Specification_Level1_Level2.pdf filename_glob = 'ENMAP*SPECTRAL_IMAGE*' filename_regex = r""" ^ENMAP (?P<satellite>\d{2})- (?P<product_type>____L[12][ABC])- (?P<datatake_id>DT\d{10})_ (?P<date>\d{8}T\d{6})Z_ (?P<tile_id>\d{3})_ (?P<version>V\d{6})_ (?P<processing_date>\d{8}T\d{6})Z- """ date_format = '%Y%m%dT%H%M%S' all_bands = tuple(f'B{n}' for n in ALL_BANDS) default_bands = tuple(f'B{n}' for n in DEFAULT_BANDS) rgb_bands = ('B48', 'B30', 'B16') # Exact values vary from image to image, here are useful defaults: # https://www.enmap.org/data/doc/EnMAP_Spectral_Bands_update.xlsx wavelengths: ClassVar[dict[str, float]] = { 'B1': 0.418416, 'B2': 0.424043, 'B3': 0.429457, 'B4': 0.434686, 'B5': 0.439758, 'B6': 0.444699, 'B7': 0.449539, 'B8': 0.454306, 'B9': 0.459031, 'B10': 0.463730, 'B11': 0.468411, 'B12': 0.473080, 'B13': 0.477744, 'B14': 0.482411, 'B15': 0.487087, 'B16': 0.491780, 'B17': 0.496497, 'B18': 0.501243, 'B19': 0.506020, 'B20': 0.510829, 'B21': 0.515672, 'B22': 0.520551, 'B23': 0.525467, 'B24': 0.530424, 'B25': 0.535422, 'B26': 0.540463, 'B27': 0.545551, 'B28': 0.550687, 'B29': 0.555873, 'B30': 0.561112, 'B31': 0.566405, 'B32': 0.571756, 'B33': 0.577166, 'B34': 0.582636, 'B35': 0.588171, 'B36': 0.593773, 'B37': 0.599446, 'B38': 0.605193, 'B39': 0.611017, 'B40': 0.616923, 'B41': 0.622921, 'B42': 0.628987, 'B43': 0.635112, 'B44': 0.641294, 'B45': 0.647537, 'B46': 0.653841, 'B47': 0.660207, 'B48': 0.666637, 'B49': 0.673131, 'B50': 0.679691, 'B51': 0.686319, 'B52': 0.693014, 'B53': 0.699780, 'B54': 0.706617, 'B55': 0.713524, 'B56': 0.720501, 'B57': 0.727545, 'B58': 0.734654, 'B59': 0.741826, 'B60': 0.749060, 'B61': 0.756353, 'B62': 0.763703, 'B63': 0.771108, 'B64': 0.778567, 'B65': 0.786078, 'B66': 0.793639, 'B67': 0.801249, 'B68': 0.808905, 'B69': 0.816608, 'B70': 0.824355, 'B71': 0.832145, 'B72': 0.839976, 'B73': 0.847847, 'B74': 0.855757, 'B75': 0.863703, 'B76': 0.871683, 'B77': 0.879693, 'B78': 0.887729, 'B79': 0.895789, 'B80': 0.903870, 'B81': 0.911968, 'B82': 0.920081, 'B83': 0.928204, 'B84': 0.936335, 'B85': 0.944470, 'B86': 0.952608, 'B87': 0.960748, 'B88': 0.968892, 'B89': 0.977037, 'B90': 0.985186, 'B91': 0.993338, 'B92': 0.901961, 'B93': 0.911571, 'B94': 0.921320, 'B95': 0.931203, 'B96': 0.941218, 'B97': 0.951360, 'B98': 0.961628, 'B99': 0.972016, 'B100': 0.982523, 'B101': 0.993144, 'B102': 1.00388, 'B103': 1.01472, 'B104': 1.02566, 'B105': 1.03670, 'B106': 1.04784, 'B107': 1.05907, 'B108': 1.07039, 'B109': 1.08178, 'B110': 1.09326, 'B111': 1.10481, 'B112': 1.11643, 'B113': 1.12810, 'B114': 1.13984, 'B115': 1.15162, 'B116': 1.16344, 'B117': 1.17530, 'B118': 1.18720, 'B119': 1.19911, 'B120': 1.21105, 'B121': 1.22300, 'B122': 1.23497, 'B123': 1.24694, 'B124': 1.25893, 'B125': 1.27092, 'B126': 1.28292, 'B127': 1.29491, 'B128': 1.30690, 'B129': 1.31888, 'B130': 1.33085, 'B131': 1.34282, 'B132': 1.35476, 'B133': 1.36669, 'B134': 1.37860, 'B135': 1.39048, 'B136': 1.46110, 'B137': 1.47274, 'B138': 1.48434, 'B139': 1.49589, 'B140': 1.50740, 'B141': 1.51887, 'B142': 1.53029, 'B143': 1.54167, 'B144': 1.55301, 'B145': 1.56430, 'B146': 1.57555, 'B147': 1.58676, 'B148': 1.59791, 'B149': 1.60902, 'B150': 1.62009, 'B151': 1.63111, 'B152': 1.64207, 'B153': 1.65300, 'B154': 1.66387, 'B155': 1.67470, 'B156': 1.68547, 'B157': 1.69620, 'B158': 1.70687, 'B159': 1.71750, 'B160': 1.72808, 'B161': 1.73860, 'B162': 1.74908, 'B163': 1.75951, 'B164': 1.93914, 'B165': 1.94869, 'B166': 1.95820, 'B167': 1.96766, 'B168': 1.97708, 'B169': 1.98645, 'B170': 1.99579, 'B171': 2.00508, 'B172': 2.01433, 'B173': 2.02354, 'B174': 2.03270, 'B175': 2.04183, 'B176': 2.05092, 'B177': 2.05996, 'B178': 2.06897, 'B179': 2.07793, 'B180': 2.08686, 'B181': 2.09574, 'B182': 2.10459, 'B183': 2.11340, 'B184': 2.12217, 'B185': 2.13090, 'B186': 2.13960, 'B187': 2.14826, 'B188': 2.15688, 'B189': 2.16547, 'B190': 2.17402, 'B191': 2.18253, 'B192': 2.19101, 'B193': 2.19945, 'B194': 2.20786, 'B195': 2.21624, 'B196': 2.22458, 'B197': 2.23289, 'B198': 2.24116, 'B199': 2.24940, 'B200': 2.25761, 'B201': 2.26579, 'B202': 2.27393, 'B203': 2.28204, 'B204': 2.29012, 'B205': 2.29817, 'B206': 2.30619, 'B207': 2.31417, 'B208': 2.32213, 'B209': 2.33005, 'B210': 2.33794, 'B211': 2.34581, 'B212': 2.35364, 'B213': 2.36144, 'B214': 2.36921, 'B215': 2.37695, 'B216': 2.38466, 'B217': 2.39234, 'B218': 2.40000, 'B219': 2.40762, 'B220': 2.41521, 'B221': 2.42278, 'B222': 2.43032, 'B223': 2.43782, 'B224': 2.44530, }
[docs] def __init__( self, paths: Path | Iterable[Path] = 'data', crs: CRS | None = None, res: float | tuple[float, float] | None = None, bands: Sequence[str] | None = None, transforms: Callable[[dict[str, Any]], dict[str, Any]] | None = None, cache: bool = True, ) -> None: """Initialize a new EnMAP instance. Args: paths: one or more root directories to search or files to load crs: :term:`coordinate reference system (CRS)` to warp to (defaults to the CRS of the first file found) res: resolution of the dataset in units of CRS in (xres, yres) format. If a single float is provided, it is used for both the x and y resolution. (defaults to the resolution of the first file found) bands: bands to return (defaults to all bands) transforms: a function/transform that takes an input sample and returns a transformed version cache: if True, cache file handle to speed up repeated sampling Raises: DatasetNotFoundError: If dataset is not found. """ bands = bands or self.default_bands super().__init__(paths, crs, res, bands, transforms, cache)
[docs] def plot(self, sample: dict[str, Any], suptitle: str | None = None) -> Figure: """Plot a sample from the dataset. Args: sample: A sample returned by :meth:`RasterDataset.__getitem__`. suptitle: optional string to use as a suptitle Returns: A matplotlib Figure with the rendered sample. Raises: RGBBandsMissingError: If *bands* does not include all RGB bands. """ rgb_indices = [] for band in self.rgb_bands: if band in self.bands: rgb_indices.append(self.bands.index(band)) else: raise RGBBandsMissingError() image = sample['image'][rgb_indices].cpu().numpy() image = np.clip(image, 0, None) image = rearrange(image, 'c h w -> h w c') image = percentile_normalization(image) fig, ax = plt.subplots() ax.imshow(image) ax.axis('off') if suptitle: fig.suptitle(suptitle) return fig

Docs

Access comprehensive developer documentation for PyTorch

View Docs

Tutorials

Get in-depth tutorials for beginners and advanced developers

View Tutorials

Resources

Find development resources and get your questions answered

View Resources