opencropphenotyping 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. {opencropphenotyping-0.2.0/src/opencropphenotyping.egg-info → opencropphenotyping-0.3.0}/PKG-INFO +149 -8
  2. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/README.md +145 -7
  3. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/pyproject.toml +6 -1
  4. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/src/opencropphenotyping/indices.py +200 -24
  5. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/src/opencropphenotyping/io.py +317 -1
  6. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/src/opencropphenotyping/segmentation.py +27 -1
  7. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0/src/opencropphenotyping.egg-info}/PKG-INFO +149 -8
  8. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/tests/test_indices.py +103 -3
  9. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/tests/test_io.py +279 -0
  10. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/tests/test_segmentation.py +34 -1
  11. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/LICENSE +0 -0
  12. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/setup.cfg +0 -0
  13. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/src/opencropphenotyping/batch_processing.py +0 -0
  14. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/src/opencropphenotyping/cli.py +0 -0
  15. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/src/opencropphenotyping/coco.py +0 -0
  16. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/src/opencropphenotyping/evaluation.py +0 -0
  17. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/src/opencropphenotyping/pipeline.py +0 -0
  18. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/src/opencropphenotyping/statistics.py +0 -0
  19. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/src/opencropphenotyping/traits.py +0 -0
  20. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/src/opencropphenotyping/visualization.py +0 -0
  21. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/src/opencropphenotyping.egg-info/SOURCES.txt +0 -0
  22. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/src/opencropphenotyping.egg-info/dependency_links.txt +0 -0
  23. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/src/opencropphenotyping.egg-info/entry_points.txt +0 -0
  24. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/src/opencropphenotyping.egg-info/requires.txt +0 -0
  25. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/src/opencropphenotyping.egg-info/top_level.txt +0 -0
  26. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/tests/test_batch_processing.py +0 -0
  27. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/tests/test_cli.py +0 -0
  28. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/tests/test_coco.py +0 -0
  29. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/tests/test_evaluation.py +0 -0
  30. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/tests/test_pipeline.py +0 -0
  31. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/tests/test_statistics.py +0 -0
  32. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/tests/test_toy_dataset.py +0 -0
  33. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/tests/test_traits.py +0 -0
  34. {opencropphenotyping-0.2.0 → opencropphenotyping-0.3.0}/tests/test_visualization.py +0 -0
@@ -1,8 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencropphenotyping
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Open-source tools for crop phenotyping using multispectral geospatial imagery
5
5
  Author: Aurélien Peter
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: Programming Language :: Python :: 3.11
8
+ Classifier: Operating System :: OS Independent
6
9
  Requires-Python: >=3.11
7
10
  Description-Content-Type: text/markdown
8
11
  License-File: LICENSE
@@ -26,15 +29,23 @@ Dynamic: license-file
26
29
 
27
30
  [![CI](https://github.com/Aurelien-Peter/OpenCropPhenotyping/actions/workflows/ci.yml/badge.svg)](https://github.com/Aurelien-Peter/OpenCropPhenotyping/actions/workflows/ci.yml)
28
31
  [![codecov](https://codecov.io/github/Aurelien-Peter/OpenCropPhenotyping/graph/badge.svg?token=7SAC1M1VY5)](https://codecov.io/github/Aurelien-Peter/OpenCropPhenotyping)
32
+ [![PyPI Version](https://img.shields.io/pypi/v/opencropphenotyping)](https://pypi.org/project/opencropphenotyping/)
33
+ [![Python versions](https://img.shields.io/pypi/pyversions/opencropphenotyping)](https://pypi.org/project/opencropphenotyping/)
34
+ [![Docker publish](https://github.com/Aurelien-Peter/OpenCropPhenotyping/actions/workflows/publish-docker.yml/badge.svg)](https://github.com/Aurelien-Peter/OpenCropPhenotyping/actions/workflows/publish_docker.yml)
29
35
 
30
36
  **An open-source Python framework for high-throughput crop phenotyping using drone and satellite imagery.**
31
37
 
32
38
  ## About the project
33
39
 
34
40
  OpenCropPhenotyping is an open-source project dedicated to reproducible high-throughput crop phenotyping using remote sensing data.
41
+
35
42
  The objective is to provide reproducible workflows to extract agronomic traits from UAV and Sentinel-2 imagery, from raw image preprocessing to trait extraction, statistical analysis and visualization.
43
+
44
+
36
45
  The project currently combines multispectral Sentinel-2 processing with classical RGB UAV image analysis. The first UAV developments focus on crop-row detection, vegetation segmentation and plant-position analysis, with the objective of progressively extending the framework toward more advanced high-throughput phenotyping workflows.
37
46
 
47
+ The project includes automated testing, continuous integration, code coverage monitoring, and package distribution through PyPI. Docker support provides a reproducible runtime environment for command-line processing.
48
+
38
49
  ## Current Features:
39
50
  **Sentinel-2**
40
51
  - [X] Sentinel-2 imagery reading
@@ -51,13 +62,12 @@ The project currently combines multispectral Sentinel-2 processing with classica
51
62
  - [X] Processing results export
52
63
  - [X] Batch processing of multiple Sentinel-2 products
53
64
  - [X] Visualization
54
- - [X] Unit Tests
55
- - [X] Command-Line Interface (CLI)
56
65
 
57
66
  **UAV RGB**
58
67
  - [X] RGB UAV imagery reading
59
68
  - [X] RGB vegetation indices
60
69
  - [X] Vegetation segmentation
70
+ - [X] Vegetation fraction estimation
61
71
  - [X] Crop-row orientation estimation
62
72
  - [X] Crop-row detection
63
73
  - [X] Crop-row boundary detection
@@ -66,12 +76,22 @@ The project currently combines multispectral Sentinel-2 processing with classica
66
76
  - [X] Georeferenced UAV Image support
67
77
  - [X] Experimental plot metadata integration
68
78
  - [X] UAV RGB workflow demonstration
69
-
70
- **Software quality**
71
- - [X] Visualization utilities
72
- - [X] Unit tests
73
- - [X] Code quality checks with Ruff
79
+ - [x] Georeferenced raster metadata validation
80
+ - [x] GeoTIFF raster tiling with geospatial metadata preservation
81
+ - [x] Reconstruction of raster mosaics from tiles
82
+
83
+ **Software quality & distribution**
84
+
85
+ - [X] Unit and integration tests with pytest
86
+ - [X] Automated code quality checks with Ruff
87
+ - [X] Automated CI with GitHub Actions
88
+ - [X] Test coverage monitoring with pytest-cov and Codecov
89
+ - [X] Python package build and distribution through PyPI
90
+ - [X] Docker containerization
91
+ - [X] Automated Docker image publishing through GitHub Actions
92
+ - [X] Dependency update management with Dependabot
74
93
  - [X] Reproducible toy datasets
94
+ - [X] Command-line interface (CLI)
75
95
 
76
96
  ## Case studies
77
97
 
@@ -676,6 +696,127 @@ opencropphenotyping batch-uav \
676
696
 
677
697
  The CLI follows the same processing pipeline as the Python API and can therefore be used for reproducible processing of individual UAV datasets or complete directories of datasets.
678
698
 
699
+ ## Georeferenced raster support and tiling
700
+
701
+ OpenCropPhenotyping provides utilities to validate georeferenced raster metadata, split GeoTIFF rasters into smaller tiles, and reconstruct a raster mosaic from these tiles.
702
+
703
+ These utilities support the handling of large UAV orthomosaics while preserving their spatial reference information.
704
+
705
+ ### Available functions
706
+
707
+ - `validate_georeferenced_raster()`: checks the consistency of raster georeferencing metadata.
708
+ - `tile_raster()`: divides a raster into smaller tiles while preserving their spatial metadata.
709
+ - `merge_raster_tiles()`: reconstructs a raster mosaic from georeferenced tiles.
710
+
711
+ The functions operate on existing georeferenced rasters. They do not generate orthomosaics from raw UAV photographs, which requires a dedicated photogrammetry workflow.
712
+
713
+ ## Docker
714
+
715
+ OpenCropPhenotyping is available as a Docker image, providing a reproducible Linux environment with the package and its dependencies pre-installed.
716
+
717
+ Docker images are published to GitHub Container Registry (GHCR) when a new version is released.
718
+
719
+ ### Requirements
720
+
721
+ - [Docker Desktop](https://www.docker.com/products/docker-desktop/) or Docker Engine
722
+ - UAV or Sentinel-2 input data (toy datasets are included in the image)
723
+ - A published OpenCropPhenotyping Docker image
724
+
725
+ ### Download the image
726
+
727
+ Pull a specific released version:
728
+
729
+ ```bash
730
+ docker pull ghcr.io/aurelien-peter/opencropphenotyping:VERSION
731
+ ```
732
+
733
+ Replace `VERSION` with an available release tag, such as `0.2.2`.
734
+
735
+ ### Check the installation
736
+
737
+ Display the available CLI commands:
738
+
739
+ ```bash
740
+ docker run --rm ghcr.io/aurelien-peter/opencropphenotyping:VERSION --help
741
+ ```
742
+
743
+ Available commands include:
744
+
745
+ - `process`: process a single Sentinel-2 product.
746
+ - `batch`: process multiple Sentinel-2 products.
747
+ - `segment-uav`: process a single UAV RGB dataset.
748
+ - `batch-uav`: process multiple UAV datasets.
749
+
750
+ ### Process Sentinel-2 imagery
751
+
752
+ Input data and output directories are provided through a bind mount. In the following example, a local `data` directory is mounted at `/data` inside the container.
753
+
754
+ ```bash
755
+ docker run --rm \
756
+ --mount type=bind,source=/absolute/path/to/data,target=/data \
757
+ ghcr.io/aurelien-peter/opencropphenotyping:VERSION \
758
+ process \
759
+ --input-dir /data/raw/sentinel_product \
760
+ --output-dir /data/results \
761
+ --processed-dir /data/processed \
762
+ --indices ndvi \
763
+ --ndvi-threshold 0.3 \
764
+ --resolution 10
765
+ ```
766
+
767
+ Replace `/absolute/path/to/data` with the absolute path to the local directory containing your data.
768
+
769
+ The input path must point to a Sentinel-2 product supported by the pipeline. Results written under `/data` are available in the corresponding local directory after the container exits.
770
+
771
+ ### Process UAV RGB imagery
772
+
773
+ A single UAV dataset requires an RGB image, its georeferenced GeoTIFF and a GeoPackage describing the experimental plot.
774
+
775
+ ```bash
776
+ docker run --rm \
777
+ --mount type=bind,source=/absolute/path/to/data,target=/data \
778
+ ghcr.io/aurelien-peter/opencropphenotyping:VERSION \
779
+ segment-uav \
780
+ --image /data/uav/image.png \
781
+ --geotiff /data/uav/image_georef.tif \
782
+ --geopackage /data/uav/plots.gpkg \
783
+ --output-dir /data/results/uav
784
+ ```
785
+
786
+ To process several UAV datasets, use the `batch-uav` command. Each dataset must be stored in its own subdirectory containing the required input files.
787
+
788
+ ```bash
789
+ docker run --rm \
790
+ --mount type=bind,source=/absolute/path/to/data,target=/data \
791
+ ghcr.io/aurelien-peter/opencropphenotyping:VERSION \
792
+ batch-uav \
793
+ --input-dir /data/uav \
794
+ --output-dir /data/results/uav
795
+ ```
796
+
797
+ ### Build the image locally
798
+
799
+ To build the Docker image from the source code instead of pulling a published release, clone the repository and run:
800
+
801
+ ```bash
802
+ git clone https://github.com/Aurelien-Peter/OpenCropPhenotyping.git
803
+ cd OpenCropPhenotyping
804
+
805
+ docker build -t opencropphenotyping:local .
806
+ ```
807
+
808
+ Check the local image:
809
+
810
+ ```bash
811
+ docker run --rm opencropphenotyping:local --help
812
+ ```
813
+
814
+ ### Notes
815
+
816
+ - The container is designed for command-line processing jobs. It starts, executes the requested command and exits when the job is complete.
817
+ - Use a bind mount for both input data and output directories to keep files accessible outside the container.
818
+
819
+
679
820
  ## Contributing
680
821
 
681
822
  Contributions are welcome. If you have ideas for improvements, bug fixes or new features, feel free to open an issue or submit a pull request.
@@ -2,15 +2,23 @@
2
2
 
3
3
  [![CI](https://github.com/Aurelien-Peter/OpenCropPhenotyping/actions/workflows/ci.yml/badge.svg)](https://github.com/Aurelien-Peter/OpenCropPhenotyping/actions/workflows/ci.yml)
4
4
  [![codecov](https://codecov.io/github/Aurelien-Peter/OpenCropPhenotyping/graph/badge.svg?token=7SAC1M1VY5)](https://codecov.io/github/Aurelien-Peter/OpenCropPhenotyping)
5
+ [![PyPI Version](https://img.shields.io/pypi/v/opencropphenotyping)](https://pypi.org/project/opencropphenotyping/)
6
+ [![Python versions](https://img.shields.io/pypi/pyversions/opencropphenotyping)](https://pypi.org/project/opencropphenotyping/)
7
+ [![Docker publish](https://github.com/Aurelien-Peter/OpenCropPhenotyping/actions/workflows/publish-docker.yml/badge.svg)](https://github.com/Aurelien-Peter/OpenCropPhenotyping/actions/workflows/publish_docker.yml)
5
8
 
6
9
  **An open-source Python framework for high-throughput crop phenotyping using drone and satellite imagery.**
7
10
 
8
11
  ## About the project
9
12
 
10
13
  OpenCropPhenotyping is an open-source project dedicated to reproducible high-throughput crop phenotyping using remote sensing data.
14
+
11
15
  The objective is to provide reproducible workflows to extract agronomic traits from UAV and Sentinel-2 imagery, from raw image preprocessing to trait extraction, statistical analysis and visualization.
16
+
17
+
12
18
  The project currently combines multispectral Sentinel-2 processing with classical RGB UAV image analysis. The first UAV developments focus on crop-row detection, vegetation segmentation and plant-position analysis, with the objective of progressively extending the framework toward more advanced high-throughput phenotyping workflows.
13
19
 
20
+ The project includes automated testing, continuous integration, code coverage monitoring, and package distribution through PyPI. Docker support provides a reproducible runtime environment for command-line processing.
21
+
14
22
  ## Current Features:
15
23
  **Sentinel-2**
16
24
  - [X] Sentinel-2 imagery reading
@@ -27,13 +35,12 @@ The project currently combines multispectral Sentinel-2 processing with classica
27
35
  - [X] Processing results export
28
36
  - [X] Batch processing of multiple Sentinel-2 products
29
37
  - [X] Visualization
30
- - [X] Unit Tests
31
- - [X] Command-Line Interface (CLI)
32
38
 
33
39
  **UAV RGB**
34
40
  - [X] RGB UAV imagery reading
35
41
  - [X] RGB vegetation indices
36
42
  - [X] Vegetation segmentation
43
+ - [X] Vegetation fraction estimation
37
44
  - [X] Crop-row orientation estimation
38
45
  - [X] Crop-row detection
39
46
  - [X] Crop-row boundary detection
@@ -42,12 +49,22 @@ The project currently combines multispectral Sentinel-2 processing with classica
42
49
  - [X] Georeferenced UAV Image support
43
50
  - [X] Experimental plot metadata integration
44
51
  - [X] UAV RGB workflow demonstration
45
-
46
- **Software quality**
47
- - [X] Visualization utilities
48
- - [X] Unit tests
49
- - [X] Code quality checks with Ruff
52
+ - [x] Georeferenced raster metadata validation
53
+ - [x] GeoTIFF raster tiling with geospatial metadata preservation
54
+ - [x] Reconstruction of raster mosaics from tiles
55
+
56
+ **Software quality & distribution**
57
+
58
+ - [X] Unit and integration tests with pytest
59
+ - [X] Automated code quality checks with Ruff
60
+ - [X] Automated CI with GitHub Actions
61
+ - [X] Test coverage monitoring with pytest-cov and Codecov
62
+ - [X] Python package build and distribution through PyPI
63
+ - [X] Docker containerization
64
+ - [X] Automated Docker image publishing through GitHub Actions
65
+ - [X] Dependency update management with Dependabot
50
66
  - [X] Reproducible toy datasets
67
+ - [X] Command-line interface (CLI)
51
68
 
52
69
  ## Case studies
53
70
 
@@ -652,6 +669,127 @@ opencropphenotyping batch-uav \
652
669
 
653
670
  The CLI follows the same processing pipeline as the Python API and can therefore be used for reproducible processing of individual UAV datasets or complete directories of datasets.
654
671
 
672
+ ## Georeferenced raster support and tiling
673
+
674
+ OpenCropPhenotyping provides utilities to validate georeferenced raster metadata, split GeoTIFF rasters into smaller tiles, and reconstruct a raster mosaic from these tiles.
675
+
676
+ These utilities support the handling of large UAV orthomosaics while preserving their spatial reference information.
677
+
678
+ ### Available functions
679
+
680
+ - `validate_georeferenced_raster()`: checks the consistency of raster georeferencing metadata.
681
+ - `tile_raster()`: divides a raster into smaller tiles while preserving their spatial metadata.
682
+ - `merge_raster_tiles()`: reconstructs a raster mosaic from georeferenced tiles.
683
+
684
+ The functions operate on existing georeferenced rasters. They do not generate orthomosaics from raw UAV photographs, which requires a dedicated photogrammetry workflow.
685
+
686
+ ## Docker
687
+
688
+ OpenCropPhenotyping is available as a Docker image, providing a reproducible Linux environment with the package and its dependencies pre-installed.
689
+
690
+ Docker images are published to GitHub Container Registry (GHCR) when a new version is released.
691
+
692
+ ### Requirements
693
+
694
+ - [Docker Desktop](https://www.docker.com/products/docker-desktop/) or Docker Engine
695
+ - UAV or Sentinel-2 input data (toy datasets are included in the image)
696
+ - A published OpenCropPhenotyping Docker image
697
+
698
+ ### Download the image
699
+
700
+ Pull a specific released version:
701
+
702
+ ```bash
703
+ docker pull ghcr.io/aurelien-peter/opencropphenotyping:VERSION
704
+ ```
705
+
706
+ Replace `VERSION` with an available release tag, such as `0.2.2`.
707
+
708
+ ### Check the installation
709
+
710
+ Display the available CLI commands:
711
+
712
+ ```bash
713
+ docker run --rm ghcr.io/aurelien-peter/opencropphenotyping:VERSION --help
714
+ ```
715
+
716
+ Available commands include:
717
+
718
+ - `process`: process a single Sentinel-2 product.
719
+ - `batch`: process multiple Sentinel-2 products.
720
+ - `segment-uav`: process a single UAV RGB dataset.
721
+ - `batch-uav`: process multiple UAV datasets.
722
+
723
+ ### Process Sentinel-2 imagery
724
+
725
+ Input data and output directories are provided through a bind mount. In the following example, a local `data` directory is mounted at `/data` inside the container.
726
+
727
+ ```bash
728
+ docker run --rm \
729
+ --mount type=bind,source=/absolute/path/to/data,target=/data \
730
+ ghcr.io/aurelien-peter/opencropphenotyping:VERSION \
731
+ process \
732
+ --input-dir /data/raw/sentinel_product \
733
+ --output-dir /data/results \
734
+ --processed-dir /data/processed \
735
+ --indices ndvi \
736
+ --ndvi-threshold 0.3 \
737
+ --resolution 10
738
+ ```
739
+
740
+ Replace `/absolute/path/to/data` with the absolute path to the local directory containing your data.
741
+
742
+ The input path must point to a Sentinel-2 product supported by the pipeline. Results written under `/data` are available in the corresponding local directory after the container exits.
743
+
744
+ ### Process UAV RGB imagery
745
+
746
+ A single UAV dataset requires an RGB image, its georeferenced GeoTIFF and a GeoPackage describing the experimental plot.
747
+
748
+ ```bash
749
+ docker run --rm \
750
+ --mount type=bind,source=/absolute/path/to/data,target=/data \
751
+ ghcr.io/aurelien-peter/opencropphenotyping:VERSION \
752
+ segment-uav \
753
+ --image /data/uav/image.png \
754
+ --geotiff /data/uav/image_georef.tif \
755
+ --geopackage /data/uav/plots.gpkg \
756
+ --output-dir /data/results/uav
757
+ ```
758
+
759
+ To process several UAV datasets, use the `batch-uav` command. Each dataset must be stored in its own subdirectory containing the required input files.
760
+
761
+ ```bash
762
+ docker run --rm \
763
+ --mount type=bind,source=/absolute/path/to/data,target=/data \
764
+ ghcr.io/aurelien-peter/opencropphenotyping:VERSION \
765
+ batch-uav \
766
+ --input-dir /data/uav \
767
+ --output-dir /data/results/uav
768
+ ```
769
+
770
+ ### Build the image locally
771
+
772
+ To build the Docker image from the source code instead of pulling a published release, clone the repository and run:
773
+
774
+ ```bash
775
+ git clone https://github.com/Aurelien-Peter/OpenCropPhenotyping.git
776
+ cd OpenCropPhenotyping
777
+
778
+ docker build -t opencropphenotyping:local .
779
+ ```
780
+
781
+ Check the local image:
782
+
783
+ ```bash
784
+ docker run --rm opencropphenotyping:local --help
785
+ ```
786
+
787
+ ### Notes
788
+
789
+ - The container is designed for command-line processing jobs. It starts, executes the requested command and exits when the job is complete.
790
+ - Use a bind mount for both input data and output directories to keep files accessible outside the container.
791
+
792
+
655
793
  ## Contributing
656
794
 
657
795
  Contributions are welcome. If you have ideas for improvements, bug fixes or new features, feel free to open an issue or submit a pull request.
@@ -5,13 +5,18 @@ build-backend = "setuptools.build_meta"
5
5
 
6
6
  [project]
7
7
  name = "opencropphenotyping"
8
- version = "0.2.0"
8
+ version = "0.3.0"
9
9
  description = "Open-source tools for crop phenotyping using multispectral geospatial imagery"
10
10
  authors = [
11
11
  {name = "Aurélien Peter"}
12
12
  ]
13
13
  readme = "README.md"
14
14
  requires-python = ">=3.11"
15
+ classifiers = [
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3.11",
18
+ "Operating System :: OS Independent",
19
+ ]
15
20
 
16
21
  dependencies = [
17
22
  "numpy",
@@ -144,7 +144,166 @@ def compute_savi(red_band: np.ndarray, nir_band: np.ndarray, L_factor : float =
144
144
 
145
145
  return savi.astype(np.float32)
146
146
 
147
+ def compute_exg(
148
+ rgb: tuple[np.ndarray, np.ndarray, np.ndarray],
149
+ ) -> np.ndarray:
150
+ """Compute the Excess Green Index (ExG).
151
+
152
+ Parameters
153
+ ----------
154
+ rgb : tuple[np.ndarray, np.ndarray, np.ndarray]
155
+ RGB image channels as (red, green, blue).
156
+
157
+ Returns
158
+ -------
159
+ np.ndarray
160
+ ExG image with dtype float32.
161
+ """
162
+ red, green, blue = (band.astype(np.float32) for band in rgb)
163
+
164
+ return 2 * green - red - blue
165
+
166
+ def compute_exr(
167
+ rgb: tuple[np.ndarray, np.ndarray, np.ndarray],
168
+ ) -> np.ndarray:
169
+ """Compute the Excess Red Index (ExR).
170
+
171
+ Parameters
172
+ ----------
173
+ rgb : tuple[np.ndarray, np.ndarray, np.ndarray]
174
+ RGB image channels as (red, green, blue).
175
+
176
+ Returns
177
+ -------
178
+ np.ndarray
179
+ ExR image with dtype float32.
180
+ """
181
+ red, green, _ = (band.astype(np.float32) for band in rgb)
182
+
183
+ return 1.4 * red - green
184
+
185
+
186
+ def compute_exgr(
187
+ rgb: tuple[np.ndarray, np.ndarray, np.ndarray],
188
+ ) -> np.ndarray:
189
+ """Compute the Excess Green minus Excess Red Index (ExGR).
190
+
191
+ Parameters
192
+ ----------
193
+ rgb : tuple[np.ndarray, np.ndarray, np.ndarray]
194
+ RGB image channels as (red, green, blue).
195
+
196
+ Returns
197
+ -------
198
+ np.ndarray
199
+ ExGR image with dtype float32.
200
+ """
201
+ exg = compute_exg(rgb)
202
+ exr = compute_exr(rgb)
203
+
204
+ return exg - exr
205
+
206
+
207
+ def compute_vari(
208
+ rgb: tuple[np.ndarray, np.ndarray, np.ndarray],
209
+ ) -> np.ndarray:
210
+ """Compute the Visible Atmospherically Resistant Index (VARI).
211
+
212
+ Parameters
213
+ ----------
214
+ rgb : tuple[np.ndarray, np.ndarray, np.ndarray]
215
+ RGB image channels as (red, green, blue).
216
+
217
+ Returns
218
+ -------
219
+ np.ndarray
220
+ VARI image with dtype float32.
221
+ """
222
+ red, green, blue = (band.astype(np.float32) for band in rgb)
223
+
224
+ numerator = green - red
225
+ denominator = green + red - blue
226
+
227
+ result = np.full(numerator.shape, np.nan, dtype=np.float32)
228
+
229
+ np.divide(
230
+ numerator,
231
+ denominator,
232
+ out=result,
233
+ where=denominator != 0,
234
+ )
235
+
236
+ return result
237
+
238
+
239
+ def compute_gli(
240
+ rgb: tuple[np.ndarray, np.ndarray, np.ndarray],
241
+ ) -> np.ndarray:
242
+ """Compute the Green Leaf Index (GLI).
243
+
244
+ Parameters
245
+ ----------
246
+ rgb : tuple[np.ndarray, np.ndarray, np.ndarray]
247
+ RGB image channels as (red, green, blue).
248
+
249
+ Returns
250
+ -------
251
+ np.ndarray
252
+ GLI image with dtype float32.
253
+ """
254
+ red, green, blue = (band.astype(np.float32) for band in rgb)
255
+
256
+ numerator = 2 * green - red - blue
257
+ denominator = 2 * green + red + blue
258
+
259
+ result = np.full(numerator.shape, np.nan, dtype=np.float32)
260
+
261
+ np.divide(
262
+ numerator,
263
+ denominator,
264
+ out=result,
265
+ where=denominator != 0,
266
+ )
267
+
268
+ return result
269
+
270
+
271
+ def compute_rgbvi(
272
+ rgb: tuple[np.ndarray, np.ndarray, np.ndarray],
273
+ ) -> np.ndarray:
274
+ """Compute the Red Green Blue Vegetation Index (RGBVI).
275
+
276
+ Parameters
277
+ ----------
278
+ rgb : tuple[np.ndarray, np.ndarray, np.ndarray]
279
+ RGB image channels as (red, green, blue).
280
+
281
+ Returns
282
+ -------
283
+ np.ndarray
284
+ RGBVI image with dtype float32.
285
+ """
286
+ red, green, blue = (band.astype(np.float32) for band in rgb)
287
+
288
+ green_squared = green**2
289
+ red_blue = red * blue
290
+
291
+ numerator = green_squared - red_blue
292
+ denominator = green_squared + red_blue
293
+
294
+ result = np.full(numerator.shape, np.nan, dtype=np.float32)
295
+
296
+ np.divide(
297
+ numerator,
298
+ denominator,
299
+ out=result,
300
+ where=denominator != 0,
301
+ )
302
+
303
+ return result
304
+
147
305
  VEGETATION_INDICES = {
306
+ # Satellite
148
307
  "ndvi": {
149
308
  "function": compute_ndvi,
150
309
  "bands": ["red_band", "nir_band"],
@@ -161,6 +320,37 @@ VEGETATION_INDICES = {
161
320
  "function": compute_gndvi,
162
321
  "bands": ["nir_band", "green_band"],
163
322
  },
323
+ # UAV RGB
324
+ "exg": {
325
+ "bands": ["red_band", "green_band", "blue_band"],
326
+ "function": compute_exg,
327
+ "input_type": "rgb",
328
+ },
329
+ "exr": {
330
+ "bands": ["red_band", "green_band", "blue_band"],
331
+ "function": compute_exr,
332
+ "input_type": "rgb",
333
+ },
334
+ "exgr": {
335
+ "bands": ["red_band", "green_band", "blue_band"],
336
+ "function": compute_exgr,
337
+ "input_type": "rgb",
338
+ },
339
+ "vari": {
340
+ "bands": ["red_band", "green_band", "blue_band"],
341
+ "function": compute_vari,
342
+ "input_type": "rgb",
343
+ },
344
+ "gli": {
345
+ "bands": ["red_band", "green_band", "blue_band"],
346
+ "function": compute_gli,
347
+ "input_type": "rgb",
348
+ },
349
+ "rgbvi": {
350
+ "bands": ["red_band", "green_band", "blue_band"],
351
+ "function": compute_rgbvi,
352
+ "input_type": "rgb",
353
+ },
164
354
  }
165
355
 
166
356
  def compute_indexes(
@@ -168,6 +358,7 @@ def compute_indexes(
168
358
  nir_band: np.ndarray | None = None,
169
359
  green_band: np.ndarray | None = None,
170
360
  red_edge_band: np.ndarray | None = None,
361
+ blue_band: np.ndarray | None = None,
171
362
  indices: list[str] | None = None,
172
363
  ) -> dict[str, np.ndarray]:
173
364
  """Compute vegetation indices from available spectral bands.
@@ -182,6 +373,8 @@ def compute_indexes(
182
373
  Green spectral band.
183
374
  red_edge_band : np.ndarray or None, optional
184
375
  Red-edge spectral band.
376
+ blue_band : np.ndarray or None, optional
377
+ Blue spectral band.
185
378
  indices : list[str] or None, optional
186
379
  Names of the vegetation indices to compute. If None, all
187
380
  available vegetation indices are requested.
@@ -201,13 +394,14 @@ def compute_indexes(
201
394
  results = {}
202
395
 
203
396
  if indices is None:
204
- indices = ["ndvi", "savi", "ndre", "gndvi"]
397
+ indices = list(VEGETATION_INDICES)
205
398
 
206
399
  available_bands = {
207
400
  "red_band": red_band,
208
401
  "nir_band": nir_band,
209
402
  "green_band": green_band,
210
403
  "red_edge_band": red_edge_band,
404
+ "blue_band": blue_band,
211
405
  }
212
406
 
213
407
  for index in indices:
@@ -227,27 +421,9 @@ def compute_indexes(
227
421
  for band in required_bands
228
422
  ]
229
423
 
230
- results[index] = compute_function(*band_arrays)
424
+ if index_config.get("input_type") == "rgb":
425
+ results[index] = compute_function(tuple(band_arrays))
426
+ else:
427
+ results[index] = compute_function(*band_arrays)
231
428
 
232
- return results
233
-
234
- def compute_exg(
235
- rgb: tuple[np.ndarray, np.ndarray, np.ndarray],
236
- ) -> np.ndarray:
237
- """Compute the Excess Green Index (ExG).
238
-
239
- Parameters
240
- ----------
241
- rgb : tuple[np.ndarray, np.ndarray, np.ndarray]
242
- RGB image channels as (red, green, blue).
243
-
244
- Returns
245
- -------
246
- np.ndarray
247
- ExG image with dtype float32.
248
- """
249
- red = rgb[0].astype(np.float32)
250
- green = rgb[1].astype(np.float32)
251
- blue = rgb[2].astype(np.float32)
252
-
253
- return 2 * green - red - blue
429
+ return results