Skip to content

Commit

Permalink
Remove SatelliteImage class for reading sensor metadata in favor of…
Browse files Browse the repository at this point in the history
… a `Raster` option (#628)
  • Loading branch information
rhugonnet authored Nov 20, 2024
1 parent 049f39b commit b39408f
Show file tree
Hide file tree
Showing 23 changed files with 321 additions and 509 deletions.
1 change: 1 addition & 0 deletions dev-environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ dependencies:
- pylint
- netcdf4 # To write synthetic data with chunksizes
- dask-memusage
- pre-commit

# Doc dependencies
- sphinx
Expand Down
2 changes: 1 addition & 1 deletion doc/source/about_geoutils.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ header-rows: 1
* - ```{eval-rst}
.. literalinclude:: code/about_geoutils_sidebyside_raster_geoutils.py
:language: python
:lines: 14-29
:lines: 15-30
```
- ```{eval-rst}
Expand Down
47 changes: 13 additions & 34 deletions doc/source/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ documentation.

(api-raster-attrs)=

### Unique attributes
### Main attributes

```{eval-rst}
.. autosummary::
Expand All @@ -60,16 +60,25 @@ documentation.
Raster.height
Raster.width
Raster.count
Raster.count_on_disk
Raster.bands
Raster.bands_on_disk
Raster.res
Raster.bounds
Raster.dtype
```

### Other attributes

```{eval-rst}
.. autosummary::
:toctree: gen_modules/
Raster.count_on_disk
Raster.bands_on_disk
Raster.is_loaded
Raster.is_modified
Raster.name
Raster.driver
Raster.tags
```

(api-geo-handle)=
Expand Down Expand Up @@ -203,36 +212,6 @@ And reverse operations.
Raster.__array_function__
```

## SatelliteImage

```{eval-rst}
.. minigallery:: geoutils.SatelliteImage
:add-heading:
```

### Opening a file

```{eval-rst}
.. autosummary::
:toctree: gen_modules/
SatelliteImage
```

### Satellite image metadata

```{eval-rst}
.. autosummary::
:toctree: gen_modules/
SatelliteImage.datetime
SatelliteImage.tile_name
SatelliteImage.satellite
SatelliteImage.sensor
SatelliteImage.product
SatelliteImage.version
```

## Mask

```{eval-rst}
Expand Down Expand Up @@ -289,7 +268,7 @@ And reverse operations.
Vector.info
```

### Unique attributes
### Main attributes

```{eval-rst}
.. autosummary::
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import warnings

warnings.filterwarnings("ignore", category=UserWarning, message="For reprojection, nodata must be set.*")
warnings.filterwarnings("ignore", category=UserWarning, message="One raster has a pixel interpretation*")
####

import geoutils as gu
Expand Down
2 changes: 1 addition & 1 deletion doc/source/conf.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#
#
# Configuration file for the Sphinx documentation builder.
#
import glob
Expand Down Expand Up @@ -124,7 +125,6 @@
inheritance_alias = {
"geoutils.raster.raster.Raster": "geoutils.Raster",
"geoutils.raster.raster.Mask": "geoutils.Mask",
"geoutils.raster.satimg.SatelliteImage": "geoutils.SatelliteImage",
"geoutils.vector.Vector": "geoutils.Vector",
"xdem.dem.DEM": "xdem.DEM",
}
Expand Down
1 change: 1 addition & 0 deletions doc/source/core_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ core_match_ref
core_py_ops
core_array_funcs
core_lazy_load
core_parsing
core_inheritance
```
44 changes: 7 additions & 37 deletions doc/source/core_inheritance.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ kernelspec:
name: geoutils
---
(core-inheritance)=
# Inheritance to geo-images and beyond
# Inheritance to DEMs and beyond

Inheritance is practical to naturally pass down parent methods and attributes to child classes.

Expand All @@ -20,12 +20,13 @@ implemented in GeoUtils.

## Overview of {class}`~geoutils.Raster` inheritance


Below is a diagram showing current {class}`~geoutils.Raster` inheritance, which extends into other packages such as [xDEM](https://xdem.readthedocs.io/)
Current {class}`~geoutils.Raster` inheritance extends into other packages, such as [xDEM](https://xdem.readthedocs.io/)
for analyzing digital elevation models.
Within GeoUtils, inheritance extends only to {class}`~geoutils.Mask` that implements overloaded methods specific to binary raster masks,
as shown in the diagram below.

```{eval-rst}
.. inheritance-diagram:: geoutils.raster.raster geoutils.raster.satimg
.. inheritance-diagram:: geoutils.raster.raster
:top-classes: geoutils.raster.raster.Raster
```

Expand All @@ -37,42 +38,11 @@ Among others, it also adds a {attr}`~xdem.DEM.vcrs` property to consistently man
If you are DEM-enthusiastic, **[check-out our sister package xDEM](https://xdem.readthedocs.io/) for digital elevation models.**
```

## The internal {class}`~geoutils.SatelliteImage` subclass

GeoUtils subclasses {class}`Rasters<geoutils.Raster>` to {class}`SatelliteImages<geoutils.SatelliteImage>` for remote sensing users interested in parsing
metadata from space- or airborne imagery.

Based on the filename, or auxiliary files, the {class}`~geoutils.SatelliteImage` class attempts to automatically parse a
{attr}`~geoutils.SatelliteImage.datetime`, {attr}`~geoutils.SatelliteImage.sensor`, {attr}`~geoutils.SatelliteImage.tile_name`,
and other information.

```{code-cell} ipython3
import geoutils as gu
# Instantiate a geo-image from an ASTER image
filename_geoimg = gu.examples.get_path("exploradores_aster_dem")
geoimg = gu.SatelliteImage(filename_geoimg, silent=False)
```

```{code-cell} ipython3
# Instantiate a geo-image from a Landsat 7 image
filename_geoimg2 = gu.examples.get_path("everest_landsat_b4")
geoimg2 = gu.SatelliteImage(filename_geoimg2, silent=False)
```

Along these additional attributes, the {class}`~geoutils.SatelliteImage` possesses the same main attributes as a {class}`~geoutils.Raster`.

```{code-cell} ipython3
# The geo-image main attributes
geoimg
```

## And beyond

Many types of geospatial data can be viewed as a subclass of {class}`Rasters<geoutils.Raster>`, which have more attributes and require their own methods:
**spectral images**, **velocity fields**, **phase difference maps**, etc...

If you are interested to build your own subclass of {class}`~geoutils.Raster`, you can take example of the structure of {class}`geoutils.SatelliteImage` and
{class}`xdem.DEM`. Then, just add any of your own attributes and methods, and overload parent methods if necessary! Don't hesitate to reach out on our
If you are interested to build your own subclass of {class}`~geoutils.Raster`, you can take example of the structure of {class}`xdem.DEM`.
Then, just add any of your own attributes and methods, and overload parent methods if necessary! Don't hesitate to reach out on our
GitHub if you have a subclassing project.
62 changes: 62 additions & 0 deletions doc/source/core_parsing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
file_format: mystnb
jupytext:
formats: md:myst
text_representation:
extension: .md
format_name: myst
kernelspec:
display_name: geoutils-env
language: python
name: geoutils
---
(satimg-parsing)=

# Sensor metadata parsing

GeoUtils functionalities for remote sensing users interested in parsing metadata from space- or airborne imagery.

## Parsing metadata at raster instantiation

A {class}`~geoutils.Raster` can be instantiated while trying to parse metadata usint the ``parse_sensor_metadata`` argument.

```{code-cell} ipython3
import geoutils as gu
# Parse metadata from an ASTER raster
filename_aster = gu.examples.get_path("exploradores_aster_dem")
rast_aster = gu.Raster(filename_aster, parse_sensor_metadata=True, silent=False)
```


```{code-cell} ipython3
# Parse metadata from a Landsat 7 raster
filename_landsat = gu.examples.get_path("everest_landsat_b4")
rast_landsat = gu.Raster(filename_landsat, parse_sensor_metadata=True, silent=False)
```

The metadata is then stored in the {attr}`~geoutils.Raster.tags` attribute of the raster.

```{code-cell} ipython3
rast_aster.tags
```

For tiled products such as SRTM, the tile naming is also retrieved, and converted to usable tile sizes and extents based on known metadata.

## Supported sensors

Right now are supported:
- Landsat,
- Sentinel-2,
- SPOT,
- ASTER,
- ArcticDEM and REMA,
- ALOS,
- SRTM,
- TanDEM-X, and
- NASADEM.

```{important}
Sensor metadata parsing is still in development. We hope to add the ability to parse from
auxiliary files in the future (such as [here](https://github.com/jlandmann/glaciersat/blob/master/glaciersat/core/imagery.py)).
```
1 change: 0 additions & 1 deletion doc/source/data_object_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,4 @@ raster_class
vector_class
pointcloud_class
mask_class
satimg_class
```
8 changes: 4 additions & 4 deletions doc/source/feature_overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,10 @@ import os
os.remove("myaoi.gpkg")
```

## Parsing metadata with {class}`~geoutils.SatelliteImage`
## Parsing sensor metadata

In our case, `rast` would be better opened using the {class}`~geoutils.Raster` object {class}`~geoutils.SatelliteImage` instead, which tentatively parses
metadata recognized from the filename or auxiliary files.
In our case, `rast` would be better opened using the ``parse_sensor_metadata`` argument of a `{class}`~geoutils.Raster`
, which tentatively parses metadata recognized from the filename or auxiliary files.

```{code-cell} ipython3
# Name of the image we used
Expand All @@ -254,7 +254,7 @@ print(os.path.basename(filename_rast))

```{code-cell} ipython3
# Open while parsing metadata
rast = gu.SatelliteImage(filename_rast, silent=False)
rast = gu.Raster(filename_rast, parse_sensor_metadata=True, silent=False)
```

```{admonition} Wrap-up
Expand Down
63 changes: 0 additions & 63 deletions doc/source/satimg_class.md

This file was deleted.

14 changes: 7 additions & 7 deletions examples/io/open_save/read_satimg.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""
Parsing image metadata
======================
Parsing sensor metadata
=======================
This example demonstrates the instantiation of an image through :class:`~geoutils.SatelliteImage`.
This example demonstrates the instantiation of a raster while parsing image sensor metadata.
"""

import geoutils as gu
Expand All @@ -15,9 +15,9 @@
print(os.path.basename(filename_geoimg))

# %%
# We open it as a geo-image, un-silencing the attribute retrieval to see the parsed data.
img = gu.SatelliteImage(filename_geoimg, silent=False)
# We open it as a raster with the option to parse metadata, un-silencing the attribute retrieval to see it printed.
img = gu.Raster(filename_geoimg, parse_sensor_metadata=True, silent=False)

# %%
# We have now retrieved the metadata. For the rest, the :class:`~geoutils.SatelliteImage` is a subclass of :class:`~geoutils.Raster`, and behaves similarly.
img
# We have now retrieved the metadata, stored in the :attr:`geoutils.Raster.tags` attribute.
img.tags
2 changes: 1 addition & 1 deletion geoutils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from geoutils import examples, projtools, raster, vector # noqa
from geoutils._config import config # noqa
from geoutils.raster import Mask, Raster, SatelliteImage # noqa
from geoutils.raster import Mask, Raster # noqa
from geoutils.vector import Vector # noqa

try:
Expand Down
2 changes: 1 addition & 1 deletion geoutils/raster/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
from geoutils.raster.geotransformations import * # noqa
from geoutils.raster.multiraster import * # noqa
from geoutils.raster.sampling import * # noqa
from geoutils.raster.satimg import SatelliteImage # noqa
from geoutils.raster.satimg import * # noqa

__all__ = ["RasterType", "Raster"]
Loading

0 comments on commit b39408f

Please sign in to comment.