opencropphenotyping 0.2.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/LICENSE +21 -0
  2. opencropphenotyping-0.2.0/PKG-INFO +695 -0
  3. opencropphenotyping-0.2.0/README.md +671 -0
  4. opencropphenotyping-0.2.0/pyproject.toml +53 -0
  5. opencropphenotyping-0.2.0/setup.cfg +4 -0
  6. opencropphenotyping-0.2.0/src/opencropphenotyping/batch_processing.py +128 -0
  7. opencropphenotyping-0.2.0/src/opencropphenotyping/cli.py +218 -0
  8. opencropphenotyping-0.2.0/src/opencropphenotyping/coco.py +175 -0
  9. opencropphenotyping-0.2.0/src/opencropphenotyping/evaluation.py +352 -0
  10. opencropphenotyping-0.2.0/src/opencropphenotyping/indices.py +253 -0
  11. opencropphenotyping-0.2.0/src/opencropphenotyping/io.py +540 -0
  12. opencropphenotyping-0.2.0/src/opencropphenotyping/pipeline.py +393 -0
  13. opencropphenotyping-0.2.0/src/opencropphenotyping/segmentation.py +1320 -0
  14. opencropphenotyping-0.2.0/src/opencropphenotyping/statistics.py +17 -0
  15. opencropphenotyping-0.2.0/src/opencropphenotyping/traits.py +60 -0
  16. opencropphenotyping-0.2.0/src/opencropphenotyping/visualization.py +467 -0
  17. opencropphenotyping-0.2.0/src/opencropphenotyping.egg-info/PKG-INFO +695 -0
  18. opencropphenotyping-0.2.0/src/opencropphenotyping.egg-info/SOURCES.txt +32 -0
  19. opencropphenotyping-0.2.0/src/opencropphenotyping.egg-info/dependency_links.txt +1 -0
  20. opencropphenotyping-0.2.0/src/opencropphenotyping.egg-info/entry_points.txt +2 -0
  21. opencropphenotyping-0.2.0/src/opencropphenotyping.egg-info/requires.txt +15 -0
  22. opencropphenotyping-0.2.0/src/opencropphenotyping.egg-info/top_level.txt +1 -0
  23. opencropphenotyping-0.2.0/tests/test_batch_processing.py +217 -0
  24. opencropphenotyping-0.2.0/tests/test_cli.py +359 -0
  25. opencropphenotyping-0.2.0/tests/test_coco.py +289 -0
  26. opencropphenotyping-0.2.0/tests/test_evaluation.py +341 -0
  27. opencropphenotyping-0.2.0/tests/test_indices.py +425 -0
  28. opencropphenotyping-0.2.0/tests/test_io.py +570 -0
  29. opencropphenotyping-0.2.0/tests/test_pipeline.py +564 -0
  30. opencropphenotyping-0.2.0/tests/test_segmentation.py +1464 -0
  31. opencropphenotyping-0.2.0/tests/test_statistics.py +52 -0
  32. opencropphenotyping-0.2.0/tests/test_toy_dataset.py +37 -0
  33. opencropphenotyping-0.2.0/tests/test_traits.py +82 -0
  34. opencropphenotyping-0.2.0/tests/test_visualization.py +105 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Aurelien-Peter
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,695 @@
1
+ Metadata-Version: 2.4
2
+ Name: opencropphenotyping
3
+ Version: 0.2.0
4
+ Summary: Open-source tools for crop phenotyping using multispectral geospatial imagery
5
+ Author: Aurélien Peter
6
+ Requires-Python: >=3.11
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: numpy
10
+ Requires-Dist: pandas
11
+ Requires-Dist: scipy
12
+ Requires-Dist: rasterio
13
+ Requires-Dist: geopandas
14
+ Requires-Dist: matplotlib
15
+ Requires-Dist: pillow
16
+ Requires-Dist: typer
17
+ Provides-Extra: dev
18
+ Requires-Dist: pytest; extra == "dev"
19
+ Requires-Dist: pytest-cov; extra == "dev"
20
+ Requires-Dist: ruff; extra == "dev"
21
+ Requires-Dist: jupyter; extra == "dev"
22
+ Requires-Dist: plotly; extra == "dev"
23
+ Dynamic: license-file
24
+
25
+ # OpenCropPhenotyping
26
+
27
+ [![CI](https://github.com/Aurelien-Peter/OpenCropPhenotyping/actions/workflows/ci.yml/badge.svg)](https://github.com/Aurelien-Peter/OpenCropPhenotyping/actions/workflows/ci.yml)
28
+ [![codecov](https://codecov.io/github/Aurelien-Peter/OpenCropPhenotyping/graph/badge.svg?token=7SAC1M1VY5)](https://codecov.io/github/Aurelien-Peter/OpenCropPhenotyping)
29
+
30
+ **An open-source Python framework for high-throughput crop phenotyping using drone and satellite imagery.**
31
+
32
+ ## About the project
33
+
34
+ OpenCropPhenotyping is an open-source project dedicated to reproducible high-throughput crop phenotyping using remote sensing data.
35
+ 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.
36
+ 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
+
38
+ ## Current Features:
39
+ **Sentinel-2**
40
+ - [X] Sentinel-2 imagery reading
41
+ - [X] Sentinel-2 band selection and resampling
42
+ - [X] NDVI computation
43
+ - [X] NDRE computation
44
+ - [X] GNDVI computation
45
+ - [X] SAVI computation
46
+ - [X] Generic vegetation index computation
47
+ - [X] Vegetation masking
48
+ - [X] Crop cover estimation
49
+ - [X] Statistical analysis
50
+ - [X] Sentinel-2 processing pipeline
51
+ - [X] Processing results export
52
+ - [X] Batch processing of multiple Sentinel-2 products
53
+ - [X] Visualization
54
+ - [X] Unit Tests
55
+ - [X] Command-Line Interface (CLI)
56
+
57
+ **UAV RGB**
58
+ - [X] RGB UAV imagery reading
59
+ - [X] RGB vegetation indices
60
+ - [X] Vegetation segmentation
61
+ - [X] Crop-row orientation estimation
62
+ - [X] Crop-row detection
63
+ - [X] Crop-row boundary detection
64
+ - [X] Planting position estimation from plot geometry
65
+ - [X] Vegetation based plant occupancy estimation
66
+ - [X] Georeferenced UAV Image support
67
+ - [X] Experimental plot metadata integration
68
+ - [X] UAV RGB workflow demonstration
69
+
70
+ **Software quality**
71
+ - [X] Visualization utilities
72
+ - [X] Unit tests
73
+ - [X] Code quality checks with Ruff
74
+ - [X] Reproducible toy datasets
75
+
76
+ ## Case studies
77
+
78
+ The project includes reproducible case studies based on real agricultural areas in Southern France.
79
+
80
+ Current case studies:
81
+
82
+ - Maize monitoring with Sentinel-2 (Occitanie)
83
+ - UAV RGB crop-row and plant-position analysis on a toy dataset
84
+
85
+ ## Roadmap
86
+
87
+ ### Version 0.1
88
+ #### Sentinel-2
89
+
90
+ - Read Sentinel-2 imagery
91
+ - NDVI computation
92
+ - Visualization
93
+ - GeoTIFF export
94
+ - PNG export
95
+ - Toy dataset
96
+ - Unit tests
97
+
98
+ ---
99
+
100
+ ### Version 0.2
101
+ #### Vegetation indices and processing pipeline
102
+
103
+ - NDRE computation
104
+ - SAVI computation
105
+ - GNDVI computation
106
+ - Generic vegetation index computation
107
+ - Statistics
108
+ - Vegetation masking
109
+ - Trait Extraction (Crop cover)
110
+ - Sentinel-2 processing pipeline
111
+ - Processing results export
112
+ - Batch processing
113
+ - Command-line interface (CLI)
114
+
115
+ ---
116
+
117
+ ### Version 0.3
118
+ #### Drone imagery
119
+
120
+ - RGB UAV imagery reading
121
+ - RGB vegetation indices
122
+ - Vegetation segmentation
123
+ - Crop-row orientation estimation
124
+ - Crop-row detection
125
+ - Plant-position estimation
126
+ - Experimental plot geometry integration
127
+ - Georeferenced UAV image support
128
+ - UAV image tiling
129
+ - Batch processing of large UAV images
130
+
131
+ Current v0.3 development includes a classical, interpretable workflow for crop-row and plant-position analysis. Plant occupancy estimation currently relies on vegetation fraction within theoretical planting positions and is sensitive to plant development stage and image quality.
132
+
133
+ ---
134
+
135
+ ### Version 0.4
136
+ #### Machine Learning
137
+
138
+ - Feature extraction
139
+ - Dataset preparation
140
+ - Classical classifiers (Random Forest, SVM)
141
+ - Crop classification
142
+ - Model evaluation
143
+ - Model persistence
144
+
145
+ ### Version 0.5
146
+ #### Deep Learning
147
+
148
+ - PyTorch support
149
+ - CNN semantic segmentation
150
+ - U-Net implementation
151
+ - Training pipeline
152
+ - Inference pipeline
153
+ - Model visualization
154
+
155
+ ### Version 1.0
156
+
157
+ Complete crop phenotyping workflow
158
+
159
+ ## For which users?
160
+
161
+ This project is intended for researchers, agronomists, engineers working in remote sensing, as well as for UAV practitioners and interested students.
162
+ The project is also suitable for anyone wishing to learn how to process drone or Sentinel-2 imagery using Python.
163
+
164
+ ## Installation
165
+
166
+ git clone ...
167
+
168
+ cd OpenCropPhenotyping
169
+
170
+ conda env create -f environment.yml
171
+
172
+ conda activate opencropphenotyping
173
+
174
+ pip install -e .
175
+
176
+ ## How to use
177
+
178
+ The repository already includes a small Sentinel-2 toy dataset.
179
+
180
+ No additional data download is required to run the examples
181
+
182
+ ## Command-line interface
183
+
184
+ OpenCropPhenotyping provides a command-line interface to process Sentinel-2 products directly from a terminal.
185
+
186
+ After installing the package, the opencropphenotyping command provides two main operations:
187
+
188
+ - process: process a single Sentinel-2 product.
189
+ - batch: process multiple Sentinel-2 products contained in a directory.
190
+
191
+ ### Process a single product
192
+
193
+ ```python
194
+ opencropphenotyping process \
195
+ --input-dir path/to/Sentinel2_product \
196
+ --output-dir path/to/results \
197
+ --processed-dir path/to/processed \
198
+ --indices ndvi \
199
+ --ndvi-threshold 0.3 \
200
+ --resolution 10
201
+ ```
202
+
203
+ The command processes the Sentinel-2 product, computes the requested vegetation indices, generates the vegetation mask and crop-cover statistics, and exports the results.
204
+
205
+ ### Process multiple products
206
+
207
+ ```python
208
+ opencropphenotyping batch \
209
+ --input-dir path/to/sentinel2_products \
210
+ --output-dir path/to/results \
211
+ --processed-dir path/to/processed \
212
+ --indices ndvi \
213
+ --ndvi-threshold 0.3 \
214
+ --resolution 10
215
+ ```
216
+
217
+ The input directory should contain one Sentinel-2 product per subdirectory. Each product is processed independently and its results are stored in a dedicated subdirectory.
218
+
219
+ For example:
220
+
221
+ input/
222
+ ├── S2A_MSIL2A_product_1.SAFE/
223
+ └── S2B_MSIL2A_product_2.SAFE/
224
+
225
+ produces:
226
+
227
+ results/
228
+ ├── S2A_MSIL2A_product_1.SAFE/
229
+ └── S2B_MSIL2A_product_2.SAFE/
230
+
231
+ ### Get help
232
+
233
+ General help is available with:
234
+
235
+ ```python
236
+ opencropphenotyping --help
237
+ ```
238
+
239
+ Help for an individual command can be obtained with:
240
+
241
+ ```python
242
+ opencropphenotyping process --help
243
+ ```
244
+
245
+ ```python
246
+ opencropphenotyping batch --help
247
+ ```
248
+
249
+ ```python
250
+ opencropphenotyping segment_uav --help
251
+ ```
252
+
253
+ ```python
254
+ opencropphenotyping process_uav_segmentation --help
255
+ ```
256
+
257
+ If an error occurs while processing a product, the CLI reports the error and exits with a non-zero status code.
258
+
259
+ ## Example workflow
260
+
261
+ OpenCropPhenotyping currently provides two complementary image-processing workflows:
262
+
263
+ - Sentinel-2 multispectral processing
264
+ - UAV RGB crop-row and plant-position analysis
265
+
266
+ ## Sentinel-2 workflow
267
+
268
+ The Sentinel-2 workflow processes multispectral bands to compute vegetation indices, derive vegetation masks and estimate crop cover.
269
+
270
+ ### Sentinel-2 input bands
271
+
272
+ #### Sentinel-2 Red band (B04)
273
+
274
+ ![B04](docs/images/red.png)
275
+
276
+ #### Sentinel-2 Near Infra Red band (B08)
277
+
278
+ ![B08](docs/images/nir.png)
279
+
280
+ #### Green band (B03)
281
+
282
+ ![B03](docs/images/green.png)
283
+
284
+ #### Red Edge band (B05)
285
+
286
+ ![B05](docs/images/red_edge.png)
287
+
288
+ ↓
289
+
290
+ ### Vegetation indices
291
+
292
+ The selected Sentinel-2 bands are combined to compute several vegetation indices:
293
+
294
+ B04 Red ───────┬──→ NDVI
295
+                   └──→ SAVI
296
+
297
+ B08 NIR ───────┬──→ NDVI
298
+                   ├──→ SAVI
299
+                   ├──→ GNDVI
300
+                   └──→ NDRE
301
+
302
+ B03 Green ────────→ GNDVI
303
+
304
+ B05 Red Edge ──────→ NDRE
305
+
306
+ #### NDVI — Normalized Difference Vegetation Index
307
+
308
+ ![NDVI](docs/images/ndvi.png)
309
+
310
+ #### NDRE — Normalized Difference Red Edge Index
311
+
312
+ ![NDRE](docs/images/ndre.png)
313
+
314
+ #### GNDVI — Green Normalized Difference Vegetation Index
315
+
316
+ ![GNDVI](docs/images/gndvi.png)
317
+
318
+ #### SAVI — Soil-Adjusted Vegetation Index
319
+
320
+ ![SAVI](docs/images/savi.png)
321
+
322
+ ↓
323
+
324
+ ### Statistics and visualization
325
+
326
+ Statistics are computed for each vegetation index to characterize the distribution of pixel values.
327
+
328
+ #### NDVI distribution
329
+
330
+ ![NDVI distribution](docs/images/ndvi_hist_0.png)
331
+
332
+ #### NDVI boxplot
333
+
334
+ ![NDVI boxplot](docs/images/ndvi_hist_1.png)
335
+
336
+ ↓
337
+
338
+ ### Trait extraction
339
+
340
+ The NDVI image is used to create a vegetation mask and estimate crop cover.
341
+
342
+ #### Vegetation mask
343
+
344
+ ![Vegetation mask](docs/images/vegetation_mask_custom.png)
345
+
346
+ Crop cover: **39.24%**
347
+
348
+ ↓
349
+
350
+ ### Export
351
+
352
+ The processing results can be exported to a dedicated output directory.
353
+ For batch processing, each Sentinel-2 product is exported to its own subdirectory.
354
+
355
+ The exported files include:
356
+
357
+ - GeoTIFF files for the computed vegetation indices;
358
+ - a GeoTIFF file containing the vegetation mask;
359
+ - a CSV file containing statistics for each vegetation index;
360
+ - a text file containing the estimated crop cover.
361
+
362
+ The results directory is organized as follows:
363
+
364
+ results/
365
+ ├── indices/
366
+ │    ├── ndvi.tif
367
+ │    ├── savi.tif
368
+ │    ├── ndre.tif
369
+ │    └── gndvi.tif
370
+ ├── vegetation_mask.tif
371
+ ├── statistics.csv
372
+ └── crop_cover.txt
373
+
374
+ ### Processing pipeline
375
+
376
+ The Sentinel-2 processing pipeline provides a high-level interface to process Sentinel-2 imagery and extract vegetation-related traits.
377
+
378
+ ```python
379
+ from pathlib import Path
380
+
381
+ from opencropphenotyping.pipeline import (
382
+ process_sentinel2,
383
+ export_results,
384
+ )
385
+
386
+ input_dir = Path("data/raw")
387
+ output_dir = Path("data/processed")
388
+
389
+ result = process_sentinel2(
390
+ input_dir=input_dir,
391
+ indices=["ndvi", "ndre"],
392
+ resolution=10,
393
+ ndvi_threshold=0.3,
394
+ )
395
+
396
+ export_results(
397
+ result,
398
+ output_dir=output_dir,
399
+ )
400
+ ```
401
+
402
+ The indices parameter can be used to select which vegetation indices are computed:
403
+
404
+ ```python
405
+ indices=["ndvi"]
406
+ ```
407
+
408
+ or:
409
+
410
+ ```python
411
+ indices=["ndvi", "savi", "ndre", "gndvi"]
412
+ ```
413
+
414
+ If ```python indices=None```, all available vegetation indices are requested.
415
+
416
+ If the bands required for a requested index are unavailable, that index is not computed and the pipeline continues processing the other available indices.
417
+
418
+ When NDVI is available, the pipeline also creates a vegetation mask and estimates crop cover.
419
+
420
+ ### Processing results
421
+
422
+ The process_sentinel2() function returns a ProcessingResult object containing:
423
+
424
+ - the computed vegetation indices;
425
+ - the raster profile;
426
+ - statistics for each computed index;
427
+ - the vegetation mask, when NDVI is available;
428
+ - the crop cover estimate, when NDVI is available.
429
+
430
+ The results can then be exported using export_results().
431
+
432
+ ## RGB UAV imagery
433
+
434
+ OpenCropPhenotyping also provides a classical RGB UAV workflow for crop-row and plant-position analysis.
435
+
436
+ The workflow is designed around a combination of:
437
+
438
+ - RGB image analysis
439
+ - ExG vegetation segmentation
440
+ - crop-row geometry
441
+ - georeferenced raster data
442
+ - experimental plot geometry
443
+ - plot-level metadata
444
+ - theoretical planting positions
445
+ - vegetation fraction within planting positions
446
+
447
+ The workflow can be demonstrated step by step or accessed through the high-level plant-detection function.
448
+
449
+ #### Load UAV RGB image
450
+
451
+ The workflow starts from an RGB UAV image.
452
+
453
+ ![UAV RGB image](docs/images/rgb.png)
454
+
455
+
456
+ ↓
457
+
458
+ #### Georeferenced UAV image and experimental plot
459
+
460
+ To integrate experimental plot information into the image-processing workflow, the UAV image is converted into a georeferenced GeoTIFF.
461
+
462
+ The GeoTIFF stores both the RGB raster data and the spatial information required to relate image pixels to spatial coordinates.
463
+
464
+ The corresponding experimental plot is stored in a GeoPackage containing the plot geometry and experimental metadata, including:
465
+
466
+ - ```image_id```
467
+ - ```n_rows```
468
+ - ```n_plants```
469
+ - ```geometry```
470
+
471
+ The plot geometry is validated against the GeoTIFF to ensure that the experimental plot is correctly aligned with the image.
472
+
473
+ The plot geometry is then rasterized and transformed using the same crop-row rotation as the UAV image. This provides the spatial boundaries used to define crop-row regions and theoretical planting positions.
474
+
475
+ ↓
476
+
477
+ #### Vegetation segmentation
478
+
479
+ RGB imagery is converted into an Excess Green (ExG) vegetation index and thresholded to produce a vegetation mask.
480
+
481
+ ![Exg Mask](docs/images/exg_rotated.png)
482
+
483
+
484
+ ↓
485
+
486
+ #### Crop-row detection
487
+
488
+ The vegetation profile is used to estimate crop-row orientation and identify crop-row positions.
489
+ Experimental plot metadata are then used to define the expected number of crop rows and their spatial boundaries.
490
+
491
+ ![Crop-Row profile](docs/images/crop_row_profile.png)
492
+
493
+ ↓
494
+
495
+ #### Plant occupancy estimation
496
+
497
+ The experimental plot geometry and ```n_plants``` metadata are used to define theoretical planting positions along each crop row.
498
+
499
+ Vegetation fraction within each theoretical planting position is then used as an indicator of plant occupancy.
500
+
501
+ ![Plant Detection](docs/images/rgb_detection.png)
502
+
503
+
504
+ The current approach provides an interpretable classical baseline for UAV crop phenotyping. Its performance is influenced by plant development stage and the strength of the vegetation signal in the RGB imagery.
505
+
506
+ #### UAV workflow demonstration
507
+
508
+ A dedicated notebook demonstrates the complete workflow and the use of the package functions:
509
+
510
+ notebooks/
511
+ └── 06_UAV RGB workflow demonstration.ipynb
512
+
513
+ The notebook also contains examples of intermediate visualizations and exported figures used for project documentation with batch processing function.
514
+
515
+ #### RGB UAV imagery
516
+
517
+ RGB images are loaded as three NumPy arrays corresponding to the red, green and blue channels:
518
+ ```python
519
+ from opencropphenotyping.rgb import read_rgb_image
520
+
521
+ red, green, blue = read_rgb_image(image_path)
522
+ ```
523
+ The three returned arrays have the same spatial dimensions as the input image.
524
+
525
+ This functionality provides the foundation for RGB-based vegetation segmentation, crop-row detection and plant-position analysis.
526
+
527
+ ### UAV RGB processing
528
+
529
+ The UAV RGB processing pipeline provides a high-level interface for plant occupancy estimation from RGB drone imagery.
530
+
531
+ A UAV dataset is composed of:
532
+
533
+ * an RGB image;
534
+ * a georeferenced GeoTIFF corresponding to the image;
535
+ * a GeoPackage containing the experimental plot geometry and metadata.
536
+
537
+ The GeoPackage contains the plot geometry together with the `image_id`, `n_rows` and `n_plants` attributes used by the pipeline.
538
+
539
+ A single UAV dataset can be processed using the `detect_plants()` function:
540
+
541
+ ```python
542
+ from pathlib import Path
543
+
544
+ from opencropphenotyping.plants import detect_plants
545
+ from opencropphenotyping.io import export_uav_results
546
+
547
+ image_path = Path("data/raw/uav/image.png")
548
+ geotiff_path = Path("data/raw/uav/image_georef.tif")
549
+ geopackage_path = Path("data/raw/uav/plots.gpkg")
550
+
551
+ result = detect_plants(
552
+ image_path=image_path,
553
+ geotiff_path=geotiff_path,
554
+ geopackage_path=geopackage_path,
555
+ threshold=25,
556
+ vegetation_fraction_threshold=0.04,
557
+ )
558
+
559
+ export_uav_results(
560
+ result,
561
+ output_dir=Path("data/processed/uav"),
562
+ )
563
+ ```
564
+
565
+ The pipeline:
566
+
567
+ * reads the RGB UAV image and computes the Excess Green (ExG) vegetation index;
568
+ * estimates the crop-row orientation and rotates the image and plot geometry accordingly;
569
+ * segments vegetation from the ExG image;
570
+ * detects crop rows;
571
+ * determines crop-row boundaries from the experimental plot geometry;
572
+ * estimates theoretical planting positions from the `n_plants` metadata;
573
+ * calculates vegetation fraction around each expected planting position;
574
+ * identifies potential missing plants using the vegetation-fraction threshold.
575
+
576
+ The `threshold` parameter controls vegetation segmentation from ExG values.
577
+
578
+ The `vegetation_fraction_threshold` parameter is used to classify potential missing plants. Lower values require less vegetation to classify a planting position as occupied.
579
+
580
+ ### Processing results
581
+
582
+ The `detect_plants()` function returns a `UAVSegmentationResult` object containing:
583
+
584
+ * the plant-level dataframe;
585
+ * the estimated crop-row positions;
586
+ * the crop-row boundaries;
587
+ * the estimated row orientation;
588
+ * the vegetation mask;
589
+ * the rotated RGB image;
590
+ * the rotated ExG image.
591
+
592
+ The results can be exported using `export_uav_results()`.
593
+
594
+ By default, the export includes the plant-level results and the detected crop-row positions and boundaries. Intermediate raster outputs can also be exported with:
595
+
596
+ ```python
597
+ export_uav_results(
598
+ result,
599
+ output_dir=output_dir,
600
+ export_intermediate=True,
601
+ )
602
+ ```
603
+
604
+ ### UAV batch processing
605
+
606
+ Several UAV datasets can be processed from a parent directory using `process_uav_batch()`.
607
+
608
+ Each dataset must be stored in a separate subdirectory containing one RGB image, one georeferenced GeoTIFF and one GeoPackage:
609
+
610
+ ```text
611
+ data/raw/uav/
612
+ ├── plot_103_DSC01167/
613
+ │ ├── image.png
614
+ │ ├── image_georef.tif
615
+ │ └── plots.gpkg
616
+ ├── plot_104_DSC09694/
617
+ │ ├── image.png
618
+ │ ├── image_georef.tif
619
+ │ └── plots.gpkg
620
+ └── plot_108_DSC01166/
621
+ ├── image.png
622
+ ├── image_georef.tif
623
+ └── plots.gpkg
624
+ ```
625
+
626
+ The batch function processes each dataset independently and stores the results in a corresponding output subdirectory:
627
+
628
+ ```python
629
+ from pathlib import Path
630
+
631
+ from opencropphenotyping.batch_processing import process_uav_batch
632
+
633
+ process_uav_batch(
634
+ input_dir=Path("data/raw/uav"),
635
+ output_dir=Path("data/processed/uav"),
636
+ threshold=25,
637
+ vegetation_fraction_threshold=0.04,
638
+ export_intermediate=True,
639
+ )
640
+ ```
641
+
642
+ If one dataset cannot be processed, the error is reported and processing continues with the remaining datasets.
643
+
644
+ ### Command-line interface
645
+
646
+ The UAV processing pipeline is also available through the command-line interface.
647
+
648
+ To process a single UAV dataset:
649
+
650
+ ```bash
651
+ opencropphenotyping segment-uav \
652
+ --image-path data/raw/uav/image.png \
653
+ --geotiff-path data/raw/uav/image_georef.tif \
654
+ --geopackage-path data/raw/uav/plots.gpkg \
655
+ --output-dir data/processed/uav
656
+ ```
657
+
658
+ To process several UAV datasets from a parent directory:
659
+
660
+ ```bash
661
+ opencropphenotyping batch-uav \
662
+ --input-dir data/raw/uav \
663
+ --output-dir data/processed/uav
664
+ ```
665
+
666
+ Optional parameters can be used to modify the vegetation segmentation and plant-occupancy thresholds:
667
+
668
+ ```bash
669
+ opencropphenotyping batch-uav \
670
+ --input-dir data/raw/uav \
671
+ --output-dir data/processed/uav \
672
+ --threshold 25 \
673
+ --vegetation-fraction-threshold 0.04 \
674
+ --export-intermediate
675
+ ```
676
+
677
+ 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
+
679
+ ## Contributing
680
+
681
+ 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.
682
+
683
+ ## Documentation
684
+
685
+ Documentation will be progressively added as the project evolves.
686
+ The repository currently provides detailed notebooks illustrating the development and application of the processing workflows.
687
+
688
+ ## Version
689
+
690
+ This project follows Semantic Versioning (SemVer).
691
+ See the Releases page for available versions and change logs.
692
+
693
+ ## LICENSE
694
+
695
+ See the LICENSE file.