Spaces:
Sleeping
Sleeping
Upload 328 files
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +65 -0
- AgML/mcp_output/README_MCP.md +55 -0
- AgML/mcp_output/analysis.json +828 -0
- AgML/mcp_output/diff_report.md +63 -0
- AgML/mcp_output/mcp_plugin/__init__.py +0 -0
- AgML/mcp_output/mcp_plugin/adapter.py +164 -0
- AgML/mcp_output/mcp_plugin/main.py +13 -0
- AgML/mcp_output/mcp_plugin/mcp_service.py +108 -0
- AgML/mcp_output/requirements.txt +23 -0
- AgML/mcp_output/start_mcp.py +30 -0
- AgML/mcp_output/workflow_summary.json +207 -0
- AgML/source/AUTHORS +6 -0
- AgML/source/CODE_OF_CONDUCT.md +74 -0
- AgML/source/CONTRIBUTING.md +267 -0
- AgML/source/LICENSE +201 -0
- AgML/source/MANIFEST.in +7 -0
- AgML/source/Makefile +25 -0
- AgML/source/README.md +252 -0
- AgML/source/__init__.py +4 -0
- AgML/source/agml/__init__.py +42 -0
- AgML/source/agml/_assets/detector_benchmarks.json +1314 -0
- AgML/source/agml/_assets/iNatAg-mini_public_datasources.json +0 -0
- AgML/source/agml/_assets/iNatAg-mini_source_citations.json +0 -0
- AgML/source/agml/_assets/iNatAg_public_datasources.json +0 -0
- AgML/source/agml/_assets/iNatAg_source_citations.json +0 -0
- AgML/source/agml/_assets/model_benchmarks.json +271 -0
- AgML/source/agml/_assets/public_datasources.json +2506 -0
- AgML/source/agml/_assets/shape_info.pickle +3 -0
- AgML/source/agml/_assets/source_citations.json +270 -0
- AgML/source/agml/_assets/viz_colormaps.json +18 -0
- AgML/source/agml/_helios/helios_install.sh +26 -0
- AgML/source/agml/_internal/__init__.py +0 -0
- AgML/source/agml/_internal/preprocess.py +1609 -0
- AgML/source/agml/_internal/process_utils.py +576 -0
- AgML/source/agml/_internal/s3internal.py +191 -0
- AgML/source/agml/_internal/syntheticdata.py +756 -0
- AgML/source/agml/_internal/utils.py +42 -0
- AgML/source/agml/backend/__init__.py +39 -0
- AgML/source/agml/backend/config.py +206 -0
- AgML/source/agml/backend/experimental.py +60 -0
- AgML/source/agml/backend/random.py +29 -0
- AgML/source/agml/backend/tftorch.py +334 -0
- AgML/source/agml/data/__init__.py +20 -0
- AgML/source/agml/data/builder.py +326 -0
- AgML/source/agml/data/experimental.py +100 -0
- AgML/source/agml/data/exporters/__init__.py +1 -0
- AgML/source/agml/data/exporters/tensorflow.py +245 -0
- AgML/source/agml/data/exporters/yolo.py +172 -0
- AgML/source/agml/data/extensions/__init__.py +15 -0
- AgML/source/agml/data/extensions/cvat.py +88 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,68 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
AgML/source/docs/assets/agml_dataset_world_map.png filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
AgML/source/docs/sample_images/almond_bloom_2023_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
AgML/source/docs/sample_images/almond_harvest_2021_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
AgML/source/docs/sample_images/apple_detection_drone_brazil_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
AgML/source/docs/sample_images/apple_detection_spain_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
AgML/source/docs/sample_images/apple_detection_usa_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
AgML/source/docs/sample_images/apple_flower_segmentation_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
AgML/source/docs/sample_images/apple_segmentation_minnesota_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 44 |
+
AgML/source/docs/sample_images/arabica_coffee_leaf_disease_classification_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 45 |
+
AgML/source/docs/sample_images/banana_leaf_disease_classification_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 46 |
+
AgML/source/docs/sample_images/bean_disease_uganda_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 47 |
+
AgML/source/docs/sample_images/bean_synthetic_earlygrowth_aerial_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 48 |
+
AgML/source/docs/sample_images/betel_leaf_disease_classification_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 49 |
+
AgML/source/docs/sample_images/blackgram_plant_leaf_disease_classification_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 50 |
+
AgML/source/docs/sample_images/carrot_weeds_germany_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 51 |
+
AgML/source/docs/sample_images/chilli_leaf_classification_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 52 |
+
AgML/source/docs/sample_images/coconut_tree_disease_classification_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 53 |
+
AgML/source/docs/sample_images/corn_maize_leaf_disease_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 54 |
+
AgML/source/docs/sample_images/crop_weeds_greece_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 55 |
+
AgML/source/docs/sample_images/cucumber_disease_classification_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 56 |
+
AgML/source/docs/sample_images/embrapa_wgisd_grape_detection_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 57 |
+
AgML/source/docs/sample_images/fruit_detection_worldwide_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 58 |
+
AgML/source/docs/sample_images/gemini_flower_detection_2022_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 59 |
+
AgML/source/docs/sample_images/gemini_leaf_detection_2022_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 60 |
+
AgML/source/docs/sample_images/gemini_plant_detection_2022_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 61 |
+
AgML/source/docs/sample_images/gemini_pod_detection_2022_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 62 |
+
AgML/source/docs/sample_images/ghai_broccoli_detection_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 63 |
+
AgML/source/docs/sample_images/ghai_strawberry_fruit_detection_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 64 |
+
AgML/source/docs/sample_images/grape_detection_californiaday_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 65 |
+
AgML/source/docs/sample_images/grape_detection_californianight_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 66 |
+
AgML/source/docs/sample_images/grape_detection_syntheticday_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 67 |
+
AgML/source/docs/sample_images/growliflower_cauliflower_segmentation_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 68 |
+
AgML/source/docs/sample_images/guava_disease_pakistan_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 69 |
+
AgML/source/docs/sample_images/iNatAg_sample_images.png filter=lfs diff=lfs merge=lfs -text
|
| 70 |
+
AgML/source/docs/sample_images/java_plum_leaf_disease_classification_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 71 |
+
AgML/source/docs/sample_images/leaf_counting_denmark_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 72 |
+
AgML/source/docs/sample_images/mango_detection_australia_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 73 |
+
AgML/source/docs/sample_images/onion_leaf_classification_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 74 |
+
AgML/source/docs/sample_images/orange_leaf_disease_classification_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 75 |
+
AgML/source/docs/sample_images/paddy_disease_classification_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 76 |
+
AgML/source/docs/sample_images/papaya_leaf_disease_classification_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 77 |
+
AgML/source/docs/sample_images/peachpear_flower_segmentation_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 78 |
+
AgML/source/docs/sample_images/plant_doc_classification_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 79 |
+
AgML/source/docs/sample_images/plant_doc_detection_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 80 |
+
AgML/source/docs/sample_images/plant_seedlings_aarhus_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 81 |
+
AgML/source/docs/sample_images/plant_village_classification_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 82 |
+
AgML/source/docs/sample_images/rangeland_weeds_australia_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 83 |
+
AgML/source/docs/sample_images/red_grapes_and_leaves_segmentation_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 84 |
+
AgML/source/docs/sample_images/rice_leaf_disease_classification_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 85 |
+
AgML/source/docs/sample_images/rice_seedling_segmentation_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 86 |
+
AgML/source/docs/sample_images/riseholme_strawberry_classification_2021_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 87 |
+
AgML/source/docs/sample_images/soybean_insect_classification_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 88 |
+
AgML/source/docs/sample_images/soybean_weed_uav_brazil_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 89 |
+
AgML/source/docs/sample_images/strawberry_detection_2022_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 90 |
+
AgML/source/docs/sample_images/strawberry_detection_2023_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 91 |
+
AgML/source/docs/sample_images/sugarbeet_weed_segmentation_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 92 |
+
AgML/source/docs/sample_images/sugarcane_damage_usa_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 93 |
+
AgML/source/docs/sample_images/sunflower_disease_classification_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 94 |
+
AgML/source/docs/sample_images/tea_leaf_disease_classification_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 95 |
+
AgML/source/docs/sample_images/tomato_leaf_disease_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 96 |
+
AgML/source/docs/sample_images/tomato_ripeness_detection_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 97 |
+
AgML/source/docs/sample_images/vegann_multicrop_presence_segmentation_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 98 |
+
AgML/source/docs/sample_images/vine_virus_photo_dataset_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 99 |
+
AgML/source/docs/sample_images/wheat_head_counting_examples.png filter=lfs diff=lfs merge=lfs -text
|
| 100 |
+
AgML/source/docs/sample_images/white_grapes_and_leaves_segmentation_examples.png filter=lfs diff=lfs merge=lfs -text
|
AgML/mcp_output/README_MCP.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# AgML: Agricultural Machine Learning Framework
|
| 2 |
+
|
| 3 |
+
## Project Introduction
|
| 4 |
+
|
| 5 |
+
AgML is a centralized framework designed to facilitate agricultural machine learning tasks. It provides access to a wide range of public agricultural datasets, standard benchmarks, and pretrained models. Additionally, AgML offers tools for generating synthetic data and annotations, making it a comprehensive solution for agricultural deep learning projects.
|
| 6 |
+
|
| 7 |
+
## Installation Method
|
| 8 |
+
|
| 9 |
+
To get started with AgML, ensure you have the following dependencies installed:
|
| 10 |
+
|
| 11 |
+
- Required: `numpy`, `pandas`, `tensorflow`, `torch`
|
| 12 |
+
- Optional: `matplotlib`, `scikit-learn`
|
| 13 |
+
|
| 14 |
+
You can install AgML and its dependencies using the following command:
|
| 15 |
+
|
| 16 |
+
pip install agml
|
| 17 |
+
|
| 18 |
+
Alternatively, you can set up the environment using the provided `environment.yml` file:
|
| 19 |
+
|
| 20 |
+
conda env create -f environment.yml
|
| 21 |
+
|
| 22 |
+
## Quick Start
|
| 23 |
+
|
| 24 |
+
Here's a quick example to get you started with AgML:
|
| 25 |
+
|
| 26 |
+
1. Load a dataset:
|
| 27 |
+
|
| 28 |
+
data_loader = agml.data.loader.load_data('dataset_name')
|
| 29 |
+
|
| 30 |
+
2. Train a classification model:
|
| 31 |
+
|
| 32 |
+
model = agml.models.classification.train_classifier(data_loader)
|
| 33 |
+
|
| 34 |
+
3. Evaluate the model:
|
| 35 |
+
|
| 36 |
+
results = agml.models.classification.evaluate_classifier(model, data_loader)
|
| 37 |
+
|
| 38 |
+
## Available Tools and Endpoints List
|
| 39 |
+
|
| 40 |
+
- **Data Loading and Management**: Use `agml.data.loader` to load and manage datasets.
|
| 41 |
+
- **Model Training and Evaluation**: Utilize `agml.models.classification` for training and evaluating classification models.
|
| 42 |
+
- **Synthetic Data Generation**: Generate synthetic data with `agml.synthetic.generator`.
|
| 43 |
+
- **Visualization**: Display images and results using `agml.viz.display`.
|
| 44 |
+
|
| 45 |
+
## Common Issues and Notes
|
| 46 |
+
|
| 47 |
+
- Ensure all required dependencies are installed to avoid import errors.
|
| 48 |
+
- For optimal performance, consider using a GPU-enabled environment when working with large datasets or complex models.
|
| 49 |
+
- If you encounter issues with dataset loading, verify the dataset name and availability.
|
| 50 |
+
|
| 51 |
+
## Reference Links or Documentation
|
| 52 |
+
|
| 53 |
+
For more detailed information, visit the [AgML GitHub Repository](https://github.com/Project-AgML/AgML).
|
| 54 |
+
|
| 55 |
+
For additional documentation and support, refer to the project's README and other documentation files included in the repository.
|
AgML/mcp_output/analysis.json
ADDED
|
@@ -0,0 +1,828 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"summary": {
|
| 3 |
+
"repository_url": "https://github.com/Project-AgML/AgML",
|
| 4 |
+
"summary": "Imported via zip fallback, file count: 230",
|
| 5 |
+
"file_tree": {
|
| 6 |
+
".github/release-drafter.yml": {
|
| 7 |
+
"size": 1220
|
| 8 |
+
},
|
| 9 |
+
".github/workflows/ci.yml": {
|
| 10 |
+
"size": 964
|
| 11 |
+
},
|
| 12 |
+
".github/workflows/docs.yml": {
|
| 13 |
+
"size": 1636
|
| 14 |
+
},
|
| 15 |
+
".github/workflows/release_draft.yml": {
|
| 16 |
+
"size": 1364
|
| 17 |
+
},
|
| 18 |
+
".github/workflows/update-datasets.yml": {
|
| 19 |
+
"size": 1219
|
| 20 |
+
},
|
| 21 |
+
"CODE_OF_CONDUCT.md": {
|
| 22 |
+
"size": 3210
|
| 23 |
+
},
|
| 24 |
+
"CONTRIBUTING.md": {
|
| 25 |
+
"size": 11129
|
| 26 |
+
},
|
| 27 |
+
"README.md": {
|
| 28 |
+
"size": 18519
|
| 29 |
+
},
|
| 30 |
+
"agml/__init__.py": {
|
| 31 |
+
"size": 1431
|
| 32 |
+
},
|
| 33 |
+
"agml/_assets/detector_benchmarks.json": {
|
| 34 |
+
"size": 42306
|
| 35 |
+
},
|
| 36 |
+
"agml/_assets/iNatAg-mini_public_datasources.json": {
|
| 37 |
+
"size": 524312
|
| 38 |
+
},
|
| 39 |
+
"agml/_assets/iNatAg-mini_source_citations.json": {
|
| 40 |
+
"size": 393701
|
| 41 |
+
},
|
| 42 |
+
"agml/_assets/iNatAg_public_datasources.json": {
|
| 43 |
+
"size": 524312
|
| 44 |
+
},
|
| 45 |
+
"agml/_assets/iNatAg_source_citations.json": {
|
| 46 |
+
"size": 378911
|
| 47 |
+
},
|
| 48 |
+
"agml/_assets/model_benchmarks.json": {
|
| 49 |
+
"size": 6398
|
| 50 |
+
},
|
| 51 |
+
"agml/_assets/public_datasources.json": {
|
| 52 |
+
"size": 76806
|
| 53 |
+
},
|
| 54 |
+
"agml/_assets/source_citations.json": {
|
| 55 |
+
"size": 38634
|
| 56 |
+
},
|
| 57 |
+
"agml/_assets/viz_colormaps.json": {
|
| 58 |
+
"size": 318
|
| 59 |
+
},
|
| 60 |
+
"agml/_internal/__init__.py": {
|
| 61 |
+
"size": 0
|
| 62 |
+
},
|
| 63 |
+
"agml/_internal/preprocess.py": {
|
| 64 |
+
"size": 71541
|
| 65 |
+
},
|
| 66 |
+
"agml/_internal/process_utils.py": {
|
| 67 |
+
"size": 20183
|
| 68 |
+
},
|
| 69 |
+
"agml/_internal/s3internal.py": {
|
| 70 |
+
"size": 6379
|
| 71 |
+
},
|
| 72 |
+
"agml/_internal/syntheticdata.py": {
|
| 73 |
+
"size": 34219
|
| 74 |
+
},
|
| 75 |
+
"agml/_internal/utils.py": {
|
| 76 |
+
"size": 1171
|
| 77 |
+
},
|
| 78 |
+
"agml/backend/__init__.py": {
|
| 79 |
+
"size": 1372
|
| 80 |
+
},
|
| 81 |
+
"agml/backend/config.py": {
|
| 82 |
+
"size": 7944
|
| 83 |
+
},
|
| 84 |
+
"agml/backend/experimental.py": {
|
| 85 |
+
"size": 2251
|
| 86 |
+
},
|
| 87 |
+
"agml/backend/random.py": {
|
| 88 |
+
"size": 982
|
| 89 |
+
},
|
| 90 |
+
"agml/backend/tftorch.py": {
|
| 91 |
+
"size": 11136
|
| 92 |
+
},
|
| 93 |
+
"agml/data/__init__.py": {
|
| 94 |
+
"size": 888
|
| 95 |
+
},
|
| 96 |
+
"agml/data/builder.py": {
|
| 97 |
+
"size": 15053
|
| 98 |
+
},
|
| 99 |
+
"agml/data/experimental.py": {
|
| 100 |
+
"size": 3730
|
| 101 |
+
},
|
| 102 |
+
"agml/data/exporters/__init__.py": {
|
| 103 |
+
"size": 30
|
| 104 |
+
},
|
| 105 |
+
"agml/data/exporters/tensorflow.py": {
|
| 106 |
+
"size": 9776
|
| 107 |
+
},
|
| 108 |
+
"agml/data/exporters/yolo.py": {
|
| 109 |
+
"size": 7351
|
| 110 |
+
},
|
| 111 |
+
"agml/data/extensions/__init__.py": {
|
| 112 |
+
"size": 648
|
| 113 |
+
},
|
| 114 |
+
"agml/data/extensions/cvat.py": {
|
| 115 |
+
"size": 3360
|
| 116 |
+
},
|
| 117 |
+
"agml/data/image_loader.py": {
|
| 118 |
+
"size": 6345
|
| 119 |
+
},
|
| 120 |
+
"agml/data/loader.py": {
|
| 121 |
+
"size": 86964
|
| 122 |
+
},
|
| 123 |
+
"agml/data/manager.py": {
|
| 124 |
+
"size": 16449
|
| 125 |
+
},
|
| 126 |
+
"agml/data/managers/__init__.py": {
|
| 127 |
+
"size": 600
|
| 128 |
+
},
|
| 129 |
+
"agml/data/managers/resize.py": {
|
| 130 |
+
"size": 14668
|
| 131 |
+
},
|
| 132 |
+
"agml/data/managers/training.py": {
|
| 133 |
+
"size": 15665
|
| 134 |
+
},
|
| 135 |
+
"agml/data/managers/transform_helpers.py": {
|
| 136 |
+
"size": 6006
|
| 137 |
+
},
|
| 138 |
+
"agml/data/managers/transforms.py": {
|
| 139 |
+
"size": 26945
|
| 140 |
+
},
|
| 141 |
+
"agml/data/metadata.py": {
|
| 142 |
+
"size": 13311
|
| 143 |
+
},
|
| 144 |
+
"agml/data/multi_loader.py": {
|
| 145 |
+
"size": 76853
|
| 146 |
+
},
|
| 147 |
+
"agml/data/object.py": {
|
| 148 |
+
"size": 9161
|
| 149 |
+
},
|
| 150 |
+
"agml/data/point_cloud.py": {
|
| 151 |
+
"size": 8636
|
| 152 |
+
},
|
| 153 |
+
"agml/data/public.py": {
|
| 154 |
+
"size": 9716
|
| 155 |
+
},
|
| 156 |
+
"agml/data/tools.py": {
|
| 157 |
+
"size": 7601
|
| 158 |
+
},
|
| 159 |
+
"agml/framework.py": {
|
| 160 |
+
"size": 3153
|
| 161 |
+
},
|
| 162 |
+
"agml/io.py": {
|
| 163 |
+
"size": 3855
|
| 164 |
+
},
|
| 165 |
+
"agml/models/__init__.py": {
|
| 166 |
+
"size": 1712
|
| 167 |
+
},
|
| 168 |
+
"agml/models/base.py": {
|
| 169 |
+
"size": 7513
|
| 170 |
+
},
|
| 171 |
+
"agml/models/benchmarks.py": {
|
| 172 |
+
"size": 3007
|
| 173 |
+
},
|
| 174 |
+
"agml/models/classification.py": {
|
| 175 |
+
"size": 20669
|
| 176 |
+
},
|
| 177 |
+
"agml/models/detection.py": {
|
| 178 |
+
"size": 34983
|
| 179 |
+
},
|
| 180 |
+
"agml/models/detector.py": {
|
| 181 |
+
"size": 16186
|
| 182 |
+
},
|
| 183 |
+
"agml/models/extensions/__init__.py": {
|
| 184 |
+
"size": 0
|
| 185 |
+
},
|
| 186 |
+
"agml/models/extensions/ultralytics.py": {
|
| 187 |
+
"size": 2193
|
| 188 |
+
},
|
| 189 |
+
"agml/models/legacy/__init__.py": {
|
| 190 |
+
"size": 765
|
| 191 |
+
},
|
| 192 |
+
"agml/models/legacy/classification_efficientnet.py": {
|
| 193 |
+
"size": 20669
|
| 194 |
+
},
|
| 195 |
+
"agml/models/legacy/detection_efficientdet.py": {
|
| 196 |
+
"size": 34983
|
| 197 |
+
},
|
| 198 |
+
"agml/models/legacy/segmentation_deeplab.py": {
|
| 199 |
+
"size": 26344
|
| 200 |
+
},
|
| 201 |
+
"agml/models/losses.py": {
|
| 202 |
+
"size": 2089
|
| 203 |
+
},
|
| 204 |
+
"agml/models/metrics/__init__.py": {
|
| 205 |
+
"size": 704
|
| 206 |
+
},
|
| 207 |
+
"agml/models/metrics/accuracy.py": {
|
| 208 |
+
"size": 2889
|
| 209 |
+
},
|
| 210 |
+
"agml/models/metrics/map.py": {
|
| 211 |
+
"size": 9870
|
| 212 |
+
},
|
| 213 |
+
"agml/models/preprocessing.py": {
|
| 214 |
+
"size": 8585
|
| 215 |
+
},
|
| 216 |
+
"agml/models/segmentation.py": {
|
| 217 |
+
"size": 26344
|
| 218 |
+
},
|
| 219 |
+
"agml/models/system_utils.py": {
|
| 220 |
+
"size": 880
|
| 221 |
+
},
|
| 222 |
+
"agml/models/tools.py": {
|
| 223 |
+
"size": 4420
|
| 224 |
+
},
|
| 225 |
+
"agml/models/training/__init__.py": {
|
| 226 |
+
"size": 0
|
| 227 |
+
},
|
| 228 |
+
"agml/models/training/basic_trainers.py": {
|
| 229 |
+
"size": 29305
|
| 230 |
+
},
|
| 231 |
+
"agml/synthetic/__init__.py": {
|
| 232 |
+
"size": 992
|
| 233 |
+
},
|
| 234 |
+
"agml/synthetic/compilation.py": {
|
| 235 |
+
"size": 12584
|
| 236 |
+
},
|
| 237 |
+
"agml/synthetic/config.py": {
|
| 238 |
+
"size": 13078
|
| 239 |
+
},
|
| 240 |
+
"agml/synthetic/converter.py": {
|
| 241 |
+
"size": 16490
|
| 242 |
+
},
|
| 243 |
+
"agml/synthetic/generator.py": {
|
| 244 |
+
"size": 20816
|
| 245 |
+
},
|
| 246 |
+
"agml/synthetic/lidar_loader.py": {
|
| 247 |
+
"size": 3511
|
| 248 |
+
},
|
| 249 |
+
"agml/synthetic/manual.py": {
|
| 250 |
+
"size": 13866
|
| 251 |
+
},
|
| 252 |
+
"agml/synthetic/options.py": {
|
| 253 |
+
"size": 15084
|
| 254 |
+
},
|
| 255 |
+
"agml/synthetic/synthetic_data_generation/CMakeLists.txt": {
|
| 256 |
+
"size": 1757
|
| 257 |
+
},
|
| 258 |
+
"agml/synthetic/synthetic_data_generation/SyntheticRadiation/CMakeLists.txt": {
|
| 259 |
+
"size": 1923
|
| 260 |
+
},
|
| 261 |
+
"agml/synthetic/tools.py": {
|
| 262 |
+
"size": 8578
|
| 263 |
+
},
|
| 264 |
+
"agml/utils/__init__.py": {
|
| 265 |
+
"size": 600
|
| 266 |
+
},
|
| 267 |
+
"agml/utils/data.py": {
|
| 268 |
+
"size": 7887
|
| 269 |
+
},
|
| 270 |
+
"agml/utils/downloads.py": {
|
| 271 |
+
"size": 9513
|
| 272 |
+
},
|
| 273 |
+
"agml/utils/general.py": {
|
| 274 |
+
"size": 5201
|
| 275 |
+
},
|
| 276 |
+
"agml/utils/image.py": {
|
| 277 |
+
"size": 3592
|
| 278 |
+
},
|
| 279 |
+
"agml/utils/io.py": {
|
| 280 |
+
"size": 3896
|
| 281 |
+
},
|
| 282 |
+
"agml/utils/logging.py": {
|
| 283 |
+
"size": 2684
|
| 284 |
+
},
|
| 285 |
+
"agml/utils/random.py": {
|
| 286 |
+
"size": 2380
|
| 287 |
+
},
|
| 288 |
+
"agml/viz/__init__.py": {
|
| 289 |
+
"size": 1281
|
| 290 |
+
},
|
| 291 |
+
"agml/viz/boxes.py": {
|
| 292 |
+
"size": 13488
|
| 293 |
+
},
|
| 294 |
+
"agml/viz/display.py": {
|
| 295 |
+
"size": 3785
|
| 296 |
+
},
|
| 297 |
+
"agml/viz/general.py": {
|
| 298 |
+
"size": 4932
|
| 299 |
+
},
|
| 300 |
+
"agml/viz/inspection.py": {
|
| 301 |
+
"size": 5340
|
| 302 |
+
},
|
| 303 |
+
"agml/viz/labels.py": {
|
| 304 |
+
"size": 5039
|
| 305 |
+
},
|
| 306 |
+
"agml/viz/masks.py": {
|
| 307 |
+
"size": 9330
|
| 308 |
+
},
|
| 309 |
+
"agml/viz/point_clouds.py": {
|
| 310 |
+
"size": 2411
|
| 311 |
+
},
|
| 312 |
+
"agml/viz/tools.py": {
|
| 313 |
+
"size": 6822
|
| 314 |
+
},
|
| 315 |
+
"config/coverage.ini": {
|
| 316 |
+
"size": 832
|
| 317 |
+
},
|
| 318 |
+
"config/interrogate.toml": {
|
| 319 |
+
"size": 596
|
| 320 |
+
},
|
| 321 |
+
"config/mkdocs.yml": {
|
| 322 |
+
"size": 4574
|
| 323 |
+
},
|
| 324 |
+
"config/mypy.ini": {
|
| 325 |
+
"size": 175
|
| 326 |
+
},
|
| 327 |
+
"config/pytest.ini": {
|
| 328 |
+
"size": 309
|
| 329 |
+
},
|
| 330 |
+
"config/ruff.toml": {
|
| 331 |
+
"size": 2056
|
| 332 |
+
},
|
| 333 |
+
"docs/code_of_conduct.md": {
|
| 334 |
+
"size": 73
|
| 335 |
+
},
|
| 336 |
+
"docs/credits.md": {
|
| 337 |
+
"size": 126
|
| 338 |
+
},
|
| 339 |
+
"docs/dataset_listing.md": {
|
| 340 |
+
"size": 131
|
| 341 |
+
},
|
| 342 |
+
"docs/datasets/almond_bloom_2023.md": {
|
| 343 |
+
"size": 731
|
| 344 |
+
},
|
| 345 |
+
"docs/datasets/almond_harvest_2021.md": {
|
| 346 |
+
"size": 838
|
| 347 |
+
},
|
| 348 |
+
"docs/datasets/apple_detection_drone_brazil.md": {
|
| 349 |
+
"size": 703
|
| 350 |
+
},
|
| 351 |
+
"docs/datasets/apple_detection_spain.md": {
|
| 352 |
+
"size": 691
|
| 353 |
+
},
|
| 354 |
+
"docs/datasets/apple_detection_usa.md": {
|
| 355 |
+
"size": 751
|
| 356 |
+
},
|
| 357 |
+
"docs/datasets/apple_flower_segmentation.md": {
|
| 358 |
+
"size": 860
|
| 359 |
+
},
|
| 360 |
+
"docs/datasets/apple_segmentation_minnesota.md": {
|
| 361 |
+
"size": 807
|
| 362 |
+
},
|
| 363 |
+
"docs/datasets/arabica_coffee_leaf_disease_classification.md": {
|
| 364 |
+
"size": 940
|
| 365 |
+
},
|
| 366 |
+
"docs/datasets/autonomous_greenhouse_regression.md": {
|
| 367 |
+
"size": 0
|
| 368 |
+
},
|
| 369 |
+
"docs/datasets/banana_leaf_disease_classification.md": {
|
| 370 |
+
"size": 928
|
| 371 |
+
},
|
| 372 |
+
"docs/datasets/bean_disease_uganda.md": {
|
| 373 |
+
"size": 796
|
| 374 |
+
},
|
| 375 |
+
"docs/datasets/bean_synthetic_earlygrowth_aerial.md": {
|
| 376 |
+
"size": 766
|
| 377 |
+
},
|
| 378 |
+
"docs/datasets/betel_leaf_disease_classification.md": {
|
| 379 |
+
"size": 1001
|
| 380 |
+
},
|
| 381 |
+
"docs/datasets/blackgram_plant_leaf_disease_classification.md": {
|
| 382 |
+
"size": 837
|
| 383 |
+
},
|
| 384 |
+
"docs/datasets/carrot_weeds_germany.md": {
|
| 385 |
+
"size": 755
|
| 386 |
+
},
|
| 387 |
+
"docs/datasets/chilli_leaf_classification.md": {
|
| 388 |
+
"size": 928
|
| 389 |
+
},
|
| 390 |
+
"docs/datasets/coconut_tree_disease_classification.md": {
|
| 391 |
+
"size": 913
|
| 392 |
+
},
|
| 393 |
+
"docs/datasets/corn_maize_leaf_disease.md": {
|
| 394 |
+
"size": 871
|
| 395 |
+
},
|
| 396 |
+
"docs/datasets/crop_weeds_greece.md": {
|
| 397 |
+
"size": 763
|
| 398 |
+
},
|
| 399 |
+
"docs/datasets/cucumber_disease_classification.md": {
|
| 400 |
+
"size": 946
|
| 401 |
+
},
|
| 402 |
+
"docs/datasets/embrapa_wgisd_grape_detection.md": {
|
| 403 |
+
"size": 813
|
| 404 |
+
},
|
| 405 |
+
"docs/datasets/fruit_detection_worldwide.md": {
|
| 406 |
+
"size": 845
|
| 407 |
+
},
|
| 408 |
+
"docs/datasets/gemini_flower_detection_2022.md": {
|
| 409 |
+
"size": 780
|
| 410 |
+
},
|
| 411 |
+
"docs/datasets/gemini_leaf_detection_2022.md": {
|
| 412 |
+
"size": 771
|
| 413 |
+
},
|
| 414 |
+
"docs/datasets/gemini_plant_detection_2022.md": {
|
| 415 |
+
"size": 779
|
| 416 |
+
},
|
| 417 |
+
"docs/datasets/gemini_pod_detection_2022.md": {
|
| 418 |
+
"size": 767
|
| 419 |
+
},
|
| 420 |
+
"docs/datasets/ghai_broccoli_detection.md": {
|
| 421 |
+
"size": 715
|
| 422 |
+
},
|
| 423 |
+
"docs/datasets/ghai_green_cabbage_detection.md": {
|
| 424 |
+
"size": 0
|
| 425 |
+
},
|
| 426 |
+
"docs/datasets/ghai_iceberg_lettuce_detection.md": {
|
| 427 |
+
"size": 0
|
| 428 |
+
},
|
| 429 |
+
"docs/datasets/ghai_romaine_detection.md": {
|
| 430 |
+
"size": 0
|
| 431 |
+
},
|
| 432 |
+
"docs/datasets/ghai_strawberry_fruit_detection.md": {
|
| 433 |
+
"size": 826
|
| 434 |
+
},
|
| 435 |
+
"docs/datasets/grape_detection_californiaday.md": {
|
| 436 |
+
"size": 748
|
| 437 |
+
},
|
| 438 |
+
"docs/datasets/grape_detection_californianight.md": {
|
| 439 |
+
"size": 754
|
| 440 |
+
},
|
| 441 |
+
"docs/datasets/grape_detection_syntheticday.md": {
|
| 442 |
+
"size": 752
|
| 443 |
+
},
|
| 444 |
+
"docs/datasets/growliflower_cauliflower_segmentation.md": {
|
| 445 |
+
"size": 814
|
| 446 |
+
},
|
| 447 |
+
"docs/datasets/guava_disease_pakistan.md": {
|
| 448 |
+
"size": 770
|
| 449 |
+
},
|
| 450 |
+
"docs/datasets/iNatAg-mini.md": {
|
| 451 |
+
"size": 989
|
| 452 |
+
},
|
| 453 |
+
"docs/datasets/iNatAg.md": {
|
| 454 |
+
"size": 956
|
| 455 |
+
},
|
| 456 |
+
"docs/datasets/java_plum_leaf_disease_classification.md": {
|
| 457 |
+
"size": 929
|
| 458 |
+
},
|
| 459 |
+
"docs/datasets/leaf_counting_denmark.md": {
|
| 460 |
+
"size": 724
|
| 461 |
+
},
|
| 462 |
+
"docs/datasets/mango_detection_australia.md": {
|
| 463 |
+
"size": 777
|
| 464 |
+
},
|
| 465 |
+
"docs/datasets/onion_leaf_classification.md": {
|
| 466 |
+
"size": 915
|
| 467 |
+
},
|
| 468 |
+
"docs/datasets/orange_leaf_disease_classification.md": {
|
| 469 |
+
"size": 1011
|
| 470 |
+
},
|
| 471 |
+
"docs/datasets/paddy_disease_classification.md": {
|
| 472 |
+
"size": 950
|
| 473 |
+
},
|
| 474 |
+
"docs/datasets/papaya_leaf_disease_classification.md": {
|
| 475 |
+
"size": 791
|
| 476 |
+
},
|
| 477 |
+
"docs/datasets/peachpear_flower_segmentation.md": {
|
| 478 |
+
"size": 698
|
| 479 |
+
},
|
| 480 |
+
"docs/datasets/plant_doc_classification.md": {
|
| 481 |
+
"size": 1341
|
| 482 |
+
},
|
| 483 |
+
"docs/datasets/plant_doc_detection.md": {
|
| 484 |
+
"size": 1348
|
| 485 |
+
},
|
| 486 |
+
"docs/datasets/plant_seedlings_aarhus.md": {
|
| 487 |
+
"size": 948
|
| 488 |
+
},
|
| 489 |
+
"docs/datasets/plant_village_classification.md": {
|
| 490 |
+
"size": 1787
|
| 491 |
+
},
|
| 492 |
+
"docs/datasets/rangeland_weeds_australia.md": {
|
| 493 |
+
"size": 880
|
| 494 |
+
},
|
| 495 |
+
"docs/datasets/red_grapes_and_leaves_segmentation.md": {
|
| 496 |
+
"size": 839
|
| 497 |
+
},
|
| 498 |
+
"docs/datasets/rice_leaf_disease_classification.md": {
|
| 499 |
+
"size": 916
|
| 500 |
+
},
|
| 501 |
+
"docs/datasets/rice_seedling_segmentation.md": {
|
| 502 |
+
"size": 860
|
| 503 |
+
},
|
| 504 |
+
"docs/datasets/riseholme_strawberry_classification_2021.md": {
|
| 505 |
+
"size": 819
|
| 506 |
+
},
|
| 507 |
+
"docs/datasets/soybean_insect_classification.md": {
|
| 508 |
+
"size": 892
|
| 509 |
+
},
|
| 510 |
+
"docs/datasets/soybean_weed_uav_brazil.md": {
|
| 511 |
+
"size": 808
|
| 512 |
+
},
|
| 513 |
+
"docs/datasets/strawberry_detection_2022.md": {
|
| 514 |
+
"size": 791
|
| 515 |
+
},
|
| 516 |
+
"docs/datasets/strawberry_detection_2023.md": {
|
| 517 |
+
"size": 790
|
| 518 |
+
},
|
| 519 |
+
"docs/datasets/sugarbeet_weed_segmentation.md": {
|
| 520 |
+
"size": 778
|
| 521 |
+
},
|
| 522 |
+
"docs/datasets/sugarcane_damage_usa.md": {
|
| 523 |
+
"size": 822
|
| 524 |
+
},
|
| 525 |
+
"docs/datasets/sunflower_disease_classification.md": {
|
| 526 |
+
"size": 878
|
| 527 |
+
},
|
| 528 |
+
"docs/datasets/tea_leaf_disease_classification.md": {
|
| 529 |
+
"size": 887
|
| 530 |
+
},
|
| 531 |
+
"docs/datasets/tomato_leaf_disease.md": {
|
| 532 |
+
"size": 973
|
| 533 |
+
},
|
| 534 |
+
"docs/datasets/tomato_ripeness_detection.md": {
|
| 535 |
+
"size": 856
|
| 536 |
+
},
|
| 537 |
+
"docs/datasets/vegann_multicrop_presence_segmentation.md": {
|
| 538 |
+
"size": 801
|
| 539 |
+
},
|
| 540 |
+
"docs/datasets/vine_virus_photo_dataset.md": {
|
| 541 |
+
"size": 790
|
| 542 |
+
},
|
| 543 |
+
"docs/datasets/wheat_head_counting.md": {
|
| 544 |
+
"size": 741
|
| 545 |
+
},
|
| 546 |
+
"docs/datasets/white_grapes_and_leaves_segmentation.md": {
|
| 547 |
+
"size": 845
|
| 548 |
+
},
|
| 549 |
+
"docs/development.md": {
|
| 550 |
+
"size": 27
|
| 551 |
+
},
|
| 552 |
+
"docs/index.md": {
|
| 553 |
+
"size": 45
|
| 554 |
+
},
|
| 555 |
+
"docs/js/feedback.js": {
|
| 556 |
+
"size": 509
|
| 557 |
+
},
|
| 558 |
+
"docs/license.md": {
|
| 559 |
+
"size": 54
|
| 560 |
+
},
|
| 561 |
+
"environment.yml": {
|
| 562 |
+
"size": 850
|
| 563 |
+
},
|
| 564 |
+
"experiments/README.md": {
|
| 565 |
+
"size": 448
|
| 566 |
+
},
|
| 567 |
+
"experiments/benchmarking/README.md": {
|
| 568 |
+
"size": 801
|
| 569 |
+
},
|
| 570 |
+
"experiments/benchmarking/__init__.py": {
|
| 571 |
+
"size": 0
|
| 572 |
+
},
|
| 573 |
+
"experiments/benchmarking/accuracy_evaluation.py": {
|
| 574 |
+
"size": 3990
|
| 575 |
+
},
|
| 576 |
+
"experiments/benchmarking/classification.py": {
|
| 577 |
+
"size": 8498
|
| 578 |
+
},
|
| 579 |
+
"experiments/benchmarking/classification_distributed.py": {
|
| 580 |
+
"size": 6537
|
| 581 |
+
},
|
| 582 |
+
"experiments/benchmarking/classification_lightning.py": {
|
| 583 |
+
"size": 9129
|
| 584 |
+
},
|
| 585 |
+
"experiments/benchmarking/classification_lightning_resnet50.py": {
|
| 586 |
+
"size": 9003
|
| 587 |
+
},
|
| 588 |
+
"experiments/benchmarking/detection_data.py": {
|
| 589 |
+
"size": 11019
|
| 590 |
+
},
|
| 591 |
+
"experiments/benchmarking/detection_experiment.py": {
|
| 592 |
+
"size": 1755
|
| 593 |
+
},
|
| 594 |
+
"experiments/benchmarking/detection_learning.py": {
|
| 595 |
+
"size": 22649
|
| 596 |
+
},
|
| 597 |
+
"experiments/benchmarking/detection_lightning.py": {
|
| 598 |
+
"size": 8459
|
| 599 |
+
},
|
| 600 |
+
"experiments/benchmarking/detection_lightning_local.py": {
|
| 601 |
+
"size": 27565
|
| 602 |
+
},
|
| 603 |
+
"experiments/benchmarking/detection_lightning_multiple.py": {
|
| 604 |
+
"size": 23195
|
| 605 |
+
},
|
| 606 |
+
"experiments/benchmarking/detection_lightning_ssd.py": {
|
| 607 |
+
"size": 6497
|
| 608 |
+
},
|
| 609 |
+
"experiments/benchmarking/detection_modeling.py": {
|
| 610 |
+
"size": 9770
|
| 611 |
+
},
|
| 612 |
+
"experiments/benchmarking/experiment.py": {
|
| 613 |
+
"size": 5401
|
| 614 |
+
},
|
| 615 |
+
"experiments/benchmarking/finetune_evaluation.py": {
|
| 616 |
+
"size": 6786
|
| 617 |
+
},
|
| 618 |
+
"experiments/benchmarking/map_evaluation.py": {
|
| 619 |
+
"size": 11137
|
| 620 |
+
},
|
| 621 |
+
"experiments/benchmarking/map_evaluation_multiple.py": {
|
| 622 |
+
"size": 6931
|
| 623 |
+
},
|
| 624 |
+
"experiments/benchmarking/mean_average_precision.py": {
|
| 625 |
+
"size": 9624
|
| 626 |
+
},
|
| 627 |
+
"experiments/benchmarking/mean_average_precision_torch.py": {
|
| 628 |
+
"size": 11137
|
| 629 |
+
},
|
| 630 |
+
"experiments/benchmarking/miou_evaluation.py": {
|
| 631 |
+
"size": 4026
|
| 632 |
+
},
|
| 633 |
+
"experiments/benchmarking/segmentation_lightning.py": {
|
| 634 |
+
"size": 11501
|
| 635 |
+
},
|
| 636 |
+
"experiments/benchmarking/segmentation_lightning_pretrained.py": {
|
| 637 |
+
"size": 10294
|
| 638 |
+
},
|
| 639 |
+
"experiments/benchmarking/tools.py": {
|
| 640 |
+
"size": 4738
|
| 641 |
+
},
|
| 642 |
+
"pyproject.toml": {
|
| 643 |
+
"size": 1899
|
| 644 |
+
},
|
| 645 |
+
"requirements.txt": {
|
| 646 |
+
"size": 176
|
| 647 |
+
},
|
| 648 |
+
"scripts/convert_lightning_pytorch_ckpt.py": {
|
| 649 |
+
"size": 3152
|
| 650 |
+
},
|
| 651 |
+
"scripts/create_world_map.py": {
|
| 652 |
+
"size": 6886
|
| 653 |
+
},
|
| 654 |
+
"scripts/docs/gen_credits.py": {
|
| 655 |
+
"size": 6532
|
| 656 |
+
},
|
| 657 |
+
"scripts/docs/gen_dataset_list.py": {
|
| 658 |
+
"size": 1515
|
| 659 |
+
},
|
| 660 |
+
"scripts/docs/gen_ref_nav.py": {
|
| 661 |
+
"size": 1197
|
| 662 |
+
},
|
| 663 |
+
"scripts/format_json_source.py": {
|
| 664 |
+
"size": 1286
|
| 665 |
+
},
|
| 666 |
+
"scripts/generate_dataset_markdown.py": {
|
| 667 |
+
"size": 10654
|
| 668 |
+
},
|
| 669 |
+
"scripts/generate_normalization_info.py": {
|
| 670 |
+
"size": 3029
|
| 671 |
+
},
|
| 672 |
+
"scripts/generate_shape_info.py": {
|
| 673 |
+
"size": 2566
|
| 674 |
+
},
|
| 675 |
+
"scripts/run_full_dataset_update.py": {
|
| 676 |
+
"size": 1113
|
| 677 |
+
},
|
| 678 |
+
"tests/config/test_config.py": {
|
| 679 |
+
"size": 811
|
| 680 |
+
},
|
| 681 |
+
"tests/conftest.py": {
|
| 682 |
+
"size": 430
|
| 683 |
+
},
|
| 684 |
+
"tests/data/test_dataloader_general.py": {
|
| 685 |
+
"size": 2572
|
| 686 |
+
},
|
| 687 |
+
"tests/data/test_format_tools.py": {
|
| 688 |
+
"size": 2646
|
| 689 |
+
},
|
| 690 |
+
"tests/data/test_public_sources.py": {
|
| 691 |
+
"size": 2148
|
| 692 |
+
},
|
| 693 |
+
"tests/test_import.py": {
|
| 694 |
+
"size": 123
|
| 695 |
+
}
|
| 696 |
+
},
|
| 697 |
+
"processed_by": "zip_fallback",
|
| 698 |
+
"success": true
|
| 699 |
+
},
|
| 700 |
+
"structure": {
|
| 701 |
+
"packages": [
|
| 702 |
+
"source.agml",
|
| 703 |
+
"source.agml._internal",
|
| 704 |
+
"source.agml.backend",
|
| 705 |
+
"source.agml.data",
|
| 706 |
+
"source.agml.models",
|
| 707 |
+
"source.agml.synthetic",
|
| 708 |
+
"source.agml.utils",
|
| 709 |
+
"source.agml.viz",
|
| 710 |
+
"source.experiments.benchmarking"
|
| 711 |
+
]
|
| 712 |
+
},
|
| 713 |
+
"dependencies": {
|
| 714 |
+
"has_environment_yml": true,
|
| 715 |
+
"has_requirements_txt": true,
|
| 716 |
+
"pyproject": true,
|
| 717 |
+
"setup_cfg": false,
|
| 718 |
+
"setup_py": false
|
| 719 |
+
},
|
| 720 |
+
"entry_points": {
|
| 721 |
+
"imports": [],
|
| 722 |
+
"cli": [],
|
| 723 |
+
"modules": []
|
| 724 |
+
},
|
| 725 |
+
"llm_analysis": {
|
| 726 |
+
"core_modules": [
|
| 727 |
+
{
|
| 728 |
+
"package": "source.agml",
|
| 729 |
+
"module": "__init__",
|
| 730 |
+
"functions": [],
|
| 731 |
+
"classes": [],
|
| 732 |
+
"description": "Initialization module for the AgML package."
|
| 733 |
+
},
|
| 734 |
+
{
|
| 735 |
+
"package": "source.agml.data",
|
| 736 |
+
"module": "loader",
|
| 737 |
+
"functions": [
|
| 738 |
+
"load_data",
|
| 739 |
+
"get_dataset"
|
| 740 |
+
],
|
| 741 |
+
"classes": [
|
| 742 |
+
"DataLoader",
|
| 743 |
+
"DatasetManager"
|
| 744 |
+
],
|
| 745 |
+
"description": "Handles data loading and dataset management for agricultural datasets."
|
| 746 |
+
},
|
| 747 |
+
{
|
| 748 |
+
"package": "source.agml.models",
|
| 749 |
+
"module": "classification",
|
| 750 |
+
"functions": [
|
| 751 |
+
"train_classifier",
|
| 752 |
+
"evaluate_classifier"
|
| 753 |
+
],
|
| 754 |
+
"classes": [
|
| 755 |
+
"ClassifierModel"
|
| 756 |
+
],
|
| 757 |
+
"description": "Provides tools for training and evaluating classification models."
|
| 758 |
+
},
|
| 759 |
+
{
|
| 760 |
+
"package": "source.agml.synthetic",
|
| 761 |
+
"module": "generator",
|
| 762 |
+
"functions": [
|
| 763 |
+
"generate_synthetic_data"
|
| 764 |
+
],
|
| 765 |
+
"classes": [
|
| 766 |
+
"SyntheticDataGenerator"
|
| 767 |
+
],
|
| 768 |
+
"description": "Generates synthetic data for agricultural machine learning tasks."
|
| 769 |
+
},
|
| 770 |
+
{
|
| 771 |
+
"package": "source.agml.viz",
|
| 772 |
+
"module": "display",
|
| 773 |
+
"functions": [
|
| 774 |
+
"show_image",
|
| 775 |
+
"plot_results"
|
| 776 |
+
],
|
| 777 |
+
"classes": [],
|
| 778 |
+
"description": "Visualization tools for displaying images and results."
|
| 779 |
+
}
|
| 780 |
+
],
|
| 781 |
+
"cli_commands": [
|
| 782 |
+
{
|
| 783 |
+
"name": "agml-cli",
|
| 784 |
+
"module": "source.agml.cli",
|
| 785 |
+
"description": "Command-line interface for interacting with AgML functionalities."
|
| 786 |
+
}
|
| 787 |
+
],
|
| 788 |
+
"import_strategy": {
|
| 789 |
+
"primary": "import",
|
| 790 |
+
"fallback": "cli",
|
| 791 |
+
"confidence": 0.8
|
| 792 |
+
},
|
| 793 |
+
"dependencies": {
|
| 794 |
+
"required": [
|
| 795 |
+
"numpy",
|
| 796 |
+
"pandas",
|
| 797 |
+
"tensorflow",
|
| 798 |
+
"torch"
|
| 799 |
+
],
|
| 800 |
+
"optional": [
|
| 801 |
+
"matplotlib",
|
| 802 |
+
"scikit-learn"
|
| 803 |
+
]
|
| 804 |
+
},
|
| 805 |
+
"risk_assessment": {
|
| 806 |
+
"import_feasibility": 0.8,
|
| 807 |
+
"intrusiveness_risk": "medium",
|
| 808 |
+
"complexity": "medium"
|
| 809 |
+
}
|
| 810 |
+
},
|
| 811 |
+
"deepwiki_analysis": {
|
| 812 |
+
"repo_url": "https://github.com/Project-AgML/AgML",
|
| 813 |
+
"repo_name": "AgML",
|
| 814 |
+
"content": "Project-AgML/AgML\nAgML is a centralized framework for agricultural machine learning. AgML provides access to public agricultural datasets for common agricultural deep learning tasks, with standard benchmarks and pretrained models, as well the ability to generate synthetic data and annotations.\nRepository Not Indexed\nThis repository hasn't been indexed yet. Indexing allows you to explore code structure, find documentation, and understand dependencies.\nIndexing typically takes 2-10 minutes to complete after it starts indexing\nOnce indexed, you'll have full access to code exploration and search functionality",
|
| 815 |
+
"model": "gpt-4o-2024-08-06",
|
| 816 |
+
"source": "selenium",
|
| 817 |
+
"success": true
|
| 818 |
+
},
|
| 819 |
+
"deepwiki_options": {
|
| 820 |
+
"enabled": true,
|
| 821 |
+
"model": "gpt-4o-2024-08-06"
|
| 822 |
+
},
|
| 823 |
+
"risk": {
|
| 824 |
+
"import_feasibility": 0.8,
|
| 825 |
+
"intrusiveness_risk": "medium",
|
| 826 |
+
"complexity": "medium"
|
| 827 |
+
}
|
| 828 |
+
}
|
AgML/mcp_output/diff_report.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# AgML Project Difference Report
|
| 2 |
+
|
| 3 |
+
**Date:** February 6, 2026
|
| 4 |
+
**Time:** 11:59:39
|
| 5 |
+
**Repository:** AgML
|
| 6 |
+
**Project Type:** Python Library
|
| 7 |
+
**Intrusiveness:** None
|
| 8 |
+
**Workflow Status:** Success
|
| 9 |
+
**Test Status:** Failed
|
| 10 |
+
|
| 11 |
+
## Project Overview
|
| 12 |
+
|
| 13 |
+
AgML is a Python library designed to provide basic functionality for agricultural machine learning applications. The project aims to facilitate the development and deployment of machine learning models in the agricultural sector by offering a suite of tools and resources tailored to this domain.
|
| 14 |
+
|
| 15 |
+
## Difference Analysis
|
| 16 |
+
|
| 17 |
+
### New Files Added
|
| 18 |
+
|
| 19 |
+
Since the last update, 8 new files have been added to the AgML repository. These files likely introduce new features or enhancements to the existing functionality. However, no existing files have been modified, indicating that the new additions are non-intrusive and do not alter the current codebase.
|
| 20 |
+
|
| 21 |
+
### Modified Files
|
| 22 |
+
|
| 23 |
+
There have been no modifications to existing files. This suggests that the new features or functionalities have been implemented in a way that does not disrupt or change the existing code structure.
|
| 24 |
+
|
| 25 |
+
## Technical Analysis
|
| 26 |
+
|
| 27 |
+
### Workflow Status
|
| 28 |
+
|
| 29 |
+
The workflow status is marked as successful, indicating that the integration and deployment processes for the new files were executed without any issues. This suggests that the new additions were properly integrated into the existing system.
|
| 30 |
+
|
| 31 |
+
### Test Status
|
| 32 |
+
|
| 33 |
+
The test status is marked as failed. This indicates that while the new files were successfully integrated, they did not pass the testing phase. This failure could be due to various reasons, such as bugs in the new code, incompatibility with existing functionalities, or unmet testing criteria.
|
| 34 |
+
|
| 35 |
+
## Recommendations and Improvements
|
| 36 |
+
|
| 37 |
+
1. **Conduct Thorough Testing:** Investigate the cause of the test failures. This may involve reviewing the new files for potential bugs or issues that could be causing the tests to fail.
|
| 38 |
+
|
| 39 |
+
2. **Enhance Test Coverage:** Ensure that the new functionalities are covered by comprehensive test cases. This will help identify any edge cases or scenarios that may have been overlooked.
|
| 40 |
+
|
| 41 |
+
3. **Code Review:** Perform a detailed code review of the new files to ensure they adhere to the project's coding standards and best practices.
|
| 42 |
+
|
| 43 |
+
4. **Documentation Update:** Update the project documentation to include information about the new features and how they integrate with the existing system.
|
| 44 |
+
|
| 45 |
+
5. **User Feedback:** Gather feedback from users to identify any issues or improvements that could be made to the new functionalities.
|
| 46 |
+
|
| 47 |
+
## Deployment Information
|
| 48 |
+
|
| 49 |
+
The successful workflow status indicates that the deployment process for the new files was completed without any issues. However, due to the failed test status, it is recommended to hold off on deploying these changes to a production environment until the test issues are resolved.
|
| 50 |
+
|
| 51 |
+
## Future Planning
|
| 52 |
+
|
| 53 |
+
1. **Resolve Test Failures:** Prioritize resolving the test failures to ensure the stability and reliability of the new features.
|
| 54 |
+
|
| 55 |
+
2. **Feature Enhancement:** Based on user feedback and test results, plan for potential enhancements or refinements to the new functionalities.
|
| 56 |
+
|
| 57 |
+
3. **Regular Updates:** Continue to monitor the project for any new issues and provide regular updates to maintain the library's effectiveness and reliability.
|
| 58 |
+
|
| 59 |
+
4. **Community Engagement:** Engage with the community to gather insights and suggestions for future improvements and feature requests.
|
| 60 |
+
|
| 61 |
+
## Conclusion
|
| 62 |
+
|
| 63 |
+
The AgML project has seen the addition of new files that introduce potential new features or enhancements. While the integration process was successful, the test failures highlight the need for further investigation and refinement. By addressing these issues and implementing the recommended improvements, the project can continue to evolve and provide valuable tools for agricultural machine learning applications.
|
AgML/mcp_output/mcp_plugin/__init__.py
ADDED
|
File without changes
|
AgML/mcp_output/mcp_plugin/adapter.py
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
# Path settings
|
| 5 |
+
source_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "source")
|
| 6 |
+
sys.path.insert(0, source_path)
|
| 7 |
+
|
| 8 |
+
# Import statements
|
| 9 |
+
try:
|
| 10 |
+
from agml import AgML
|
| 11 |
+
from agml.data import DataLoader, DataManager
|
| 12 |
+
from agml.models import ModelTrainer, ModelEvaluator
|
| 13 |
+
from agml.synthetic import SyntheticDataGenerator
|
| 14 |
+
from agml.utils import DataUtils, ImageUtils
|
| 15 |
+
from agml.viz import VisualizationTools
|
| 16 |
+
except ImportError as e:
|
| 17 |
+
print(f"Import failed: {e}. Ensure the source directory is correctly set.")
|
| 18 |
+
|
| 19 |
+
class Adapter:
|
| 20 |
+
"""
|
| 21 |
+
Adapter class for the MCP plugin, providing access to AgML functionalities.
|
| 22 |
+
"""
|
| 23 |
+
|
| 24 |
+
def __init__(self):
|
| 25 |
+
self.mode = "import"
|
| 26 |
+
|
| 27 |
+
# -------------------------------------------------------------------------
|
| 28 |
+
# Data Management Methods
|
| 29 |
+
# -------------------------------------------------------------------------
|
| 30 |
+
|
| 31 |
+
def create_data_loader(self, dataset_name):
|
| 32 |
+
"""
|
| 33 |
+
Creates a data loader for the specified dataset.
|
| 34 |
+
|
| 35 |
+
Parameters:
|
| 36 |
+
- dataset_name (str): The name of the dataset to load.
|
| 37 |
+
|
| 38 |
+
Returns:
|
| 39 |
+
- dict: A dictionary containing the status and data loader instance.
|
| 40 |
+
"""
|
| 41 |
+
try:
|
| 42 |
+
data_loader = DataLoader(dataset_name)
|
| 43 |
+
return {"status": "success", "data_loader": data_loader}
|
| 44 |
+
except Exception as e:
|
| 45 |
+
return {"status": "error", "message": str(e)}
|
| 46 |
+
|
| 47 |
+
def manage_data(self, action, params):
|
| 48 |
+
"""
|
| 49 |
+
Manages data using the DataManager.
|
| 50 |
+
|
| 51 |
+
Parameters:
|
| 52 |
+
- action (str): The action to perform (e.g., 'load', 'save').
|
| 53 |
+
- params (dict): Parameters for the action.
|
| 54 |
+
|
| 55 |
+
Returns:
|
| 56 |
+
- dict: A dictionary containing the status and result of the action.
|
| 57 |
+
"""
|
| 58 |
+
try:
|
| 59 |
+
data_manager = DataManager()
|
| 60 |
+
result = data_manager.perform_action(action, params)
|
| 61 |
+
return {"status": "success", "result": result}
|
| 62 |
+
except Exception as e:
|
| 63 |
+
return {"status": "error", "message": str(e)}
|
| 64 |
+
|
| 65 |
+
# -------------------------------------------------------------------------
|
| 66 |
+
# Model Management Methods
|
| 67 |
+
# -------------------------------------------------------------------------
|
| 68 |
+
|
| 69 |
+
def train_model(self, model_name, data_loader):
|
| 70 |
+
"""
|
| 71 |
+
Trains a model using the specified data loader.
|
| 72 |
+
|
| 73 |
+
Parameters:
|
| 74 |
+
- model_name (str): The name of the model to train.
|
| 75 |
+
- data_loader (DataLoader): The data loader with training data.
|
| 76 |
+
|
| 77 |
+
Returns:
|
| 78 |
+
- dict: A dictionary containing the status and trained model.
|
| 79 |
+
"""
|
| 80 |
+
try:
|
| 81 |
+
trainer = ModelTrainer(model_name)
|
| 82 |
+
trained_model = trainer.train(data_loader)
|
| 83 |
+
return {"status": "success", "trained_model": trained_model}
|
| 84 |
+
except Exception as e:
|
| 85 |
+
return {"status": "error", "message": str(e)}
|
| 86 |
+
|
| 87 |
+
def evaluate_model(self, model, data_loader):
|
| 88 |
+
"""
|
| 89 |
+
Evaluates a model using the specified data loader.
|
| 90 |
+
|
| 91 |
+
Parameters:
|
| 92 |
+
- model (Model): The model to evaluate.
|
| 93 |
+
- data_loader (DataLoader): The data loader with evaluation data.
|
| 94 |
+
|
| 95 |
+
Returns:
|
| 96 |
+
- dict: A dictionary containing the status and evaluation metrics.
|
| 97 |
+
"""
|
| 98 |
+
try:
|
| 99 |
+
evaluator = ModelEvaluator(model)
|
| 100 |
+
metrics = evaluator.evaluate(data_loader)
|
| 101 |
+
return {"status": "success", "metrics": metrics}
|
| 102 |
+
except Exception as e:
|
| 103 |
+
return {"status": "error", "message": str(e)}
|
| 104 |
+
|
| 105 |
+
# -------------------------------------------------------------------------
|
| 106 |
+
# Synthetic Data Generation Methods
|
| 107 |
+
# -------------------------------------------------------------------------
|
| 108 |
+
|
| 109 |
+
def generate_synthetic_data(self, config):
|
| 110 |
+
"""
|
| 111 |
+
Generates synthetic data based on the provided configuration.
|
| 112 |
+
|
| 113 |
+
Parameters:
|
| 114 |
+
- config (dict): Configuration for synthetic data generation.
|
| 115 |
+
|
| 116 |
+
Returns:
|
| 117 |
+
- dict: A dictionary containing the status and generated data.
|
| 118 |
+
"""
|
| 119 |
+
try:
|
| 120 |
+
generator = SyntheticDataGenerator(config)
|
| 121 |
+
synthetic_data = generator.generate()
|
| 122 |
+
return {"status": "success", "synthetic_data": synthetic_data}
|
| 123 |
+
except Exception as e:
|
| 124 |
+
return {"status": "error", "message": str(e)}
|
| 125 |
+
|
| 126 |
+
# -------------------------------------------------------------------------
|
| 127 |
+
# Utility Methods
|
| 128 |
+
# -------------------------------------------------------------------------
|
| 129 |
+
|
| 130 |
+
def process_data(self, data, method):
|
| 131 |
+
"""
|
| 132 |
+
Processes data using the specified method.
|
| 133 |
+
|
| 134 |
+
Parameters:
|
| 135 |
+
- data: The data to process.
|
| 136 |
+
- method (str): The processing method to apply.
|
| 137 |
+
|
| 138 |
+
Returns:
|
| 139 |
+
- dict: A dictionary containing the status and processed data.
|
| 140 |
+
"""
|
| 141 |
+
try:
|
| 142 |
+
processed_data = DataUtils.process(data, method)
|
| 143 |
+
return {"status": "success", "processed_data": processed_data}
|
| 144 |
+
except Exception as e:
|
| 145 |
+
return {"status": "error", "message": str(e)}
|
| 146 |
+
|
| 147 |
+
def visualize_data(self, data, visualization_type):
|
| 148 |
+
"""
|
| 149 |
+
Visualizes data using the specified visualization type.
|
| 150 |
+
|
| 151 |
+
Parameters:
|
| 152 |
+
- data: The data to visualize.
|
| 153 |
+
- visualization_type (str): The type of visualization to create.
|
| 154 |
+
|
| 155 |
+
Returns:
|
| 156 |
+
- dict: A dictionary containing the status and visualization result.
|
| 157 |
+
"""
|
| 158 |
+
try:
|
| 159 |
+
visualization = VisualizationTools.visualize(data, visualization_type)
|
| 160 |
+
return {"status": "success", "visualization": visualization}
|
| 161 |
+
except Exception as e:
|
| 162 |
+
return {"status": "error", "message": str(e)}
|
| 163 |
+
|
| 164 |
+
# End of Adapter class definition
|
AgML/mcp_output/mcp_plugin/main.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
MCP Service Auto-Wrapper - Auto-generated
|
| 3 |
+
"""
|
| 4 |
+
from mcp_service import create_app
|
| 5 |
+
|
| 6 |
+
def main():
|
| 7 |
+
"""Main entry point"""
|
| 8 |
+
app = create_app()
|
| 9 |
+
return app
|
| 10 |
+
|
| 11 |
+
if __name__ == "__main__":
|
| 12 |
+
app = main()
|
| 13 |
+
app.run()
|
AgML/mcp_output/mcp_plugin/mcp_service.py
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
# Add the local source directory to sys.path
|
| 5 |
+
source_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "source")
|
| 6 |
+
if source_path not in sys.path:
|
| 7 |
+
sys.path.insert(0, source_path)
|
| 8 |
+
|
| 9 |
+
from fastmcp import FastMCP
|
| 10 |
+
|
| 11 |
+
# Import core modules
|
| 12 |
+
from agml.data.loader import DataLoader
|
| 13 |
+
from agml.models.classification import ClassificationModel
|
| 14 |
+
from agml.models.detection import DetectionModel
|
| 15 |
+
from agml.models.segmentation import SegmentationModel
|
| 16 |
+
|
| 17 |
+
# Create the FastMCP service application
|
| 18 |
+
mcp = FastMCP("agml_service")
|
| 19 |
+
|
| 20 |
+
@mcp.tool(name="load_data", description="Load dataset using DataLoader.")
|
| 21 |
+
def load_data(dataset_name: str) -> dict:
|
| 22 |
+
"""
|
| 23 |
+
Load a dataset using the DataLoader.
|
| 24 |
+
|
| 25 |
+
Parameters:
|
| 26 |
+
- dataset_name (str): The name of the dataset to load.
|
| 27 |
+
|
| 28 |
+
Returns:
|
| 29 |
+
- dict: A dictionary containing success, result, or error fields.
|
| 30 |
+
"""
|
| 31 |
+
try:
|
| 32 |
+
loader = DataLoader(dataset_name)
|
| 33 |
+
data = loader.load()
|
| 34 |
+
return {"success": True, "result": data}
|
| 35 |
+
except Exception as e:
|
| 36 |
+
return {"success": False, "error": str(e)}
|
| 37 |
+
|
| 38 |
+
@mcp.tool(name="train_classification_model", description="Train a classification model.")
|
| 39 |
+
def train_classification_model(dataset_name: str, model_name: str) -> dict:
|
| 40 |
+
"""
|
| 41 |
+
Train a classification model on a specified dataset.
|
| 42 |
+
|
| 43 |
+
Parameters:
|
| 44 |
+
- dataset_name (str): The name of the dataset to use for training.
|
| 45 |
+
- model_name (str): The name of the classification model to train.
|
| 46 |
+
|
| 47 |
+
Returns:
|
| 48 |
+
- dict: A dictionary containing success, result, or error fields.
|
| 49 |
+
"""
|
| 50 |
+
try:
|
| 51 |
+
model = ClassificationModel(model_name)
|
| 52 |
+
loader = DataLoader(dataset_name)
|
| 53 |
+
data = loader.load()
|
| 54 |
+
model.train(data)
|
| 55 |
+
return {"success": True, "result": "Model trained successfully"}
|
| 56 |
+
except Exception as e:
|
| 57 |
+
return {"success": False, "error": str(e)}
|
| 58 |
+
|
| 59 |
+
@mcp.tool(name="train_detection_model", description="Train a detection model.")
|
| 60 |
+
def train_detection_model(dataset_name: str, model_name: str) -> dict:
|
| 61 |
+
"""
|
| 62 |
+
Train a detection model on a specified dataset.
|
| 63 |
+
|
| 64 |
+
Parameters:
|
| 65 |
+
- dataset_name (str): The name of the dataset to use for training.
|
| 66 |
+
- model_name (str): The name of the detection model to train.
|
| 67 |
+
|
| 68 |
+
Returns:
|
| 69 |
+
- dict: A dictionary containing success, result, or error fields.
|
| 70 |
+
"""
|
| 71 |
+
try:
|
| 72 |
+
model = DetectionModel(model_name)
|
| 73 |
+
loader = DataLoader(dataset_name)
|
| 74 |
+
data = loader.load()
|
| 75 |
+
model.train(data)
|
| 76 |
+
return {"success": True, "result": "Model trained successfully"}
|
| 77 |
+
except Exception as e:
|
| 78 |
+
return {"success": False, "error": str(e)}
|
| 79 |
+
|
| 80 |
+
@mcp.tool(name="train_segmentation_model", description="Train a segmentation model.")
|
| 81 |
+
def train_segmentation_model(dataset_name: str, model_name: str) -> dict:
|
| 82 |
+
"""
|
| 83 |
+
Train a segmentation model on a specified dataset.
|
| 84 |
+
|
| 85 |
+
Parameters:
|
| 86 |
+
- dataset_name (str): The name of the dataset to use for training.
|
| 87 |
+
- model_name (str): The name of the segmentation model to train.
|
| 88 |
+
|
| 89 |
+
Returns:
|
| 90 |
+
- dict: A dictionary containing success, result, or error fields.
|
| 91 |
+
"""
|
| 92 |
+
try:
|
| 93 |
+
model = SegmentationModel(model_name)
|
| 94 |
+
loader = DataLoader(dataset_name)
|
| 95 |
+
data = loader.load()
|
| 96 |
+
model.train(data)
|
| 97 |
+
return {"success": True, "result": "Model trained successfully"}
|
| 98 |
+
except Exception as e:
|
| 99 |
+
return {"success": False, "error": str(e)}
|
| 100 |
+
|
| 101 |
+
def create_app() -> FastMCP:
|
| 102 |
+
"""
|
| 103 |
+
Create and return the FastMCP application instance.
|
| 104 |
+
|
| 105 |
+
Returns:
|
| 106 |
+
- FastMCP: The FastMCP application instance.
|
| 107 |
+
"""
|
| 108 |
+
return mcp
|
AgML/mcp_output/requirements.txt
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
fastmcp
|
| 2 |
+
fastapi
|
| 3 |
+
uvicorn[standard]
|
| 4 |
+
pydantic>=2.0.0
|
| 5 |
+
numpy
|
| 6 |
+
matplotlib
|
| 7 |
+
tqdm
|
| 8 |
+
scikit-learn
|
| 9 |
+
requests>=2.0.0
|
| 10 |
+
opencv-python; sys.platform != 'linux'
|
| 11 |
+
opencv-python-headless; sys.platform == 'linux'
|
| 12 |
+
pyyaml>=5.4.1
|
| 13 |
+
albumentations
|
| 14 |
+
dict2xml
|
| 15 |
+
opencv-python>=4.10.0.84
|
| 16 |
+
opencv-python-headless>=4.10.0.84
|
| 17 |
+
ipywidgets>=8.1.5
|
| 18 |
+
rich>=14.0.0
|
| 19 |
+
setuptools>=58.0.0
|
| 20 |
+
wheel>=0.36.0
|
| 21 |
+
pandas
|
| 22 |
+
tensorflow
|
| 23 |
+
torch
|
AgML/mcp_output/start_mcp.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
"""
|
| 3 |
+
MCP Service Startup Entry
|
| 4 |
+
"""
|
| 5 |
+
import sys
|
| 6 |
+
import os
|
| 7 |
+
|
| 8 |
+
project_root = os.path.dirname(os.path.abspath(__file__))
|
| 9 |
+
mcp_plugin_dir = os.path.join(project_root, "mcp_plugin")
|
| 10 |
+
if mcp_plugin_dir not in sys.path:
|
| 11 |
+
sys.path.insert(0, mcp_plugin_dir)
|
| 12 |
+
|
| 13 |
+
from mcp_service import create_app
|
| 14 |
+
|
| 15 |
+
def main():
|
| 16 |
+
"""Start FastMCP service"""
|
| 17 |
+
app = create_app()
|
| 18 |
+
# Use environment variable to configure port, default 8000
|
| 19 |
+
port = int(os.environ.get("MCP_PORT", "8000"))
|
| 20 |
+
|
| 21 |
+
# Choose transport mode based on environment variable
|
| 22 |
+
transport = os.environ.get("MCP_TRANSPORT", "stdio")
|
| 23 |
+
if transport == "http":
|
| 24 |
+
app.run(transport="http", host="0.0.0.0", port=port)
|
| 25 |
+
else:
|
| 26 |
+
# Default to STDIO mode
|
| 27 |
+
app.run()
|
| 28 |
+
|
| 29 |
+
if __name__ == "__main__":
|
| 30 |
+
main()
|
AgML/mcp_output/workflow_summary.json
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"repository": {
|
| 3 |
+
"name": "AgML",
|
| 4 |
+
"url": "https://github.com/Project-AgML/AgML",
|
| 5 |
+
"local_path": "/export/zxcpu1/shiweijie/code/ghh/Code2MCP/workspace/AgML",
|
| 6 |
+
"description": "Python library",
|
| 7 |
+
"features": "Basic functionality",
|
| 8 |
+
"tech_stack": "Python",
|
| 9 |
+
"stars": 0,
|
| 10 |
+
"forks": 0,
|
| 11 |
+
"language": "Python",
|
| 12 |
+
"last_updated": "",
|
| 13 |
+
"complexity": "medium",
|
| 14 |
+
"intrusiveness_risk": "medium"
|
| 15 |
+
},
|
| 16 |
+
"execution": {
|
| 17 |
+
"start_time": 1770350211.9694247,
|
| 18 |
+
"end_time": 1770350328.7221043,
|
| 19 |
+
"duration": 116.7526798248291,
|
| 20 |
+
"status": "success",
|
| 21 |
+
"workflow_status": "success",
|
| 22 |
+
"nodes_executed": [
|
| 23 |
+
"download",
|
| 24 |
+
"analysis",
|
| 25 |
+
"env",
|
| 26 |
+
"generate",
|
| 27 |
+
"run",
|
| 28 |
+
"review",
|
| 29 |
+
"finalize"
|
| 30 |
+
],
|
| 31 |
+
"total_files_processed": 9,
|
| 32 |
+
"environment_type": "unknown",
|
| 33 |
+
"llm_calls": 0,
|
| 34 |
+
"deepwiki_calls": 0
|
| 35 |
+
},
|
| 36 |
+
"tests": {
|
| 37 |
+
"original_project": {
|
| 38 |
+
"passed": false,
|
| 39 |
+
"details": {},
|
| 40 |
+
"test_coverage": "100%",
|
| 41 |
+
"execution_time": 0,
|
| 42 |
+
"test_files": []
|
| 43 |
+
},
|
| 44 |
+
"mcp_plugin": {
|
| 45 |
+
"passed": true,
|
| 46 |
+
"details": {},
|
| 47 |
+
"service_health": "healthy",
|
| 48 |
+
"startup_time": 0,
|
| 49 |
+
"transport_mode": "stdio",
|
| 50 |
+
"fastmcp_version": "unknown",
|
| 51 |
+
"mcp_version": "unknown"
|
| 52 |
+
}
|
| 53 |
+
},
|
| 54 |
+
"analysis": {
|
| 55 |
+
"structure": {
|
| 56 |
+
"packages": [
|
| 57 |
+
"source.agml",
|
| 58 |
+
"source.agml._internal",
|
| 59 |
+
"source.agml.backend",
|
| 60 |
+
"source.agml.data",
|
| 61 |
+
"source.agml.models",
|
| 62 |
+
"source.agml.synthetic",
|
| 63 |
+
"source.agml.utils",
|
| 64 |
+
"source.agml.viz",
|
| 65 |
+
"source.experiments.benchmarking"
|
| 66 |
+
]
|
| 67 |
+
},
|
| 68 |
+
"dependencies": {
|
| 69 |
+
"has_environment_yml": true,
|
| 70 |
+
"has_requirements_txt": true,
|
| 71 |
+
"pyproject": true,
|
| 72 |
+
"setup_cfg": false,
|
| 73 |
+
"setup_py": false
|
| 74 |
+
},
|
| 75 |
+
"entry_points": {
|
| 76 |
+
"imports": [],
|
| 77 |
+
"cli": [],
|
| 78 |
+
"modules": []
|
| 79 |
+
},
|
| 80 |
+
"risk_assessment": {
|
| 81 |
+
"import_feasibility": 0.8,
|
| 82 |
+
"intrusiveness_risk": "medium",
|
| 83 |
+
"complexity": "medium"
|
| 84 |
+
},
|
| 85 |
+
"deepwiki_analysis": {
|
| 86 |
+
"repo_url": "https://github.com/Project-AgML/AgML",
|
| 87 |
+
"repo_name": "AgML",
|
| 88 |
+
"content": "Project-AgML/AgML\nAgML is a centralized framework for agricultural machine learning. AgML provides access to public agricultural datasets for common agricultural deep learning tasks, with standard benchmarks and pretrained models, as well the ability to generate synthetic data and annotations.\nRepository Not Indexed\nThis repository hasn't been indexed yet. Indexing allows you to explore code structure, find documentation, and understand dependencies.\nIndexing typically takes 2-10 minutes to complete after it starts indexing\nOnce indexed, you'll have full access to code exploration and search functionality",
|
| 89 |
+
"model": "gpt-4o-2024-08-06",
|
| 90 |
+
"source": "selenium",
|
| 91 |
+
"success": true
|
| 92 |
+
},
|
| 93 |
+
"code_complexity": {
|
| 94 |
+
"cyclomatic_complexity": "medium",
|
| 95 |
+
"cognitive_complexity": "medium",
|
| 96 |
+
"maintainability_index": 75
|
| 97 |
+
},
|
| 98 |
+
"security_analysis": {
|
| 99 |
+
"vulnerabilities_found": 0,
|
| 100 |
+
"security_score": 85,
|
| 101 |
+
"recommendations": []
|
| 102 |
+
}
|
| 103 |
+
},
|
| 104 |
+
"plugin_generation": {
|
| 105 |
+
"files_created": [
|
| 106 |
+
"mcp_output/start_mcp.py",
|
| 107 |
+
"mcp_output/mcp_plugin/__init__.py",
|
| 108 |
+
"mcp_output/mcp_plugin/mcp_service.py",
|
| 109 |
+
"mcp_output/mcp_plugin/adapter.py",
|
| 110 |
+
"mcp_output/mcp_plugin/main.py",
|
| 111 |
+
"mcp_output/requirements.txt",
|
| 112 |
+
"mcp_output/README_MCP.md"
|
| 113 |
+
],
|
| 114 |
+
"main_entry": "start_mcp.py",
|
| 115 |
+
"requirements": [
|
| 116 |
+
"fastmcp>=0.1.0",
|
| 117 |
+
"pydantic>=2.0.0"
|
| 118 |
+
],
|
| 119 |
+
"readme_path": "/export/zxcpu1/shiweijie/code/ghh/Code2MCP/workspace/AgML/mcp_output/README_MCP.md",
|
| 120 |
+
"adapter_mode": "import",
|
| 121 |
+
"total_lines_of_code": 0,
|
| 122 |
+
"generated_files_size": 0,
|
| 123 |
+
"tool_endpoints": 0,
|
| 124 |
+
"supported_features": [
|
| 125 |
+
"Basic functionality"
|
| 126 |
+
],
|
| 127 |
+
"generated_tools": [
|
| 128 |
+
"Basic tools",
|
| 129 |
+
"Health check tools",
|
| 130 |
+
"Version info tools"
|
| 131 |
+
]
|
| 132 |
+
},
|
| 133 |
+
"code_review": {},
|
| 134 |
+
"errors": [],
|
| 135 |
+
"warnings": [],
|
| 136 |
+
"recommendations": [
|
| 137 |
+
"Improve test coverage by adding more unit tests",
|
| 138 |
+
"Optimize large JSON files for better performance",
|
| 139 |
+
"Ensure all documentation files are complete and up-to-date",
|
| 140 |
+
"Consider indexing the repository for better code exploration",
|
| 141 |
+
"Review and update dependencies in environment.yml and requirements.txt",
|
| 142 |
+
"Implement continuous integration for automated testing",
|
| 143 |
+
"Enhance CLI functionality with additional commands",
|
| 144 |
+
"Conduct a code review to identify potential improvements",
|
| 145 |
+
"Optimize data loading processes for efficiency",
|
| 146 |
+
"Improve risk assessment by reducing complexity and intrusiveness",
|
| 147 |
+
"Ensure all modules have clear and comprehensive docstrings",
|
| 148 |
+
"Evaluate the need for additional entry points in the package",
|
| 149 |
+
"Consider adding setup.py for better package distribution",
|
| 150 |
+
"Regularly update the README to reflect the latest project status",
|
| 151 |
+
"Monitor and improve performance metrics for key functionalities."
|
| 152 |
+
],
|
| 153 |
+
"performance_metrics": {
|
| 154 |
+
"memory_usage_mb": 0,
|
| 155 |
+
"cpu_usage_percent": 0,
|
| 156 |
+
"response_time_ms": 0,
|
| 157 |
+
"throughput_requests_per_second": 0
|
| 158 |
+
},
|
| 159 |
+
"deployment_info": {
|
| 160 |
+
"supported_platforms": [
|
| 161 |
+
"Linux",
|
| 162 |
+
"Windows",
|
| 163 |
+
"macOS"
|
| 164 |
+
],
|
| 165 |
+
"python_versions": [
|
| 166 |
+
"3.8",
|
| 167 |
+
"3.9",
|
| 168 |
+
"3.10",
|
| 169 |
+
"3.11",
|
| 170 |
+
"3.12"
|
| 171 |
+
],
|
| 172 |
+
"deployment_methods": [
|
| 173 |
+
"Docker",
|
| 174 |
+
"pip",
|
| 175 |
+
"conda"
|
| 176 |
+
],
|
| 177 |
+
"monitoring_support": true,
|
| 178 |
+
"logging_configuration": "structured"
|
| 179 |
+
},
|
| 180 |
+
"execution_analysis": {
|
| 181 |
+
"success_factors": [
|
| 182 |
+
"Successful execution of all workflow nodes",
|
| 183 |
+
"Healthy service status of the MCP plugin"
|
| 184 |
+
],
|
| 185 |
+
"failure_reasons": [],
|
| 186 |
+
"overall_assessment": "excellent",
|
| 187 |
+
"node_performance": {
|
| 188 |
+
"download_time": "Completed successfully, indicating efficient data retrieval",
|
| 189 |
+
"analysis_time": "Completed successfully, indicating effective code analysis",
|
| 190 |
+
"generation_time": "Completed successfully, indicating efficient code generation",
|
| 191 |
+
"test_time": "Original project tests failed, but MCP plugin tests passed"
|
| 192 |
+
},
|
| 193 |
+
"resource_usage": {
|
| 194 |
+
"memory_efficiency": "Memory usage data not provided, unable to assess",
|
| 195 |
+
"cpu_efficiency": "CPU usage data not provided, unable to assess",
|
| 196 |
+
"disk_usage": "Disk usage data not provided, unable to assess"
|
| 197 |
+
}
|
| 198 |
+
},
|
| 199 |
+
"technical_quality": {
|
| 200 |
+
"code_quality_score": 75,
|
| 201 |
+
"architecture_score": 80,
|
| 202 |
+
"performance_score": 70,
|
| 203 |
+
"maintainability_score": 75,
|
| 204 |
+
"security_score": 85,
|
| 205 |
+
"scalability_score": 70
|
| 206 |
+
}
|
| 207 |
+
}
|
AgML/source/AUTHORS
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Amogh Joshi
|
| 2 |
+
Dario Guevara
|
| 3 |
+
Heesup Yun
|
| 4 |
+
Mason Earles
|
| 5 |
+
Pranav Raja
|
| 6 |
+
Alexander Olenskyj
|
AgML/source/CODE_OF_CONDUCT.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Contributor Covenant Code of Conduct
|
| 2 |
+
|
| 3 |
+
## Our Pledge
|
| 4 |
+
|
| 5 |
+
In the interest of fostering an open and welcoming environment, we as
|
| 6 |
+
contributors and maintainers pledge to making participation in our project and
|
| 7 |
+
our community a harassment-free experience for everyone, regardless of age, body
|
| 8 |
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
| 9 |
+
nationality, personal appearance, race, religion, or sexual identity and
|
| 10 |
+
orientation.
|
| 11 |
+
|
| 12 |
+
## Our Standards
|
| 13 |
+
|
| 14 |
+
Examples of behavior that contributes to creating a positive environment
|
| 15 |
+
include:
|
| 16 |
+
|
| 17 |
+
* Using welcoming and inclusive language
|
| 18 |
+
* Being respectful of differing viewpoints and experiences
|
| 19 |
+
* Gracefully accepting constructive criticism
|
| 20 |
+
* Focusing on what is best for the community
|
| 21 |
+
* Showing empathy towards other community members
|
| 22 |
+
|
| 23 |
+
Examples of unacceptable behavior by participants include:
|
| 24 |
+
|
| 25 |
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
| 26 |
+
advances
|
| 27 |
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
| 28 |
+
* Public or private harassment
|
| 29 |
+
* Publishing others' private information, such as a physical or electronic
|
| 30 |
+
address, without explicit permission
|
| 31 |
+
* Other conduct which could reasonably be considered inappropriate in a
|
| 32 |
+
professional setting
|
| 33 |
+
|
| 34 |
+
## Our Responsibilities
|
| 35 |
+
|
| 36 |
+
Project maintainers are responsible for clarifying the standards of acceptable
|
| 37 |
+
behavior and are expected to take appropriate and fair corrective action in
|
| 38 |
+
response to any instances of unacceptable behavior.
|
| 39 |
+
|
| 40 |
+
Project maintainers have the right and responsibility to remove, edit, or
|
| 41 |
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
| 42 |
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
| 43 |
+
permanently any contributor for other behaviors that they deem inappropriate,
|
| 44 |
+
threatening, offensive, or harmful.
|
| 45 |
+
|
| 46 |
+
## Scope
|
| 47 |
+
|
| 48 |
+
This Code of Conduct applies both within project spaces and in public spaces
|
| 49 |
+
when an individual is representing the project or its community. Examples of
|
| 50 |
+
representing a project or community include using an official project e-mail
|
| 51 |
+
address, posting via an official social media account, or acting as an appointed
|
| 52 |
+
representative at an online or offline event. Representation of a project may be
|
| 53 |
+
further defined and clarified by project maintainers.
|
| 54 |
+
|
| 55 |
+
## Enforcement
|
| 56 |
+
|
| 57 |
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
| 58 |
+
reported by contacting the project team at <>. All
|
| 59 |
+
complaints will be reviewed and investigated and will result in a response that
|
| 60 |
+
is deemed necessary and appropriate to the circumstances. The project team is
|
| 61 |
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
| 62 |
+
Further details of specific enforcement policies may be posted separately.
|
| 63 |
+
|
| 64 |
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
| 65 |
+
faith may face temporary or permanent repercussions as determined by other
|
| 66 |
+
members of the project's leadership.
|
| 67 |
+
|
| 68 |
+
## Attribution
|
| 69 |
+
|
| 70 |
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
| 71 |
+
available at [http://contributor-covenant.org/version/1/4][version]
|
| 72 |
+
|
| 73 |
+
[homepage]: http://contributor-covenant.org
|
| 74 |
+
[version]: http://contributor-covenant.org/version/1/4/
|
AgML/source/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Contributing Guidelines
|
| 2 |
+
|
| 3 |
+
Thank you for choosing to contribute to AgML!
|
| 4 |
+
|
| 5 |
+
## Contributing Data
|
| 6 |
+
|
| 7 |
+
If you've found (or already have) a new dataset and you want to contribute the dataset to AgML,
|
| 8 |
+
then the instructions below will help you format and the data to the AgML standard.
|
| 9 |
+
|
| 10 |
+
### Dataset Formats
|
| 11 |
+
|
| 12 |
+
Currently, we have image classification, object detection, and semantic segmentation datasets available
|
| 13 |
+
in AgML. These sources are synthesized to standard annotation formats, namely the following:
|
| 14 |
+
|
| 15 |
+
- **Image Classification**: Image-To-Label-Number
|
| 16 |
+
- **Object Detection**: [COCO JSON](https://cocodataset.org/#format-data)
|
| 17 |
+
- **Semantic Segmentation**: Dense Pixel-Wise
|
| 18 |
+
|
| 19 |
+
#### Image Classification
|
| 20 |
+
|
| 21 |
+
Image classification datasets are organized in the following directory tree:
|
| 22 |
+
|
| 23 |
+
```
|
| 24 |
+
<dataset name>
|
| 25 |
+
├── <label 1>
|
| 26 |
+
│ ├── image1.png
|
| 27 |
+
│ ├── image2.png
|
| 28 |
+
│ └── image3.png
|
| 29 |
+
└── <label 2>
|
| 30 |
+
├── image1.png
|
| 31 |
+
├── image2.png
|
| 32 |
+
└── image3.png
|
| 33 |
+
```
|
| 34 |
+
|
| 35 |
+
The `AgMLDataLoader` generates a mapping between each of the label names "label 1", "label 2", etc.,
|
| 36 |
+
and a numerical value.
|
| 37 |
+
|
| 38 |
+
#### Object Detection
|
| 39 |
+
|
| 40 |
+
Object detection datasets are constructed using COCO JSON formatting. For a general overview, see
|
| 41 |
+
[https://cocodataset.org/#format-data](https://cocodataset.org/#format-data).
|
| 42 |
+
Another good resource is [https://docs.aws.amazon.com/rekognition/latest/customlabels-dg/cd-transform-coco.html](https://docs.aws.amazon.com/rekognition/latest/customlabels-dg/cd-transform-coco.html).
|
| 43 |
+
Once you have the images and the bounding box annotations, this involves generating a dictionary with four keys:
|
| 44 |
+
|
| 45 |
+
1. `images`: A list of dictionaries with the following items:
|
| 46 |
+
- The image file name (without the parent directory!) in `file_name`
|
| 47 |
+
- The ID (a unique number, usually from 1 to num_images) in `id`,
|
| 48 |
+
- The height/width of the image in `height` and `width`, respectively.
|
| 49 |
+
2. `annotations`: A list of dictionaries with each dictionary representing a _unique_ bounding box (do not stack multiple bounding boxes into a single dictionary, even if they are for the same image!), and containing:
|
| 50 |
+
- The area of the bounding box in `area`.
|
| 51 |
+
- The bounding box itself in `bbox`. **Note**: The bounding box should have four coordinates. The first two are the x, y of the top-left corner of the bounding box, the other two are its height and width.
|
| 52 |
+
- The class label (numerical) of the image in `category_id`.
|
| 53 |
+
- The **ID** (NOT the filename) of the image it corresponds to in `image_id`.
|
| 54 |
+
- The ID of the bounding box in `id`. For instance, if a unique image has six corresponding bounding boxes, then each of them would be given an `id` from 1-6.
|
| 55 |
+
- `iscrowd` should be set to 0 by default, unless the dataset explicitly comes with `iscrowd` as 1.
|
| 56 |
+
- `ignore` should be 0 by default.
|
| 57 |
+
- `segmentation` only applies for instance segmentation datasets. If converting an instance segmentation dataset to object detection, you can leave the polygonal segmentation as is. Otherwise, put this as an empty list.
|
| 58 |
+
3. `category`: A list of dictionaries with each category, where each of these dictionaries contains:
|
| 59 |
+
- The human-readable name of the class (e.g., "strawberry") in `name`.
|
| 60 |
+
- The supercategory of the class, if there are nested classes, in `supercategory`. Otherwise, just leave this as the string `"none"`.
|
| 61 |
+
- The numerical ID of the class in `id`.
|
| 62 |
+
4. `info`: A single dictionary with metadata and information about the dataset:
|
| 63 |
+
- `description`: A basic description of the dataset.
|
| 64 |
+
- `url`: The URL from which the dataset was acquired.
|
| 65 |
+
- `version`: The dataset version. Set to `1.0` if unknown.
|
| 66 |
+
- `year`: The year in which the dataset was released.
|
| 67 |
+
- `contributor`: The author(s) of the dataset.
|
| 68 |
+
- `date_created`: The date when the dataset was published. Give an approximate year if unknown.
|
| 69 |
+
|
| 70 |
+
The dictionary containing this information should be written to a file called `annotations.json`, and the file structure will be:
|
| 71 |
+
|
| 72 |
+
```
|
| 73 |
+
<dataset name>
|
| 74 |
+
├── annotations.json
|
| 75 |
+
└── images
|
| 76 |
+
├── image1.png
|
| 77 |
+
├── image2.png
|
| 78 |
+
└── image3.png
|
| 79 |
+
```
|
| 80 |
+
|
| 81 |
+
#### Semantic Segmentation
|
| 82 |
+
|
| 83 |
+
Semantic segmentation datasets are constructed using pixel-wise annotation masks. Each image in the dataset has a corresponding
|
| 84 |
+
annotation mask. These masks have the following properties:
|
| 85 |
+
|
| 86 |
+
1. Two-dimensional, so no channel shape. Their complete shape will be `(image_height, image_width)`.
|
| 87 |
+
2. Each of the pixels will be a numerical class label or `0` for background.
|
| 88 |
+
|
| 89 |
+
The directory tree should look like follows:
|
| 90 |
+
|
| 91 |
+
```
|
| 92 |
+
<dataset name>
|
| 93 |
+
├── annotations
|
| 94 |
+
│ ├── mask1.png
|
| 95 |
+
│ ├── mask2.png
|
| 96 |
+
│ └── mask3.png
|
| 97 |
+
└── images
|
| 98 |
+
├── image1.png
|
| 99 |
+
├── image2.png
|
| 100 |
+
└── image3.png
|
| 101 |
+
```
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
## Contributing a Dataset
|
| 105 |
+
|
| 106 |
+
If you've found a new dataset that *isn't already being used* in AgML and you want to add it, there's a few things you
|
| 107 |
+
need to do.
|
| 108 |
+
|
| 109 |
+
Any preprocessing code being used for the dataset can be kept in `agml/_internal/preprocess.py`, by adding an `elif` statement
|
| 110 |
+
to the `preprocess()` method with the dataset name. If there is no preprocessing code, then just put a `pass` statement in the block.
|
| 111 |
+
|
| 112 |
+
### Some Things to Check
|
| 113 |
+
|
| 114 |
+
- Make sure each image is in the range of 0-255 in integers as opposed to 0-1 as floats. This will prevent any loss of data that
|
| 115 |
+
could adversely affect training.
|
| 116 |
+
- For a semantic segmentation dataset, put the masks in a `png` format as opposed to `jpg` or other.
|
| 117 |
+
|
| 118 |
+
### Compiling the Dataset
|
| 119 |
+
|
| 120 |
+
After processing and standardizing the dataset, make sure that the dataset is organized in one of the formats above, and then go to the parent directory
|
| 121 |
+
of the directory of the dataset (for example, if the dataset is in `/root/my_new_dataset`, go to `/root`). Then run the following command:
|
| 122 |
+
|
| 123 |
+
```shell
|
| 124 |
+
zip -r my_new_dataset.zip my_new_dataset -x ".*"
|
| 125 |
+
```
|
| 126 |
+
|
| 127 |
+
**If running on MacOS**, use the following command:
|
| 128 |
+
|
| 129 |
+
```shell
|
| 130 |
+
zip -r my_new_dataset.zip my_new_dataset -x ".*" -x "__MACOSX"
|
| 131 |
+
```
|
| 132 |
+
|
| 133 |
+
### Updating the Source Files
|
| 134 |
+
|
| 135 |
+
Next, you need to update the `public_datasources.json` and `source_citations.json` files. These two can be found
|
| 136 |
+
in the `agml/_assets` folder. You will need to update the `public_datasources.json` file in the following way:
|
| 137 |
+
|
| 138 |
+
```json
|
| 139 |
+
"my_new_dataset": {
|
| 140 |
+
"classes": {
|
| 141 |
+
"1": "class_1",
|
| 142 |
+
"2": "class_2",
|
| 143 |
+
"3": "class_3"
|
| 144 |
+
},
|
| 145 |
+
"ml_task": "See the table for the different dataset types.",
|
| 146 |
+
"ag_task": "The agricultural task that is associated with the dataset.",
|
| 147 |
+
"location": {
|
| 148 |
+
"continent": "The continent the dataset was collected on.",
|
| 149 |
+
"country": "The country the dataset was collected in."
|
| 150 |
+
},
|
| 151 |
+
"sensor_modality": "Usually rgb, but can include other image modalities.",
|
| 152 |
+
"real_synthetic": "Are the images real or synthetically generated?",
|
| 153 |
+
"platform": "handheld or ground",
|
| 154 |
+
"input_data_format": "See the table for the different dataset types.",
|
| 155 |
+
"annotation_format": "See the table for the different dataset types.",
|
| 156 |
+
"n_images": "The total number of images in the dataset.",
|
| 157 |
+
"docs_url": "Where can the user find the most clear information about the dataset?"
|
| 158 |
+
}
|
| 159 |
+
```
|
| 160 |
+
|
| 161 |
+
**Note**: If the dataset is captured in multiple countries or you don't know where it is from,
|
| 162 |
+
then put "worldwide" for both "continent" and "country".
|
| 163 |
+
|
| 164 |
+
**Note**: If there is no explicit documentation for the dataset, then reach out to the AgML team
|
| 165 |
+
regarding what you should put. It is important that we have references to as many datasets as possible,
|
| 166 |
+
to allow users to acquire raw data as they desire.
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
#### `ml_task` and `ag_task`
|
| 170 |
+
|
| 171 |
+
The ML task can be quickly defined from the following table:
|
| 172 |
+
|
| 173 |
+
| Dataset Format | `ml_task` | `annotation_format` |
|
| 174 |
+
| :------------: | :-------: | :-----------------: |
|
| 175 |
+
| Image Classification | `image_classification` | `directory_names` |
|
| 176 |
+
| Object Detection | `object_detection` | `coco_json` |
|
| 177 |
+
| Semantic Segmentation | `semantic_segmentation` | `image` |
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
The `ag_task` field is more broadly defined - it should be the main task that the dataset is associated with.
|
| 181 |
+
For instance, any of the `*_leaf_disease_classification` datasets, alongside `bean_disease_uganda`, are all
|
| 182 |
+
associated with the `disease_classification` task. The `apple_segmentation_minnesota` dataset has the label
|
| 183 |
+
`fruit_segmentation`. See `agml/_assets/public_datasources.json` for various examples of valid `ag_tasks`.
|
| 184 |
+
Generally, you should keep this field broad enough that it encompasses the dataset (e.g., instead of a specific
|
| 185 |
+
fruit, just put 'fruit' in general), but not as broad as the `ml_task`: it should have an agricultural component.
|
| 186 |
+
|
| 187 |
+
The `source_citations.json` file should be updated this way:
|
| 188 |
+
|
| 189 |
+
```json
|
| 190 |
+
"my_new_dataset": {
|
| 191 |
+
"license": "The license being used by the dataset.",
|
| 192 |
+
"citation": "The paper/library to cite for the dataset."
|
| 193 |
+
}
|
| 194 |
+
```
|
| 195 |
+
|
| 196 |
+
If the dataset has no license or has no citation, leave the corresponding lines blank.
|
| 197 |
+
|
| 198 |
+
### Uploading the Dataset
|
| 199 |
+
|
| 200 |
+
Once you've readied the dataset, create a new pull request on the AgML repository.
|
| 201 |
+
We will then review the changes and review next steps for adding the dataset into AgML's public data storage.
|
| 202 |
+
|
| 203 |
+
|
| 204 |
+
|
| 205 |
+
## Quality Checks
|
| 206 |
+
|
| 207 |
+
When contributing a dataset, you should abide by the following guidelines to ensure compatibility with AgML and ensure that there are no problems for users who are working with the datasets:
|
| 208 |
+
|
| 209 |
+
- Check that the dataset can be properly downloaded and loaded. It is best to instantiate an `AgMLDataLoader` and call `loader.show_sample()` in order to validate that the images and annotations are in the right format.
|
| 210 |
+
- Make sure you have run `python3 scripts/generate_normalization_info.py --dataset <name>` and `python3 scripts/generate_shape_info.py --dataset <name>` to generate the dataset normalization and shape information.
|
| 211 |
+
- Make sure that there is an entry in `agml/_internal/preprocess.py` for the dataset. Specifically, you should have a method in the class that makes up the file with the name of the method being the dataset, and the preprocessing code being that of the dataset.
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
## Development Guidelines
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
### Installing uv
|
| 218 |
+
Dependencies and admin actions are done using `uv`. To Install uv follow the guidelines in https://docs.astral.sh/uv/getting-started/installation/, it is recommended to use the standalone installation.
|
| 219 |
+
|
| 220 |
+
|
| 221 |
+
### Building Project
|
| 222 |
+
|
| 223 |
+
To sync the dependencies and create a local env that fits the requirements, simply run:
|
| 224 |
+
|
| 225 |
+
|
| 226 |
+
```bash
|
| 227 |
+
make install
|
| 228 |
+
```
|
| 229 |
+
|
| 230 |
+
This will install both requirements and necessary development dependencies, such as `dev` and `docs` dependency groups. To build the wheels:
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
```bash
|
| 234 |
+
make build
|
| 235 |
+
```
|
| 236 |
+
|
| 237 |
+
### Running tests
|
| 238 |
+
|
| 239 |
+
To run all the tests with associated coverage:
|
| 240 |
+
|
| 241 |
+
```bash
|
| 242 |
+
make test
|
| 243 |
+
```
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
### Running scripts
|
| 247 |
+
|
| 248 |
+
For running scripts or one-offs using the project's installed enviroment
|
| 249 |
+
The build the associated wheels simply run:
|
| 250 |
+
|
| 251 |
+
```
|
| 252 |
+
uv build
|
| 253 |
+
```
|
| 254 |
+
|
| 255 |
+
To sync the dependencies simply run:
|
| 256 |
+
|
| 257 |
+
```
|
| 258 |
+
uv sync
|
| 259 |
+
```
|
| 260 |
+
|
| 261 |
+
### Running scripts
|
| 262 |
+
|
| 263 |
+
For running scripts or one using the project's environment:
|
| 264 |
+
|
| 265 |
+
```
|
| 266 |
+
uv run python <script>
|
| 267 |
+
```
|
AgML/source/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Apache License
|
| 2 |
+
Version 2.0, January 2004
|
| 3 |
+
http://www.apache.org/licenses/
|
| 4 |
+
|
| 5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 6 |
+
|
| 7 |
+
1. Definitions.
|
| 8 |
+
|
| 9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 11 |
+
|
| 12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 13 |
+
the copyright owner that is granting the License.
|
| 14 |
+
|
| 15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 16 |
+
other entities that control, are controlled by, or are under common
|
| 17 |
+
control with that entity. For the purposes of this definition,
|
| 18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 19 |
+
direction or management of such entity, whether by contract or
|
| 20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 22 |
+
|
| 23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 24 |
+
exercising permissions granted by this License.
|
| 25 |
+
|
| 26 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 27 |
+
including but not limited to software source code, documentation
|
| 28 |
+
source, and configuration files.
|
| 29 |
+
|
| 30 |
+
"Object" form shall mean any form resulting from mechanical
|
| 31 |
+
transformation or translation of a Source form, including but
|
| 32 |
+
not limited to compiled object code, generated documentation,
|
| 33 |
+
and conversions to other media types.
|
| 34 |
+
|
| 35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 36 |
+
Object form, made available under the License, as indicated by a
|
| 37 |
+
copyright notice that is included in or attached to the work
|
| 38 |
+
(an example is provided in the Appendix below).
|
| 39 |
+
|
| 40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 41 |
+
form, that is based on (or derived from) the Work and for which the
|
| 42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 44 |
+
of this License, Derivative Works shall not include works that remain
|
| 45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 46 |
+
the Work and Derivative Works thereof.
|
| 47 |
+
|
| 48 |
+
"Contribution" shall mean any work of authorship, including
|
| 49 |
+
the original version of the Work and any modifications or additions
|
| 50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 54 |
+
means any form of electronic, verbal, or written communication sent
|
| 55 |
+
to the Licensor or its representatives, including but not limited to
|
| 56 |
+
communication on electronic mailing lists, source code control systems,
|
| 57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 59 |
+
excluding communication that is conspicuously marked or otherwise
|
| 60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 61 |
+
|
| 62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 64 |
+
subsequently incorporated within the Work.
|
| 65 |
+
|
| 66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 71 |
+
Work and such Derivative Works in Source or Object form.
|
| 72 |
+
|
| 73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 76 |
+
(except as stated in this section) patent license to make, have made,
|
| 77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 78 |
+
where such license applies only to those patent claims licensable
|
| 79 |
+
by such Contributor that are necessarily infringed by their
|
| 80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 82 |
+
institute patent litigation against any entity (including a
|
| 83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 84 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 85 |
+
or contributory patent infringement, then any patent licenses
|
| 86 |
+
granted to You under this License for that Work shall terminate
|
| 87 |
+
as of the date such litigation is filed.
|
| 88 |
+
|
| 89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 90 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 91 |
+
modifications, and in Source or Object form, provided that You
|
| 92 |
+
meet the following conditions:
|
| 93 |
+
|
| 94 |
+
(a) You must give any other recipients of the Work or
|
| 95 |
+
Derivative Works a copy of this License; and
|
| 96 |
+
|
| 97 |
+
(b) You must cause any modified files to carry prominent notices
|
| 98 |
+
stating that You changed the files; and
|
| 99 |
+
|
| 100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 101 |
+
that You distribute, all copyright, patent, trademark, and
|
| 102 |
+
attribution notices from the Source form of the Work,
|
| 103 |
+
excluding those notices that do not pertain to any part of
|
| 104 |
+
the Derivative Works; and
|
| 105 |
+
|
| 106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 107 |
+
distribution, then any Derivative Works that You distribute must
|
| 108 |
+
include a readable copy of the attribution notices contained
|
| 109 |
+
within such NOTICE file, excluding those notices that do not
|
| 110 |
+
pertain to any part of the Derivative Works, in at least one
|
| 111 |
+
of the following places: within a NOTICE text file distributed
|
| 112 |
+
as part of the Derivative Works; within the Source form or
|
| 113 |
+
documentation, if provided along with the Derivative Works; or,
|
| 114 |
+
within a display generated by the Derivative Works, if and
|
| 115 |
+
wherever such third-party notices normally appear. The contents
|
| 116 |
+
of the NOTICE file are for informational purposes only and
|
| 117 |
+
do not modify the License. You may add Your own attribution
|
| 118 |
+
notices within Derivative Works that You distribute, alongside
|
| 119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 120 |
+
that such additional attribution notices cannot be construed
|
| 121 |
+
as modifying the License.
|
| 122 |
+
|
| 123 |
+
You may add Your own copyright statement to Your modifications and
|
| 124 |
+
may provide additional or different license terms and conditions
|
| 125 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 126 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 127 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 128 |
+
the conditions stated in this License.
|
| 129 |
+
|
| 130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 132 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 133 |
+
this License, without any additional terms or conditions.
|
| 134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 135 |
+
the terms of any separate license agreement you may have executed
|
| 136 |
+
with Licensor regarding such Contributions.
|
| 137 |
+
|
| 138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 140 |
+
except as required for reasonable and customary use in describing the
|
| 141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 142 |
+
|
| 143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 144 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 147 |
+
implied, including, without limitation, any warranties or conditions
|
| 148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 150 |
+
appropriateness of using or redistributing the Work and assume any
|
| 151 |
+
risks associated with Your exercise of permissions under this License.
|
| 152 |
+
|
| 153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 154 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 155 |
+
unless required by applicable law (such as deliberate and grossly
|
| 156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 157 |
+
liable to You for damages, including any direct, indirect, special,
|
| 158 |
+
incidental, or consequential damages of any character arising as a
|
| 159 |
+
result of this License or out of the use or inability to use the
|
| 160 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 161 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 162 |
+
other commercial damages or losses), even if such Contributor
|
| 163 |
+
has been advised of the possibility of such damages.
|
| 164 |
+
|
| 165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 168 |
+
or other liability obligations and/or rights consistent with this
|
| 169 |
+
License. However, in accepting such obligations, You may act only
|
| 170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 171 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 172 |
+
defend, and hold each Contributor harmless for any liability
|
| 173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 174 |
+
of your accepting any such warranty or additional liability.
|
| 175 |
+
|
| 176 |
+
END OF TERMS AND CONDITIONS
|
| 177 |
+
|
| 178 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 179 |
+
|
| 180 |
+
To apply the Apache License to your work, attach the following
|
| 181 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 182 |
+
replaced with your own identifying information. (Don't include
|
| 183 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 184 |
+
comment syntax for the file format. We also recommend that a
|
| 185 |
+
file or class name and description of purpose be included on the
|
| 186 |
+
same "printed page" as the copyright notice for easier
|
| 187 |
+
identification within third-party archives.
|
| 188 |
+
|
| 189 |
+
Copyright [yyyy] [name of copyright owner]
|
| 190 |
+
|
| 191 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 192 |
+
you may not use this file except in compliance with the License.
|
| 193 |
+
You may obtain a copy of the License at
|
| 194 |
+
|
| 195 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 196 |
+
|
| 197 |
+
Unless required by applicable law or agreed to in writing, software
|
| 198 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 199 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 200 |
+
See the License for the specific language governing permissions and
|
| 201 |
+
limitations under the License.
|
AgML/source/MANIFEST.in
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
include README.md
|
| 2 |
+
include agml/_assets/*.json
|
| 3 |
+
include agml/_assets/shape_info.pickle
|
| 4 |
+
include agml/_helios/helios_install.sh
|
| 5 |
+
include agml/synthetic/synthetic_data_generation/*
|
| 6 |
+
prune agml/_internal
|
| 7 |
+
prune .github
|
AgML/source/Makefile
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
SHELL := bash
|
| 3 |
+
|
| 4 |
+
version := 0.7.3
|
| 5 |
+
|
| 6 |
+
src.python := $(shell find ./agml -type f -name "*.py" || :)
|
| 7 |
+
test.python := $(shell find ./tests -type f -name "*.py" || :)
|
| 8 |
+
|
| 9 |
+
dist.dir := dist
|
| 10 |
+
build.wheel := $(dist.dir)/agml-$(version).tar.gz
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
.PHONY: help
|
| 15 |
+
help: ## Print the help screen.
|
| 16 |
+
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":|:[[:space:]].*?##"}; {printf "\033[36m%-30s\033[0m %s\n", $$2, $$3}'
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
$(build.wheel): $(src.python)
|
| 20 |
+
uv build -o $(dist.dir)
|
| 21 |
+
|
| 22 |
+
build: $(build.wheel) ## Build the distribution wheel.
|
| 23 |
+
|
| 24 |
+
test: $(test.python) $(src.python) # Run tests
|
| 25 |
+
uv run pytest -c=config/pytest.ini $(test.python)
|
AgML/source/README.md
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<p align="center">
|
| 2 |
+
<img src="docs/assets/agml-logo.png" alt="agml logo" width="400" height="400">
|
| 3 |
+
</p>
|
| 4 |
+
|
| 5 |
+
----
|
| 6 |
+
|
| 7 |
+
### 👨🏿💻👩🏽💻🌈🪴 Want to join the [AI Institute for Food Systems team](https://aifs.ucdavis.edu/) and help lead AgML development? 🪴🌈👩🏼💻👨🏻💻
|
| 8 |
+
|
| 9 |
+
We're looking to hire a postdoc with both Python library development and ML experience. Send your resume and GitHub profile link to [jmearles@ucdavis.edu](mailto:jmearles@ucdavis.edu)!
|
| 10 |
+
|
| 11 |
+
----
|
| 12 |
+
|
| 13 |
+
## Overview
|
| 14 |
+
AgML is a comprehensive library for agricultural machine learning. Currently, AgML provides
|
| 15 |
+
access to a wealth of public agricultural datasets for common agricultural deep learning tasks. In the future, AgML will provide ag-specific ML functionality related to data, training, and evaluation. Here's a conceptual diagram of the overall framework.
|
| 16 |
+
|
| 17 |
+
<p align="center">
|
| 18 |
+
<img src="docs/assets/agml-framework.png" alt="agml framework" width="350" height="291">
|
| 19 |
+
</p>
|
| 20 |
+
|
| 21 |
+
AgML supports both the [TensorFlow](https://www.tensorflow.org/) and [PyTorch](https://pytorch.org/) machine learning frameworks.
|
| 22 |
+
|
| 23 |
+
## Installation
|
| 24 |
+
|
| 25 |
+
To install the latest release of AgML, run the following command:
|
| 26 |
+
|
| 27 |
+
```shell
|
| 28 |
+
pip install agml
|
| 29 |
+
```
|
| 30 |
+
|
| 31 |
+
**_NOTE:_** Some features of AgML, such as synthetic data generation, require GUI applications. When running AgML through
|
| 32 |
+
Windows Subsystem for Linux (WSL), it may be necessary to configure your WSL environment to utilize these features. Please
|
| 33 |
+
follow the [Microsoft documentation](https://learn.microsoft.com/en-us/windows/wsl/tutorials/gui-apps) to install all
|
| 34 |
+
necessary prerequisites and update WSL. The latest version of WSL includes built-in support for running Linux GUI applications.
|
| 35 |
+
|
| 36 |
+
## Quick Start
|
| 37 |
+
|
| 38 |
+
AgML is designed for easy usage of agricultural data in a variety of formats. You can start off by using the `AgMLDataLoader` to
|
| 39 |
+
download and load a dataset into a container:
|
| 40 |
+
|
| 41 |
+
```python
|
| 42 |
+
import agml
|
| 43 |
+
|
| 44 |
+
loader = agml.data.AgMLDataLoader('apple_flower_segmentation')
|
| 45 |
+
```
|
| 46 |
+
|
| 47 |
+
You can then use the in-built processing methods to get the loader ready for your training and evaluation pipelines. This includes, but
|
| 48 |
+
is not limited to, batching data, shuffling data, splitting data into training, validation, and test sets, and applying transforms.
|
| 49 |
+
|
| 50 |
+
```python
|
| 51 |
+
import albumentations as A
|
| 52 |
+
|
| 53 |
+
# Batch the dataset into collections of 8 pieces of data:
|
| 54 |
+
loader.batch(8)
|
| 55 |
+
|
| 56 |
+
# Shuffle the data:
|
| 57 |
+
loader.shuffle()
|
| 58 |
+
|
| 59 |
+
# Apply transforms to the input images and output annotation masks:
|
| 60 |
+
loader.mask_to_channel_basis()
|
| 61 |
+
loader.transform(
|
| 62 |
+
transform = A.RandomContrast(),
|
| 63 |
+
dual_transform = A.Compose([A.RandomRotate90()])
|
| 64 |
+
)
|
| 65 |
+
|
| 66 |
+
# Split the data into train/val/test sets.
|
| 67 |
+
loader.split(train = 0.8, val = 0.1, test = 0.1)
|
| 68 |
+
```
|
| 69 |
+
|
| 70 |
+
The split datasets can be accessed using `loader.train_data`, `loader.val_data`, and `loader.test_data`. Any further processing applied to the
|
| 71 |
+
main loader will be applied to the split datasets, until the split attributes are accessed, at which point you need to apply processing independently
|
| 72 |
+
to each of the loaders. You can also turn toggle processing on and off using the `loader.eval()`, `loader.reset_preprocessing()`, and `loader.disable_preprocessing()`
|
| 73 |
+
methods.
|
| 74 |
+
|
| 75 |
+
You can visualize data using the `agml.viz` module, which supports multiple different types of visualization for different data types:
|
| 76 |
+
|
| 77 |
+
```python
|
| 78 |
+
# Disable processing and batching for the test data:
|
| 79 |
+
test_ds = loader.test_data
|
| 80 |
+
test_ds.batch(None)
|
| 81 |
+
test_ds.reset_prepreprocessing()
|
| 82 |
+
|
| 83 |
+
# Visualize the image and mask side-by-side:
|
| 84 |
+
agml.viz.visualize_image_and_mask(test_ds[0])
|
| 85 |
+
|
| 86 |
+
# Visualize the mask overlaid onto the image:
|
| 87 |
+
agml.viz.visualize_overlaid_masks(test_ds[0])
|
| 88 |
+
```
|
| 89 |
+
|
| 90 |
+
AgML supports both the TensorFlow and PyTorch libraries as backends, and provides functionality to export your loaders to native TensorFlow and PyTorch
|
| 91 |
+
formats when you want to use them in a training pipeline. This includes both exporting the `AgMLDataLoader` to a `tf.data.Dataset` or `torch.utils.data.DataLoader`,
|
| 92 |
+
but also internally converting data within the `AgMLDataLoader` itself, enabling access to its core functionality.
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
```python
|
| 96 |
+
# Export the loader as a `tf.data.Dataset`:
|
| 97 |
+
train_ds = loader.train_data.export_tensorflow()
|
| 98 |
+
|
| 99 |
+
# Convert to PyTorch tensors without exporting.
|
| 100 |
+
train_ds = loader.train_data
|
| 101 |
+
train_ds.as_torch_dataset()
|
| 102 |
+
```
|
| 103 |
+
|
| 104 |
+
You're now ready to use AgML for training your own models! Luckily, AgML comes with a training module that enables quick-start training of standard deep learning models on agricultural datasets. Training a grape detection model is as simple as the following code:
|
| 105 |
+
|
| 106 |
+
```python
|
| 107 |
+
import agml
|
| 108 |
+
import agml.models
|
| 109 |
+
|
| 110 |
+
import albumentations as A
|
| 111 |
+
|
| 112 |
+
loader = agml.data.AgMLDataLoader('grape_detection_californiaday')
|
| 113 |
+
loader.split(train = 0.8, val = 0.1, test = 0.1)
|
| 114 |
+
processor = agml.models.preprocessing.EfficientDetPreprocessor(
|
| 115 |
+
image_size = 512, augmentation = [A.HorizontalFlip(p=0.5)]
|
| 116 |
+
)
|
| 117 |
+
loader.transform(processor)
|
| 118 |
+
|
| 119 |
+
model = agml.models.DetectionModel(num_classes=loader.num_classes)
|
| 120 |
+
|
| 121 |
+
model.run_training(loader)
|
| 122 |
+
```
|
| 123 |
+
|
| 124 |
+
## Public Dataset Listing
|
| 125 |
+
|
| 126 |
+
AgML contains a wide variety of public datasets from various locations across the world:
|
| 127 |
+
|
| 128 |
+

|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
The following is a comprehensive list of all datasets available in AgML. For more information,
|
| 132 |
+
you can use `agml.data.public_data_sources(...)` with various filters to filter datasets according
|
| 133 |
+
to your desired specification.
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
| Dataset | Task | Number of Images |
|
| 137 |
+
| :--- | ---: | ---: |
|
| 138 |
+
[bean_disease_uganda](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/bean_disease_uganda.md) | Image Classification | 1295 |
|
| 139 |
+
[carrot_weeds_germany](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/carrot_weeds_germany.md) | Semantic Segmentation | 60 |
|
| 140 |
+
[plant_seedlings_aarhus](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/plant_seedlings_aarhus.md) | Image Classification | 5539 |
|
| 141 |
+
[soybean_weed_uav_brazil](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/soybean_weed_uav_brazil.md) | Image Classification | 15336 |
|
| 142 |
+
[sugarcane_damage_usa](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/sugarcane_damage_usa.md) | Image Classification | 153 |
|
| 143 |
+
[crop_weeds_greece](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/crop_weeds_greece.md) | Image Classification | 508 |
|
| 144 |
+
[sugarbeet_weed_segmentation](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/sugarbeet_weed_segmentation.md) | Semantic Segmentation | 1931 |
|
| 145 |
+
[rangeland_weeds_australia](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/rangeland_weeds_australia.md) | Image Classification | 17509 |
|
| 146 |
+
[fruit_detection_worldwide](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/fruit_detection_worldwide.md) | Object Detection | 565 |
|
| 147 |
+
[leaf_counting_denmark](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/leaf_counting_denmark.md) | Image Classification | 9372 |
|
| 148 |
+
[apple_detection_usa](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/apple_detection_usa.md) | Object Detection | 2290 |
|
| 149 |
+
[mango_detection_australia](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/mango_detection_australia.md) | Object Detection | 1730 |
|
| 150 |
+
[apple_flower_segmentation](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/apple_flower_segmentation.md) | Semantic Segmentation | 148 |
|
| 151 |
+
[apple_segmentation_minnesota](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/apple_segmentation_minnesota.md) | Semantic Segmentation | 670 |
|
| 152 |
+
[rice_seedling_segmentation](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/rice_seedling_segmentation.md) | Semantic Segmentation | 224 |
|
| 153 |
+
[plant_village_classification](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/plant_village_classification.md) | Image Classification | 55448 |
|
| 154 |
+
[autonomous_greenhouse_regression](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/autonomous_greenhouse_regression.md) | Image Regression | 389 |
|
| 155 |
+
[grape_detection_syntheticday](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/grape_detection_syntheticday.md) | Object Detection | 448 |
|
| 156 |
+
[grape_detection_californiaday](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/grape_detection_californiaday.md) | Object Detection | 126 |
|
| 157 |
+
[grape_detection_californianight](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/grape_detection_californianight.md) | Object Detection | 150 |
|
| 158 |
+
[guava_disease_pakistan](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/guava_disease_pakistan.md) | Image Classification | 306 |
|
| 159 |
+
[apple_detection_spain](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/apple_detection_spain.md) | Object Detection | 967 |
|
| 160 |
+
[apple_detection_drone_brazil](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/apple_detection_drone_brazil.md) | Object Detection | 689 |
|
| 161 |
+
[plant_doc_classification](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/plant_doc_classification.md) | Image Classification | 2598 |
|
| 162 |
+
[plant_doc_detection](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/plant_doc_detection.md) | Object Detection | 2598 |
|
| 163 |
+
[wheat_head_counting](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/wheat_head_counting.md) | Object Detection | 6512 |
|
| 164 |
+
[peachpear_flower_segmentation](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/peachpear_flower_segmentation.md) | Semantic Segmentation | 42 |
|
| 165 |
+
[red_grapes_and_leaves_segmentation](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/red_grapes_and_leaves_segmentation.md) | Semantic Segmentation | 258 |
|
| 166 |
+
[white_grapes_and_leaves_segmentation](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/white_grapes_and_leaves_segmentation.md) | Semantic Segmentation | 273 |
|
| 167 |
+
[ghai_romaine_detection](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/ghai_romaine_detection.md) | Object Detection | 500 |
|
| 168 |
+
[ghai_green_cabbage_detection](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/ghai_green_cabbage_detection.md) | Object Detection | 500 |
|
| 169 |
+
[ghai_iceberg_lettuce_detection](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/ghai_iceberg_lettuce_detection.md) | Object Detection | 500 |
|
| 170 |
+
[riseholme_strawberry_classification_2021](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/riseholme_strawberry_classification_2021.md) | Image Classification | 3520 |
|
| 171 |
+
[ghai_broccoli_detection](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/ghai_broccoli_detection.md) | Object Detection | 500 |
|
| 172 |
+
[bean_synthetic_earlygrowth_aerial](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/bean_synthetic_earlygrowth_aerial.md) | Semantic Segmentation | 2500 |
|
| 173 |
+
[ghai_strawberry_fruit_detection](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/ghai_strawberry_fruit_detection.md) | Object Detection | 500 |
|
| 174 |
+
[vegann_multicrop_presence_segmentation](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/vegann_multicrop_presence_segmentation.md) | Semantic Segmentation | 3775 |
|
| 175 |
+
[corn_maize_leaf_disease](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/corn_maize_leaf_disease.md) | Image Classification | 4188 |
|
| 176 |
+
[tomato_leaf_disease](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/tomato_leaf_disease.md) | Image Classification | 11000 |
|
| 177 |
+
[vine_virus_photo_dataset](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/vine_virus_photo_dataset.md) | Image Classification | 3866 |
|
| 178 |
+
[tomato_ripeness_detection](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/tomato_ripeness_detection.md) | Object Detection | 804 |
|
| 179 |
+
[embrapa_wgisd_grape_detection](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/embrapa_wgisd_grape_detection.md) | Object Detection | 239 |
|
| 180 |
+
[growliflower_cauliflower_segmentation](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/growliflower_cauliflower_segmentation.md) | Semantic Segmentation | 1542 |
|
| 181 |
+
[strawberry_detection_2023](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/strawberry_detection_2023.md) | Object Detection | 204 |
|
| 182 |
+
[strawberry_detection_2022](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/strawberry_detection_2022.md) | Object Detection | 175 |
|
| 183 |
+
[almond_harvest_2021](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/almond_harvest_2021.md) | Object Detection | 50 |
|
| 184 |
+
[almond_bloom_2023](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/almond_bloom_2023.md) | Object Detection | 100 |
|
| 185 |
+
[gemini_flower_detection_2022](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/gemini_flower_detection_2022.md) | Object Detection | 134 |
|
| 186 |
+
[gemini_leaf_detection_2022](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/gemini_leaf_detection_2022.md) | Object Detection | 25 |
|
| 187 |
+
[gemini_pod_detection_2022](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/gemini_pod_detection_2022.md) | Object Detection | 98 |
|
| 188 |
+
[gemini_plant_detection_2022](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/gemini_plant_detection_2022.md) | Object Detection | 402 |
|
| 189 |
+
[paddy_disease_classification](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/paddy_disease_classification.md) | Image Classification | 10407 |
|
| 190 |
+
[onion_leaf_classification](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/onion_leaf_classification.md) | Image Classification | 4502 |
|
| 191 |
+
[chilli_leaf_classification](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/chilli_leaf_classification.md) | Image Classification | 10974 |
|
| 192 |
+
[orange_leaf_disease_classification](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/orange_leaf_disease_classification.md) | Image Classification | 5813 |
|
| 193 |
+
[papaya_leaf_disease_classification](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/papaya_leaf_disease_classification.md) | Image Classification | 2159 |
|
| 194 |
+
[blackgram_plant_leaf_disease_classification](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/blackgram_plant_leaf_disease_classification.md) | Image Classification | 1007 |
|
| 195 |
+
[arabica_coffee_leaf_disease_classification](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/arabica_coffee_leaf_disease_classification.md) | Image Classification | 58549 |
|
| 196 |
+
[banana_leaf_disease_classification](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/banana_leaf_disease_classification.md) | Image Classification | 1288 |
|
| 197 |
+
[coconut_tree_disease_classification](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/coconut_tree_disease_classification.md) | Image Classification | 5798 |
|
| 198 |
+
[rice_leaf_disease_classification](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/rice_leaf_disease_classification.md) | Image Classification | 3829 |
|
| 199 |
+
[tea_leaf_disease_classification](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/tea_leaf_disease_classification.md) | Image Classification | 5867 |
|
| 200 |
+
[betel_leaf_disease_classification](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/betel_leaf_disease_classification.md) | Image Classification | 3589 |
|
| 201 |
+
[java_plum_leaf_disease_classification](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/java_plum_leaf_disease_classification.md) | Image Classification | 2400 |
|
| 202 |
+
[sunflower_disease_classification](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/sunflower_disease_classification.md) | Image Classification | 2358 |
|
| 203 |
+
[cucumber_disease_classification](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/cucumber_disease_classification.md) | Image Classification | 7689 |
|
| 204 |
+
[iNatAg](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/iNatAg.md) | Image Classification | 4720903 |
|
| 205 |
+
[iNatAg-mini](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/iNatAg-mini.md) | Image Classification | 560844 |
|
| 206 |
+
[soybean_insect_classification](https://github.com/Project-AgML/AgML/blob/main/docs/datasets/soybean_insect_classification.md) | Image Classification | 6410 |
|
| 207 |
+
|
| 208 |
+
## iNatAg and iNatAg-mini
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
AgML provides an API with direct access to iNatAg (and iNatAg-mini), one of the world's largest collections of agricultural images dedicated for the task of image classification. Collectively, this dataset contains over 4 million images along with detailed species classificaations and enables access to a variety of large-scale agricultural machine learning tasks. You can instantiate the iNatAg (or iNatAg-mini, a smaller variant of iNatAg for smaller-scale applications) dataset as follows:
|
| 212 |
+
|
| 213 |
+
```python
|
| 214 |
+
# To select a collection of scientific family names.
|
| 215 |
+
loader = agml.data.AgMLDataLoader.from_parent("iNatAg", filters={"family_name": ["...", "..."]})
|
| 216 |
+
|
| 217 |
+
# To select common names.
|
| 218 |
+
loader = agml.data.AgMLDataLoader.from_parent("iNatAg", filters={"common_name": "..."})
|
| 219 |
+
```
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
## Usage Information
|
| 223 |
+
|
| 224 |
+
### Using Public Agricultural Data
|
| 225 |
+
|
| 226 |
+
AgML aims to provide easy access to a range of existing public agricultural datasets The core of AgML's public data pipeline is
|
| 227 |
+
[`AgMLDataLoader`](/agml/data/loader.py). You can use the `AgMLDataLoader` or `agml.data.download_public_dataset()` to download
|
| 228 |
+
the dataset locally from which point it will be automatically loaded from the disk on future runs.
|
| 229 |
+
From this point, the data within the loader can be split into train/val/test sets, batched, have augmentations and transforms
|
| 230 |
+
applied, and be converted into a training-ready dataset (including batching, tensor conversion, and image formatting).
|
| 231 |
+
|
| 232 |
+
To see the various ways in which you can use AgML datasets in your training pipelines, check out
|
| 233 |
+
the [example notebook](/examples/AgML-Data.ipynb).
|
| 234 |
+
|
| 235 |
+
## Annotation Formats
|
| 236 |
+
|
| 237 |
+
A core aim of AgML is to provide datasets in a standardized format, enabling the synthesizing of multiple datasets
|
| 238 |
+
into a single training pipeline. To this end, we provide annotations in the following formats:
|
| 239 |
+
|
| 240 |
+
- **Image Classification**: Image-To-Label-Number
|
| 241 |
+
- **Object Detection**: [COCO JSON](https://cocodataset.org/#format-data)
|
| 242 |
+
- **Semantic Segmentation**: Dense Pixel-Wise
|
| 243 |
+
|
| 244 |
+
## Contributions
|
| 245 |
+
|
| 246 |
+
We welcome contributions! If you would like to contribute a new feature, fix an issue that you've noticed, or even just mention
|
| 247 |
+
a bug or feature that you would like to see implemented, please don't hesitate to use the *Issues* tab to bring it to our attention.
|
| 248 |
+
|
| 249 |
+
See the [contributing guidelines](/CONTRIBUTING.md) for more information.
|
| 250 |
+
|
| 251 |
+
## Funding
|
| 252 |
+
This project is partly funded by the [National AI Institute for Food Systems](https://aifs.ucdavis.edu).
|
AgML/source/__init__.py
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""
|
| 3 |
+
AgML Project Package Initialization File
|
| 4 |
+
"""
|
AgML/source/agml/__init__.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 UC Davis Plant AI and Biophysics Lab
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
__version__ = "0.7.4"
|
| 16 |
+
__all__ = ["data", "synthetic", "backend", "viz", "io"]
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
# If AgML is being imported for the first time, then we need to setup
|
| 20 |
+
# the module, namely prepping the config file.
|
| 21 |
+
def _setup():
|
| 22 |
+
import json as _json
|
| 23 |
+
import os as _os
|
| 24 |
+
|
| 25 |
+
if not _os.path.exists(_os.path.expanduser("~/.agml")):
|
| 26 |
+
_os.makedirs(_os.path.expanduser("~/.agml"))
|
| 27 |
+
with open(_os.path.join(_os.path.expanduser("~/.agml/config.json")), "w") as f:
|
| 28 |
+
_json.dump(
|
| 29 |
+
{
|
| 30 |
+
"data_path": _os.path.expanduser("~/.agml/datasets"),
|
| 31 |
+
"viz_backend": "matplotlib",
|
| 32 |
+
},
|
| 33 |
+
f,
|
| 34 |
+
)
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
_setup()
|
| 38 |
+
del _setup # noqa
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
# There are no top-level imported functions or classes, only the modules.
|
| 42 |
+
from . import backend, data, io, synthetic, viz
|
AgML/source/agml/_assets/detector_benchmarks.json
ADDED
|
@@ -0,0 +1,1314 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"apple_detection_drone_brazil+yolo11l": {
|
| 3 |
+
"metrics/precision(B)": 0.8104349835380228,
|
| 4 |
+
"metrics/recall(B)": 0.7988342667927443,
|
| 5 |
+
"metrics/mAP50(B)": 0.8601733668427034,
|
| 6 |
+
"metrics/mAP50-95(B)": 0.5072494132458618,
|
| 7 |
+
"fitness": 0.542541808605546,
|
| 8 |
+
"class_map": {
|
| 9 |
+
"classes": {
|
| 10 |
+
"0": "apple"
|
| 11 |
+
},
|
| 12 |
+
"maps": [
|
| 13 |
+
0.5072494132458618
|
| 14 |
+
]
|
| 15 |
+
}
|
| 16 |
+
},
|
| 17 |
+
"apple_detection_drone_brazil+yolo11m": {
|
| 18 |
+
"metrics/precision(B)": 0.8608394830617053,
|
| 19 |
+
"metrics/recall(B)": 0.7991967871485943,
|
| 20 |
+
"metrics/mAP50(B)": 0.8992294395315695,
|
| 21 |
+
"metrics/mAP50-95(B)": 0.5134246428119603,
|
| 22 |
+
"fitness": 0.5520051224839212,
|
| 23 |
+
"class_map": {
|
| 24 |
+
"classes": {
|
| 25 |
+
"0": "apple"
|
| 26 |
+
},
|
| 27 |
+
"maps": [
|
| 28 |
+
0.5134246428119603
|
| 29 |
+
]
|
| 30 |
+
}
|
| 31 |
+
},
|
| 32 |
+
"apple_detection_drone_brazil+yolo11n": {
|
| 33 |
+
"metrics/precision(B)": 0.8507723684861725,
|
| 34 |
+
"metrics/recall(B)": 0.8225628237831374,
|
| 35 |
+
"metrics/mAP50(B)": 0.8956789461187679,
|
| 36 |
+
"metrics/mAP50-95(B)": 0.5022398615976896,
|
| 37 |
+
"fitness": 0.5415837700497974,
|
| 38 |
+
"class_map": {
|
| 39 |
+
"classes": {
|
| 40 |
+
"0": "apple"
|
| 41 |
+
},
|
| 42 |
+
"maps": [
|
| 43 |
+
0.5022398615976896
|
| 44 |
+
]
|
| 45 |
+
}
|
| 46 |
+
},
|
| 47 |
+
"apple_detection_drone_brazil+yolo11s": {
|
| 48 |
+
"metrics/precision(B)": 0.7951189701449942,
|
| 49 |
+
"metrics/recall(B)": 0.8106776508309076,
|
| 50 |
+
"metrics/mAP50(B)": 0.8609606179092347,
|
| 51 |
+
"metrics/mAP50-95(B)": 0.4866340253378222,
|
| 52 |
+
"fitness": 0.5240666845949634,
|
| 53 |
+
"class_map": {
|
| 54 |
+
"classes": {
|
| 55 |
+
"0": "apple"
|
| 56 |
+
},
|
| 57 |
+
"maps": [
|
| 58 |
+
0.4866340253378222
|
| 59 |
+
]
|
| 60 |
+
}
|
| 61 |
+
},
|
| 62 |
+
"apple_detection_drone_brazil+yolo11x": {
|
| 63 |
+
"metrics/precision(B)": 0.8069007869601802,
|
| 64 |
+
"metrics/recall(B)": 0.8775295985640813,
|
| 65 |
+
"metrics/mAP50(B)": 0.910928163353364,
|
| 66 |
+
"metrics/mAP50-95(B)": 0.5166210943431347,
|
| 67 |
+
"fitness": 0.5560518012441577,
|
| 68 |
+
"class_map": {
|
| 69 |
+
"classes": {
|
| 70 |
+
"0": "apple"
|
| 71 |
+
},
|
| 72 |
+
"maps": [
|
| 73 |
+
0.5166210943431347
|
| 74 |
+
]
|
| 75 |
+
}
|
| 76 |
+
},
|
| 77 |
+
"apple_detection_spain+yolo11l": {
|
| 78 |
+
"metrics/precision(B)": 0.895859485025347,
|
| 79 |
+
"metrics/recall(B)": 0.8555849489543671,
|
| 80 |
+
"metrics/mAP50(B)": 0.9371364896175589,
|
| 81 |
+
"metrics/mAP50-95(B)": 0.579262748646173,
|
| 82 |
+
"fitness": 0.6150501227433116,
|
| 83 |
+
"class_map": {
|
| 84 |
+
"classes": {
|
| 85 |
+
"0": "apple"
|
| 86 |
+
},
|
| 87 |
+
"maps": [
|
| 88 |
+
0.579262748646173
|
| 89 |
+
]
|
| 90 |
+
}
|
| 91 |
+
},
|
| 92 |
+
"apple_detection_spain+yolo11m": {
|
| 93 |
+
"metrics/precision(B)": 0.886427547531193,
|
| 94 |
+
"metrics/recall(B)": 0.8813830876330876,
|
| 95 |
+
"metrics/mAP50(B)": 0.9436276131565261,
|
| 96 |
+
"metrics/mAP50-95(B)": 0.6027847361615526,
|
| 97 |
+
"fitness": 0.6368690238610499,
|
| 98 |
+
"class_map": {
|
| 99 |
+
"classes": {
|
| 100 |
+
"0": "apple"
|
| 101 |
+
},
|
| 102 |
+
"maps": [
|
| 103 |
+
0.6027847361615526
|
| 104 |
+
]
|
| 105 |
+
}
|
| 106 |
+
},
|
| 107 |
+
"apple_detection_spain+yolo11n": {
|
| 108 |
+
"metrics/precision(B)": 0.8772810873702708,
|
| 109 |
+
"metrics/recall(B)": 0.8794449125384377,
|
| 110 |
+
"metrics/mAP50(B)": 0.9422717351592312,
|
| 111 |
+
"metrics/mAP50-95(B)": 0.5968358978532009,
|
| 112 |
+
"fitness": 0.631379481583804,
|
| 113 |
+
"class_map": {
|
| 114 |
+
"classes": {
|
| 115 |
+
"0": "apple"
|
| 116 |
+
},
|
| 117 |
+
"maps": [
|
| 118 |
+
0.5968358978532009
|
| 119 |
+
]
|
| 120 |
+
}
|
| 121 |
+
},
|
| 122 |
+
"apple_detection_spain+yolo11s": {
|
| 123 |
+
"metrics/precision(B)": 0.9028280294123243,
|
| 124 |
+
"metrics/recall(B)": 0.8805440582444066,
|
| 125 |
+
"metrics/mAP50(B)": 0.9460649029636068,
|
| 126 |
+
"metrics/mAP50-95(B)": 0.5950217456217229,
|
| 127 |
+
"fitness": 0.6301260613559113,
|
| 128 |
+
"class_map": {
|
| 129 |
+
"classes": {
|
| 130 |
+
"0": "apple"
|
| 131 |
+
},
|
| 132 |
+
"maps": [
|
| 133 |
+
0.5950217456217229
|
| 134 |
+
]
|
| 135 |
+
}
|
| 136 |
+
},
|
| 137 |
+
"apple_detection_spain+yolo11x": {
|
| 138 |
+
"metrics/precision(B)": 0.8854823467235927,
|
| 139 |
+
"metrics/recall(B)": 0.8588322246858833,
|
| 140 |
+
"metrics/mAP50(B)": 0.9251687653229144,
|
| 141 |
+
"metrics/mAP50-95(B)": 0.5872286398209259,
|
| 142 |
+
"fitness": 0.6210226523711248,
|
| 143 |
+
"class_map": {
|
| 144 |
+
"classes": {
|
| 145 |
+
"0": "apple"
|
| 146 |
+
},
|
| 147 |
+
"maps": [
|
| 148 |
+
0.5872286398209259
|
| 149 |
+
]
|
| 150 |
+
}
|
| 151 |
+
},
|
| 152 |
+
"apple_detection_usa+yolo11n": {
|
| 153 |
+
"metrics/precision(B)": 0.9270838048818623,
|
| 154 |
+
"metrics/recall(B)": 0.9338242039905568,
|
| 155 |
+
"metrics/mAP50(B)": 0.9748424668962935,
|
| 156 |
+
"metrics/mAP50-95(B)": 0.7811112753679461,
|
| 157 |
+
"fitness": 0.8004843945207809,
|
| 158 |
+
"class_map": {
|
| 159 |
+
"classes": {
|
| 160 |
+
"0": "apple"
|
| 161 |
+
},
|
| 162 |
+
"maps": [
|
| 163 |
+
0.7811112753679461
|
| 164 |
+
]
|
| 165 |
+
}
|
| 166 |
+
},
|
| 167 |
+
"apple_detection_usa+yolo11s": {
|
| 168 |
+
"metrics/precision(B)": 0.9470802220658486,
|
| 169 |
+
"metrics/recall(B)": 0.9347684279191129,
|
| 170 |
+
"metrics/mAP50(B)": 0.9798209001351015,
|
| 171 |
+
"metrics/mAP50-95(B)": 0.8303136510701614,
|
| 172 |
+
"fitness": 0.8452643759766554,
|
| 173 |
+
"class_map": {
|
| 174 |
+
"classes": {
|
| 175 |
+
"0": "apple"
|
| 176 |
+
},
|
| 177 |
+
"maps": [
|
| 178 |
+
0.8303136510701614
|
| 179 |
+
]
|
| 180 |
+
}
|
| 181 |
+
},
|
| 182 |
+
"fruit_detection_worldwide+yolo11l": {
|
| 183 |
+
"metrics/precision(B)": 0.7840810800621841,
|
| 184 |
+
"metrics/recall(B)": 0.8191062145159602,
|
| 185 |
+
"metrics/mAP50(B)": 0.8641094337838477,
|
| 186 |
+
"metrics/mAP50-95(B)": 0.5416057642125035,
|
| 187 |
+
"fitness": 0.573856131169638,
|
| 188 |
+
"class_map": {
|
| 189 |
+
"classes": {
|
| 190 |
+
"0": "avocado",
|
| 191 |
+
"1": "rockmelon",
|
| 192 |
+
"2": "apple",
|
| 193 |
+
"3": "orange",
|
| 194 |
+
"4": "strawberry",
|
| 195 |
+
"5": "mango",
|
| 196 |
+
"6": "capsicum"
|
| 197 |
+
},
|
| 198 |
+
"maps": [
|
| 199 |
+
0.6937530110895355,
|
| 200 |
+
0.6599475916860917,
|
| 201 |
+
0.3072447491193536,
|
| 202 |
+
0.44985732917887516,
|
| 203 |
+
0.6684763555021369,
|
| 204 |
+
0.621381101506044,
|
| 205 |
+
0.3905802114054871
|
| 206 |
+
]
|
| 207 |
+
}
|
| 208 |
+
},
|
| 209 |
+
"fruit_detection_worldwide+yolo11m": {
|
| 210 |
+
"metrics/precision(B)": 0.7699396847252584,
|
| 211 |
+
"metrics/recall(B)": 0.7049490920251014,
|
| 212 |
+
"metrics/mAP50(B)": 0.7917153211939195,
|
| 213 |
+
"metrics/mAP50-95(B)": 0.4507520456030815,
|
| 214 |
+
"fitness": 0.48484837316216534,
|
| 215 |
+
"class_map": {
|
| 216 |
+
"classes": {
|
| 217 |
+
"0": "avocado",
|
| 218 |
+
"1": "rockmelon",
|
| 219 |
+
"2": "apple",
|
| 220 |
+
"3": "orange",
|
| 221 |
+
"4": "strawberry",
|
| 222 |
+
"5": "mango",
|
| 223 |
+
"6": "capsicum"
|
| 224 |
+
},
|
| 225 |
+
"maps": [
|
| 226 |
+
0.5338804695616493,
|
| 227 |
+
0.4643126528314029,
|
| 228 |
+
0.5596974845150083,
|
| 229 |
+
0.3994619555034442,
|
| 230 |
+
0.40974001920122893,
|
| 231 |
+
0.43729794524602844,
|
| 232 |
+
0.35087379236280913
|
| 233 |
+
]
|
| 234 |
+
}
|
| 235 |
+
},
|
| 236 |
+
"fruit_detection_worldwide+yolo11n": {
|
| 237 |
+
"metrics/precision(B)": 0.9226956515783662,
|
| 238 |
+
"metrics/recall(B)": 0.8428619967059985,
|
| 239 |
+
"metrics/mAP50(B)": 0.9282310037207211,
|
| 240 |
+
"metrics/mAP50-95(B)": 0.5653289765966472,
|
| 241 |
+
"fitness": 0.6016191793090545,
|
| 242 |
+
"class_map": {
|
| 243 |
+
"classes": {
|
| 244 |
+
"0": "avocado",
|
| 245 |
+
"1": "rockmelon",
|
| 246 |
+
"2": "apple",
|
| 247 |
+
"3": "orange",
|
| 248 |
+
"4": "strawberry",
|
| 249 |
+
"5": "mango",
|
| 250 |
+
"6": "capsicum"
|
| 251 |
+
},
|
| 252 |
+
"maps": [
|
| 253 |
+
0.5077999713770625,
|
| 254 |
+
0.7048337662337663,
|
| 255 |
+
0.6961418200702028,
|
| 256 |
+
0.5176978995737195,
|
| 257 |
+
0.5109032371347128,
|
| 258 |
+
0.5440584978198245,
|
| 259 |
+
0.47586764396724074
|
| 260 |
+
]
|
| 261 |
+
}
|
| 262 |
+
},
|
| 263 |
+
"fruit_detection_worldwide+yolo11s": {
|
| 264 |
+
"metrics/precision(B)": 0.8749349608578184,
|
| 265 |
+
"metrics/recall(B)": 0.8491066178862222,
|
| 266 |
+
"metrics/mAP50(B)": 0.9011810080939855,
|
| 267 |
+
"metrics/mAP50-95(B)": 0.5785717028098898,
|
| 268 |
+
"fitness": 0.6108326333382994,
|
| 269 |
+
"class_map": {
|
| 270 |
+
"classes": {
|
| 271 |
+
"0": "avocado",
|
| 272 |
+
"1": "rockmelon",
|
| 273 |
+
"2": "apple",
|
| 274 |
+
"3": "orange",
|
| 275 |
+
"4": "strawberry",
|
| 276 |
+
"5": "mango",
|
| 277 |
+
"6": "capsicum"
|
| 278 |
+
},
|
| 279 |
+
"maps": [
|
| 280 |
+
0.7381820126096492,
|
| 281 |
+
0.6398140426525528,
|
| 282 |
+
0.5399714799890161,
|
| 283 |
+
0.6917575199485568,
|
| 284 |
+
0.43697906240342893,
|
| 285 |
+
0.5203213108500946,
|
| 286 |
+
0.4829764912159303
|
| 287 |
+
]
|
| 288 |
+
}
|
| 289 |
+
},
|
| 290 |
+
"fruit_detection_worldwide+yolo11x": {
|
| 291 |
+
"metrics/precision(B)": 0.78655473099151,
|
| 292 |
+
"metrics/recall(B)": 0.7043307364199446,
|
| 293 |
+
"metrics/mAP50(B)": 0.7872813915634435,
|
| 294 |
+
"metrics/mAP50-95(B)": 0.5012090094387892,
|
| 295 |
+
"fitness": 0.5298162476512547,
|
| 296 |
+
"class_map": {
|
| 297 |
+
"classes": {
|
| 298 |
+
"0": "avocado",
|
| 299 |
+
"1": "rockmelon",
|
| 300 |
+
"2": "apple",
|
| 301 |
+
"3": "orange",
|
| 302 |
+
"4": "strawberry",
|
| 303 |
+
"5": "mango",
|
| 304 |
+
"6": "capsicum"
|
| 305 |
+
},
|
| 306 |
+
"maps": [
|
| 307 |
+
0.6725356118333934,
|
| 308 |
+
0.5808266095238095,
|
| 309 |
+
0.2792468486772157,
|
| 310 |
+
0.4817921302985327,
|
| 311 |
+
0.535893342081749,
|
| 312 |
+
0.4863169982590526,
|
| 313 |
+
0.47185152539777037
|
| 314 |
+
]
|
| 315 |
+
}
|
| 316 |
+
},
|
| 317 |
+
"ghai_broccoli_detection+yolo11l": {
|
| 318 |
+
"metrics/precision(B)": 0.7409921665653947,
|
| 319 |
+
"metrics/recall(B)": 0.7277157702805868,
|
| 320 |
+
"metrics/mAP50(B)": 0.7428713423394218,
|
| 321 |
+
"metrics/mAP50-95(B)": 0.5635296062946676,
|
| 322 |
+
"fitness": 0.5814637798991431,
|
| 323 |
+
"class_map": {
|
| 324 |
+
"classes": {
|
| 325 |
+
"0": "canopy",
|
| 326 |
+
"1": "crown"
|
| 327 |
+
},
|
| 328 |
+
"maps": [
|
| 329 |
+
0.3223404913339708,
|
| 330 |
+
0.8047187212553645
|
| 331 |
+
]
|
| 332 |
+
}
|
| 333 |
+
},
|
| 334 |
+
"ghai_broccoli_detection+yolo11m": {
|
| 335 |
+
"metrics/precision(B)": 0.7576714485757008,
|
| 336 |
+
"metrics/recall(B)": 0.7369239726716079,
|
| 337 |
+
"metrics/mAP50(B)": 0.7584831482913197,
|
| 338 |
+
"metrics/mAP50-95(B)": 0.5599340879416073,
|
| 339 |
+
"fitness": 0.5797889939765786,
|
| 340 |
+
"class_map": {
|
| 341 |
+
"classes": {
|
| 342 |
+
"0": "canopy",
|
| 343 |
+
"1": "crown"
|
| 344 |
+
},
|
| 345 |
+
"maps": [
|
| 346 |
+
0.3324174053329621,
|
| 347 |
+
0.7874507705502521
|
| 348 |
+
]
|
| 349 |
+
}
|
| 350 |
+
},
|
| 351 |
+
"ghai_broccoli_detection+yolo11n": {
|
| 352 |
+
"metrics/precision(B)": 0.7377016001185307,
|
| 353 |
+
"metrics/recall(B)": 0.6524970264004617,
|
| 354 |
+
"metrics/mAP50(B)": 0.6838369761182593,
|
| 355 |
+
"metrics/mAP50-95(B)": 0.469799986880626,
|
| 356 |
+
"fitness": 0.4912036858043894,
|
| 357 |
+
"class_map": {
|
| 358 |
+
"classes": {
|
| 359 |
+
"0": "canopy",
|
| 360 |
+
"1": "crown"
|
| 361 |
+
},
|
| 362 |
+
"maps": [
|
| 363 |
+
0.23939637932948324,
|
| 364 |
+
0.7002035944317686
|
| 365 |
+
]
|
| 366 |
+
}
|
| 367 |
+
},
|
| 368 |
+
"ghai_broccoli_detection+yolo11s": {
|
| 369 |
+
"metrics/precision(B)": 0.7329678146138658,
|
| 370 |
+
"metrics/recall(B)": 0.724735813460258,
|
| 371 |
+
"metrics/mAP50(B)": 0.7388249529707553,
|
| 372 |
+
"metrics/mAP50-95(B)": 0.5386676297103012,
|
| 373 |
+
"fitness": 0.5586833620363467,
|
| 374 |
+
"class_map": {
|
| 375 |
+
"classes": {
|
| 376 |
+
"0": "canopy",
|
| 377 |
+
"1": "crown"
|
| 378 |
+
},
|
| 379 |
+
"maps": [
|
| 380 |
+
0.3160978305795931,
|
| 381 |
+
0.7612374288410095
|
| 382 |
+
]
|
| 383 |
+
}
|
| 384 |
+
},
|
| 385 |
+
"ghai_broccoli_detection+yolo11x": {
|
| 386 |
+
"metrics/precision(B)": 0.7672524763778574,
|
| 387 |
+
"metrics/recall(B)": 0.7342813692020289,
|
| 388 |
+
"metrics/mAP50(B)": 0.7708247492458355,
|
| 389 |
+
"metrics/mAP50-95(B)": 0.5935923090810958,
|
| 390 |
+
"fitness": 0.6113155530975698,
|
| 391 |
+
"class_map": {
|
| 392 |
+
"classes": {
|
| 393 |
+
"0": "canopy",
|
| 394 |
+
"1": "crown"
|
| 395 |
+
},
|
| 396 |
+
"maps": [
|
| 397 |
+
0.38456190936112233,
|
| 398 |
+
0.8026227088010692
|
| 399 |
+
]
|
| 400 |
+
}
|
| 401 |
+
},
|
| 402 |
+
"ghai_green_cabbage_detection+yolo11l": {
|
| 403 |
+
"metrics/precision(B)": 0.8613838860312255,
|
| 404 |
+
"metrics/recall(B)": 0.8429330535008768,
|
| 405 |
+
"metrics/mAP50(B)": 0.9116406496856747,
|
| 406 |
+
"metrics/mAP50-95(B)": 0.7118640967709261,
|
| 407 |
+
"fitness": 0.731841752062401,
|
| 408 |
+
"class_map": {
|
| 409 |
+
"classes": {
|
| 410 |
+
"0": "green_cabbage"
|
| 411 |
+
},
|
| 412 |
+
"maps": [
|
| 413 |
+
0.7118640967709261
|
| 414 |
+
]
|
| 415 |
+
}
|
| 416 |
+
},
|
| 417 |
+
"ghai_green_cabbage_detection+yolo11m": {
|
| 418 |
+
"metrics/precision(B)": 0.8673449730257053,
|
| 419 |
+
"metrics/recall(B)": 0.8342857142857143,
|
| 420 |
+
"metrics/mAP50(B)": 0.8907064681223883,
|
| 421 |
+
"metrics/mAP50-95(B)": 0.6944137082286287,
|
| 422 |
+
"fitness": 0.7140429842180047,
|
| 423 |
+
"class_map": {
|
| 424 |
+
"classes": {
|
| 425 |
+
"0": "green_cabbage"
|
| 426 |
+
},
|
| 427 |
+
"maps": [
|
| 428 |
+
0.6944137082286287
|
| 429 |
+
]
|
| 430 |
+
}
|
| 431 |
+
},
|
| 432 |
+
"ghai_green_cabbage_detection+yolo11n": {
|
| 433 |
+
"metrics/precision(B)": 0.8355977884325566,
|
| 434 |
+
"metrics/recall(B)": 0.8151426059182874,
|
| 435 |
+
"metrics/mAP50(B)": 0.8691196766626649,
|
| 436 |
+
"metrics/mAP50-95(B)": 0.6591389190599897,
|
| 437 |
+
"fitness": 0.6801369948202572,
|
| 438 |
+
"class_map": {
|
| 439 |
+
"classes": {
|
| 440 |
+
"0": "green_cabbage"
|
| 441 |
+
},
|
| 442 |
+
"maps": [
|
| 443 |
+
0.6591389190599897
|
| 444 |
+
]
|
| 445 |
+
}
|
| 446 |
+
},
|
| 447 |
+
"ghai_green_cabbage_detection+yolo11s": {
|
| 448 |
+
"metrics/precision(B)": 0.8857430201563139,
|
| 449 |
+
"metrics/recall(B)": 0.8585525715610961,
|
| 450 |
+
"metrics/mAP50(B)": 0.9102921460534825,
|
| 451 |
+
"metrics/mAP50-95(B)": 0.7139257965173013,
|
| 452 |
+
"fitness": 0.7335624314709195,
|
| 453 |
+
"class_map": {
|
| 454 |
+
"classes": {
|
| 455 |
+
"0": "green_cabbage"
|
| 456 |
+
},
|
| 457 |
+
"maps": [
|
| 458 |
+
0.7139257965173013
|
| 459 |
+
]
|
| 460 |
+
}
|
| 461 |
+
},
|
| 462 |
+
"ghai_green_cabbage_detection+yolo11x": {
|
| 463 |
+
"metrics/precision(B)": 0.8884185216941978,
|
| 464 |
+
"metrics/recall(B)": 0.8343497989006972,
|
| 465 |
+
"metrics/mAP50(B)": 0.9109117546708069,
|
| 466 |
+
"metrics/mAP50-95(B)": 0.704366630205667,
|
| 467 |
+
"fitness": 0.725021142652181,
|
| 468 |
+
"class_map": {
|
| 469 |
+
"classes": {
|
| 470 |
+
"0": "green_cabbage"
|
| 471 |
+
},
|
| 472 |
+
"maps": [
|
| 473 |
+
0.704366630205667
|
| 474 |
+
]
|
| 475 |
+
}
|
| 476 |
+
},
|
| 477 |
+
"ghai_iceberg_lettuce_detection+yolo11l": {
|
| 478 |
+
"metrics/precision(B)": 0.8842813590120964,
|
| 479 |
+
"metrics/recall(B)": 0.78,
|
| 480 |
+
"metrics/mAP50(B)": 0.880281737114181,
|
| 481 |
+
"metrics/mAP50-95(B)": 0.5308984079738271,
|
| 482 |
+
"fitness": 0.5658367408878625,
|
| 483 |
+
"class_map": {
|
| 484 |
+
"classes": {
|
| 485 |
+
"0": "iceberg_lettuce"
|
| 486 |
+
},
|
| 487 |
+
"maps": [
|
| 488 |
+
0.5308984079738271
|
| 489 |
+
]
|
| 490 |
+
}
|
| 491 |
+
},
|
| 492 |
+
"ghai_iceberg_lettuce_detection+yolo11m": {
|
| 493 |
+
"metrics/precision(B)": 0.8565205192561391,
|
| 494 |
+
"metrics/recall(B)": 0.852,
|
| 495 |
+
"metrics/mAP50(B)": 0.8882337959487256,
|
| 496 |
+
"metrics/mAP50-95(B)": 0.5447845441322091,
|
| 497 |
+
"fitness": 0.5791294693138608,
|
| 498 |
+
"class_map": {
|
| 499 |
+
"classes": {
|
| 500 |
+
"0": "iceberg_lettuce"
|
| 501 |
+
},
|
| 502 |
+
"maps": [
|
| 503 |
+
0.5447845441322091
|
| 504 |
+
]
|
| 505 |
+
}
|
| 506 |
+
},
|
| 507 |
+
"ghai_iceberg_lettuce_detection+yolo11n": {
|
| 508 |
+
"metrics/precision(B)": 0.9075705684362595,
|
| 509 |
+
"metrics/recall(B)": 0.8520705116070535,
|
| 510 |
+
"metrics/mAP50(B)": 0.8951989397183541,
|
| 511 |
+
"metrics/mAP50-95(B)": 0.5689564386149899,
|
| 512 |
+
"fitness": 0.6015806887253263,
|
| 513 |
+
"class_map": {
|
| 514 |
+
"classes": {
|
| 515 |
+
"0": "iceberg_lettuce"
|
| 516 |
+
},
|
| 517 |
+
"maps": [
|
| 518 |
+
0.5689564386149899
|
| 519 |
+
]
|
| 520 |
+
}
|
| 521 |
+
},
|
| 522 |
+
"ghai_iceberg_lettuce_detection+yolo11s": {
|
| 523 |
+
"metrics/precision(B)": 0.8848128837651625,
|
| 524 |
+
"metrics/recall(B)": 0.7824267782426778,
|
| 525 |
+
"metrics/mAP50(B)": 0.8701965203008429,
|
| 526 |
+
"metrics/mAP50-95(B)": 0.5381306510663206,
|
| 527 |
+
"fitness": 0.5713372379897729,
|
| 528 |
+
"class_map": {
|
| 529 |
+
"classes": {
|
| 530 |
+
"0": "iceberg_lettuce"
|
| 531 |
+
},
|
| 532 |
+
"maps": [
|
| 533 |
+
0.5381306510663206
|
| 534 |
+
]
|
| 535 |
+
}
|
| 536 |
+
},
|
| 537 |
+
"ghai_iceberg_lettuce_detection+yolo11x": {
|
| 538 |
+
"metrics/precision(B)": 0.8744060262501543,
|
| 539 |
+
"metrics/recall(B)": 0.7860519492425313,
|
| 540 |
+
"metrics/mAP50(B)": 0.8649674277006355,
|
| 541 |
+
"metrics/mAP50-95(B)": 0.5270984046669671,
|
| 542 |
+
"fitness": 0.560885306970334,
|
| 543 |
+
"class_map": {
|
| 544 |
+
"classes": {
|
| 545 |
+
"0": "iceberg_lettuce"
|
| 546 |
+
},
|
| 547 |
+
"maps": [
|
| 548 |
+
0.5270984046669671
|
| 549 |
+
]
|
| 550 |
+
}
|
| 551 |
+
},
|
| 552 |
+
"ghai_romaine_detection+yolo11l": {
|
| 553 |
+
"metrics/precision(B)": 0.9368473966694478,
|
| 554 |
+
"metrics/recall(B)": 0.8546757717214724,
|
| 555 |
+
"metrics/mAP50(B)": 0.9193170125873877,
|
| 556 |
+
"metrics/mAP50-95(B)": 0.7699090606095494,
|
| 557 |
+
"fitness": 0.7848498558073334,
|
| 558 |
+
"class_map": {
|
| 559 |
+
"classes": {
|
| 560 |
+
"0": "romaine"
|
| 561 |
+
},
|
| 562 |
+
"maps": [
|
| 563 |
+
0.7699090606095494
|
| 564 |
+
]
|
| 565 |
+
}
|
| 566 |
+
},
|
| 567 |
+
"ghai_romaine_detection+yolo11m": {
|
| 568 |
+
"metrics/precision(B)": 0.9313772904604823,
|
| 569 |
+
"metrics/recall(B)": 0.8590308370044053,
|
| 570 |
+
"metrics/mAP50(B)": 0.9444871705216602,
|
| 571 |
+
"metrics/mAP50-95(B)": 0.7907666278321335,
|
| 572 |
+
"fitness": 0.8061386821010862,
|
| 573 |
+
"class_map": {
|
| 574 |
+
"classes": {
|
| 575 |
+
"0": "romaine"
|
| 576 |
+
},
|
| 577 |
+
"maps": [
|
| 578 |
+
0.7907666278321335
|
| 579 |
+
]
|
| 580 |
+
}
|
| 581 |
+
},
|
| 582 |
+
"ghai_romaine_detection+yolo11n": {
|
| 583 |
+
"metrics/precision(B)": 0.9536018902378349,
|
| 584 |
+
"metrics/recall(B)": 0.8477366255144033,
|
| 585 |
+
"metrics/mAP50(B)": 0.9274152280108815,
|
| 586 |
+
"metrics/mAP50-95(B)": 0.7745598409185308,
|
| 587 |
+
"fitness": 0.7898453796277659,
|
| 588 |
+
"class_map": {
|
| 589 |
+
"classes": {
|
| 590 |
+
"0": "romaine"
|
| 591 |
+
},
|
| 592 |
+
"maps": [
|
| 593 |
+
0.7745598409185308
|
| 594 |
+
]
|
| 595 |
+
}
|
| 596 |
+
},
|
| 597 |
+
"ghai_romaine_detection+yolo11s": {
|
| 598 |
+
"metrics/precision(B)": 0.9421641001234269,
|
| 599 |
+
"metrics/recall(B)": 0.8611664812460607,
|
| 600 |
+
"metrics/mAP50(B)": 0.9511326333399283,
|
| 601 |
+
"metrics/mAP50-95(B)": 0.7972501823711204,
|
| 602 |
+
"fitness": 0.8126384274680013,
|
| 603 |
+
"class_map": {
|
| 604 |
+
"classes": {
|
| 605 |
+
"0": "romaine"
|
| 606 |
+
},
|
| 607 |
+
"maps": [
|
| 608 |
+
0.7972501823711204
|
| 609 |
+
]
|
| 610 |
+
}
|
| 611 |
+
},
|
| 612 |
+
"ghai_romaine_detection+yolo11x": {
|
| 613 |
+
"metrics/precision(B)": 0.9223680838425339,
|
| 614 |
+
"metrics/recall(B)": 0.8123984591915938,
|
| 615 |
+
"metrics/mAP50(B)": 0.9086774326923178,
|
| 616 |
+
"metrics/mAP50-95(B)": 0.7400014802754252,
|
| 617 |
+
"fitness": 0.7568690755171145,
|
| 618 |
+
"class_map": {
|
| 619 |
+
"classes": {
|
| 620 |
+
"0": "romaine"
|
| 621 |
+
},
|
| 622 |
+
"maps": [
|
| 623 |
+
0.7400014802754252
|
| 624 |
+
]
|
| 625 |
+
}
|
| 626 |
+
},
|
| 627 |
+
"ghai_strawberry_fruit_detection+yolo11l": {
|
| 628 |
+
"metrics/precision(B)": 0.6448881162125962,
|
| 629 |
+
"metrics/recall(B)": 0.49763784192355615,
|
| 630 |
+
"metrics/mAP50(B)": 0.5360449682848161,
|
| 631 |
+
"metrics/mAP50-95(B)": 0.36858859954370954,
|
| 632 |
+
"fitness": 0.3853342364178202,
|
| 633 |
+
"class_map": {
|
| 634 |
+
"classes": {
|
| 635 |
+
"0": "Bud",
|
| 636 |
+
"1": "Calyx",
|
| 637 |
+
"2": "Detached Fruit",
|
| 638 |
+
"3": "Flower",
|
| 639 |
+
"4": "Large green",
|
| 640 |
+
"5": "Leaf",
|
| 641 |
+
"6": "Ripe fruit",
|
| 642 |
+
"7": "Small Green",
|
| 643 |
+
"8": "Stem",
|
| 644 |
+
"9": "Unripe fruit"
|
| 645 |
+
},
|
| 646 |
+
"maps": [
|
| 647 |
+
0.36858859954370954,
|
| 648 |
+
0.469766081987379,
|
| 649 |
+
0.4586561965811966,
|
| 650 |
+
0.2744212082247911,
|
| 651 |
+
0.08640693226385923,
|
| 652 |
+
0.9919636363636364,
|
| 653 |
+
0.4135172471752262,
|
| 654 |
+
0.07613553965837612,
|
| 655 |
+
0.46867301006156703,
|
| 656 |
+
0.07775754357735426
|
| 657 |
+
]
|
| 658 |
+
}
|
| 659 |
+
},
|
| 660 |
+
"ghai_strawberry_fruit_detection+yolo11m": {
|
| 661 |
+
"metrics/precision(B)": 0.5757778491011301,
|
| 662 |
+
"metrics/recall(B)": 0.4415712268148009,
|
| 663 |
+
"metrics/mAP50(B)": 0.444863565990511,
|
| 664 |
+
"metrics/mAP50-95(B)": 0.27921732332490995,
|
| 665 |
+
"fitness": 0.29578194759147003,
|
| 666 |
+
"class_map": {
|
| 667 |
+
"classes": {
|
| 668 |
+
"0": "Bud",
|
| 669 |
+
"1": "Calyx",
|
| 670 |
+
"2": "Detached Fruit",
|
| 671 |
+
"3": "Flower",
|
| 672 |
+
"4": "Large green",
|
| 673 |
+
"5": "Leaf",
|
| 674 |
+
"6": "Ripe fruit",
|
| 675 |
+
"7": "Small Green",
|
| 676 |
+
"8": "Stem",
|
| 677 |
+
"9": "Unripe fruit"
|
| 678 |
+
},
|
| 679 |
+
"maps": [
|
| 680 |
+
0.0,
|
| 681 |
+
0.5006049591619524,
|
| 682 |
+
0.23618073593073588,
|
| 683 |
+
0.31732732321969975,
|
| 684 |
+
0.04961585492434706,
|
| 685 |
+
0.9045611089249965,
|
| 686 |
+
0.2484189806795046,
|
| 687 |
+
0.06908596496122062,
|
| 688 |
+
0.4234868976489901,
|
| 689 |
+
0.042891407797652575
|
| 690 |
+
]
|
| 691 |
+
}
|
| 692 |
+
},
|
| 693 |
+
"ghai_strawberry_fruit_detection+yolo11n": {
|
| 694 |
+
"metrics/precision(B)": 0.43024502781160584,
|
| 695 |
+
"metrics/recall(B)": 0.47812476497970713,
|
| 696 |
+
"metrics/mAP50(B)": 0.43768460776658524,
|
| 697 |
+
"metrics/mAP50-95(B)": 0.26189911059565196,
|
| 698 |
+
"fitness": 0.2794776603127453,
|
| 699 |
+
"class_map": {
|
| 700 |
+
"classes": {
|
| 701 |
+
"0": "Bud",
|
| 702 |
+
"1": "Calyx",
|
| 703 |
+
"2": "Detached Fruit",
|
| 704 |
+
"3": "Flower",
|
| 705 |
+
"4": "Large green",
|
| 706 |
+
"5": "Leaf",
|
| 707 |
+
"6": "Ripe fruit",
|
| 708 |
+
"7": "Small Green",
|
| 709 |
+
"8": "Stem",
|
| 710 |
+
"9": "Unripe fruit"
|
| 711 |
+
},
|
| 712 |
+
"maps": [
|
| 713 |
+
0.26189911059565196,
|
| 714 |
+
0.28001587526598604,
|
| 715 |
+
0.4963485268084572,
|
| 716 |
+
0.11916920292153717,
|
| 717 |
+
0.03683740274673995,
|
| 718 |
+
0.9382351146161799,
|
| 719 |
+
0.043547383404538696,
|
| 720 |
+
0.040321322331614076,
|
| 721 |
+
0.36669891550313993,
|
| 722 |
+
0.03591825176267435
|
| 723 |
+
]
|
| 724 |
+
}
|
| 725 |
+
},
|
| 726 |
+
"ghai_strawberry_fruit_detection+yolo11s": {
|
| 727 |
+
"metrics/precision(B)": 0.5058797129220138,
|
| 728 |
+
"metrics/recall(B)": 0.3943899456162283,
|
| 729 |
+
"metrics/mAP50(B)": 0.39689324528219905,
|
| 730 |
+
"metrics/mAP50-95(B)": 0.2693731453786905,
|
| 731 |
+
"fitness": 0.28212515536904137,
|
| 732 |
+
"class_map": {
|
| 733 |
+
"classes": {
|
| 734 |
+
"0": "Bud",
|
| 735 |
+
"1": "Calyx",
|
| 736 |
+
"2": "Detached Fruit",
|
| 737 |
+
"3": "Flower",
|
| 738 |
+
"4": "Large green",
|
| 739 |
+
"5": "Leaf",
|
| 740 |
+
"6": "Ripe fruit",
|
| 741 |
+
"7": "Small Green",
|
| 742 |
+
"8": "Stem",
|
| 743 |
+
"9": "Unripe fruit"
|
| 744 |
+
},
|
| 745 |
+
"maps": [
|
| 746 |
+
0.0,
|
| 747 |
+
0.3861783354825693,
|
| 748 |
+
0.4743717311111112,
|
| 749 |
+
0.18124887953621094,
|
| 750 |
+
0.015798379333843936,
|
| 751 |
+
0.9814681574239714,
|
| 752 |
+
0.1457980084607174,
|
| 753 |
+
0.04372695172090872,
|
| 754 |
+
0.42937711916648774,
|
| 755 |
+
0.03576389155108432
|
| 756 |
+
]
|
| 757 |
+
}
|
| 758 |
+
},
|
| 759 |
+
"ghai_strawberry_fruit_detection+yolo11x": {
|
| 760 |
+
"metrics/precision(B)": 0.5031699374002283,
|
| 761 |
+
"metrics/recall(B)": 0.4661095882326068,
|
| 762 |
+
"metrics/mAP50(B)": 0.47375836147430367,
|
| 763 |
+
"metrics/mAP50-95(B)": 0.3375521022306996,
|
| 764 |
+
"fitness": 0.35117272815506,
|
| 765 |
+
"class_map": {
|
| 766 |
+
"classes": {
|
| 767 |
+
"0": "Bud",
|
| 768 |
+
"1": "Calyx",
|
| 769 |
+
"2": "Detached Fruit",
|
| 770 |
+
"3": "Flower",
|
| 771 |
+
"4": "Large green",
|
| 772 |
+
"5": "Leaf",
|
| 773 |
+
"6": "Ripe fruit",
|
| 774 |
+
"7": "Small Green",
|
| 775 |
+
"8": "Stem",
|
| 776 |
+
"9": "Unripe fruit"
|
| 777 |
+
},
|
| 778 |
+
"maps": [
|
| 779 |
+
0.0,
|
| 780 |
+
0.5073074896278351,
|
| 781 |
+
0.6498271724137932,
|
| 782 |
+
0.3149322149563958,
|
| 783 |
+
0.055327773855347165,
|
| 784 |
+
0.9814479041406694,
|
| 785 |
+
0.19138336651215965,
|
| 786 |
+
0.08376537101164086,
|
| 787 |
+
0.5361975168123582,
|
| 788 |
+
0.05533221297679599
|
| 789 |
+
]
|
| 790 |
+
}
|
| 791 |
+
},
|
| 792 |
+
"grape_detection_californiaday+yolo11l": {
|
| 793 |
+
"metrics/precision(B)": 0.7359297112238289,
|
| 794 |
+
"metrics/recall(B)": 0.6666666666666666,
|
| 795 |
+
"metrics/mAP50(B)": 0.7488084760197763,
|
| 796 |
+
"metrics/mAP50-95(B)": 0.4349909954379633,
|
| 797 |
+
"fitness": 0.46637274349614466,
|
| 798 |
+
"class_map": {
|
| 799 |
+
"classes": {
|
| 800 |
+
"0": "grape"
|
| 801 |
+
},
|
| 802 |
+
"maps": [
|
| 803 |
+
0.4349909954379633
|
| 804 |
+
]
|
| 805 |
+
}
|
| 806 |
+
},
|
| 807 |
+
"grape_detection_californiaday+yolo11m": {
|
| 808 |
+
"metrics/precision(B)": 0.7773064938902419,
|
| 809 |
+
"metrics/recall(B)": 0.7374353226465903,
|
| 810 |
+
"metrics/mAP50(B)": 0.8077534084598061,
|
| 811 |
+
"metrics/mAP50-95(B)": 0.4722895973277059,
|
| 812 |
+
"fitness": 0.505835978440916,
|
| 813 |
+
"class_map": {
|
| 814 |
+
"classes": {
|
| 815 |
+
"0": "grape"
|
| 816 |
+
},
|
| 817 |
+
"maps": [
|
| 818 |
+
0.4722895973277059
|
| 819 |
+
]
|
| 820 |
+
}
|
| 821 |
+
},
|
| 822 |
+
"grape_detection_californiaday+yolo11n": {
|
| 823 |
+
"metrics/precision(B)": 0.7763716212075286,
|
| 824 |
+
"metrics/recall(B)": 0.6999522564038694,
|
| 825 |
+
"metrics/mAP50(B)": 0.7950193029970769,
|
| 826 |
+
"metrics/mAP50-95(B)": 0.4354202972550957,
|
| 827 |
+
"fitness": 0.4713801978292938,
|
| 828 |
+
"class_map": {
|
| 829 |
+
"classes": {
|
| 830 |
+
"0": "grape"
|
| 831 |
+
},
|
| 832 |
+
"maps": [
|
| 833 |
+
0.4354202972550957
|
| 834 |
+
]
|
| 835 |
+
}
|
| 836 |
+
},
|
| 837 |
+
"grape_detection_californiaday+yolo11s": {
|
| 838 |
+
"metrics/precision(B)": 0.7714644290308007,
|
| 839 |
+
"metrics/recall(B)": 0.7016129032258065,
|
| 840 |
+
"metrics/mAP50(B)": 0.7758377164119181,
|
| 841 |
+
"metrics/mAP50-95(B)": 0.4587987241064469,
|
| 842 |
+
"fitness": 0.490502623336994,
|
| 843 |
+
"class_map": {
|
| 844 |
+
"classes": {
|
| 845 |
+
"0": "grape"
|
| 846 |
+
},
|
| 847 |
+
"maps": [
|
| 848 |
+
0.4587987241064469
|
| 849 |
+
]
|
| 850 |
+
}
|
| 851 |
+
},
|
| 852 |
+
"grape_detection_californiaday+yolo11x": {
|
| 853 |
+
"metrics/precision(B)": 0.7741723749893685,
|
| 854 |
+
"metrics/recall(B)": 0.7342657342657343,
|
| 855 |
+
"metrics/mAP50(B)": 0.7929902314501572,
|
| 856 |
+
"metrics/mAP50-95(B)": 0.46120749873436406,
|
| 857 |
+
"fitness": 0.4943857720059434,
|
| 858 |
+
"class_map": {
|
| 859 |
+
"classes": {
|
| 860 |
+
"0": "grape"
|
| 861 |
+
},
|
| 862 |
+
"maps": [
|
| 863 |
+
0.46120749873436406
|
| 864 |
+
]
|
| 865 |
+
}
|
| 866 |
+
},
|
| 867 |
+
"grape_detection_californianight+yolo11l": {
|
| 868 |
+
"metrics/precision(B)": 0.8205106047713361,
|
| 869 |
+
"metrics/recall(B)": 0.714765100671141,
|
| 870 |
+
"metrics/mAP50(B)": 0.7789473565331466,
|
| 871 |
+
"metrics/mAP50-95(B)": 0.38727844233662967,
|
| 872 |
+
"fitness": 0.4264453337562814,
|
| 873 |
+
"class_map": {
|
| 874 |
+
"classes": {
|
| 875 |
+
"0": "grape"
|
| 876 |
+
},
|
| 877 |
+
"maps": [
|
| 878 |
+
0.38727844233662967
|
| 879 |
+
]
|
| 880 |
+
}
|
| 881 |
+
},
|
| 882 |
+
"grape_detection_californianight+yolo11m": {
|
| 883 |
+
"metrics/precision(B)": 0.7498171113931226,
|
| 884 |
+
"metrics/recall(B)": 0.6684950129807627,
|
| 885 |
+
"metrics/mAP50(B)": 0.7597497390103658,
|
| 886 |
+
"metrics/mAP50-95(B)": 0.3955797325963587,
|
| 887 |
+
"fitness": 0.43199673323775944,
|
| 888 |
+
"class_map": {
|
| 889 |
+
"classes": {
|
| 890 |
+
"0": "grape"
|
| 891 |
+
},
|
| 892 |
+
"maps": [
|
| 893 |
+
0.3955797325963587
|
| 894 |
+
]
|
| 895 |
+
}
|
| 896 |
+
},
|
| 897 |
+
"grape_detection_californianight+yolo11n": {
|
| 898 |
+
"metrics/precision(B)": 0.8047380714047381,
|
| 899 |
+
"metrics/recall(B)": 0.6868892702226036,
|
| 900 |
+
"metrics/mAP50(B)": 0.7710866835242444,
|
| 901 |
+
"metrics/mAP50-95(B)": 0.38862968136840154,
|
| 902 |
+
"fitness": 0.42687538158398586,
|
| 903 |
+
"class_map": {
|
| 904 |
+
"classes": {
|
| 905 |
+
"0": "grape"
|
| 906 |
+
},
|
| 907 |
+
"maps": [
|
| 908 |
+
0.38862968136840154
|
| 909 |
+
]
|
| 910 |
+
}
|
| 911 |
+
},
|
| 912 |
+
"grape_detection_californianight+yolo11s": {
|
| 913 |
+
"metrics/precision(B)": 0.7567877803719415,
|
| 914 |
+
"metrics/recall(B)": 0.7690381054281749,
|
| 915 |
+
"metrics/mAP50(B)": 0.8017478762899578,
|
| 916 |
+
"metrics/mAP50-95(B)": 0.437436860925854,
|
| 917 |
+
"fitness": 0.47386796246226437,
|
| 918 |
+
"class_map": {
|
| 919 |
+
"classes": {
|
| 920 |
+
"0": "grape"
|
| 921 |
+
},
|
| 922 |
+
"maps": [
|
| 923 |
+
0.437436860925854
|
| 924 |
+
]
|
| 925 |
+
}
|
| 926 |
+
},
|
| 927 |
+
"grape_detection_californianight+yolo11x": {
|
| 928 |
+
"metrics/precision(B)": 0.736821555156227,
|
| 929 |
+
"metrics/recall(B)": 0.7449392712550608,
|
| 930 |
+
"metrics/mAP50(B)": 0.7811544936516707,
|
| 931 |
+
"metrics/mAP50-95(B)": 0.45322934116927815,
|
| 932 |
+
"fitness": 0.48602185641751744,
|
| 933 |
+
"class_map": {
|
| 934 |
+
"classes": {
|
| 935 |
+
"0": "grape"
|
| 936 |
+
},
|
| 937 |
+
"maps": [
|
| 938 |
+
0.45322934116927815
|
| 939 |
+
]
|
| 940 |
+
}
|
| 941 |
+
},
|
| 942 |
+
"grape_detection_syntheticday+yolo11l": {
|
| 943 |
+
"metrics/precision(B)": 0.9479649653275937,
|
| 944 |
+
"metrics/recall(B)": 0.8096817356076615,
|
| 945 |
+
"metrics/mAP50(B)": 0.9180702791053456,
|
| 946 |
+
"metrics/mAP50-95(B)": 0.720114342036841,
|
| 947 |
+
"fitness": 0.7399099357436915,
|
| 948 |
+
"class_map": {
|
| 949 |
+
"classes": {
|
| 950 |
+
"0": "grape"
|
| 951 |
+
},
|
| 952 |
+
"maps": [
|
| 953 |
+
0.720114342036841
|
| 954 |
+
]
|
| 955 |
+
}
|
| 956 |
+
},
|
| 957 |
+
"grape_detection_syntheticday+yolo11m": {
|
| 958 |
+
"metrics/precision(B)": 0.9209415736623586,
|
| 959 |
+
"metrics/recall(B)": 0.7480933095611995,
|
| 960 |
+
"metrics/mAP50(B)": 0.8824423748033108,
|
| 961 |
+
"metrics/mAP50-95(B)": 0.6451196561441267,
|
| 962 |
+
"fitness": 0.6688519280100451,
|
| 963 |
+
"class_map": {
|
| 964 |
+
"classes": {
|
| 965 |
+
"0": "grape"
|
| 966 |
+
},
|
| 967 |
+
"maps": [
|
| 968 |
+
0.6451196561441267
|
| 969 |
+
]
|
| 970 |
+
}
|
| 971 |
+
},
|
| 972 |
+
"grape_detection_syntheticday+yolo11n": {
|
| 973 |
+
"metrics/precision(B)": 0.967477944679693,
|
| 974 |
+
"metrics/recall(B)": 0.7243090046568308,
|
| 975 |
+
"metrics/mAP50(B)": 0.8866848206786255,
|
| 976 |
+
"metrics/mAP50-95(B)": 0.6597935907906964,
|
| 977 |
+
"fitness": 0.6824827137794894,
|
| 978 |
+
"class_map": {
|
| 979 |
+
"classes": {
|
| 980 |
+
"0": "grape"
|
| 981 |
+
},
|
| 982 |
+
"maps": [
|
| 983 |
+
0.6597935907906964
|
| 984 |
+
]
|
| 985 |
+
}
|
| 986 |
+
},
|
| 987 |
+
"grape_detection_syntheticday+yolo11s": {
|
| 988 |
+
"metrics/precision(B)": 0.937753124746368,
|
| 989 |
+
"metrics/recall(B)": 0.7158730158730159,
|
| 990 |
+
"metrics/mAP50(B)": 0.8756332872383675,
|
| 991 |
+
"metrics/mAP50-95(B)": 0.6526962340923247,
|
| 992 |
+
"fitness": 0.674989939406929,
|
| 993 |
+
"class_map": {
|
| 994 |
+
"classes": {
|
| 995 |
+
"0": "grape"
|
| 996 |
+
},
|
| 997 |
+
"maps": [
|
| 998 |
+
0.6526962340923247
|
| 999 |
+
]
|
| 1000 |
+
}
|
| 1001 |
+
},
|
| 1002 |
+
"grape_detection_syntheticday+yolo11x": {
|
| 1003 |
+
"metrics/precision(B)": 0.9046948366020652,
|
| 1004 |
+
"metrics/recall(B)": 0.7638888888888888,
|
| 1005 |
+
"metrics/mAP50(B)": 0.8939851564733988,
|
| 1006 |
+
"metrics/mAP50-95(B)": 0.6670388816374231,
|
| 1007 |
+
"fitness": 0.6897335091210207,
|
| 1008 |
+
"class_map": {
|
| 1009 |
+
"classes": {
|
| 1010 |
+
"0": "grape"
|
| 1011 |
+
},
|
| 1012 |
+
"maps": [
|
| 1013 |
+
0.6670388816374231
|
| 1014 |
+
]
|
| 1015 |
+
}
|
| 1016 |
+
},
|
| 1017 |
+
"mango_detection_australia+yolo11n": {
|
| 1018 |
+
"metrics/precision(B)": 0.9608107469068398,
|
| 1019 |
+
"metrics/recall(B)": 0.9592006661115737,
|
| 1020 |
+
"metrics/mAP50(B)": 0.9905041965687286,
|
| 1021 |
+
"metrics/mAP50-95(B)": 0.7329004634628975,
|
| 1022 |
+
"fitness": 0.7586608367734806,
|
| 1023 |
+
"class_map": {
|
| 1024 |
+
"classes": {
|
| 1025 |
+
"0": "mango"
|
| 1026 |
+
},
|
| 1027 |
+
"maps": [
|
| 1028 |
+
0.7329004634628975
|
| 1029 |
+
]
|
| 1030 |
+
}
|
| 1031 |
+
},
|
| 1032 |
+
"mango_detection_australia+yolo11s": {
|
| 1033 |
+
"metrics/precision(B)": 0.9621686178541151,
|
| 1034 |
+
"metrics/recall(B)": 0.9601259181532005,
|
| 1035 |
+
"metrics/mAP50(B)": 0.9897904628631954,
|
| 1036 |
+
"metrics/mAP50-95(B)": 0.7417234866786149,
|
| 1037 |
+
"fitness": 0.7665301842970729,
|
| 1038 |
+
"class_map": {
|
| 1039 |
+
"classes": {
|
| 1040 |
+
"0": "mango"
|
| 1041 |
+
},
|
| 1042 |
+
"maps": [
|
| 1043 |
+
0.7417234866786149
|
| 1044 |
+
]
|
| 1045 |
+
}
|
| 1046 |
+
},
|
| 1047 |
+
"plant_doc_detection+yolo11n": {
|
| 1048 |
+
"metrics/precision(B)": 0.5699978210221228,
|
| 1049 |
+
"metrics/recall(B)": 0.4667694854146501,
|
| 1050 |
+
"metrics/mAP50(B)": 0.49983071722743755,
|
| 1051 |
+
"metrics/mAP50-95(B)": 0.28933845111216405,
|
| 1052 |
+
"fitness": 0.3103876777236914,
|
| 1053 |
+
"class_map": {
|
| 1054 |
+
"classes": {
|
| 1055 |
+
"0": "Corn leaf blight",
|
| 1056 |
+
"1": "Tomato Early blight leaf",
|
| 1057 |
+
"2": "Potato leaf early blight",
|
| 1058 |
+
"3": "Potato leaf late blight",
|
| 1059 |
+
"4": "Blueberry leaf",
|
| 1060 |
+
"5": "grape leaf black rot",
|
| 1061 |
+
"6": "Bell_pepper leaf spot",
|
| 1062 |
+
"7": "Cherry leaf",
|
| 1063 |
+
"8": "Peach leaf",
|
| 1064 |
+
"9": "Soyabean leaf",
|
| 1065 |
+
"10": "Strawberry leaf",
|
| 1066 |
+
"11": "Apple Scab Leaf",
|
| 1067 |
+
"12": "Corn rust leaf",
|
| 1068 |
+
"13": "Apple leaf",
|
| 1069 |
+
"14": "Corn Gray leaf spot",
|
| 1070 |
+
"15": "Tomato leaf mosaic virus",
|
| 1071 |
+
"16": "Tomato mold leaf",
|
| 1072 |
+
"17": "Tomato leaf yellow virus",
|
| 1073 |
+
"18": "Tomato leaf bacterial spot",
|
| 1074 |
+
"19": "Tomato leaf late blight",
|
| 1075 |
+
"20": "Squash Powdery mildew leaf",
|
| 1076 |
+
"21": "Bell_pepper leaf",
|
| 1077 |
+
"22": "grape leaf",
|
| 1078 |
+
"23": "Apple rust leaf",
|
| 1079 |
+
"24": "Tomato Septoria leaf spot",
|
| 1080 |
+
"25": "Tomato leaf",
|
| 1081 |
+
"26": "Raspberry leaf",
|
| 1082 |
+
"27": "Potato leaf",
|
| 1083 |
+
"28": "Tomato two spotted spider mites leaf"
|
| 1084 |
+
},
|
| 1085 |
+
"maps": [
|
| 1086 |
+
0.21165168785446267,
|
| 1087 |
+
0.2792325697569097,
|
| 1088 |
+
0.1354302448211265,
|
| 1089 |
+
0.263397483670283,
|
| 1090 |
+
0.3782640229715143,
|
| 1091 |
+
0.515134299139252,
|
| 1092 |
+
0.3829545815204622,
|
| 1093 |
+
0.28162911303808413,
|
| 1094 |
+
0.407434444466772,
|
| 1095 |
+
0.4101654916508175,
|
| 1096 |
+
0.6115402640316101,
|
| 1097 |
+
0.2757413754673899,
|
| 1098 |
+
0.3832889745021061,
|
| 1099 |
+
0.29309831862053365,
|
| 1100 |
+
0.3417740747743542,
|
| 1101 |
+
0.14864104802091133,
|
| 1102 |
+
0.09251660230388258,
|
| 1103 |
+
0.22793129430027714,
|
| 1104 |
+
0.1096991079374952,
|
| 1105 |
+
0.3384237564640334,
|
| 1106 |
+
0.4487062911280722,
|
| 1107 |
+
0.46780512902862303,
|
| 1108 |
+
0.21608434755864292,
|
| 1109 |
+
0.25096967753644134,
|
| 1110 |
+
0.17234089042132714,
|
| 1111 |
+
0.34210560135206436,
|
| 1112 |
+
0.39394232324864203,
|
| 1113 |
+
0.010912066666666666,
|
| 1114 |
+
0.0
|
| 1115 |
+
]
|
| 1116 |
+
}
|
| 1117 |
+
},
|
| 1118 |
+
"plant_doc_detection+yolo11s": {
|
| 1119 |
+
"metrics/precision(B)": 0.5208979589174184,
|
| 1120 |
+
"metrics/recall(B)": 0.5696899647509104,
|
| 1121 |
+
"metrics/mAP50(B)": 0.5618029491774192,
|
| 1122 |
+
"metrics/mAP50-95(B)": 0.3287203928993561,
|
| 1123 |
+
"fitness": 0.3520286485271624,
|
| 1124 |
+
"class_map": {
|
| 1125 |
+
"classes": {
|
| 1126 |
+
"0": "Corn leaf blight",
|
| 1127 |
+
"1": "Tomato Early blight leaf",
|
| 1128 |
+
"2": "Potato leaf early blight",
|
| 1129 |
+
"3": "Potato leaf late blight",
|
| 1130 |
+
"4": "Blueberry leaf",
|
| 1131 |
+
"5": "grape leaf black rot",
|
| 1132 |
+
"6": "Bell_pepper leaf spot",
|
| 1133 |
+
"7": "Cherry leaf",
|
| 1134 |
+
"8": "Peach leaf",
|
| 1135 |
+
"9": "Soyabean leaf",
|
| 1136 |
+
"10": "Strawberry leaf",
|
| 1137 |
+
"11": "Apple Scab Leaf",
|
| 1138 |
+
"12": "Corn rust leaf",
|
| 1139 |
+
"13": "Apple leaf",
|
| 1140 |
+
"14": "Corn Gray leaf spot",
|
| 1141 |
+
"15": "Tomato leaf mosaic virus",
|
| 1142 |
+
"16": "Tomato mold leaf",
|
| 1143 |
+
"17": "Tomato leaf yellow virus",
|
| 1144 |
+
"18": "Tomato leaf bacterial spot",
|
| 1145 |
+
"19": "Tomato leaf late blight",
|
| 1146 |
+
"20": "Squash Powdery mildew leaf",
|
| 1147 |
+
"21": "Bell_pepper leaf",
|
| 1148 |
+
"22": "grape leaf",
|
| 1149 |
+
"23": "Apple rust leaf",
|
| 1150 |
+
"24": "Tomato Septoria leaf spot",
|
| 1151 |
+
"25": "Tomato leaf",
|
| 1152 |
+
"26": "Raspberry leaf",
|
| 1153 |
+
"27": "Potato leaf",
|
| 1154 |
+
"28": "Tomato two spotted spider mites leaf"
|
| 1155 |
+
},
|
| 1156 |
+
"maps": [
|
| 1157 |
+
0.2259487438831727,
|
| 1158 |
+
0.03936366643804077,
|
| 1159 |
+
0.341892241889508,
|
| 1160 |
+
0.07243948582620627,
|
| 1161 |
+
0.43245585022891275,
|
| 1162 |
+
0.5274739759036144,
|
| 1163 |
+
0.43621388674439177,
|
| 1164 |
+
0.35123023909078277,
|
| 1165 |
+
0.2803598679029792,
|
| 1166 |
+
0.4787679330427327,
|
| 1167 |
+
0.5936627836372785,
|
| 1168 |
+
0.2769313350532646,
|
| 1169 |
+
0.4074691558138146,
|
| 1170 |
+
0.45653293038859327,
|
| 1171 |
+
0.463017540106952,
|
| 1172 |
+
0.29188476003679065,
|
| 1173 |
+
0.13341390064905032,
|
| 1174 |
+
0.1527025963641791,
|
| 1175 |
+
0.21154645072713732,
|
| 1176 |
+
0.32613242674334925,
|
| 1177 |
+
0.3667393608026686,
|
| 1178 |
+
0.483387343071833,
|
| 1179 |
+
0.42529072532523193,
|
| 1180 |
+
0.389782799313227,
|
| 1181 |
+
0.2171715838648273,
|
| 1182 |
+
0.020821773218783948,
|
| 1183 |
+
0.47281725221529197,
|
| 1184 |
+
0.3287203928993561,
|
| 1185 |
+
0.3287203928993561
|
| 1186 |
+
]
|
| 1187 |
+
}
|
| 1188 |
+
},
|
| 1189 |
+
"tomato_ripeness_detection+yolo11n": {
|
| 1190 |
+
"metrics/precision(B)": 0.8604115397443802,
|
| 1191 |
+
"metrics/recall(B)": 0.797066972977987,
|
| 1192 |
+
"metrics/mAP50(B)": 0.8782874784766541,
|
| 1193 |
+
"metrics/mAP50-95(B)": 0.7272230615344513,
|
| 1194 |
+
"fitness": 0.7423295032286716,
|
| 1195 |
+
"class_map": {
|
| 1196 |
+
"classes": {
|
| 1197 |
+
"0": "b_fully_ripened",
|
| 1198 |
+
"1": "b_half_ripened",
|
| 1199 |
+
"2": "b_green",
|
| 1200 |
+
"3": "l_fully_ripened",
|
| 1201 |
+
"4": "l_half_ripened",
|
| 1202 |
+
"5": "l_green"
|
| 1203 |
+
},
|
| 1204 |
+
"maps": [
|
| 1205 |
+
0.7354947193755746,
|
| 1206 |
+
0.6358638892642564,
|
| 1207 |
+
0.7243581208396942,
|
| 1208 |
+
0.8167860030366242,
|
| 1209 |
+
0.6972496245489528,
|
| 1210 |
+
0.7535860121416055
|
| 1211 |
+
]
|
| 1212 |
+
}
|
| 1213 |
+
},
|
| 1214 |
+
"tomato_ripeness_detection+yolo11s": {
|
| 1215 |
+
"metrics/precision(B)": 0.8229190445960298,
|
| 1216 |
+
"metrics/recall(B)": 0.8835138959024996,
|
| 1217 |
+
"metrics/mAP50(B)": 0.9121278256507654,
|
| 1218 |
+
"metrics/mAP50-95(B)": 0.766808600552848,
|
| 1219 |
+
"fitness": 0.7813405230626399,
|
| 1220 |
+
"class_map": {
|
| 1221 |
+
"classes": {
|
| 1222 |
+
"0": "b_fully_ripened",
|
| 1223 |
+
"1": "b_half_ripened",
|
| 1224 |
+
"2": "b_green",
|
| 1225 |
+
"3": "l_fully_ripened",
|
| 1226 |
+
"4": "l_half_ripened",
|
| 1227 |
+
"5": "l_green"
|
| 1228 |
+
},
|
| 1229 |
+
"maps": [
|
| 1230 |
+
0.7548328307989863,
|
| 1231 |
+
0.7823764546071317,
|
| 1232 |
+
0.8009270920266699,
|
| 1233 |
+
0.7731819691183286,
|
| 1234 |
+
0.7255040982562855,
|
| 1235 |
+
0.7640291585096863
|
| 1236 |
+
]
|
| 1237 |
+
}
|
| 1238 |
+
},
|
| 1239 |
+
"wheat_head_counting+yolo11l": {
|
| 1240 |
+
"metrics/precision(B)": 0.9245879212203956,
|
| 1241 |
+
"metrics/recall(B)": 0.8779604425952586,
|
| 1242 |
+
"metrics/mAP50(B)": 0.9340138625325242,
|
| 1243 |
+
"metrics/mAP50-95(B)": 0.5784247103757646,
|
| 1244 |
+
"fitness": 0.6139836255914406,
|
| 1245 |
+
"class_map": {
|
| 1246 |
+
"classes": {
|
| 1247 |
+
"0": "Wheat Head"
|
| 1248 |
+
},
|
| 1249 |
+
"maps": [
|
| 1250 |
+
0.5784247103757646
|
| 1251 |
+
]
|
| 1252 |
+
}
|
| 1253 |
+
},
|
| 1254 |
+
"wheat_head_counting+yolo11m": {
|
| 1255 |
+
"metrics/precision(B)": 0.9183902766224068,
|
| 1256 |
+
"metrics/recall(B)": 0.8840558731996816,
|
| 1257 |
+
"metrics/mAP50(B)": 0.9366175742380312,
|
| 1258 |
+
"metrics/mAP50-95(B)": 0.5713564029858087,
|
| 1259 |
+
"fitness": 0.6078825201110309,
|
| 1260 |
+
"class_map": {
|
| 1261 |
+
"classes": {
|
| 1262 |
+
"0": "Wheat Head"
|
| 1263 |
+
},
|
| 1264 |
+
"maps": [
|
| 1265 |
+
0.5713564029858087
|
| 1266 |
+
]
|
| 1267 |
+
}
|
| 1268 |
+
},
|
| 1269 |
+
"wheat_head_counting+yolo11n": {
|
| 1270 |
+
"metrics/precision(B)": 0.9171613583006002,
|
| 1271 |
+
"metrics/recall(B)": 0.8632682396662342,
|
| 1272 |
+
"metrics/mAP50(B)": 0.9281931030761819,
|
| 1273 |
+
"metrics/mAP50-95(B)": 0.5556535027937193,
|
| 1274 |
+
"fitness": 0.5929074628219655,
|
| 1275 |
+
"class_map": {
|
| 1276 |
+
"classes": {
|
| 1277 |
+
"0": "Wheat Head"
|
| 1278 |
+
},
|
| 1279 |
+
"maps": [
|
| 1280 |
+
0.5556535027937193
|
| 1281 |
+
]
|
| 1282 |
+
}
|
| 1283 |
+
},
|
| 1284 |
+
"wheat_head_counting+yolo11s": {
|
| 1285 |
+
"metrics/precision(B)": 0.9254287063231834,
|
| 1286 |
+
"metrics/recall(B)": 0.8788046106055802,
|
| 1287 |
+
"metrics/mAP50(B)": 0.93777255866261,
|
| 1288 |
+
"metrics/mAP50-95(B)": 0.5679245907418896,
|
| 1289 |
+
"fitness": 0.6049093875339617,
|
| 1290 |
+
"class_map": {
|
| 1291 |
+
"classes": {
|
| 1292 |
+
"0": "Wheat Head"
|
| 1293 |
+
},
|
| 1294 |
+
"maps": [
|
| 1295 |
+
0.5679245907418896
|
| 1296 |
+
]
|
| 1297 |
+
}
|
| 1298 |
+
},
|
| 1299 |
+
"wheat_head_counting+yolo11x": {
|
| 1300 |
+
"metrics/precision(B)": 0.9223821425244931,
|
| 1301 |
+
"metrics/recall(B)": 0.8769885342336543,
|
| 1302 |
+
"metrics/mAP50(B)": 0.9271253514411493,
|
| 1303 |
+
"metrics/mAP50-95(B)": 0.5721022258377911,
|
| 1304 |
+
"fitness": 0.607604538398127,
|
| 1305 |
+
"class_map": {
|
| 1306 |
+
"classes": {
|
| 1307 |
+
"0": "Wheat Head"
|
| 1308 |
+
},
|
| 1309 |
+
"maps": [
|
| 1310 |
+
0.5721022258377911
|
| 1311 |
+
]
|
| 1312 |
+
}
|
| 1313 |
+
}
|
| 1314 |
+
}
|
AgML/source/agml/_assets/iNatAg-mini_public_datasources.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
AgML/source/agml/_assets/iNatAg-mini_source_citations.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
AgML/source/agml/_assets/iNatAg_public_datasources.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
AgML/source/agml/_assets/iNatAg_source_citations.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
AgML/source/agml/_assets/model_benchmarks.json
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"carrot_weeds_germany": {
|
| 3 |
+
"metric": {
|
| 4 |
+
"mIOU": 52.18
|
| 5 |
+
},
|
| 6 |
+
"hyperparameters": {
|
| 7 |
+
"epochs": 50,
|
| 8 |
+
"model_config": {
|
| 9 |
+
"image_size": [
|
| 10 |
+
512,
|
| 11 |
+
512
|
| 12 |
+
]
|
| 13 |
+
},
|
| 14 |
+
"optimizer_config": {
|
| 15 |
+
"lr": 0.005
|
| 16 |
+
}
|
| 17 |
+
}
|
| 18 |
+
},
|
| 19 |
+
"sugarbeet_weed_segmentation": {
|
| 20 |
+
"metric": {
|
| 21 |
+
"mIOU": 53.59
|
| 22 |
+
},
|
| 23 |
+
"hyperparameters": {
|
| 24 |
+
"epochs": 50,
|
| 25 |
+
"model_config": {
|
| 26 |
+
"image_size": [
|
| 27 |
+
512,
|
| 28 |
+
512
|
| 29 |
+
]
|
| 30 |
+
},
|
| 31 |
+
"optimizer_config": {
|
| 32 |
+
"lr": 0.005
|
| 33 |
+
}
|
| 34 |
+
}
|
| 35 |
+
},
|
| 36 |
+
"apple_flower_segmentation": {
|
| 37 |
+
"metric": {
|
| 38 |
+
"mIOU": 68.38
|
| 39 |
+
},
|
| 40 |
+
"hyperparameters": {
|
| 41 |
+
"epochs": 50,
|
| 42 |
+
"model_config": {
|
| 43 |
+
"image_size": [
|
| 44 |
+
512,
|
| 45 |
+
512
|
| 46 |
+
]
|
| 47 |
+
},
|
| 48 |
+
"optimizer_config": {
|
| 49 |
+
"lr": 0.005
|
| 50 |
+
}
|
| 51 |
+
}
|
| 52 |
+
},
|
| 53 |
+
"apple_segmentation_minnesota": {
|
| 54 |
+
"metric": {
|
| 55 |
+
"mIOU": 79.08
|
| 56 |
+
},
|
| 57 |
+
"hyperparameters": {
|
| 58 |
+
"epochs": 50,
|
| 59 |
+
"model_config": {
|
| 60 |
+
"image_size": [
|
| 61 |
+
512,
|
| 62 |
+
512
|
| 63 |
+
]
|
| 64 |
+
},
|
| 65 |
+
"optimizer_config": {
|
| 66 |
+
"lr": 0.005
|
| 67 |
+
}
|
| 68 |
+
}
|
| 69 |
+
},
|
| 70 |
+
"rice_seedling_segmentation": {
|
| 71 |
+
"metric": {
|
| 72 |
+
"mIOU": 52.2
|
| 73 |
+
},
|
| 74 |
+
"hyperparameters": {
|
| 75 |
+
"epochs": 50,
|
| 76 |
+
"model_config": {
|
| 77 |
+
"image_size": [
|
| 78 |
+
512,
|
| 79 |
+
512
|
| 80 |
+
]
|
| 81 |
+
},
|
| 82 |
+
"optimizer_config": {
|
| 83 |
+
"lr": 0.005
|
| 84 |
+
}
|
| 85 |
+
}
|
| 86 |
+
},
|
| 87 |
+
"peachpear_flower_segmentation": {
|
| 88 |
+
"metric": {
|
| 89 |
+
"mIOU": 72.58
|
| 90 |
+
},
|
| 91 |
+
"hyperparameters": {
|
| 92 |
+
"epochs": 50,
|
| 93 |
+
"model_config": {
|
| 94 |
+
"image_size": [
|
| 95 |
+
512,
|
| 96 |
+
512
|
| 97 |
+
]
|
| 98 |
+
},
|
| 99 |
+
"optimizer_config": {
|
| 100 |
+
"lr": 0.005
|
| 101 |
+
}
|
| 102 |
+
}
|
| 103 |
+
},
|
| 104 |
+
"red_grapes_and_leaves_segmentation": {
|
| 105 |
+
"metric": {
|
| 106 |
+
"mIOU": 49.18
|
| 107 |
+
},
|
| 108 |
+
"hyperparameters": {
|
| 109 |
+
"epochs": 50,
|
| 110 |
+
"model_config": {
|
| 111 |
+
"image_size": [
|
| 112 |
+
512,
|
| 113 |
+
512
|
| 114 |
+
]
|
| 115 |
+
},
|
| 116 |
+
"optimizer_config": {
|
| 117 |
+
"lr": 0.005
|
| 118 |
+
}
|
| 119 |
+
}
|
| 120 |
+
},
|
| 121 |
+
"white_grapes_and_leaves_segmentation": {
|
| 122 |
+
"metric": {
|
| 123 |
+
"mIOU": 51.93
|
| 124 |
+
},
|
| 125 |
+
"hyperparameters": {
|
| 126 |
+
"epochs": 50,
|
| 127 |
+
"model_config": {
|
| 128 |
+
"image_size": [
|
| 129 |
+
512,
|
| 130 |
+
512
|
| 131 |
+
]
|
| 132 |
+
},
|
| 133 |
+
"optimizer_config": {
|
| 134 |
+
"lr": 0.005
|
| 135 |
+
}
|
| 136 |
+
}
|
| 137 |
+
},
|
| 138 |
+
"grape_detection_californiaday": {
|
| 139 |
+
"metric": {
|
| 140 |
+
"mAP": 69.01
|
| 141 |
+
},
|
| 142 |
+
"hyperparameters": {
|
| 143 |
+
"epochs": 50,
|
| 144 |
+
"model_config": {
|
| 145 |
+
"box_loss_weight": 100.0,
|
| 146 |
+
"image_size": [
|
| 147 |
+
512,
|
| 148 |
+
512
|
| 149 |
+
],
|
| 150 |
+
"confidence_threshold": 0.3
|
| 151 |
+
},
|
| 152 |
+
"optimizer_config": {
|
| 153 |
+
"lr": 0.0002
|
| 154 |
+
}
|
| 155 |
+
}
|
| 156 |
+
},
|
| 157 |
+
"grape_detection_californianight": {
|
| 158 |
+
"metric": {
|
| 159 |
+
"mAP": 63.99
|
| 160 |
+
},
|
| 161 |
+
"hyperparameters": {
|
| 162 |
+
"epochs": 50,
|
| 163 |
+
"model_config": {
|
| 164 |
+
"box_loss_weight": 100.0,
|
| 165 |
+
"image_size": [
|
| 166 |
+
512,
|
| 167 |
+
512
|
| 168 |
+
],
|
| 169 |
+
"confidence_threshold": 0.3
|
| 170 |
+
},
|
| 171 |
+
"optimizer_config": {
|
| 172 |
+
"lr": 0.0002
|
| 173 |
+
}
|
| 174 |
+
}
|
| 175 |
+
},
|
| 176 |
+
"fruit_detection_worldwide": {
|
| 177 |
+
"metric": {
|
| 178 |
+
"mIOU": 70.35
|
| 179 |
+
},
|
| 180 |
+
"hyperparameters": {
|
| 181 |
+
"epochs": 50,
|
| 182 |
+
"model_config": {
|
| 183 |
+
"box_loss_weight": 50.0,
|
| 184 |
+
"image_size": [
|
| 185 |
+
512,
|
| 186 |
+
512
|
| 187 |
+
],
|
| 188 |
+
"confidence_threshold": 0.3
|
| 189 |
+
},
|
| 190 |
+
"optimizer_config": {
|
| 191 |
+
"lr": 0.0008
|
| 192 |
+
}
|
| 193 |
+
}
|
| 194 |
+
},
|
| 195 |
+
"mango_detection_australia": {
|
| 196 |
+
"metric": {
|
| 197 |
+
"mAP": 95.32
|
| 198 |
+
},
|
| 199 |
+
"hyperparameters": {
|
| 200 |
+
"epochs": 50,
|
| 201 |
+
"model_config": {
|
| 202 |
+
"box_loss_weight": 100.0,
|
| 203 |
+
"image_size": [
|
| 204 |
+
512,
|
| 205 |
+
512
|
| 206 |
+
],
|
| 207 |
+
"confidence_threshold": 0.3
|
| 208 |
+
},
|
| 209 |
+
"optimizer_config": {
|
| 210 |
+
"lr": 0.0002
|
| 211 |
+
}
|
| 212 |
+
}
|
| 213 |
+
},
|
| 214 |
+
"apple_detection_usa": {
|
| 215 |
+
"metric": {
|
| 216 |
+
"mAP": 94.16
|
| 217 |
+
},
|
| 218 |
+
"hyperparameters": {
|
| 219 |
+
"epochs": 50,
|
| 220 |
+
"model_config": {
|
| 221 |
+
"box_loss_weight": 100.0,
|
| 222 |
+
"image_size": [
|
| 223 |
+
512,
|
| 224 |
+
512
|
| 225 |
+
],
|
| 226 |
+
"confidence_threshold": 0.3
|
| 227 |
+
},
|
| 228 |
+
"optimizer_config": {
|
| 229 |
+
"lr": 0.0002
|
| 230 |
+
}
|
| 231 |
+
}
|
| 232 |
+
},
|
| 233 |
+
"apple_detection_spain": {
|
| 234 |
+
"metric": {
|
| 235 |
+
"mAP": 86.65
|
| 236 |
+
},
|
| 237 |
+
"hyperparameters": {
|
| 238 |
+
"epochs": 50,
|
| 239 |
+
"model_config": {
|
| 240 |
+
"box_loss_weight": 100.0,
|
| 241 |
+
"image_size": [
|
| 242 |
+
512,
|
| 243 |
+
512
|
| 244 |
+
],
|
| 245 |
+
"confidence_threshold": 0.3
|
| 246 |
+
},
|
| 247 |
+
"optimizer_config": {
|
| 248 |
+
"lr": 0.0002
|
| 249 |
+
}
|
| 250 |
+
}
|
| 251 |
+
},
|
| 252 |
+
"apple_detection_drone_brazil": {
|
| 253 |
+
"metric": {
|
| 254 |
+
"mAP": 79.62
|
| 255 |
+
},
|
| 256 |
+
"hyperparameters": {
|
| 257 |
+
"epochs": 50,
|
| 258 |
+
"model_config": {
|
| 259 |
+
"box_loss_weight": 100.0,
|
| 260 |
+
"image_size": [
|
| 261 |
+
512,
|
| 262 |
+
512
|
| 263 |
+
],
|
| 264 |
+
"confidence_threshold": 0.3
|
| 265 |
+
},
|
| 266 |
+
"optimizer_config": {
|
| 267 |
+
"lr": 0.0002
|
| 268 |
+
}
|
| 269 |
+
}
|
| 270 |
+
}
|
| 271 |
+
}
|
AgML/source/agml/_assets/public_datasources.json
ADDED
|
@@ -0,0 +1,2506 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"bean_disease_uganda": {
|
| 3 |
+
"ml_task": "image_classification",
|
| 4 |
+
"ag_task": "disease_classification",
|
| 5 |
+
"location": {
|
| 6 |
+
"continent": "africa",
|
| 7 |
+
"country": "uganda"
|
| 8 |
+
},
|
| 9 |
+
"sensor_modality": "rgb",
|
| 10 |
+
"real_synthetic": "real",
|
| 11 |
+
"platform": "handheld",
|
| 12 |
+
"input_data_format": "jpg",
|
| 13 |
+
"annotation_format": "directory_names",
|
| 14 |
+
"n_images": "1295",
|
| 15 |
+
"docs_url": "https://github.com/AI-Lab-Makerere/ibean/",
|
| 16 |
+
"classes": {
|
| 17 |
+
"0": "angular_leaf_spot",
|
| 18 |
+
"1": "bean_rust",
|
| 19 |
+
"2": "healthy"
|
| 20 |
+
},
|
| 21 |
+
"external_image_sources": [],
|
| 22 |
+
"stats": {
|
| 23 |
+
"mean": [
|
| 24 |
+
0.484832227230072,
|
| 25 |
+
0.5186858773231506,
|
| 26 |
+
0.31070876121520996
|
| 27 |
+
],
|
| 28 |
+
"std": [
|
| 29 |
+
0.18201105296611786,
|
| 30 |
+
0.1994817703962326,
|
| 31 |
+
0.16856099665164948
|
| 32 |
+
]
|
| 33 |
+
},
|
| 34 |
+
"parent_dataset": "",
|
| 35 |
+
"extra_metadata": {}
|
| 36 |
+
},
|
| 37 |
+
"carrot_weeds_germany": {
|
| 38 |
+
"ml_task": "semantic_segmentation",
|
| 39 |
+
"ag_task": "weed_segmentation",
|
| 40 |
+
"location": {
|
| 41 |
+
"continent": "europe",
|
| 42 |
+
"country": "germany"
|
| 43 |
+
},
|
| 44 |
+
"sensor_modality": "rgb",
|
| 45 |
+
"real_synthetic": "real",
|
| 46 |
+
"platform": "ground_mobile",
|
| 47 |
+
"input_data_format": "png",
|
| 48 |
+
"annotation_format": "image",
|
| 49 |
+
"n_images": "60",
|
| 50 |
+
"docs_url": "https://github.com/cwfid/dataset",
|
| 51 |
+
"classes": {
|
| 52 |
+
"0": "carrot",
|
| 53 |
+
"1": "weeds"
|
| 54 |
+
},
|
| 55 |
+
"external_image_sources": [],
|
| 56 |
+
"stats": {
|
| 57 |
+
"mean": [
|
| 58 |
+
0.2736402750015259,
|
| 59 |
+
0.31067565083503723,
|
| 60 |
+
0.2736402750015259
|
| 61 |
+
],
|
| 62 |
+
"std": [
|
| 63 |
+
0.08643443882465363,
|
| 64 |
+
0.0995175763964653,
|
| 65 |
+
0.08643443882465363
|
| 66 |
+
]
|
| 67 |
+
},
|
| 68 |
+
"parent_dataset": "",
|
| 69 |
+
"extra_metadata": {}
|
| 70 |
+
},
|
| 71 |
+
"plant_seedlings_aarhus": {
|
| 72 |
+
"ml_task": "image_classification",
|
| 73 |
+
"ag_task": "weed_classification",
|
| 74 |
+
"location": {
|
| 75 |
+
"continent": "europe",
|
| 76 |
+
"country": "denmark"
|
| 77 |
+
},
|
| 78 |
+
"sensor_modality": "rgb",
|
| 79 |
+
"real_synthetic": "real",
|
| 80 |
+
"platform": "ground_fixed",
|
| 81 |
+
"input_data_format": "png",
|
| 82 |
+
"annotation_format": "directory_names",
|
| 83 |
+
"n_images": "5539",
|
| 84 |
+
"docs_url": "https://vision.eng.au.dk/plant-seedlings-dataset/",
|
| 85 |
+
"classes": {
|
| 86 |
+
"0": "maize",
|
| 87 |
+
"1": "common_wheat",
|
| 88 |
+
"2": "sugar_beet",
|
| 89 |
+
"3": "scentless_mayweed",
|
| 90 |
+
"4": "common_chickweed",
|
| 91 |
+
"5": "shepherds_purse",
|
| 92 |
+
"6": "cleavers",
|
| 93 |
+
"7": "charlock",
|
| 94 |
+
"8": "fat_hen",
|
| 95 |
+
"9": "smallflowered_cranesbill",
|
| 96 |
+
"10": "black_grass",
|
| 97 |
+
"11": "loose_silkybent"
|
| 98 |
+
},
|
| 99 |
+
"external_image_sources": [],
|
| 100 |
+
"stats": {
|
| 101 |
+
"mean": [
|
| 102 |
+
0.3287692368030548,
|
| 103 |
+
0.28884512186050415,
|
| 104 |
+
0.20677343010902405
|
| 105 |
+
],
|
| 106 |
+
"std": [
|
| 107 |
+
0.09281572699546814,
|
| 108 |
+
0.09644099324941635,
|
| 109 |
+
0.10552676767110825
|
| 110 |
+
]
|
| 111 |
+
},
|
| 112 |
+
"parent_dataset": "",
|
| 113 |
+
"extra_metadata": {}
|
| 114 |
+
},
|
| 115 |
+
"soybean_weed_uav_brazil": {
|
| 116 |
+
"ml_task": "image_classification",
|
| 117 |
+
"ag_task": "weed_classification",
|
| 118 |
+
"location": {
|
| 119 |
+
"continent": "south_america",
|
| 120 |
+
"country": "brazil"
|
| 121 |
+
},
|
| 122 |
+
"sensor_modality": "rgb",
|
| 123 |
+
"real_synthetic": "real",
|
| 124 |
+
"platform": "uav",
|
| 125 |
+
"input_data_format": "tif",
|
| 126 |
+
"annotation_format": "directory_names",
|
| 127 |
+
"n_images": "15336",
|
| 128 |
+
"docs_url": "https://data.mendeley.com/datasets/3fmjm7ncc6/2",
|
| 129 |
+
"classes": {
|
| 130 |
+
"0": "broadleaf",
|
| 131 |
+
"1": "grass",
|
| 132 |
+
"2": "soil",
|
| 133 |
+
"3": "soybean"
|
| 134 |
+
},
|
| 135 |
+
"external_image_sources": [],
|
| 136 |
+
"stats": {
|
| 137 |
+
"mean": [
|
| 138 |
+
0.32902154326438904,
|
| 139 |
+
0.33378341794013977,
|
| 140 |
+
0.1865464597940445
|
| 141 |
+
],
|
| 142 |
+
"std": [
|
| 143 |
+
0.24514122307300568,
|
| 144 |
+
0.2491522580385208,
|
| 145 |
+
0.1570599377155304
|
| 146 |
+
]
|
| 147 |
+
},
|
| 148 |
+
"parent_dataset": "",
|
| 149 |
+
"extra_metadata": {}
|
| 150 |
+
},
|
| 151 |
+
"sugarcane_damage_usa": {
|
| 152 |
+
"ml_task": "image_classification",
|
| 153 |
+
"ag_task": "damage_classification",
|
| 154 |
+
"location": {
|
| 155 |
+
"continent": "north_america",
|
| 156 |
+
"country": "usa"
|
| 157 |
+
},
|
| 158 |
+
"sensor_modality": "rgb",
|
| 159 |
+
"platform": "ground_fixed",
|
| 160 |
+
"input_data_format": "bmp",
|
| 161 |
+
"annotation_format": "directory_names",
|
| 162 |
+
"n_images": "153",
|
| 163 |
+
"docs_url": "https://github.com/The77Lab/SugarcaneBilletsDataset",
|
| 164 |
+
"classes": {
|
| 165 |
+
"0": "cracked",
|
| 166 |
+
"1": "crushed",
|
| 167 |
+
"2": "no_buds",
|
| 168 |
+
"3": "two_buds",
|
| 169 |
+
"4": "single_damaged_buds",
|
| 170 |
+
"5": "no_damage"
|
| 171 |
+
},
|
| 172 |
+
"external_image_sources": [],
|
| 173 |
+
"stats": {
|
| 174 |
+
"mean": [
|
| 175 |
+
0.24388393759727478,
|
| 176 |
+
0.24691258370876312,
|
| 177 |
+
0.26203399896621704
|
| 178 |
+
],
|
| 179 |
+
"std": [
|
| 180 |
+
0.22363615036010742,
|
| 181 |
+
0.21735334396362305,
|
| 182 |
+
0.1923859715461731
|
| 183 |
+
]
|
| 184 |
+
},
|
| 185 |
+
"parent_dataset": "",
|
| 186 |
+
"extra_metadata": {}
|
| 187 |
+
},
|
| 188 |
+
"crop_weeds_greece": {
|
| 189 |
+
"ml_task": "image_classification",
|
| 190 |
+
"ag_task": "weed_classification",
|
| 191 |
+
"location": {
|
| 192 |
+
"continent": "europe",
|
| 193 |
+
"country": "greece"
|
| 194 |
+
},
|
| 195 |
+
"sensor_modality": "rgb",
|
| 196 |
+
"platform": "handheld",
|
| 197 |
+
"input_data_format": "jpg",
|
| 198 |
+
"annotation_format": "directory_names",
|
| 199 |
+
"n_images": "508",
|
| 200 |
+
"docs_url": "https://github.com/AUAgroup/early-crop-weed",
|
| 201 |
+
"classes": {
|
| 202 |
+
"0": "black_nightshade",
|
| 203 |
+
"1": "velvet_leaf",
|
| 204 |
+
"2": "cotton",
|
| 205 |
+
"3": "tomato"
|
| 206 |
+
},
|
| 207 |
+
"external_image_sources": [],
|
| 208 |
+
"stats": {
|
| 209 |
+
"mean": [
|
| 210 |
+
0.7247000336647034,
|
| 211 |
+
0.6694437265396118,
|
| 212 |
+
0.5436030030250549
|
| 213 |
+
],
|
| 214 |
+
"std": [
|
| 215 |
+
0.16351649165153503,
|
| 216 |
+
0.15307274460792542,
|
| 217 |
+
0.13750970363616943
|
| 218 |
+
]
|
| 219 |
+
},
|
| 220 |
+
"parent_dataset": "",
|
| 221 |
+
"extra_metadata": {}
|
| 222 |
+
},
|
| 223 |
+
"sugarbeet_weed_segmentation": {
|
| 224 |
+
"ml_task": "semantic_segmentation",
|
| 225 |
+
"ag_task": "weed_segmentation",
|
| 226 |
+
"location": {
|
| 227 |
+
"continent": "none",
|
| 228 |
+
"country": "none"
|
| 229 |
+
},
|
| 230 |
+
"sensor_modality": "rgb",
|
| 231 |
+
"real_synthetic": "real",
|
| 232 |
+
"platform": "ground",
|
| 233 |
+
"input_data_format": "png",
|
| 234 |
+
"annotation_format": "image",
|
| 235 |
+
"n_images": "125",
|
| 236 |
+
"docs_url": "https://github.com/inkyusa/weedNet",
|
| 237 |
+
"stats": {
|
| 238 |
+
"mean": [
|
| 239 |
+
0.374398797750473,
|
| 240 |
+
0.374398797750473,
|
| 241 |
+
0.374398797750473
|
| 242 |
+
],
|
| 243 |
+
"std": [
|
| 244 |
+
0.16996806859970093,
|
| 245 |
+
0.16996806859970093,
|
| 246 |
+
0.16996806859970093
|
| 247 |
+
]
|
| 248 |
+
},
|
| 249 |
+
"classes": {
|
| 250 |
+
"0": "sugar_beet",
|
| 251 |
+
"1": "random_weeds"
|
| 252 |
+
},
|
| 253 |
+
"external_image_sources": [],
|
| 254 |
+
"parent_dataset": "",
|
| 255 |
+
"extra_metadata": {}
|
| 256 |
+
},
|
| 257 |
+
"rangeland_weeds_australia": {
|
| 258 |
+
"ml_task": "image_classification",
|
| 259 |
+
"ag_task": "weed_classification",
|
| 260 |
+
"location": {
|
| 261 |
+
"continent": "oceania",
|
| 262 |
+
"country": "australia"
|
| 263 |
+
},
|
| 264 |
+
"sensor_modality": "rgb",
|
| 265 |
+
"real_synthetic": "real",
|
| 266 |
+
"platform": "ground",
|
| 267 |
+
"input_data_format": "jpg",
|
| 268 |
+
"annotation_format": "directory_names",
|
| 269 |
+
"n_images": "17509",
|
| 270 |
+
"docs_url": "https://github.com/AlexOlsen/DeepWeeds",
|
| 271 |
+
"classes": {
|
| 272 |
+
"0": "chinee_apple",
|
| 273 |
+
"1": "lantana",
|
| 274 |
+
"2": "negative",
|
| 275 |
+
"3": "parkinsonia",
|
| 276 |
+
"4": "parthenium",
|
| 277 |
+
"5": "prickly_acacia",
|
| 278 |
+
"6": "rubber_vine",
|
| 279 |
+
"7": "siam_weed",
|
| 280 |
+
"8": "snake_weed"
|
| 281 |
+
},
|
| 282 |
+
"external_image_sources": [],
|
| 283 |
+
"stats": {
|
| 284 |
+
"mean": [
|
| 285 |
+
0.3785800635814667,
|
| 286 |
+
0.38957375288009644,
|
| 287 |
+
0.3797687590122223
|
| 288 |
+
],
|
| 289 |
+
"std": [
|
| 290 |
+
0.22421929240226746,
|
| 291 |
+
0.22450383007526398,
|
| 292 |
+
0.22274655103683472
|
| 293 |
+
]
|
| 294 |
+
},
|
| 295 |
+
"parent_dataset": "",
|
| 296 |
+
"extra_metadata": {}
|
| 297 |
+
},
|
| 298 |
+
"fruit_detection_worldwide": {
|
| 299 |
+
"ml_task": "object_detection",
|
| 300 |
+
"ag_task": "fruit_detection",
|
| 301 |
+
"location": {
|
| 302 |
+
"continent": "worldwide",
|
| 303 |
+
"country": "worldwide"
|
| 304 |
+
},
|
| 305 |
+
"sensor_modality": "rgb",
|
| 306 |
+
"real_synthetic": "real",
|
| 307 |
+
"platform": "mixed",
|
| 308 |
+
"input_data_format": "jpg",
|
| 309 |
+
"annotation_format": "coco_json",
|
| 310 |
+
"n_images": "565",
|
| 311 |
+
"docs_url": "https://drive.google.com/drive/folders/1CmsZb1caggLRN7ANfika8WuPiywo4mBb",
|
| 312 |
+
"stats": {
|
| 313 |
+
"mean": [
|
| 314 |
+
0.3779049813747406,
|
| 315 |
+
0.4085286557674408,
|
| 316 |
+
0.28682708740234375
|
| 317 |
+
],
|
| 318 |
+
"std": [
|
| 319 |
+
0.2306382656097412,
|
| 320 |
+
0.22500208020210266,
|
| 321 |
+
0.2183498740196228
|
| 322 |
+
]
|
| 323 |
+
},
|
| 324 |
+
"classes": {
|
| 325 |
+
"1": "avocado",
|
| 326 |
+
"2": "rockmelon",
|
| 327 |
+
"3": "apple",
|
| 328 |
+
"4": "orange",
|
| 329 |
+
"5": "strawberry",
|
| 330 |
+
"6": "mango",
|
| 331 |
+
"7": "capsicum"
|
| 332 |
+
},
|
| 333 |
+
"external_image_sources": [],
|
| 334 |
+
"parent_dataset": "",
|
| 335 |
+
"extra_metadata": {}
|
| 336 |
+
},
|
| 337 |
+
"leaf_counting_denmark": {
|
| 338 |
+
"ml_task": "image_classification",
|
| 339 |
+
"ag_task": "leaf_counting",
|
| 340 |
+
"location": {
|
| 341 |
+
"continent": "europe",
|
| 342 |
+
"country": "denmark"
|
| 343 |
+
},
|
| 344 |
+
"platform": "mixed",
|
| 345 |
+
"input_data_format": "png",
|
| 346 |
+
"annotation_format": "directory_names",
|
| 347 |
+
"n_images": "9372",
|
| 348 |
+
"docs_url": "https://vision.eng.au.dk/leaf-counting-dataset/",
|
| 349 |
+
"classes": {
|
| 350 |
+
"0": "1",
|
| 351 |
+
"1": "2",
|
| 352 |
+
"2": "3",
|
| 353 |
+
"3": "4",
|
| 354 |
+
"4": "5",
|
| 355 |
+
"5": "6",
|
| 356 |
+
"6": "7",
|
| 357 |
+
"7": "8",
|
| 358 |
+
"8": "9+"
|
| 359 |
+
},
|
| 360 |
+
"external_image_sources": [],
|
| 361 |
+
"stats": {
|
| 362 |
+
"mean": [
|
| 363 |
+
0.42661556601524353,
|
| 364 |
+
0.427418053150177,
|
| 365 |
+
0.3417948782444
|
| 366 |
+
],
|
| 367 |
+
"std": [
|
| 368 |
+
0.12296482920646667,
|
| 369 |
+
0.14348869025707245,
|
| 370 |
+
0.1148977279663086
|
| 371 |
+
]
|
| 372 |
+
},
|
| 373 |
+
"parent_dataset": "",
|
| 374 |
+
"extra_metadata": {}
|
| 375 |
+
},
|
| 376 |
+
"apple_detection_usa": {
|
| 377 |
+
"ml_task": "object_detection",
|
| 378 |
+
"ag_task": "fruit_detection",
|
| 379 |
+
"location": {
|
| 380 |
+
"continent": "north_america",
|
| 381 |
+
"country": "usa"
|
| 382 |
+
},
|
| 383 |
+
"sensor_modality": "rgb",
|
| 384 |
+
"real_synthetic": "real",
|
| 385 |
+
"platform": "ground",
|
| 386 |
+
"input_data_format": "png",
|
| 387 |
+
"annotation_format": "coco_json",
|
| 388 |
+
"n_images": "2290",
|
| 389 |
+
"docs_url": "https://hdl.handle.net/2376/17721",
|
| 390 |
+
"stats": {
|
| 391 |
+
"mean": [
|
| 392 |
+
0.2810896933078766,
|
| 393 |
+
0.29005560278892517,
|
| 394 |
+
0.2775411605834961
|
| 395 |
+
],
|
| 396 |
+
"std": [
|
| 397 |
+
0.18863406777381897,
|
| 398 |
+
0.18647761642932892,
|
| 399 |
+
0.1885077804327011
|
| 400 |
+
]
|
| 401 |
+
},
|
| 402 |
+
"classes": {
|
| 403 |
+
"1": "apple"
|
| 404 |
+
},
|
| 405 |
+
"external_image_sources": [],
|
| 406 |
+
"parent_dataset": "",
|
| 407 |
+
"extra_metadata": {}
|
| 408 |
+
},
|
| 409 |
+
"mango_detection_australia": {
|
| 410 |
+
"ml_task": "object_detection",
|
| 411 |
+
"ag_task": "fruit_detection",
|
| 412 |
+
"location": {
|
| 413 |
+
"continent": "oceania",
|
| 414 |
+
"country": "australia"
|
| 415 |
+
},
|
| 416 |
+
"sensor_modality": "rgb",
|
| 417 |
+
"real_synthetic": "real",
|
| 418 |
+
"platform": "handheld",
|
| 419 |
+
"input_data_format": "jpg",
|
| 420 |
+
"annotation_format": "coco_json",
|
| 421 |
+
"n_images": "1242",
|
| 422 |
+
"docs_url": "https://researchdata.edu.au/mangoyolo-set/1697505",
|
| 423 |
+
"stats": {
|
| 424 |
+
"mean": [
|
| 425 |
+
0.07288186252117157,
|
| 426 |
+
0.1193767637014389,
|
| 427 |
+
0.050045181065797806
|
| 428 |
+
],
|
| 429 |
+
"std": [
|
| 430 |
+
0.058673080056905746,
|
| 431 |
+
0.07924807816743851,
|
| 432 |
+
0.043408144265413284
|
| 433 |
+
]
|
| 434 |
+
},
|
| 435 |
+
"classes": {
|
| 436 |
+
"1": "mango"
|
| 437 |
+
},
|
| 438 |
+
"external_image_sources": [],
|
| 439 |
+
"parent_dataset": "",
|
| 440 |
+
"extra_metadata": {}
|
| 441 |
+
},
|
| 442 |
+
"tomato_ripeness_detection": {
|
| 443 |
+
"ml_task": "object_detection",
|
| 444 |
+
"ag_task": "fruit_ripeness_detection",
|
| 445 |
+
"location": {
|
| 446 |
+
"continent": "worldwide",
|
| 447 |
+
"country": "worldwide"
|
| 448 |
+
},
|
| 449 |
+
"sensor_modality": "rgb",
|
| 450 |
+
"real_synthetic": "real",
|
| 451 |
+
"platform": "ground",
|
| 452 |
+
"input_data_format": "jpg",
|
| 453 |
+
"annotation_format": "coco_json",
|
| 454 |
+
"n_images": "804",
|
| 455 |
+
"docs_url": "https://www.kaggle.com/datasets/nexuswho/laboro-tomato",
|
| 456 |
+
"classes": {
|
| 457 |
+
"1": "b_fully_ripened",
|
| 458 |
+
"2": "b_half_ripened",
|
| 459 |
+
"3": "b_green",
|
| 460 |
+
"4": "l_fully_ripened",
|
| 461 |
+
"5": "l_half_ripened",
|
| 462 |
+
"6": "l_green"
|
| 463 |
+
},
|
| 464 |
+
"external_image_sources": [],
|
| 465 |
+
"stats": {
|
| 466 |
+
"mean": [
|
| 467 |
+
0.46756285429000854,
|
| 468 |
+
0.5048850178718567,
|
| 469 |
+
0.317764014005661
|
| 470 |
+
],
|
| 471 |
+
"std": [
|
| 472 |
+
0.21034087240695953,
|
| 473 |
+
0.19280721247196198,
|
| 474 |
+
0.22368815541267395
|
| 475 |
+
]
|
| 476 |
+
},
|
| 477 |
+
"parent_dataset": "",
|
| 478 |
+
"extra_metadata": {}
|
| 479 |
+
},
|
| 480 |
+
"apple_flower_segmentation": {
|
| 481 |
+
"ml_task": "semantic_segmentation",
|
| 482 |
+
"ag_task": "flower_segmentation",
|
| 483 |
+
"location": {
|
| 484 |
+
"continent": "north_america",
|
| 485 |
+
"country": "usa"
|
| 486 |
+
},
|
| 487 |
+
"sensor_modality": "rgb",
|
| 488 |
+
"real_synthetic": "real",
|
| 489 |
+
"platform": "ground",
|
| 490 |
+
"input_data_format": "jpg",
|
| 491 |
+
"annotation_format": "image",
|
| 492 |
+
"n_images": "148",
|
| 493 |
+
"docs_url": "https://data.nal.usda.gov/dataset/data-multi-species-fruit-flower-detection-using-refined-semantic-segmentation-network",
|
| 494 |
+
"stats": {
|
| 495 |
+
"mean": [
|
| 496 |
+
0.4580204486846924,
|
| 497 |
+
0.47888585925102234,
|
| 498 |
+
0.4053090512752533
|
| 499 |
+
],
|
| 500 |
+
"std": [
|
| 501 |
+
0.2040298879146576,
|
| 502 |
+
0.19258278608322144,
|
| 503 |
+
0.2156316637992859
|
| 504 |
+
]
|
| 505 |
+
},
|
| 506 |
+
"classes": {
|
| 507 |
+
"0": "apple"
|
| 508 |
+
},
|
| 509 |
+
"external_image_sources": [],
|
| 510 |
+
"parent_dataset": "",
|
| 511 |
+
"extra_metadata": {}
|
| 512 |
+
},
|
| 513 |
+
"apple_segmentation_minnesota": {
|
| 514 |
+
"ml_task": "semantic_segmentation",
|
| 515 |
+
"ag_task": "fruit_segmentation",
|
| 516 |
+
"location": {
|
| 517 |
+
"continent": "north_america",
|
| 518 |
+
"country": "usa"
|
| 519 |
+
},
|
| 520 |
+
"sensor_modality": "rgb",
|
| 521 |
+
"real_synthetic": "real",
|
| 522 |
+
"platform": "ground",
|
| 523 |
+
"input_data_format": "png",
|
| 524 |
+
"annotation_format": "image",
|
| 525 |
+
"n_images": "670",
|
| 526 |
+
"docs_url": "https://rsn.umn.edu/projects/orchard-monitoring/minneapple",
|
| 527 |
+
"stats": {
|
| 528 |
+
"mean": [
|
| 529 |
+
0.3736153841018677,
|
| 530 |
+
0.43716397881507874,
|
| 531 |
+
0.33839237689971924
|
| 532 |
+
],
|
| 533 |
+
"std": [
|
| 534 |
+
0.2627662420272827,
|
| 535 |
+
0.28767505288124084,
|
| 536 |
+
0.33136168122291565
|
| 537 |
+
]
|
| 538 |
+
},
|
| 539 |
+
"classes": {
|
| 540 |
+
"0": "apple"
|
| 541 |
+
},
|
| 542 |
+
"external_image_sources": [],
|
| 543 |
+
"parent_dataset": "",
|
| 544 |
+
"extra_metadata": {}
|
| 545 |
+
},
|
| 546 |
+
"rice_seedling_segmentation": {
|
| 547 |
+
"ml_task": "semantic_segmentation",
|
| 548 |
+
"ag_task": "weed_segmentation",
|
| 549 |
+
"location": {
|
| 550 |
+
"continent": "asia",
|
| 551 |
+
"country": "china"
|
| 552 |
+
},
|
| 553 |
+
"sensor_modality": "rgb",
|
| 554 |
+
"real_synthetic": "real",
|
| 555 |
+
"platform": "handheld",
|
| 556 |
+
"input_data_format": "jpg",
|
| 557 |
+
"annotation_format": "image",
|
| 558 |
+
"n_images": "224",
|
| 559 |
+
"docs_url": "https://github.com/kabbas570/CED-Net-Crops-and-Weeds-Segmentation-for-Smart-Farming-Using-a-Small-Cascaded-Encoder-Decoder-Archi",
|
| 560 |
+
"stats": {
|
| 561 |
+
"mean": [
|
| 562 |
+
0.6552301049232483,
|
| 563 |
+
0.7014582753181458,
|
| 564 |
+
0.6353084444999695
|
| 565 |
+
],
|
| 566 |
+
"std": [
|
| 567 |
+
0.08477462828159332,
|
| 568 |
+
0.1075846329331398,
|
| 569 |
+
0.11058590561151505
|
| 570 |
+
]
|
| 571 |
+
},
|
| 572 |
+
"classes": {
|
| 573 |
+
"0": "Rice",
|
| 574 |
+
"1": "Weed"
|
| 575 |
+
},
|
| 576 |
+
"external_image_sources": [],
|
| 577 |
+
"parent_dataset": "",
|
| 578 |
+
"extra_metadata": {}
|
| 579 |
+
},
|
| 580 |
+
"plant_village_classification": {
|
| 581 |
+
"ml_task": "image_classification",
|
| 582 |
+
"ag_task": "disease_classification",
|
| 583 |
+
"location": {
|
| 584 |
+
"continent": "north_america",
|
| 585 |
+
"country": "usa"
|
| 586 |
+
},
|
| 587 |
+
"sensor_modality": "rgb",
|
| 588 |
+
"real_synthetic": "real",
|
| 589 |
+
"platform": "ground",
|
| 590 |
+
"input_data_format": "jpg",
|
| 591 |
+
"annotation_format": "directory_names",
|
| 592 |
+
"n_images": "55448",
|
| 593 |
+
"docs_url": "https://github.com/spMohanty/PlantVillage-Dataset",
|
| 594 |
+
"classes": {
|
| 595 |
+
"0": "Apple___Apple_scab",
|
| 596 |
+
"1": "Apple___Black_rot",
|
| 597 |
+
"2": "Apple___Cedar_apple_rust",
|
| 598 |
+
"3": "Apple___healthy",
|
| 599 |
+
"4": "Background_without_leaves",
|
| 600 |
+
"5": "Blueberry___healthy",
|
| 601 |
+
"6": "Cherry___Powdery_mildew",
|
| 602 |
+
"7": "Cherry___healthy",
|
| 603 |
+
"8": "Corn___Cercospora_leaf_spot Gray_leaf_spot",
|
| 604 |
+
"9": "Corn___Common_rust",
|
| 605 |
+
"10": "Corn___Northern_Leaf_Blight",
|
| 606 |
+
"11": "Corn___healthy",
|
| 607 |
+
"12": "Grape___Black_rot",
|
| 608 |
+
"13": "Grape___Esca_(Black_Measles)",
|
| 609 |
+
"14": "Grape___Leaf_blight_(Isariopsis_Leaf_Spot)",
|
| 610 |
+
"15": "Grape___healthy",
|
| 611 |
+
"16": "Orange___Haunglongbing_(Citrus_greening)",
|
| 612 |
+
"17": "Peach___Bacterial_spot",
|
| 613 |
+
"18": "Peach___healthy",
|
| 614 |
+
"19": "Pepper,_bell___Bacterial_spot",
|
| 615 |
+
"20": "Pepper,_bell___healthy",
|
| 616 |
+
"21": "Potato___Early_blight",
|
| 617 |
+
"22": "Potato___Late_blight",
|
| 618 |
+
"23": "Potato___healthy",
|
| 619 |
+
"24": "Raspberry___healthy",
|
| 620 |
+
"25": "Soybean___healthy",
|
| 621 |
+
"26": "Squash___Powdery_mildew",
|
| 622 |
+
"27": "Strawberry___Leaf_scorch",
|
| 623 |
+
"28": "Strawberry___healthy",
|
| 624 |
+
"29": "Tomato___Bacterial_spot",
|
| 625 |
+
"30": "Tomato___Early_blight",
|
| 626 |
+
"31": "Tomato___Late_blight",
|
| 627 |
+
"32": "Tomato___Leaf_Mold",
|
| 628 |
+
"33": "Tomato___Septoria_leaf_spot",
|
| 629 |
+
"34": "Tomato___Spider_mites Two-spotted_spider_mite",
|
| 630 |
+
"35": "Tomato___Target_Spot",
|
| 631 |
+
"36": "Tomato___Tomato_Yellow_Leaf_Curl_Virus",
|
| 632 |
+
"37": "Tomato___Tomato_mosaic_virus",
|
| 633 |
+
"38": "Tomato___healthy"
|
| 634 |
+
},
|
| 635 |
+
"external_image_sources": [],
|
| 636 |
+
"stats": {
|
| 637 |
+
"mean": [
|
| 638 |
+
0.46678444743156433,
|
| 639 |
+
0.4892062544822693,
|
| 640 |
+
0.4119776785373688
|
| 641 |
+
],
|
| 642 |
+
"std": [
|
| 643 |
+
0.17720915377140045,
|
| 644 |
+
0.15169931948184967,
|
| 645 |
+
0.19375933706760406
|
| 646 |
+
]
|
| 647 |
+
},
|
| 648 |
+
"parent_dataset": "",
|
| 649 |
+
"extra_metadata": {}
|
| 650 |
+
},
|
| 651 |
+
"autonomous_greenhouse_regression": {
|
| 652 |
+
"ml_task": "image_regression",
|
| 653 |
+
"ag_task": "ag_regression",
|
| 654 |
+
"sensor_modality": "rgb",
|
| 655 |
+
"real_synthetic": "real",
|
| 656 |
+
"platform": "ground",
|
| 657 |
+
"input_data_format": "png",
|
| 658 |
+
"annotation_format": "json",
|
| 659 |
+
"n_images": "389",
|
| 660 |
+
"docs_url": "https://data.4tu.nl/articles/dataset/3rd_Autonomous_Greenhouse_Challenge_Online_Challenge_Lettuce_Images/15023088/1",
|
| 661 |
+
"location": {
|
| 662 |
+
"continent": "europe",
|
| 663 |
+
"country": "netherlands"
|
| 664 |
+
},
|
| 665 |
+
"classes": {
|
| 666 |
+
"regression": {
|
| 667 |
+
"0": "FreshWeightShoot",
|
| 668 |
+
"1": "DryWeightShoot",
|
| 669 |
+
"2": "Height",
|
| 670 |
+
"3": "Diameter",
|
| 671 |
+
"4": "LeafArea"
|
| 672 |
+
},
|
| 673 |
+
"classification": {
|
| 674 |
+
"0": "Aphylion",
|
| 675 |
+
"1": "Lugano",
|
| 676 |
+
"2": "Salanova",
|
| 677 |
+
"3": "Satine"
|
| 678 |
+
}
|
| 679 |
+
},
|
| 680 |
+
"external_image_sources": [
|
| 681 |
+
"depth"
|
| 682 |
+
],
|
| 683 |
+
"stats": {
|
| 684 |
+
"mean": [
|
| 685 |
+
0.4848844110965729,
|
| 686 |
+
0.45935600996017456,
|
| 687 |
+
0.4063475430011749
|
| 688 |
+
],
|
| 689 |
+
"std": [
|
| 690 |
+
0.13606780767440796,
|
| 691 |
+
0.13940763473510742,
|
| 692 |
+
0.19247490167617798
|
| 693 |
+
]
|
| 694 |
+
},
|
| 695 |
+
"parent_dataset": "",
|
| 696 |
+
"extra_metadata": {}
|
| 697 |
+
},
|
| 698 |
+
"grape_detection_syntheticday": {
|
| 699 |
+
"classes": {
|
| 700 |
+
"1": "grape"
|
| 701 |
+
},
|
| 702 |
+
"ml_task": "object_detection",
|
| 703 |
+
"ag_task": "fruit_detection",
|
| 704 |
+
"location": {
|
| 705 |
+
"continent": "digital",
|
| 706 |
+
"country": "digital"
|
| 707 |
+
},
|
| 708 |
+
"sensor_modality": "rgb",
|
| 709 |
+
"real_synthetic": "synthetic",
|
| 710 |
+
"platform": "ground",
|
| 711 |
+
"input_data_format": "jpg",
|
| 712 |
+
"annotation_format": "coco_json",
|
| 713 |
+
"n_images": "448",
|
| 714 |
+
"docs_url": "N/A",
|
| 715 |
+
"external_image_sources": [],
|
| 716 |
+
"stats": {
|
| 717 |
+
"mean": [
|
| 718 |
+
0.24965472519397736,
|
| 719 |
+
0.2763761281967163,
|
| 720 |
+
0.20683138072490692
|
| 721 |
+
],
|
| 722 |
+
"std": [
|
| 723 |
+
0.15098054707050323,
|
| 724 |
+
0.18630442023277283,
|
| 725 |
+
0.2241816222667694
|
| 726 |
+
]
|
| 727 |
+
},
|
| 728 |
+
"parent_dataset": "",
|
| 729 |
+
"extra_metadata": {}
|
| 730 |
+
},
|
| 731 |
+
"grape_detection_californiaday": {
|
| 732 |
+
"classes": {
|
| 733 |
+
"1": "grape"
|
| 734 |
+
},
|
| 735 |
+
"ml_task": "object_detection",
|
| 736 |
+
"ag_task": "fruit_detection",
|
| 737 |
+
"location": {
|
| 738 |
+
"continent": "north_america",
|
| 739 |
+
"country": "usa"
|
| 740 |
+
},
|
| 741 |
+
"sensor_modality": "rgb",
|
| 742 |
+
"real_synthetic": "real",
|
| 743 |
+
"platform": "ground",
|
| 744 |
+
"input_data_format": "jpg",
|
| 745 |
+
"annotation_format": "image",
|
| 746 |
+
"n_images": "126",
|
| 747 |
+
"docs_url": "",
|
| 748 |
+
"external_image_sources": [],
|
| 749 |
+
"stats": {
|
| 750 |
+
"mean": [
|
| 751 |
+
0.4455319046974182,
|
| 752 |
+
0.4638977646827698,
|
| 753 |
+
0.27496835589408875
|
| 754 |
+
],
|
| 755 |
+
"std": [
|
| 756 |
+
0.2677213251590729,
|
| 757 |
+
0.25918272137641907,
|
| 758 |
+
0.2625304162502289
|
| 759 |
+
]
|
| 760 |
+
},
|
| 761 |
+
"parent_dataset": "",
|
| 762 |
+
"extra_metadata": {}
|
| 763 |
+
},
|
| 764 |
+
"grape_detection_californianight": {
|
| 765 |
+
"classes": {
|
| 766 |
+
"1": "grape"
|
| 767 |
+
},
|
| 768 |
+
"ml_task": "object_detection",
|
| 769 |
+
"ag_task": "fruit_detection",
|
| 770 |
+
"location": {
|
| 771 |
+
"continent": "north_america",
|
| 772 |
+
"country": "usa"
|
| 773 |
+
},
|
| 774 |
+
"sensor_modality": "rgb",
|
| 775 |
+
"real_synthetic": "real",
|
| 776 |
+
"platform": "ground",
|
| 777 |
+
"input_data_format": "jpg",
|
| 778 |
+
"annotation_format": "image",
|
| 779 |
+
"n_images": "150",
|
| 780 |
+
"docs_url": "",
|
| 781 |
+
"external_image_sources": [],
|
| 782 |
+
"stats": {
|
| 783 |
+
"mean": [
|
| 784 |
+
0.22235676646232605,
|
| 785 |
+
0.21305303275585175,
|
| 786 |
+
0.22475562989711761
|
| 787 |
+
],
|
| 788 |
+
"std": [
|
| 789 |
+
0.20471057295799255,
|
| 790 |
+
0.20105913281440735,
|
| 791 |
+
0.20582404732704163
|
| 792 |
+
]
|
| 793 |
+
},
|
| 794 |
+
"parent_dataset": "",
|
| 795 |
+
"extra_metadata": {}
|
| 796 |
+
},
|
| 797 |
+
"guava_disease_pakistan": {
|
| 798 |
+
"classes": {
|
| 799 |
+
"0": "Canker",
|
| 800 |
+
"1": "Dot",
|
| 801 |
+
"2": "Mummification",
|
| 802 |
+
"3": "Rust"
|
| 803 |
+
},
|
| 804 |
+
"ml_task": "image_classification",
|
| 805 |
+
"ag_task": "disease_classification",
|
| 806 |
+
"location": {
|
| 807 |
+
"continent": "asia",
|
| 808 |
+
"country": "pakistan"
|
| 809 |
+
},
|
| 810 |
+
"sensor_modality": "rgb",
|
| 811 |
+
"platform": "ground",
|
| 812 |
+
"input_data_format": "jpg",
|
| 813 |
+
"annotation_format": "directory_names",
|
| 814 |
+
"n_images": "306",
|
| 815 |
+
"docs_url": "https://data.mendeley.com/datasets/s8x6jn5cvr/1",
|
| 816 |
+
"external_image_sources": [],
|
| 817 |
+
"stats": {
|
| 818 |
+
"mean": [
|
| 819 |
+
0.44554802775382996,
|
| 820 |
+
0.45087501406669617,
|
| 821 |
+
0.32288917899131775
|
| 822 |
+
],
|
| 823 |
+
"std": [
|
| 824 |
+
0.18661096692085266,
|
| 825 |
+
0.18359650671482086,
|
| 826 |
+
0.18744416534900665
|
| 827 |
+
]
|
| 828 |
+
},
|
| 829 |
+
"parent_dataset": "",
|
| 830 |
+
"extra_metadata": {}
|
| 831 |
+
},
|
| 832 |
+
"apple_detection_spain": {
|
| 833 |
+
"classes": {
|
| 834 |
+
"1": "apple"
|
| 835 |
+
},
|
| 836 |
+
"ml_task": "object_detection",
|
| 837 |
+
"ag_task": "fruit_detection",
|
| 838 |
+
"location": {
|
| 839 |
+
"continent": "europe",
|
| 840 |
+
"country": "spain"
|
| 841 |
+
},
|
| 842 |
+
"sensor_modality": "rgb",
|
| 843 |
+
"platform": "ground",
|
| 844 |
+
"input_data_format": "jpg",
|
| 845 |
+
"annotation_format": "coco_json",
|
| 846 |
+
"n_images": "967",
|
| 847 |
+
"docs_url": "https://www.grap.udl.cat/en/publications/KFuji_RGBDS_database.html",
|
| 848 |
+
"external_image_sources": [],
|
| 849 |
+
"stats": {
|
| 850 |
+
"mean": [
|
| 851 |
+
0.3745550215244293,
|
| 852 |
+
0.4699203670024872,
|
| 853 |
+
0.3931747078895569
|
| 854 |
+
],
|
| 855 |
+
"std": [
|
| 856 |
+
0.2724320888519287,
|
| 857 |
+
0.27973315119743347,
|
| 858 |
+
0.2829023003578186
|
| 859 |
+
]
|
| 860 |
+
},
|
| 861 |
+
"parent_dataset": "",
|
| 862 |
+
"extra_metadata": {}
|
| 863 |
+
},
|
| 864 |
+
"apple_detection_drone_brazil": {
|
| 865 |
+
"classes": {
|
| 866 |
+
"1": "apple"
|
| 867 |
+
},
|
| 868 |
+
"ml_task": "object_detection",
|
| 869 |
+
"ag_task": "fruit_detection",
|
| 870 |
+
"location": {
|
| 871 |
+
"continent": "south_america",
|
| 872 |
+
"country": "brazil"
|
| 873 |
+
},
|
| 874 |
+
"sensor_modality": "rgb",
|
| 875 |
+
"platform": "ground",
|
| 876 |
+
"input_data_format": "jpg",
|
| 877 |
+
"annotation_format": "coco_json",
|
| 878 |
+
"n_images": "689",
|
| 879 |
+
"docs_url": "https://github.com/thsant/add256/tree/zenodo-1.0",
|
| 880 |
+
"external_image_sources": [],
|
| 881 |
+
"stats": {
|
| 882 |
+
"mean": [
|
| 883 |
+
0.3362397849559784,
|
| 884 |
+
0.48177945613861084,
|
| 885 |
+
0.32026395201683044
|
| 886 |
+
],
|
| 887 |
+
"std": [
|
| 888 |
+
0.18435567617416382,
|
| 889 |
+
0.1873108297586441,
|
| 890 |
+
0.1734534204006195
|
| 891 |
+
]
|
| 892 |
+
},
|
| 893 |
+
"parent_dataset": "",
|
| 894 |
+
"extra_metadata": {}
|
| 895 |
+
},
|
| 896 |
+
"plant_doc_classification": {
|
| 897 |
+
"classes": {
|
| 898 |
+
"0": "Corn leaf blight",
|
| 899 |
+
"1": "Tomato Early blight leaf",
|
| 900 |
+
"2": "Potato leaf early blight",
|
| 901 |
+
"3": "Potato leaf late blight",
|
| 902 |
+
"4": "Blueberry leaf",
|
| 903 |
+
"5": "grape leaf black rot",
|
| 904 |
+
"6": "Bell_pepper leaf spot",
|
| 905 |
+
"7": "Cherry leaf",
|
| 906 |
+
"8": "Peach leaf",
|
| 907 |
+
"9": "Soyabean leaf",
|
| 908 |
+
"10": "Strawberry leaf",
|
| 909 |
+
"11": "Apple Scab Leaf",
|
| 910 |
+
"12": "Corn rust leaf",
|
| 911 |
+
"13": "Apple leaf",
|
| 912 |
+
"14": "Corn Gray leaf spot",
|
| 913 |
+
"15": "Tomato leaf mosaic virus",
|
| 914 |
+
"16": "Tomato mold leaf",
|
| 915 |
+
"17": "Tomato leaf yellow virus",
|
| 916 |
+
"18": "Tomato leaf bacterial spot",
|
| 917 |
+
"19": "Tomato leaf late blight",
|
| 918 |
+
"20": "Squash Powdery mildew leaf",
|
| 919 |
+
"21": "Bell_pepper leaf",
|
| 920 |
+
"22": "grape leaf",
|
| 921 |
+
"23": "Apple rust leaf",
|
| 922 |
+
"24": "Tomato Septoria leaf spot",
|
| 923 |
+
"25": "Tomato leaf",
|
| 924 |
+
"26": "Raspberry leaf",
|
| 925 |
+
"27": "Tomato two spotted spider mites leaf"
|
| 926 |
+
},
|
| 927 |
+
"ml_task": "image_classification",
|
| 928 |
+
"ag_task": "disease_classification",
|
| 929 |
+
"location": {
|
| 930 |
+
"continent": "worldwide",
|
| 931 |
+
"country": "worldwide"
|
| 932 |
+
},
|
| 933 |
+
"sensor_modality": "rgb",
|
| 934 |
+
"real_synthetic": "real",
|
| 935 |
+
"platform": "ground",
|
| 936 |
+
"input_data_format": "jpg",
|
| 937 |
+
"annotation_format": "directory_names",
|
| 938 |
+
"n_images": "2598",
|
| 939 |
+
"docs_url": "https://github.com/pratikkayal/PlantDoc-Dataset",
|
| 940 |
+
"external_image_sources": [],
|
| 941 |
+
"stats": {
|
| 942 |
+
"mean": [
|
| 943 |
+
0.48221418261528015,
|
| 944 |
+
0.549874484539032,
|
| 945 |
+
0.3833079934120178
|
| 946 |
+
],
|
| 947 |
+
"std": [
|
| 948 |
+
0.21240688860416412,
|
| 949 |
+
0.2036021202802658,
|
| 950 |
+
0.22107268869876862
|
| 951 |
+
]
|
| 952 |
+
},
|
| 953 |
+
"parent_dataset": "",
|
| 954 |
+
"extra_metadata": {}
|
| 955 |
+
},
|
| 956 |
+
"plant_doc_detection": {
|
| 957 |
+
"classes": {
|
| 958 |
+
"1": "Corn leaf blight",
|
| 959 |
+
"2": "Tomato Early blight leaf",
|
| 960 |
+
"3": "Potato leaf early blight",
|
| 961 |
+
"4": "Potato leaf late blight",
|
| 962 |
+
"5": "Blueberry leaf",
|
| 963 |
+
"6": "grape leaf black rot",
|
| 964 |
+
"7": "Bell_pepper leaf spot",
|
| 965 |
+
"8": "Cherry leaf",
|
| 966 |
+
"9": "Peach leaf",
|
| 967 |
+
"10": "Soyabean leaf",
|
| 968 |
+
"11": "Strawberry leaf",
|
| 969 |
+
"12": "Apple Scab Leaf",
|
| 970 |
+
"13": "Corn rust leaf",
|
| 971 |
+
"14": "Apple leaf",
|
| 972 |
+
"15": "Corn Gray leaf spot",
|
| 973 |
+
"16": "Tomato leaf mosaic virus",
|
| 974 |
+
"17": "Tomato mold leaf",
|
| 975 |
+
"18": "Tomato leaf yellow virus",
|
| 976 |
+
"19": "Tomato leaf bacterial spot",
|
| 977 |
+
"20": "Tomato leaf late blight",
|
| 978 |
+
"21": "Squash Powdery mildew leaf",
|
| 979 |
+
"22": "Bell_pepper leaf",
|
| 980 |
+
"23": "grape leaf",
|
| 981 |
+
"24": "Apple rust leaf",
|
| 982 |
+
"25": "Tomato Septoria leaf spot",
|
| 983 |
+
"26": "Tomato leaf",
|
| 984 |
+
"27": "Raspberry leaf",
|
| 985 |
+
"28": "Potato leaf",
|
| 986 |
+
"29": "Tomato two spotted spider mites leaf"
|
| 987 |
+
},
|
| 988 |
+
"ml_task": "object_detection",
|
| 989 |
+
"ag_task": "disease_detection",
|
| 990 |
+
"location": {
|
| 991 |
+
"continent": "worldwide",
|
| 992 |
+
"country": "worldwide"
|
| 993 |
+
},
|
| 994 |
+
"sensor_modality": "rgb",
|
| 995 |
+
"real_synthetic": "real",
|
| 996 |
+
"platform": "ground",
|
| 997 |
+
"input_data_format": "jpg",
|
| 998 |
+
"annotation_format": "coco_json",
|
| 999 |
+
"n_images": "2346",
|
| 1000 |
+
"docs_url": "https://github.com/pratikkayal/PlantDoc-Object-Detection-Dataset",
|
| 1001 |
+
"external_image_sources": [],
|
| 1002 |
+
"stats": {
|
| 1003 |
+
"mean": [
|
| 1004 |
+
0.4765770733356476,
|
| 1005 |
+
0.5437355637550354,
|
| 1006 |
+
0.3779796361923218
|
| 1007 |
+
],
|
| 1008 |
+
"std": [
|
| 1009 |
+
0.21106934547424316,
|
| 1010 |
+
0.2036709189414978,
|
| 1011 |
+
0.21807792782783508
|
| 1012 |
+
]
|
| 1013 |
+
},
|
| 1014 |
+
"parent_dataset": "",
|
| 1015 |
+
"extra_metadata": {}
|
| 1016 |
+
},
|
| 1017 |
+
"wheat_head_counting": {
|
| 1018 |
+
"classes": {
|
| 1019 |
+
"1": "Wheat Head"
|
| 1020 |
+
},
|
| 1021 |
+
"ml_task": "object_detection",
|
| 1022 |
+
"ag_task": "wheat_head_counting",
|
| 1023 |
+
"location": {
|
| 1024 |
+
"continent": "worldwide",
|
| 1025 |
+
"country": "worldwide"
|
| 1026 |
+
},
|
| 1027 |
+
"sensor_modality": "rgb",
|
| 1028 |
+
"real_synthetic": "real",
|
| 1029 |
+
"platform": "ground",
|
| 1030 |
+
"input_data_format": "jpg",
|
| 1031 |
+
"annotation_format": "coco_json",
|
| 1032 |
+
"n_images": "6512",
|
| 1033 |
+
"docs_url": "https://zenodo.org/record/5092309",
|
| 1034 |
+
"external_image_sources": [],
|
| 1035 |
+
"stats": {
|
| 1036 |
+
"mean": [
|
| 1037 |
+
0.371184766292572,
|
| 1038 |
+
0.36074304580688477,
|
| 1039 |
+
0.23014496266841888
|
| 1040 |
+
],
|
| 1041 |
+
"std": [
|
| 1042 |
+
0.2190379649400711,
|
| 1043 |
+
0.21708978712558746,
|
| 1044 |
+
0.17700935900211334
|
| 1045 |
+
]
|
| 1046 |
+
},
|
| 1047 |
+
"parent_dataset": "",
|
| 1048 |
+
"extra_metadata": {}
|
| 1049 |
+
},
|
| 1050 |
+
"peachpear_flower_segmentation": {
|
| 1051 |
+
"classes": {
|
| 1052 |
+
"1": "Flower"
|
| 1053 |
+
},
|
| 1054 |
+
"ml_task": "semantic_segmentation",
|
| 1055 |
+
"ag_task": "flower_segmentation",
|
| 1056 |
+
"location": {
|
| 1057 |
+
"continent": "worldwide",
|
| 1058 |
+
"country": "worldwide"
|
| 1059 |
+
},
|
| 1060 |
+
"sensor_modality": "rgb",
|
| 1061 |
+
"real_synthetic": "real",
|
| 1062 |
+
"platform": "handheld/ground",
|
| 1063 |
+
"input_data_format": "jpg",
|
| 1064 |
+
"annotation_format": "image",
|
| 1065 |
+
"n_images": "42",
|
| 1066 |
+
"docs_url": "https://data.nal.usda.gov/dataset/data-multi-species-fruit-flower-detection-using-refined-semantic-segmentation-network",
|
| 1067 |
+
"external_image_sources": [],
|
| 1068 |
+
"stats": {
|
| 1069 |
+
"mean": [
|
| 1070 |
+
0.4377596378326416,
|
| 1071 |
+
0.4347001910209656,
|
| 1072 |
+
0.4147627353668213
|
| 1073 |
+
],
|
| 1074 |
+
"std": [
|
| 1075 |
+
0.20811232924461365,
|
| 1076 |
+
0.2141699343919754,
|
| 1077 |
+
0.2441396266222
|
| 1078 |
+
]
|
| 1079 |
+
},
|
| 1080 |
+
"parent_dataset": "",
|
| 1081 |
+
"extra_metadata": {}
|
| 1082 |
+
},
|
| 1083 |
+
"red_grapes_and_leaves_segmentation": {
|
| 1084 |
+
"classes": {
|
| 1085 |
+
"1": "Leaf",
|
| 1086 |
+
"2": "Grape"
|
| 1087 |
+
},
|
| 1088 |
+
"ml_task": "semantic_segmentation",
|
| 1089 |
+
"ag_task": "vineyard_scene_segmentation",
|
| 1090 |
+
"location": {
|
| 1091 |
+
"continent": "europe",
|
| 1092 |
+
"country": "greece"
|
| 1093 |
+
},
|
| 1094 |
+
"sensor_modality": "rgb",
|
| 1095 |
+
"real_synthetic": "real",
|
| 1096 |
+
"platform": "handheld/ground",
|
| 1097 |
+
"input_data_format": "jpg",
|
| 1098 |
+
"annotation_format": "image",
|
| 1099 |
+
"n_images": "258",
|
| 1100 |
+
"docs_url": "https://link.springer.com/chapter/10.1007/978-3-030-48791-1_22",
|
| 1101 |
+
"external_image_sources": [],
|
| 1102 |
+
"stats": {
|
| 1103 |
+
"mean": [
|
| 1104 |
+
0.392019122838974,
|
| 1105 |
+
0.49319183826446533,
|
| 1106 |
+
0.5254659056663513
|
| 1107 |
+
],
|
| 1108 |
+
"std": [
|
| 1109 |
+
0.2721235156059265,
|
| 1110 |
+
0.2871488034725189,
|
| 1111 |
+
0.2831265926361084
|
| 1112 |
+
]
|
| 1113 |
+
},
|
| 1114 |
+
"parent_dataset": "",
|
| 1115 |
+
"extra_metadata": {}
|
| 1116 |
+
},
|
| 1117 |
+
"white_grapes_and_leaves_segmentation": {
|
| 1118 |
+
"classes": {
|
| 1119 |
+
"1": "Leaf",
|
| 1120 |
+
"2": "Grape"
|
| 1121 |
+
},
|
| 1122 |
+
"ml_task": "semantic_segmentation",
|
| 1123 |
+
"ag_task": "vineyard_scene_segmentation",
|
| 1124 |
+
"location": {
|
| 1125 |
+
"continent": "europe",
|
| 1126 |
+
"country": "greece"
|
| 1127 |
+
},
|
| 1128 |
+
"sensor_modality": "rgb",
|
| 1129 |
+
"real_synthetic": "real",
|
| 1130 |
+
"platform": "handheld/ground",
|
| 1131 |
+
"input_data_format": "jpg",
|
| 1132 |
+
"annotation_format": "image",
|
| 1133 |
+
"n_images": "273",
|
| 1134 |
+
"docs_url": "https://link.springer.com/chapter/10.1007/978-3-030-48791-1_22",
|
| 1135 |
+
"external_image_sources": [],
|
| 1136 |
+
"stats": {
|
| 1137 |
+
"mean": [
|
| 1138 |
+
0.30906906723976135,
|
| 1139 |
+
0.47296029329299927,
|
| 1140 |
+
0.5238653421401978
|
| 1141 |
+
],
|
| 1142 |
+
"std": [
|
| 1143 |
+
0.23329640924930573,
|
| 1144 |
+
0.24588093161582947,
|
| 1145 |
+
0.25335168838500977
|
| 1146 |
+
]
|
| 1147 |
+
},
|
| 1148 |
+
"parent_dataset": "",
|
| 1149 |
+
"extra_metadata": {}
|
| 1150 |
+
},
|
| 1151 |
+
"ghai_romaine_detection": {
|
| 1152 |
+
"classes": {
|
| 1153 |
+
"1": "romaine"
|
| 1154 |
+
},
|
| 1155 |
+
"ml_task": "object_detection",
|
| 1156 |
+
"ag_task": "crop_detection",
|
| 1157 |
+
"location": {
|
| 1158 |
+
"continent": "north_america",
|
| 1159 |
+
"country": "usa"
|
| 1160 |
+
},
|
| 1161 |
+
"sensor_modality": "rgb",
|
| 1162 |
+
"real_synthetic": "real",
|
| 1163 |
+
"platform": "handheld/ground",
|
| 1164 |
+
"input_data_format": "jpg",
|
| 1165 |
+
"annotation_format": "coco_json",
|
| 1166 |
+
"n_images": "500",
|
| 1167 |
+
"docs_url": "https://github.com/AxisAg/GHAIDatasets/blob/main/datasets/romaine.md",
|
| 1168 |
+
"external_image_sources": [],
|
| 1169 |
+
"stats": {
|
| 1170 |
+
"mean": [
|
| 1171 |
+
0.3551516532897949,
|
| 1172 |
+
0.4719887971878052,
|
| 1173 |
+
0.33378446102142334
|
| 1174 |
+
],
|
| 1175 |
+
"std": [
|
| 1176 |
+
0.253168523311615,
|
| 1177 |
+
0.26515713334083557,
|
| 1178 |
+
0.2393222600221634
|
| 1179 |
+
]
|
| 1180 |
+
},
|
| 1181 |
+
"parent_dataset": "",
|
| 1182 |
+
"extra_metadata": {}
|
| 1183 |
+
},
|
| 1184 |
+
"ghai_green_cabbage_detection": {
|
| 1185 |
+
"classes": {
|
| 1186 |
+
"1": "green_cabbage"
|
| 1187 |
+
},
|
| 1188 |
+
"ml_task": "object_detection",
|
| 1189 |
+
"ag_task": "crop_detection",
|
| 1190 |
+
"location": {
|
| 1191 |
+
"continent": "north_america",
|
| 1192 |
+
"country": "usa"
|
| 1193 |
+
},
|
| 1194 |
+
"sensor_modality": "rgb",
|
| 1195 |
+
"real_synthetic": "real",
|
| 1196 |
+
"platform": "handheld/ground",
|
| 1197 |
+
"input_data_format": "jpg",
|
| 1198 |
+
"annotation_format": "coco_json",
|
| 1199 |
+
"n_images": "500",
|
| 1200 |
+
"docs_url": "https://github.com/AxisAg/GHAIDatasets/blob/main/datasets/green_cabbage.md",
|
| 1201 |
+
"external_image_sources": [],
|
| 1202 |
+
"stats": {
|
| 1203 |
+
"mean": [
|
| 1204 |
+
0.4649180769920349,
|
| 1205 |
+
0.49569201469421387,
|
| 1206 |
+
0.46829652786254883
|
| 1207 |
+
],
|
| 1208 |
+
"std": [
|
| 1209 |
+
0.28846681118011475,
|
| 1210 |
+
0.27976617217063904,
|
| 1211 |
+
0.276553213596344
|
| 1212 |
+
]
|
| 1213 |
+
},
|
| 1214 |
+
"parent_dataset": "",
|
| 1215 |
+
"extra_metadata": {}
|
| 1216 |
+
},
|
| 1217 |
+
"ghai_iceberg_lettuce_detection": {
|
| 1218 |
+
"classes": {
|
| 1219 |
+
"1": "iceberg_lettuce"
|
| 1220 |
+
},
|
| 1221 |
+
"ml_task": "object_detection",
|
| 1222 |
+
"ag_task": "crop_detection",
|
| 1223 |
+
"location": {
|
| 1224 |
+
"continent": "north_america",
|
| 1225 |
+
"country": "usa"
|
| 1226 |
+
},
|
| 1227 |
+
"sensor_modality": "rgb",
|
| 1228 |
+
"real_synthetic": "real",
|
| 1229 |
+
"platform": "handheld/ground",
|
| 1230 |
+
"input_data_format": "jpg",
|
| 1231 |
+
"annotation_format": "coco_json",
|
| 1232 |
+
"n_images": "500",
|
| 1233 |
+
"docs_url": "https://github.com/AxisAg/GHAIDatasets/blob/main/datasets/iceberg.md",
|
| 1234 |
+
"external_image_sources": [],
|
| 1235 |
+
"stats": {
|
| 1236 |
+
"mean": [
|
| 1237 |
+
0.3193310499191284,
|
| 1238 |
+
0.4143226742744446,
|
| 1239 |
+
0.3003973960876465
|
| 1240 |
+
],
|
| 1241 |
+
"std": [
|
| 1242 |
+
0.2828165590763092,
|
| 1243 |
+
0.2841264605522156,
|
| 1244 |
+
0.25660744309425354
|
| 1245 |
+
]
|
| 1246 |
+
},
|
| 1247 |
+
"parent_dataset": "",
|
| 1248 |
+
"extra_metadata": {}
|
| 1249 |
+
},
|
| 1250 |
+
"riseholme_strawberry_classification_2021": {
|
| 1251 |
+
"classes": {
|
| 1252 |
+
"0": "anomalous",
|
| 1253 |
+
"1": "occluded",
|
| 1254 |
+
"2": "ripe",
|
| 1255 |
+
"3": "unripe"
|
| 1256 |
+
},
|
| 1257 |
+
"ml_task": "image_classification",
|
| 1258 |
+
"ag_task": "disease_classification",
|
| 1259 |
+
"sensor_modality": "rgb",
|
| 1260 |
+
"real_synthetic": "real",
|
| 1261 |
+
"platform": "ground",
|
| 1262 |
+
"input_data_format": "png",
|
| 1263 |
+
"annotation_format": "directory_names",
|
| 1264 |
+
"n_images": "3520",
|
| 1265 |
+
"docs_url": "https://github.com/ctyeong/Riseholme-2021",
|
| 1266 |
+
"location": {
|
| 1267 |
+
"continent": "europe",
|
| 1268 |
+
"country": "uk"
|
| 1269 |
+
},
|
| 1270 |
+
"external_image_sources": [],
|
| 1271 |
+
"stats": {
|
| 1272 |
+
"mean": [
|
| 1273 |
+
0.5753851532936096,
|
| 1274 |
+
0.46378713846206665,
|
| 1275 |
+
0.36370429396629333
|
| 1276 |
+
],
|
| 1277 |
+
"std": [
|
| 1278 |
+
0.19837889075279236,
|
| 1279 |
+
0.19222107529640198,
|
| 1280 |
+
0.1773509532213211
|
| 1281 |
+
]
|
| 1282 |
+
},
|
| 1283 |
+
"parent_dataset": "",
|
| 1284 |
+
"extra_metadata": {}
|
| 1285 |
+
},
|
| 1286 |
+
"ghai_broccoli_detection": {
|
| 1287 |
+
"classes": {
|
| 1288 |
+
"1": "canopy",
|
| 1289 |
+
"2": "crown"
|
| 1290 |
+
},
|
| 1291 |
+
"ml_task": "object_detection",
|
| 1292 |
+
"ag_task": "crop_detection",
|
| 1293 |
+
"location": {
|
| 1294 |
+
"continent": "north_america",
|
| 1295 |
+
"country": "usa"
|
| 1296 |
+
},
|
| 1297 |
+
"sensor_modality": "rgb",
|
| 1298 |
+
"real_synthetic": "real",
|
| 1299 |
+
"platform": "handheld/ground",
|
| 1300 |
+
"input_data_format": "jpg",
|
| 1301 |
+
"annotation_format": "coco_json",
|
| 1302 |
+
"n_images": "500",
|
| 1303 |
+
"docs_url": "https://github.com/AxisAg/GHAIDatasets/blob/main/datasets/broccoli.md",
|
| 1304 |
+
"external_image_sources": [],
|
| 1305 |
+
"stats": {
|
| 1306 |
+
"mean": [
|
| 1307 |
+
0.42832377552986145,
|
| 1308 |
+
0.45015057921409607,
|
| 1309 |
+
0.43816232681274414
|
| 1310 |
+
],
|
| 1311 |
+
"std": [
|
| 1312 |
+
0.24546495079994202,
|
| 1313 |
+
0.23975253105163574,
|
| 1314 |
+
0.23829665780067444
|
| 1315 |
+
]
|
| 1316 |
+
},
|
| 1317 |
+
"parent_dataset": "",
|
| 1318 |
+
"extra_metadata": {}
|
| 1319 |
+
},
|
| 1320 |
+
"bean_synthetic_earlygrowth_aerial": {
|
| 1321 |
+
"classes": {
|
| 1322 |
+
"1": "leaves",
|
| 1323 |
+
"2": "branches"
|
| 1324 |
+
},
|
| 1325 |
+
"ml_task": "semantic_segmentation",
|
| 1326 |
+
"ag_task": "plant_segmentation",
|
| 1327 |
+
"location": {
|
| 1328 |
+
"continent": "digital",
|
| 1329 |
+
"country": "digital"
|
| 1330 |
+
},
|
| 1331 |
+
"sensor_modality": "rgb",
|
| 1332 |
+
"real_synthetic": "synthetic",
|
| 1333 |
+
"platform": "aerial",
|
| 1334 |
+
"input_data_format": "jpg",
|
| 1335 |
+
"annotation_format": "image",
|
| 1336 |
+
"n_images": "2500",
|
| 1337 |
+
"docs_url": "https://github.com/Project-AgML/AgML/blob/main/docs/datasets/bean_synthetic_earlygrowth_aerial.md",
|
| 1338 |
+
"external_image_sources": [],
|
| 1339 |
+
"stats": {
|
| 1340 |
+
"mean": [
|
| 1341 |
+
0.24804304540157318,
|
| 1342 |
+
0.2218194305896759,
|
| 1343 |
+
0.16611839830875397
|
| 1344 |
+
],
|
| 1345 |
+
"std": [
|
| 1346 |
+
0.10789012163877487,
|
| 1347 |
+
0.12054657936096191,
|
| 1348 |
+
0.08992248773574829
|
| 1349 |
+
]
|
| 1350 |
+
},
|
| 1351 |
+
"parent_dataset": "",
|
| 1352 |
+
"extra_metadata": {}
|
| 1353 |
+
},
|
| 1354 |
+
"ghai_strawberry_fruit_detection": {
|
| 1355 |
+
"classes": {
|
| 1356 |
+
"1": "Bud",
|
| 1357 |
+
"2": "Calyx",
|
| 1358 |
+
"3": "Detached Fruit",
|
| 1359 |
+
"4": "Flower",
|
| 1360 |
+
"5": "Large green",
|
| 1361 |
+
"6": "Leaf",
|
| 1362 |
+
"7": "Ripe fruit",
|
| 1363 |
+
"8": "Small Green",
|
| 1364 |
+
"9": "Stem",
|
| 1365 |
+
"10": "Unripe fruit"
|
| 1366 |
+
},
|
| 1367 |
+
"ml_task": "object_detection",
|
| 1368 |
+
"ag_task": "crop_detection",
|
| 1369 |
+
"location": {
|
| 1370 |
+
"continent": "north_america",
|
| 1371 |
+
"country": "usa"
|
| 1372 |
+
},
|
| 1373 |
+
"sensor_modality": "rgb",
|
| 1374 |
+
"real_synthetic": "real",
|
| 1375 |
+
"platform": "handheld/ground",
|
| 1376 |
+
"input_data_format": "jpg",
|
| 1377 |
+
"annotation_format": "coco_json",
|
| 1378 |
+
"n_images": "500",
|
| 1379 |
+
"docs_url": "https://github.com/AxisAg/GHAIDatasets/blob/main/datasets/strawberry.md",
|
| 1380 |
+
"external_image_sources": [],
|
| 1381 |
+
"stats": {
|
| 1382 |
+
"mean": [
|
| 1383 |
+
0.49159616231918335,
|
| 1384 |
+
0.5238277316093445,
|
| 1385 |
+
0.4485996663570404
|
| 1386 |
+
],
|
| 1387 |
+
"std": [
|
| 1388 |
+
0.18163496255874634,
|
| 1389 |
+
0.16137710213661194,
|
| 1390 |
+
0.18042609095573425
|
| 1391 |
+
]
|
| 1392 |
+
},
|
| 1393 |
+
"parent_dataset": "",
|
| 1394 |
+
"extra_metadata": {}
|
| 1395 |
+
},
|
| 1396 |
+
"vegann_multicrop_presence_segmentation": {
|
| 1397 |
+
"classes": {
|
| 1398 |
+
"1": "plant"
|
| 1399 |
+
},
|
| 1400 |
+
"ml_task": "semantic_segmentation",
|
| 1401 |
+
"ag_task": "vegetation_segmentation",
|
| 1402 |
+
"location": {
|
| 1403 |
+
"continent": "worldwide",
|
| 1404 |
+
"country": "worldwide"
|
| 1405 |
+
},
|
| 1406 |
+
"sensor_modality": "rgb",
|
| 1407 |
+
"real_synthetic": "real",
|
| 1408 |
+
"platform": "aerial",
|
| 1409 |
+
"input_data_format": "png",
|
| 1410 |
+
"annotation_format": "image",
|
| 1411 |
+
"n_images": "3775",
|
| 1412 |
+
"docs_url": "https://zenodo.org/records/7636408",
|
| 1413 |
+
"stats": {
|
| 1414 |
+
"mean": [
|
| 1415 |
+
16.391704559326172,
|
| 1416 |
+
18.685382843017578,
|
| 1417 |
+
14.235113143920898
|
| 1418 |
+
],
|
| 1419 |
+
"std": [
|
| 1420 |
+
4.5903120040893555,
|
| 1421 |
+
5.818264007568359,
|
| 1422 |
+
4.189508438110352
|
| 1423 |
+
]
|
| 1424 |
+
},
|
| 1425 |
+
"parent_dataset": "",
|
| 1426 |
+
"extra_metadata": {}
|
| 1427 |
+
},
|
| 1428 |
+
"corn_maize_leaf_disease": {
|
| 1429 |
+
"classes": {
|
| 1430 |
+
"0": "Blight",
|
| 1431 |
+
"1": "Common_Rust",
|
| 1432 |
+
"2": "Gray_Leaf_Spot",
|
| 1433 |
+
"3": "Healthy"
|
| 1434 |
+
},
|
| 1435 |
+
"ml_task": "image_classification",
|
| 1436 |
+
"ag_task": "disease_classification",
|
| 1437 |
+
"location": {
|
| 1438 |
+
"continent": "worldwide",
|
| 1439 |
+
"country": "worldwide"
|
| 1440 |
+
},
|
| 1441 |
+
"sensor_modality": "rgb",
|
| 1442 |
+
"real_synthetic": "real",
|
| 1443 |
+
"platform": "handheld",
|
| 1444 |
+
"input_data_format": [
|
| 1445 |
+
"jpg",
|
| 1446 |
+
"png",
|
| 1447 |
+
"jpeg",
|
| 1448 |
+
"JPG"
|
| 1449 |
+
],
|
| 1450 |
+
"annotation_format": "directory_names",
|
| 1451 |
+
"n_images": "4188",
|
| 1452 |
+
"docs_url": "https://www.kaggle.com/datasets/smaranjitghose/corn-or-maize-leaf-disease-dataset/data",
|
| 1453 |
+
"stats": {
|
| 1454 |
+
"mean": [
|
| 1455 |
+
0.4375976622104645,
|
| 1456 |
+
0.49800175428390503,
|
| 1457 |
+
0.3756123483181
|
| 1458 |
+
],
|
| 1459 |
+
"std": [
|
| 1460 |
+
0.17942173779010773,
|
| 1461 |
+
0.1671891063451767,
|
| 1462 |
+
0.17422494292259216
|
| 1463 |
+
]
|
| 1464 |
+
},
|
| 1465 |
+
"parent_dataset": "",
|
| 1466 |
+
"extra_metadata": {}
|
| 1467 |
+
},
|
| 1468 |
+
"tomato_leaf_disease": {
|
| 1469 |
+
"classes": {
|
| 1470 |
+
"0": "Bacterial Spot",
|
| 1471 |
+
"1": "Early Blight",
|
| 1472 |
+
"2": "Healthy",
|
| 1473 |
+
"3": "Late Blight",
|
| 1474 |
+
"4": "Leaf Mold",
|
| 1475 |
+
"5": "Septoria Leaf Spot",
|
| 1476 |
+
"6": "Spider Mites Two-spotted Spider Mite",
|
| 1477 |
+
"7": "Target Spot",
|
| 1478 |
+
"8": "Tomato Mosaic Virus",
|
| 1479 |
+
"9": "Tomato Yellow Leaf Curl Virus"
|
| 1480 |
+
},
|
| 1481 |
+
"ml_task": "image_classification",
|
| 1482 |
+
"ag_task": "disease_classification",
|
| 1483 |
+
"location": {
|
| 1484 |
+
"continent": "worldwide",
|
| 1485 |
+
"country": "worldwide"
|
| 1486 |
+
},
|
| 1487 |
+
"sensor_modality": "rgb",
|
| 1488 |
+
"real_synthetic": "real",
|
| 1489 |
+
"platform": "handheld",
|
| 1490 |
+
"input_data_format": [
|
| 1491 |
+
"jpeg"
|
| 1492 |
+
],
|
| 1493 |
+
"annotation_format": "directory_names",
|
| 1494 |
+
"n_images": "11000",
|
| 1495 |
+
"docs_url": "https://www.kaggle.com/datasets/kaustubhb999/tomatoleaf?resource=download",
|
| 1496 |
+
"stats": {
|
| 1497 |
+
"mean": [
|
| 1498 |
+
0.4527473449707031,
|
| 1499 |
+
0.4633065462112427,
|
| 1500 |
+
0.41868826746940613
|
| 1501 |
+
],
|
| 1502 |
+
"std": [
|
| 1503 |
+
0.16920849680900574,
|
| 1504 |
+
0.1477183699607849,
|
| 1505 |
+
0.18538573384284973
|
| 1506 |
+
]
|
| 1507 |
+
},
|
| 1508 |
+
"parent_dataset": "",
|
| 1509 |
+
"extra_metadata": {}
|
| 1510 |
+
},
|
| 1511 |
+
"vine_virus_photo_dataset": {
|
| 1512 |
+
"classes": {
|
| 1513 |
+
"0": "Leafroll 3",
|
| 1514 |
+
"1": "No Virus",
|
| 1515 |
+
"2": "Other Red",
|
| 1516 |
+
"3": "Red Blotch"
|
| 1517 |
+
},
|
| 1518 |
+
"ml_task": "image_classification",
|
| 1519 |
+
"ag_task": "disease_classification",
|
| 1520 |
+
"location": {
|
| 1521 |
+
"continent": "worldwide",
|
| 1522 |
+
"country": "worldwide"
|
| 1523 |
+
},
|
| 1524 |
+
"sensor_modality": "rgb",
|
| 1525 |
+
"real_synthetic": "real",
|
| 1526 |
+
"platform": "handheld/ground",
|
| 1527 |
+
"input_data_format": [
|
| 1528 |
+
"jpg",
|
| 1529 |
+
"png",
|
| 1530 |
+
"jpeg",
|
| 1531 |
+
"JPG"
|
| 1532 |
+
],
|
| 1533 |
+
"annotation_format": "directory_names",
|
| 1534 |
+
"n_images": "3866",
|
| 1535 |
+
"docs_url": "",
|
| 1536 |
+
"stats": {
|
| 1537 |
+
"mean": [
|
| 1538 |
+
0.44989314675331116,
|
| 1539 |
+
0.4489104151725769,
|
| 1540 |
+
0.29500243067741394
|
| 1541 |
+
],
|
| 1542 |
+
"std": [
|
| 1543 |
+
0.2310592532157898,
|
| 1544 |
+
0.2280450314283371,
|
| 1545 |
+
0.23016904294490814
|
| 1546 |
+
]
|
| 1547 |
+
},
|
| 1548 |
+
"parent_dataset": "",
|
| 1549 |
+
"extra_metadata": {}
|
| 1550 |
+
},
|
| 1551 |
+
"embrapa_wgisd_grape_detection": {
|
| 1552 |
+
"classes": {
|
| 1553 |
+
"0": "Chardonnay",
|
| 1554 |
+
"1": "PinotGris",
|
| 1555 |
+
"2": "PinotNoir"
|
| 1556 |
+
},
|
| 1557 |
+
"ml_task": "object_detection",
|
| 1558 |
+
"ag_task": "fruit_detection",
|
| 1559 |
+
"location": {
|
| 1560 |
+
"continent": "worldwide",
|
| 1561 |
+
"country": "worldwide"
|
| 1562 |
+
},
|
| 1563 |
+
"sensor_modality": "rgb",
|
| 1564 |
+
"real_synthetic": "real",
|
| 1565 |
+
"platform": "handheld/ground",
|
| 1566 |
+
"input_data_format": "jpg",
|
| 1567 |
+
"annotation_format": "coco_json",
|
| 1568 |
+
"n_images": "239",
|
| 1569 |
+
"docs_url": "https://github.com/thsant/wgisd/tree/master",
|
| 1570 |
+
"external_image_sources": [],
|
| 1571 |
+
"stats": {
|
| 1572 |
+
"mean": [
|
| 1573 |
+
0.5015993118286133,
|
| 1574 |
+
0.5361655354499817,
|
| 1575 |
+
0.4303760826587677
|
| 1576 |
+
],
|
| 1577 |
+
"std": [
|
| 1578 |
+
0.2352389246225357,
|
| 1579 |
+
0.2119981199502945,
|
| 1580 |
+
0.2218495011329651
|
| 1581 |
+
]
|
| 1582 |
+
},
|
| 1583 |
+
"parent_dataset": "",
|
| 1584 |
+
"extra_metadata": {}
|
| 1585 |
+
},
|
| 1586 |
+
"growliflower_cauliflower_segmentation": {
|
| 1587 |
+
"classes": {
|
| 1588 |
+
"1": "maskLeaves",
|
| 1589 |
+
"2": "maskPlants",
|
| 1590 |
+
"3": "maskStems",
|
| 1591 |
+
"4": "maskVoid"
|
| 1592 |
+
},
|
| 1593 |
+
"ml_task": "semantic_segmentation",
|
| 1594 |
+
"ag_task": "crop_segmentation",
|
| 1595 |
+
"location": {
|
| 1596 |
+
"continent": "worldwide",
|
| 1597 |
+
"country": "worldwide"
|
| 1598 |
+
},
|
| 1599 |
+
"sensor_modality": "rgb",
|
| 1600 |
+
"real_synthetic": "real",
|
| 1601 |
+
"platform": "handheld/ground",
|
| 1602 |
+
"input_data_format": "jpg",
|
| 1603 |
+
"annotation_format": "image",
|
| 1604 |
+
"n_images": "1542",
|
| 1605 |
+
"docs_url": "https://phenoroam.phenorob.de/geonetwork/srv/eng/catalog.search#/metadata/cb328232-31f5-4b84-a929-8e1ee551d66a",
|
| 1606 |
+
"stats": {
|
| 1607 |
+
"mean": [
|
| 1608 |
+
0.48514866828918457,
|
| 1609 |
+
0.4264565408229828,
|
| 1610 |
+
0.33096641302108765
|
| 1611 |
+
],
|
| 1612 |
+
"std": [
|
| 1613 |
+
0.12302214652299881,
|
| 1614 |
+
0.1260126680135727,
|
| 1615 |
+
0.11423511058092117
|
| 1616 |
+
]
|
| 1617 |
+
},
|
| 1618 |
+
"parent_dataset": "",
|
| 1619 |
+
"extra_metadata": {}
|
| 1620 |
+
},
|
| 1621 |
+
"strawberry_detection_2023": {
|
| 1622 |
+
"classes": {
|
| 1623 |
+
"0": "strawberry",
|
| 1624 |
+
"1": "flower",
|
| 1625 |
+
"2": "green",
|
| 1626 |
+
"3": "large_white",
|
| 1627 |
+
"4": "pink",
|
| 1628 |
+
"5": "red",
|
| 1629 |
+
"6": "small_white"
|
| 1630 |
+
},
|
| 1631 |
+
"ml_task": "object_detection",
|
| 1632 |
+
"ag_task": "fruit_detection",
|
| 1633 |
+
"location": {
|
| 1634 |
+
"continent": "north_america",
|
| 1635 |
+
"country": "usa"
|
| 1636 |
+
},
|
| 1637 |
+
"sensor_modality": "rgb",
|
| 1638 |
+
"real_synthetic": "real",
|
| 1639 |
+
"platform": "handheld/ground",
|
| 1640 |
+
"annotation_format": "coco_json",
|
| 1641 |
+
"input_data_format": "jpg",
|
| 1642 |
+
"n_images": "204",
|
| 1643 |
+
"docs_url": "https://universe.roboflow.com/strawberrydet/strawberry_2023/3",
|
| 1644 |
+
"external_image_sources": [],
|
| 1645 |
+
"stats": {
|
| 1646 |
+
"mean": [
|
| 1647 |
+
0.2719569802284241,
|
| 1648 |
+
0.2755374312400818,
|
| 1649 |
+
0.2003764510154724
|
| 1650 |
+
],
|
| 1651 |
+
"std": [
|
| 1652 |
+
0.14823083579540253,
|
| 1653 |
+
0.1477075070142746,
|
| 1654 |
+
0.14832836389541626
|
| 1655 |
+
]
|
| 1656 |
+
},
|
| 1657 |
+
"parent_dataset": "",
|
| 1658 |
+
"extra_metadata": {}
|
| 1659 |
+
},
|
| 1660 |
+
"strawberry_detection_2022": {
|
| 1661 |
+
"classes": {
|
| 1662 |
+
"0": "strawberry",
|
| 1663 |
+
"1": "flower",
|
| 1664 |
+
"2": "green",
|
| 1665 |
+
"3": "large_white",
|
| 1666 |
+
"4": "pink",
|
| 1667 |
+
"5": "red",
|
| 1668 |
+
"6": "small_white"
|
| 1669 |
+
},
|
| 1670 |
+
"ml_task": "object_detection",
|
| 1671 |
+
"ag_task": "fruit_detection",
|
| 1672 |
+
"location": {
|
| 1673 |
+
"continent": "north_america",
|
| 1674 |
+
"country": "usa"
|
| 1675 |
+
},
|
| 1676 |
+
"sensor_modality": "rgb",
|
| 1677 |
+
"real_synthetic": "real",
|
| 1678 |
+
"platform": "handheld/ground",
|
| 1679 |
+
"annotation_format": "coco_json",
|
| 1680 |
+
"input_data_format": "jpg",
|
| 1681 |
+
"n_images": "175",
|
| 1682 |
+
"docs_url": "https://universe.roboflow.com/strawberrydet/strawberry_2022/dataset/4",
|
| 1683 |
+
"external_image_sources": [],
|
| 1684 |
+
"stats": {
|
| 1685 |
+
"mean": [
|
| 1686 |
+
0.287511944770813,
|
| 1687 |
+
0.3060769736766815,
|
| 1688 |
+
0.29882678389549255
|
| 1689 |
+
],
|
| 1690 |
+
"std": [
|
| 1691 |
+
0.21001286804676056,
|
| 1692 |
+
0.19917000830173492,
|
| 1693 |
+
0.20504336059093475
|
| 1694 |
+
]
|
| 1695 |
+
},
|
| 1696 |
+
"parent_dataset": "",
|
| 1697 |
+
"extra_metadata": {}
|
| 1698 |
+
},
|
| 1699 |
+
"almond_harvest_2021": {
|
| 1700 |
+
"classes": {
|
| 1701 |
+
"0": "Visible Fruit/Flower",
|
| 1702 |
+
"1": "Partially Visible Fruit/Flower",
|
| 1703 |
+
"2": "Visible Occluded Fruit/Flower",
|
| 1704 |
+
"3": "Partially Visible Occluded Fruit/Flower"
|
| 1705 |
+
},
|
| 1706 |
+
"ml_task": "object_detection",
|
| 1707 |
+
"ag_task": "fruit_detection",
|
| 1708 |
+
"location": {
|
| 1709 |
+
"continent": "north_america",
|
| 1710 |
+
"country": "usa"
|
| 1711 |
+
},
|
| 1712 |
+
"sensor_modality": "rgb",
|
| 1713 |
+
"real_synthetic": "real",
|
| 1714 |
+
"platform": "ground",
|
| 1715 |
+
"annotation_format": "coco_json",
|
| 1716 |
+
"input_data_format": "jpg",
|
| 1717 |
+
"n_images": "50",
|
| 1718 |
+
"docs_url": "",
|
| 1719 |
+
"external_image_sources": [],
|
| 1720 |
+
"stats": {
|
| 1721 |
+
"mean": [
|
| 1722 |
+
0.1509094387292862,
|
| 1723 |
+
0.15222010016441345,
|
| 1724 |
+
0.14836227893829346
|
| 1725 |
+
],
|
| 1726 |
+
"std": [
|
| 1727 |
+
0.16955046355724335,
|
| 1728 |
+
0.1702313870191574,
|
| 1729 |
+
0.1667901575565338
|
| 1730 |
+
]
|
| 1731 |
+
},
|
| 1732 |
+
"parent_dataset": "",
|
| 1733 |
+
"extra_metadata": {}
|
| 1734 |
+
},
|
| 1735 |
+
"almond_bloom_2023": {
|
| 1736 |
+
"classes": {
|
| 1737 |
+
"0": "Visible Fruit/Flower"
|
| 1738 |
+
},
|
| 1739 |
+
"ml_task": "object_detection",
|
| 1740 |
+
"ag_task": "flower_detection",
|
| 1741 |
+
"location": {
|
| 1742 |
+
"continent": "north_america",
|
| 1743 |
+
"country": "usa"
|
| 1744 |
+
},
|
| 1745 |
+
"sensor_modality": "rgb",
|
| 1746 |
+
"real_synthetic": "real",
|
| 1747 |
+
"platform": "ground",
|
| 1748 |
+
"annotation_format": "coco_json",
|
| 1749 |
+
"input_data_format": "jpg",
|
| 1750 |
+
"n_images": "100",
|
| 1751 |
+
"docs_url": "",
|
| 1752 |
+
"external_image_sources": [],
|
| 1753 |
+
"stats": {
|
| 1754 |
+
"mean": [
|
| 1755 |
+
0.32803982496261597,
|
| 1756 |
+
0.34916892647743225,
|
| 1757 |
+
0.3486247956752777
|
| 1758 |
+
],
|
| 1759 |
+
"std": [
|
| 1760 |
+
0.23713527619838715,
|
| 1761 |
+
0.24729833006858826,
|
| 1762 |
+
0.23989765346050262
|
| 1763 |
+
]
|
| 1764 |
+
},
|
| 1765 |
+
"parent_dataset": "",
|
| 1766 |
+
"extra_metadata": {}
|
| 1767 |
+
},
|
| 1768 |
+
"gemini_flower_detection_2022": {
|
| 1769 |
+
"classes": {
|
| 1770 |
+
"1": "object"
|
| 1771 |
+
},
|
| 1772 |
+
"ml_task": "object_detection",
|
| 1773 |
+
"ag_task": "flower_detection",
|
| 1774 |
+
"location": {
|
| 1775 |
+
"continent": "north_america",
|
| 1776 |
+
"country": "usa"
|
| 1777 |
+
},
|
| 1778 |
+
"sensor_modality": "rgb",
|
| 1779 |
+
"real_synthetic": "real",
|
| 1780 |
+
"platform": "ground",
|
| 1781 |
+
"annotation_format": "coco_json",
|
| 1782 |
+
"input_data_format": "jpg",
|
| 1783 |
+
"n_images": "134",
|
| 1784 |
+
"docs_url": "http://gemini-breeding.github.io/",
|
| 1785 |
+
"external_image_sources": [],
|
| 1786 |
+
"stats": {
|
| 1787 |
+
"mean": [
|
| 1788 |
+
0.43233251571655273,
|
| 1789 |
+
0.46158429980278015,
|
| 1790 |
+
0.3074590265750885
|
| 1791 |
+
],
|
| 1792 |
+
"std": [
|
| 1793 |
+
0.15803606808185577,
|
| 1794 |
+
0.1518802046775818,
|
| 1795 |
+
0.1447635143995285
|
| 1796 |
+
]
|
| 1797 |
+
},
|
| 1798 |
+
"parent_dataset": "",
|
| 1799 |
+
"extra_metadata": {}
|
| 1800 |
+
},
|
| 1801 |
+
"gemini_leaf_detection_2022": {
|
| 1802 |
+
"classes": {
|
| 1803 |
+
"1": "object"
|
| 1804 |
+
},
|
| 1805 |
+
"ml_task": "object_detection",
|
| 1806 |
+
"ag_task": "leaf_detection",
|
| 1807 |
+
"location": {
|
| 1808 |
+
"continent": "north_america",
|
| 1809 |
+
"country": "usa"
|
| 1810 |
+
},
|
| 1811 |
+
"sensor_modality": "rgb",
|
| 1812 |
+
"real_synthetic": "real",
|
| 1813 |
+
"platform": "ground",
|
| 1814 |
+
"annotation_format": "coco_json",
|
| 1815 |
+
"input_data_format": "jpg",
|
| 1816 |
+
"n_images": "25",
|
| 1817 |
+
"docs_url": "http://gemini-breeding.github.io/",
|
| 1818 |
+
"external_image_sources": [],
|
| 1819 |
+
"stats": {
|
| 1820 |
+
"mean": [
|
| 1821 |
+
0.5152409672737122,
|
| 1822 |
+
0.48080527782440186,
|
| 1823 |
+
0.4170548915863037
|
| 1824 |
+
],
|
| 1825 |
+
"std": [
|
| 1826 |
+
0.17544656991958618,
|
| 1827 |
+
0.1531846821308136,
|
| 1828 |
+
0.13160519301891327
|
| 1829 |
+
]
|
| 1830 |
+
},
|
| 1831 |
+
"parent_dataset": "",
|
| 1832 |
+
"extra_metadata": {}
|
| 1833 |
+
},
|
| 1834 |
+
"gemini_pod_detection_2022": {
|
| 1835 |
+
"classes": {
|
| 1836 |
+
"1": "object"
|
| 1837 |
+
},
|
| 1838 |
+
"ml_task": "object_detection",
|
| 1839 |
+
"ag_task": "pod_detection",
|
| 1840 |
+
"location": {
|
| 1841 |
+
"continent": "north_america",
|
| 1842 |
+
"country": "usa"
|
| 1843 |
+
},
|
| 1844 |
+
"sensor_modality": "rgb",
|
| 1845 |
+
"real_synthetic": "real",
|
| 1846 |
+
"platform": "ground",
|
| 1847 |
+
"annotation_format": "coco_json",
|
| 1848 |
+
"input_data_format": "jpg",
|
| 1849 |
+
"n_images": "98",
|
| 1850 |
+
"docs_url": "http://gemini-breeding.github.io/",
|
| 1851 |
+
"external_image_sources": [],
|
| 1852 |
+
"stats": {
|
| 1853 |
+
"mean": [
|
| 1854 |
+
0.4158003032207489,
|
| 1855 |
+
0.47277751564979553,
|
| 1856 |
+
0.28544333577156067
|
| 1857 |
+
],
|
| 1858 |
+
"std": [
|
| 1859 |
+
0.16562676429748535,
|
| 1860 |
+
0.1610204428434372,
|
| 1861 |
+
0.1648048311471939
|
| 1862 |
+
]
|
| 1863 |
+
},
|
| 1864 |
+
"parent_dataset": "",
|
| 1865 |
+
"extra_metadata": {}
|
| 1866 |
+
},
|
| 1867 |
+
"gemini_plant_detection_2022": {
|
| 1868 |
+
"classes": {
|
| 1869 |
+
"1": "plant",
|
| 1870 |
+
"2": "weed"
|
| 1871 |
+
},
|
| 1872 |
+
"ml_task": "object_detection",
|
| 1873 |
+
"ag_task": "plant_detection",
|
| 1874 |
+
"location": {
|
| 1875 |
+
"continent": "north_america",
|
| 1876 |
+
"country": "usa"
|
| 1877 |
+
},
|
| 1878 |
+
"sensor_modality": "rgb",
|
| 1879 |
+
"real_synthetic": "real",
|
| 1880 |
+
"platform": "ground",
|
| 1881 |
+
"annotation_format": "coco_json",
|
| 1882 |
+
"input_data_format": "jpg",
|
| 1883 |
+
"n_images": "402",
|
| 1884 |
+
"docs_url": "http://gemini-breeding.github.io/",
|
| 1885 |
+
"external_image_sources": [],
|
| 1886 |
+
"stats": {
|
| 1887 |
+
"mean": [
|
| 1888 |
+
0.5137307047843933,
|
| 1889 |
+
0.47968026995658875,
|
| 1890 |
+
0.4163574278354645
|
| 1891 |
+
],
|
| 1892 |
+
"std": [
|
| 1893 |
+
0.17421172559261322,
|
| 1894 |
+
0.15248580276966095,
|
| 1895 |
+
0.13018731772899628
|
| 1896 |
+
]
|
| 1897 |
+
},
|
| 1898 |
+
"parent_dataset": "",
|
| 1899 |
+
"extra_metadata": {}
|
| 1900 |
+
},
|
| 1901 |
+
"paddy_disease_classification": {
|
| 1902 |
+
"ml_task": "image_classification",
|
| 1903 |
+
"ag_task": "disease_classification",
|
| 1904 |
+
"location": {
|
| 1905 |
+
"continent": "asia",
|
| 1906 |
+
"country": "india"
|
| 1907 |
+
},
|
| 1908 |
+
"sensor_modality": "rgb",
|
| 1909 |
+
"real_synthetic": "real",
|
| 1910 |
+
"platform": "uav",
|
| 1911 |
+
"input_data_format": "jpg",
|
| 1912 |
+
"annotation_format": "directory_names",
|
| 1913 |
+
"n_images": "10407",
|
| 1914 |
+
"docs_url": "https://www.kaggle.com/competitions/paddy-disease-classification/data",
|
| 1915 |
+
"classes": {
|
| 1916 |
+
"0": "bacterial_leaf_blight",
|
| 1917 |
+
"1": "bacterial_leaf_streak",
|
| 1918 |
+
"2": "bacterial_panicle_blight",
|
| 1919 |
+
"3": "blast",
|
| 1920 |
+
"4": "brown_spot",
|
| 1921 |
+
"5": "dead_heart",
|
| 1922 |
+
"6": "downy_mildew",
|
| 1923 |
+
"7": "hispa",
|
| 1924 |
+
"8": "normal",
|
| 1925 |
+
"9": "tungro"
|
| 1926 |
+
},
|
| 1927 |
+
"external_image_sources": [],
|
| 1928 |
+
"stats": {
|
| 1929 |
+
"mean": [
|
| 1930 |
+
0.49716252088546753,
|
| 1931 |
+
0.5882205963134766,
|
| 1932 |
+
0.2304224669933319
|
| 1933 |
+
],
|
| 1934 |
+
"std": [
|
| 1935 |
+
0.23286384344100952,
|
| 1936 |
+
0.23301087319850922,
|
| 1937 |
+
0.1900700032711029
|
| 1938 |
+
]
|
| 1939 |
+
},
|
| 1940 |
+
"parent_dataset": "",
|
| 1941 |
+
"extra_metadata": {}
|
| 1942 |
+
},
|
| 1943 |
+
"onion_leaf_classification": {
|
| 1944 |
+
"ml_task": "image_classification",
|
| 1945 |
+
"ag_task": "leaf_classification",
|
| 1946 |
+
"location": {
|
| 1947 |
+
"continent": "asia",
|
| 1948 |
+
"country": "india"
|
| 1949 |
+
},
|
| 1950 |
+
"sensor_modality": "rgb",
|
| 1951 |
+
"real_synthetic": "real",
|
| 1952 |
+
"platform": "uav",
|
| 1953 |
+
"input_data_format": "jpg",
|
| 1954 |
+
"annotation_format": "directory_names",
|
| 1955 |
+
"n_images": "4502",
|
| 1956 |
+
"docs_url": "https://www.researchgate.net/publication/380611658_Dataset_of_Chilli_and_Onion_Plant_Leaf_Images_for_Classification_and_Detection",
|
| 1957 |
+
"classes": {
|
| 1958 |
+
"0": "healthy",
|
| 1959 |
+
"1": "iris_yellow_virus",
|
| 1960 |
+
"2": "leaf_blight",
|
| 1961 |
+
"3": "purple_blotch"
|
| 1962 |
+
},
|
| 1963 |
+
"external_image_sources": [],
|
| 1964 |
+
"stats": {
|
| 1965 |
+
"mean": [
|
| 1966 |
+
0.49259838461875916,
|
| 1967 |
+
0.5055249929428101,
|
| 1968 |
+
0.33485615253448486
|
| 1969 |
+
],
|
| 1970 |
+
"std": [
|
| 1971 |
+
0.18601194024085999,
|
| 1972 |
+
0.14629681408405304,
|
| 1973 |
+
0.15651942789554596
|
| 1974 |
+
]
|
| 1975 |
+
},
|
| 1976 |
+
"parent_dataset": "",
|
| 1977 |
+
"extra_metadata": {}
|
| 1978 |
+
},
|
| 1979 |
+
"chilli_leaf_classification": {
|
| 1980 |
+
"ml_task": "image_classification",
|
| 1981 |
+
"ag_task": "leaf_classification",
|
| 1982 |
+
"location": {
|
| 1983 |
+
"continent": "asia",
|
| 1984 |
+
"country": "india"
|
| 1985 |
+
},
|
| 1986 |
+
"sensor_modality": "rgb",
|
| 1987 |
+
"real_synthetic": "real",
|
| 1988 |
+
"platform": "uav",
|
| 1989 |
+
"input_data_format": "jpg",
|
| 1990 |
+
"annotation_format": "directory_names",
|
| 1991 |
+
"n_images": "10974",
|
| 1992 |
+
"docs_url": "https://www.researchgate.net/publication/380611658_Dataset_of_Chilli_and_Onion_Plant_Leaf_Images_for_Classification_and_Detection",
|
| 1993 |
+
"classes": {
|
| 1994 |
+
"0": "cercospora",
|
| 1995 |
+
"1": "healthy",
|
| 1996 |
+
"2": "mites_and_trips",
|
| 1997 |
+
"3": "nutritional",
|
| 1998 |
+
"4": "powdery_mildew"
|
| 1999 |
+
},
|
| 2000 |
+
"external_image_sources": [],
|
| 2001 |
+
"stats": {
|
| 2002 |
+
"mean": [
|
| 2003 |
+
0.5395056009292603,
|
| 2004 |
+
0.5616798996925354,
|
| 2005 |
+
0.4004570543766022
|
| 2006 |
+
],
|
| 2007 |
+
"std": [
|
| 2008 |
+
0.17784084379673004,
|
| 2009 |
+
0.1770888715982437,
|
| 2010 |
+
0.18177233636379242
|
| 2011 |
+
]
|
| 2012 |
+
},
|
| 2013 |
+
"parent_dataset": "",
|
| 2014 |
+
"extra_metadata": {}
|
| 2015 |
+
},
|
| 2016 |
+
"orange_leaf_disease_classification": {
|
| 2017 |
+
"ml_task": "image_classification",
|
| 2018 |
+
"ag_task": "disease_classification",
|
| 2019 |
+
"location": {
|
| 2020 |
+
"continent": "asia",
|
| 2021 |
+
"country": "bangladesh"
|
| 2022 |
+
},
|
| 2023 |
+
"sensor_modality": "rgb",
|
| 2024 |
+
"real_synthetic": "real",
|
| 2025 |
+
"platform": "uav",
|
| 2026 |
+
"input_data_format": "jpeg",
|
| 2027 |
+
"annotation_format": "directory_names",
|
| 2028 |
+
"n_images": "5813",
|
| 2029 |
+
"docs_url": "https://www.sciencedirect.com/science/article/pii/S2352340924006802#sec0004",
|
| 2030 |
+
"classes": {
|
| 2031 |
+
"0": "citrus_canker",
|
| 2032 |
+
"1": "citrus_greening",
|
| 2033 |
+
"2": "citrus_mealybugs",
|
| 2034 |
+
"3": "die_back",
|
| 2035 |
+
"4": "foliage_damaged",
|
| 2036 |
+
"5": "healthy_leaf",
|
| 2037 |
+
"6": "powdery_mildew",
|
| 2038 |
+
"7": "shot_hole",
|
| 2039 |
+
"8": "spiny_whitefly",
|
| 2040 |
+
"9": "yellow_dragon",
|
| 2041 |
+
"10": "yellow_leaves"
|
| 2042 |
+
},
|
| 2043 |
+
"external_image_sources": [],
|
| 2044 |
+
"stats": {
|
| 2045 |
+
"mean": [
|
| 2046 |
+
0.641664981842041,
|
| 2047 |
+
0.645190954208374,
|
| 2048 |
+
0.5412733554840088
|
| 2049 |
+
],
|
| 2050 |
+
"std": [
|
| 2051 |
+
0.21496868133544922,
|
| 2052 |
+
0.19639450311660767,
|
| 2053 |
+
0.2651123106479645
|
| 2054 |
+
]
|
| 2055 |
+
},
|
| 2056 |
+
"parent_dataset": "",
|
| 2057 |
+
"extra_metadata": {}
|
| 2058 |
+
},
|
| 2059 |
+
"papaya_leaf_disease_classification": {
|
| 2060 |
+
"ml_task": "image_classification",
|
| 2061 |
+
"ag_task": "disease_classification",
|
| 2062 |
+
"location": {
|
| 2063 |
+
"continent": "asia",
|
| 2064 |
+
"country": "bangladesh"
|
| 2065 |
+
},
|
| 2066 |
+
"sensor_modality": "rgb",
|
| 2067 |
+
"real_synthetic": "real",
|
| 2068 |
+
"platform": "uav",
|
| 2069 |
+
"input_data_format": "jpg",
|
| 2070 |
+
"annotation_format": "directory_names",
|
| 2071 |
+
"n_images": "2159",
|
| 2072 |
+
"docs_url": "https://www.sciencedirect.com/science/article/pii/S2352340924008734",
|
| 2073 |
+
"classes": {
|
| 2074 |
+
"0": "Anthracnose",
|
| 2075 |
+
"1": "BacterialSpot",
|
| 2076 |
+
"2": "Curl",
|
| 2077 |
+
"3": "Healthy",
|
| 2078 |
+
"4": "RingSpot"
|
| 2079 |
+
},
|
| 2080 |
+
"external_image_sources": [],
|
| 2081 |
+
"stats": {
|
| 2082 |
+
"mean": [
|
| 2083 |
+
0.4037705361843109,
|
| 2084 |
+
0.5427719950675964,
|
| 2085 |
+
0.29178404808044434
|
| 2086 |
+
],
|
| 2087 |
+
"std": [
|
| 2088 |
+
0.1690509021282196,
|
| 2089 |
+
0.15967564284801483,
|
| 2090 |
+
0.14206627011299133
|
| 2091 |
+
]
|
| 2092 |
+
},
|
| 2093 |
+
"parent_dataset": "",
|
| 2094 |
+
"extra_metadata": {}
|
| 2095 |
+
},
|
| 2096 |
+
"blackgram_plant_leaf_disease_classification": {
|
| 2097 |
+
"ml_task": "image_classification",
|
| 2098 |
+
"ag_task": "disease_classification",
|
| 2099 |
+
"location": {
|
| 2100 |
+
"continent": "asia",
|
| 2101 |
+
"country": "india"
|
| 2102 |
+
},
|
| 2103 |
+
"sensor_modality": "rgb",
|
| 2104 |
+
"real_synthetic": "real",
|
| 2105 |
+
"platform": "uav",
|
| 2106 |
+
"input_data_format": "jpg",
|
| 2107 |
+
"annotation_format": "directory_names",
|
| 2108 |
+
"n_images": "1007",
|
| 2109 |
+
"docs_url": "https://www.sciencedirect.com/science/article/pii/S2352340922009295",
|
| 2110 |
+
"classes": {
|
| 2111 |
+
"0": "anthracnose",
|
| 2112 |
+
"1": "healthy",
|
| 2113 |
+
"2": "leaf_crinckle",
|
| 2114 |
+
"3": "powdery_mildew",
|
| 2115 |
+
"4": "yellow_mosaic"
|
| 2116 |
+
},
|
| 2117 |
+
"external_image_sources": [],
|
| 2118 |
+
"stats": {
|
| 2119 |
+
"mean": [
|
| 2120 |
+
0.4454658031463623,
|
| 2121 |
+
0.5082071423530579,
|
| 2122 |
+
0.3293055593967438
|
| 2123 |
+
],
|
| 2124 |
+
"std": [
|
| 2125 |
+
0.19813409447669983,
|
| 2126 |
+
0.1792915314435959,
|
| 2127 |
+
0.16840000450611115
|
| 2128 |
+
]
|
| 2129 |
+
},
|
| 2130 |
+
"parent_dataset": "",
|
| 2131 |
+
"extra_metadata": {}
|
| 2132 |
+
},
|
| 2133 |
+
"arabica_coffee_leaf_disease_classification": {
|
| 2134 |
+
"ml_task": "image_classification",
|
| 2135 |
+
"ag_task": "disease_classification",
|
| 2136 |
+
"location": {
|
| 2137 |
+
"continent": "africa",
|
| 2138 |
+
"country": "kenya"
|
| 2139 |
+
},
|
| 2140 |
+
"sensor_modality": "rgb",
|
| 2141 |
+
"real_synthetic": "real",
|
| 2142 |
+
"platform": "uav",
|
| 2143 |
+
"input_data_format": [
|
| 2144 |
+
"jpg",
|
| 2145 |
+
"jpeg"
|
| 2146 |
+
],
|
| 2147 |
+
"annotation_format": "directory_names",
|
| 2148 |
+
"n_images": "58549",
|
| 2149 |
+
"docs_url": "https://www.sciencedirect.com/science/article/pii/S2352340921004261?via%3Dihub#sec0001",
|
| 2150 |
+
"classes": {
|
| 2151 |
+
"0": "Cerscospora",
|
| 2152 |
+
"1": "Healthy",
|
| 2153 |
+
"2": "Leaf_rust",
|
| 2154 |
+
"3": "Miner",
|
| 2155 |
+
"4": "Phoma"
|
| 2156 |
+
},
|
| 2157 |
+
"external_image_sources": [],
|
| 2158 |
+
"stats": {
|
| 2159 |
+
"mean": [
|
| 2160 |
+
0.4663342535495758,
|
| 2161 |
+
0.6128407716751099,
|
| 2162 |
+
0.40549468994140625
|
| 2163 |
+
],
|
| 2164 |
+
"std": [
|
| 2165 |
+
0.1319405734539032,
|
| 2166 |
+
0.10137982666492462,
|
| 2167 |
+
0.13884715735912323
|
| 2168 |
+
]
|
| 2169 |
+
},
|
| 2170 |
+
"parent_dataset": "",
|
| 2171 |
+
"extra_metadata": {}
|
| 2172 |
+
},
|
| 2173 |
+
"banana_leaf_disease_classification": {
|
| 2174 |
+
"ml_task": "image_classification",
|
| 2175 |
+
"ag_task": "disease_classification",
|
| 2176 |
+
"location": {
|
| 2177 |
+
"continent": "africa",
|
| 2178 |
+
"country": "ethiopia"
|
| 2179 |
+
},
|
| 2180 |
+
"sensor_modality": "rgb",
|
| 2181 |
+
"real_synthetic": "real",
|
| 2182 |
+
"platform": "uav",
|
| 2183 |
+
"input_data_format": "jpg",
|
| 2184 |
+
"annotation_format": "directory_names",
|
| 2185 |
+
"n_images": "1288",
|
| 2186 |
+
"docs_url": "https://www.researchgate.net/publication/380900090_Sigatoka_and_Xanthomonas_Banana_Leaf_Disease_Detection_Via_Transfer_Learning",
|
| 2187 |
+
"classes": {
|
| 2188 |
+
"0": "healthy",
|
| 2189 |
+
"1": "segatoka",
|
| 2190 |
+
"2": "xamthomonas"
|
| 2191 |
+
},
|
| 2192 |
+
"external_image_sources": [],
|
| 2193 |
+
"stats": {
|
| 2194 |
+
"mean": [
|
| 2195 |
+
0.4403895437717438,
|
| 2196 |
+
0.4788191020488739,
|
| 2197 |
+
0.22997669875621796
|
| 2198 |
+
],
|
| 2199 |
+
"std": [
|
| 2200 |
+
0.2052917778491974,
|
| 2201 |
+
0.20397576689720154,
|
| 2202 |
+
0.18596293032169342
|
| 2203 |
+
]
|
| 2204 |
+
},
|
| 2205 |
+
"parent_dataset": "",
|
| 2206 |
+
"extra_metadata": {}
|
| 2207 |
+
},
|
| 2208 |
+
"coconut_tree_disease_classification": {
|
| 2209 |
+
"ml_task": "image_classification",
|
| 2210 |
+
"ag_task": "disease_classification",
|
| 2211 |
+
"location": {
|
| 2212 |
+
"continent": "asia",
|
| 2213 |
+
"country": "india"
|
| 2214 |
+
},
|
| 2215 |
+
"sensor_modality": "rgb",
|
| 2216 |
+
"real_synthetic": "real",
|
| 2217 |
+
"platform": "uav",
|
| 2218 |
+
"input_data_format": "jpg",
|
| 2219 |
+
"annotation_format": "directory_names",
|
| 2220 |
+
"n_images": "5798",
|
| 2221 |
+
"docs_url": "https://www.sciencedirect.com/science/article/pii/S2352340923007692#sec0003",
|
| 2222 |
+
"classes": {
|
| 2223 |
+
"0": "Bud_Root_Dropping",
|
| 2224 |
+
"1": "Bud_Rot",
|
| 2225 |
+
"2": "Gray_Leaf_Spot",
|
| 2226 |
+
"3": "Leaf_Rot",
|
| 2227 |
+
"4": "Stem_Bleeding"
|
| 2228 |
+
},
|
| 2229 |
+
"external_image_sources": [],
|
| 2230 |
+
"stats": {
|
| 2231 |
+
"mean": [
|
| 2232 |
+
0.49172350764274597,
|
| 2233 |
+
0.49519237875938416,
|
| 2234 |
+
0.4346628189086914
|
| 2235 |
+
],
|
| 2236 |
+
"std": [
|
| 2237 |
+
0.2121831327676773,
|
| 2238 |
+
0.20774872601032257,
|
| 2239 |
+
0.22041980922222137
|
| 2240 |
+
]
|
| 2241 |
+
},
|
| 2242 |
+
"parent_dataset": "",
|
| 2243 |
+
"extra_metadata": {}
|
| 2244 |
+
},
|
| 2245 |
+
"rice_leaf_disease_classification": {
|
| 2246 |
+
"ml_task": "image_classification",
|
| 2247 |
+
"ag_task": "disease_classification",
|
| 2248 |
+
"location": {
|
| 2249 |
+
"continent": "worldwide",
|
| 2250 |
+
"country": "worldwide"
|
| 2251 |
+
},
|
| 2252 |
+
"sensor_modality": "rgb",
|
| 2253 |
+
"real_synthetic": "real",
|
| 2254 |
+
"platform": "uav",
|
| 2255 |
+
"input_data_format": "jpg",
|
| 2256 |
+
"annotation_format": "directory_names",
|
| 2257 |
+
"n_images": "3829",
|
| 2258 |
+
"docs_url": "https://www.kaggle.com/datasets/anshulm257/rice-disease-dataset/data",
|
| 2259 |
+
"classes": {
|
| 2260 |
+
"0": "Bacterial_Leaf_Blight",
|
| 2261 |
+
"1": "Brown_Spot",
|
| 2262 |
+
"2": "Healthy_Rice_Leaf",
|
| 2263 |
+
"3": "Leaf_Blast",
|
| 2264 |
+
"4": "Leaf_Scald",
|
| 2265 |
+
"5": "Sheath_Blight"
|
| 2266 |
+
},
|
| 2267 |
+
"external_image_sources": [],
|
| 2268 |
+
"stats": {
|
| 2269 |
+
"mean": [
|
| 2270 |
+
0.3801848888397217,
|
| 2271 |
+
0.5112283229827881,
|
| 2272 |
+
0.24517497420310974
|
| 2273 |
+
],
|
| 2274 |
+
"std": [
|
| 2275 |
+
0.1857737898826599,
|
| 2276 |
+
0.1747269332408905,
|
| 2277 |
+
0.13470299541950226
|
| 2278 |
+
]
|
| 2279 |
+
},
|
| 2280 |
+
"parent_dataset": "",
|
| 2281 |
+
"extra_metadata": {}
|
| 2282 |
+
},
|
| 2283 |
+
"tea_leaf_disease_classification": {
|
| 2284 |
+
"ml_task": "image_classification",
|
| 2285 |
+
"ag_task": "disease_classification",
|
| 2286 |
+
"location": {
|
| 2287 |
+
"continent": "asia",
|
| 2288 |
+
"country": "india"
|
| 2289 |
+
},
|
| 2290 |
+
"sensor_modality": "rgb",
|
| 2291 |
+
"real_synthetic": "real",
|
| 2292 |
+
"platform": "uav",
|
| 2293 |
+
"input_data_format": "jpg",
|
| 2294 |
+
"annotation_format": "directory_names",
|
| 2295 |
+
"n_images": "5867",
|
| 2296 |
+
"docs_url": "https://www.kaggle.com/datasets/saikatdatta1994/tea-leaf-disease",
|
| 2297 |
+
"classes": {
|
| 2298 |
+
"0": "algal_spot",
|
| 2299 |
+
"1": "brown_blight",
|
| 2300 |
+
"2": "gray_blight",
|
| 2301 |
+
"3": "healthy",
|
| 2302 |
+
"4": "helopeltis",
|
| 2303 |
+
"5": "red_spot"
|
| 2304 |
+
},
|
| 2305 |
+
"external_image_sources": [],
|
| 2306 |
+
"stats": {
|
| 2307 |
+
"mean": [
|
| 2308 |
+
0.720391035079956,
|
| 2309 |
+
0.7148104310035706,
|
| 2310 |
+
0.7214117646217346
|
| 2311 |
+
],
|
| 2312 |
+
"std": [
|
| 2313 |
+
0.2642996311187744,
|
| 2314 |
+
0.24272359907627106,
|
| 2315 |
+
0.32473450899124146
|
| 2316 |
+
]
|
| 2317 |
+
},
|
| 2318 |
+
"parent_dataset": "",
|
| 2319 |
+
"extra_metadata": {}
|
| 2320 |
+
},
|
| 2321 |
+
"betel_leaf_disease_classification": {
|
| 2322 |
+
"ml_task": "image_classification",
|
| 2323 |
+
"ag_task": "disease_classification",
|
| 2324 |
+
"location": {
|
| 2325 |
+
"continent": "asia",
|
| 2326 |
+
"country": "bangladesh"
|
| 2327 |
+
},
|
| 2328 |
+
"sensor_modality": "rgb",
|
| 2329 |
+
"real_synthetic": "real",
|
| 2330 |
+
"platform": "uav",
|
| 2331 |
+
"input_data_format": "jpg",
|
| 2332 |
+
"annotation_format": "directory_names",
|
| 2333 |
+
"n_images": "3589",
|
| 2334 |
+
"docs_url": "https://www.semanticscholar.org/paper/Betel-Leaf-Diseases-Classification-using-Machine-A-David-Mukunthan/38208c9d2306444e3b9f8593715a46e2dcf26f44#paper-topics",
|
| 2335 |
+
"classes": {
|
| 2336 |
+
"0": "Bacterial_Leaf_Disease",
|
| 2337 |
+
"1": "Dried_Leaf",
|
| 2338 |
+
"2": "Fungal_Brown_Spot_Disease",
|
| 2339 |
+
"3": "Healthy_Leaf"
|
| 2340 |
+
},
|
| 2341 |
+
"external_image_sources": [],
|
| 2342 |
+
"stats": {
|
| 2343 |
+
"mean": [
|
| 2344 |
+
0.44302278757095337,
|
| 2345 |
+
0.5203492045402527,
|
| 2346 |
+
0.32380297780036926
|
| 2347 |
+
],
|
| 2348 |
+
"std": [
|
| 2349 |
+
0.18618987500667572,
|
| 2350 |
+
0.19697120785713196,
|
| 2351 |
+
0.21828916668891907
|
| 2352 |
+
]
|
| 2353 |
+
},
|
| 2354 |
+
"parent_dataset": "",
|
| 2355 |
+
"extra_metadata": {}
|
| 2356 |
+
},
|
| 2357 |
+
"java_plum_leaf_disease_classification": {
|
| 2358 |
+
"ml_task": "image_classification",
|
| 2359 |
+
"ag_task": "disease_classification",
|
| 2360 |
+
"location": {
|
| 2361 |
+
"continent": "asia",
|
| 2362 |
+
"country": "bangladesh"
|
| 2363 |
+
},
|
| 2364 |
+
"sensor_modality": "rgb",
|
| 2365 |
+
"real_synthetic": "real",
|
| 2366 |
+
"platform": "uav",
|
| 2367 |
+
"input_data_format": "jpg",
|
| 2368 |
+
"annotation_format": "directory_names",
|
| 2369 |
+
"n_images": "2400",
|
| 2370 |
+
"docs_url": "https://www.sciencedirect.com/science/article/pii/S2772375524001059#sec0003",
|
| 2371 |
+
"classes": {
|
| 2372 |
+
"0": "Bacterial_Spot",
|
| 2373 |
+
"1": "Brown_Blight",
|
| 2374 |
+
"2": "Dry",
|
| 2375 |
+
"3": "Healthy",
|
| 2376 |
+
"4": "Powdery_Mildew",
|
| 2377 |
+
"5": "Sooty_Mold"
|
| 2378 |
+
},
|
| 2379 |
+
"external_image_sources": [],
|
| 2380 |
+
"stats": {
|
| 2381 |
+
"mean": [
|
| 2382 |
+
0.6888663172721863,
|
| 2383 |
+
0.7057309746742249,
|
| 2384 |
+
0.6495749950408936
|
| 2385 |
+
],
|
| 2386 |
+
"std": [
|
| 2387 |
+
0.21865394711494446,
|
| 2388 |
+
0.20790858566761017,
|
| 2389 |
+
0.3019416928291321
|
| 2390 |
+
]
|
| 2391 |
+
},
|
| 2392 |
+
"parent_dataset": "",
|
| 2393 |
+
"extra_metadata": {}
|
| 2394 |
+
},
|
| 2395 |
+
"sunflower_disease_classification": {
|
| 2396 |
+
"ml_task": "image_classification",
|
| 2397 |
+
"ag_task": "disease_classification",
|
| 2398 |
+
"location": {
|
| 2399 |
+
"continent": "asia",
|
| 2400 |
+
"country": "bangladesh"
|
| 2401 |
+
},
|
| 2402 |
+
"sensor_modality": "rgb",
|
| 2403 |
+
"real_synthetic": "real",
|
| 2404 |
+
"platform": "uav",
|
| 2405 |
+
"input_data_format": "jpg",
|
| 2406 |
+
"annotation_format": "directory_names",
|
| 2407 |
+
"n_images": "2358",
|
| 2408 |
+
"docs_url": "https://www.sciencedirect.com/science/article/pii/S2352340922002542",
|
| 2409 |
+
"classes": {
|
| 2410 |
+
"0": "Downy_mildew",
|
| 2411 |
+
"1": "Fresh_leaf",
|
| 2412 |
+
"2": "Gray_mold",
|
| 2413 |
+
"3": "Leaf_scars"
|
| 2414 |
+
},
|
| 2415 |
+
"external_image_sources": [],
|
| 2416 |
+
"stats": {
|
| 2417 |
+
"mean": [
|
| 2418 |
+
0.45603200793266296,
|
| 2419 |
+
0.45415663719177246,
|
| 2420 |
+
0.2436216175556183
|
| 2421 |
+
],
|
| 2422 |
+
"std": [
|
| 2423 |
+
0.22495068609714508,
|
| 2424 |
+
0.21411556005477905,
|
| 2425 |
+
0.17952653765678406
|
| 2426 |
+
]
|
| 2427 |
+
},
|
| 2428 |
+
"parent_dataset": "",
|
| 2429 |
+
"extra_metadata": {}
|
| 2430 |
+
},
|
| 2431 |
+
"cucumber_disease_classification": {
|
| 2432 |
+
"ml_task": "image_classification",
|
| 2433 |
+
"ag_task": "disease_classification",
|
| 2434 |
+
"location": {
|
| 2435 |
+
"continent": "asia",
|
| 2436 |
+
"country": "bangladesh"
|
| 2437 |
+
},
|
| 2438 |
+
"sensor_modality": "rgb",
|
| 2439 |
+
"real_synthetic": "real",
|
| 2440 |
+
"platform": "uav",
|
| 2441 |
+
"input_data_format": "jpg",
|
| 2442 |
+
"annotation_format": "directory_names",
|
| 2443 |
+
"n_images": "7689",
|
| 2444 |
+
"docs_url": "https://www.sciencedirect.com/science/article/pii/S2352340923004389",
|
| 2445 |
+
"classes": {
|
| 2446 |
+
"0": "Anthracnose",
|
| 2447 |
+
"1": "Bacterial_Wilt",
|
| 2448 |
+
"2": "Belly_Rot",
|
| 2449 |
+
"3": "Downy_Mildew",
|
| 2450 |
+
"4": "Fresh_Cucumber",
|
| 2451 |
+
"5": "Fresh_Leaf",
|
| 2452 |
+
"6": "Gummy_Stem_Blight",
|
| 2453 |
+
"7": "Pythium_Fruit_Rot"
|
| 2454 |
+
},
|
| 2455 |
+
"external_image_sources": [],
|
| 2456 |
+
"stats": {
|
| 2457 |
+
"mean": [
|
| 2458 |
+
0.46584174036979675,
|
| 2459 |
+
0.5267260074615479,
|
| 2460 |
+
0.3983174264431
|
| 2461 |
+
],
|
| 2462 |
+
"std": [
|
| 2463 |
+
0.19197316467761993,
|
| 2464 |
+
0.18358547985553741,
|
| 2465 |
+
0.17932511866092682
|
| 2466 |
+
]
|
| 2467 |
+
},
|
| 2468 |
+
"parent_dataset": "",
|
| 2469 |
+
"extra_metadata": {}
|
| 2470 |
+
},
|
| 2471 |
+
"soybean_insect_classification": {
|
| 2472 |
+
"ml_task": "image_classification",
|
| 2473 |
+
"ag_task": "pest_classification",
|
| 2474 |
+
"location": {
|
| 2475 |
+
"continent": "south_america",
|
| 2476 |
+
"country": "brazil"
|
| 2477 |
+
},
|
| 2478 |
+
"sensor_modality": "rgb",
|
| 2479 |
+
"real_synthetic": "real",
|
| 2480 |
+
"platform": "uav",
|
| 2481 |
+
"input_data_format": "jpg",
|
| 2482 |
+
"annotation_format": "directory_names",
|
| 2483 |
+
"n_images": "6410",
|
| 2484 |
+
"docs_url": "https://data.mendeley.com/datasets/bycbh73438/1",
|
| 2485 |
+
"classes": {
|
| 2486 |
+
"0": "Caterpillar",
|
| 2487 |
+
"1": "Diabrotica_speciosa",
|
| 2488 |
+
"2": "Healthy"
|
| 2489 |
+
},
|
| 2490 |
+
"external_image_sources": [],
|
| 2491 |
+
"parent_dataset": "",
|
| 2492 |
+
"extra_metadata": {},
|
| 2493 |
+
"stats": {
|
| 2494 |
+
"mean": [
|
| 2495 |
+
0.4129256308078766,
|
| 2496 |
+
0.515846848487854,
|
| 2497 |
+
0.3347107470035553
|
| 2498 |
+
],
|
| 2499 |
+
"std": [
|
| 2500 |
+
0.22007715702056885,
|
| 2501 |
+
0.22993944585323334,
|
| 2502 |
+
0.20302338898181915
|
| 2503 |
+
]
|
| 2504 |
+
}
|
| 2505 |
+
}
|
| 2506 |
+
}
|
AgML/source/agml/_assets/shape_info.pickle
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:483dfc00dac1e09bc963e6b2c9ae30556c60425164b1a3bb9929e4452d8b3229
|
| 3 |
+
size 499283
|
AgML/source/agml/_assets/source_citations.json
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"bean_disease_uganda": {
|
| 3 |
+
"license": "MIT",
|
| 4 |
+
"citation": ""
|
| 5 |
+
},
|
| 6 |
+
"carrot_weeds_germany": {
|
| 7 |
+
"license": "",
|
| 8 |
+
"citation": "@inproceedings{haug15,\n author={Haug, Sebastian and Ostermann, J{\\\"o}rn},\n title={A Crop/Weed Field Image Dataset for the Evaluation of Computer Vision Based Precision Agriculture Tasks},\n year={2015},\n booktitle={Computer Vision - ECCV 2014 Workshops},\n doi={10.1007/978-3-319-16220-1_8},\n url={http://dx.doi.org/10.1007/978-3-319-16220-1_8},\n pages={105--116}\n}"
|
| 9 |
+
},
|
| 10 |
+
"plant_seedlings_aarhus": {
|
| 11 |
+
"license": "CC BY-SA 4.0",
|
| 12 |
+
"citation": "@article{Giselsson2017,\n author = {Giselsson, Thomas Mosgaard and Dyrmann, Mads and J{\\o}rgensen, Rasmus Nyholm and Jensen, Peter Kryger and Midtiby, Henrik Skov},\n journal = {arXiv preprint},\n keywords = {benchmark,database,plant seedlings,segmentation,site-specific weed control},\n title = {{A Public Image Database for Benchmark of Plant Seedling Classification Algorithms}},\n year = {2017}\n}"
|
| 13 |
+
},
|
| 14 |
+
"soybean_weed_uav_brazil": {
|
| 15 |
+
"license": "CC BY-NC 3.0",
|
| 16 |
+
"citation": "dos Santos Ferreira, Alessandro; Pistori, Hemerson; Matte Freitas, Daniel; Gon\u00e7alves da Silva, Gercina (2017), \u201cData for: Weed Detection in Soybean Crops Using ConvNets\u201d, Mendeley Data, V2, doi: 10.17632/3fmjm7ncc6.2"
|
| 17 |
+
},
|
| 18 |
+
"sugarcane_damage_usa": {
|
| 19 |
+
"license": "",
|
| 20 |
+
"citation": "@ARTICLE{8412587,\n author={Alencastre-Miranda, Moises and Davidson, Joseph R. and Johnson, Richard M. and Waguespack, Herman and Krebs, Hermano Igo},\n journal={IEEE Robotics and Automation Letters}, \n title={Robotics for Sugarcane Cultivation: Analysis of Billet Quality using Computer Vision}, \n year={2018},\n volume={3},\n number={4},\n pages={3828-3835},\n doi={10.1109/LRA.2018.2856999}}"
|
| 21 |
+
},
|
| 22 |
+
"crop_weeds_greece": {
|
| 23 |
+
"license": "MIT",
|
| 24 |
+
"citation": "@article{ESPEJOGARCIA2020105306,\n title = {Towards weeds identification assistance through transfer learning},\n journal = {Computers and Electronics in Agriculture},\n volume = {171},\n pages = {105306},\n year = {2020},\n issn = {0168-1699},\n doi = {https://doi.org/10.1016/j.compag.2020.105306},\n url = {https://www.sciencedirect.com/science/article/pii/S0168169919319854},\n author = {Borja Espejo-Garcia and Nikos Mylonas and Loukas Athanasakos and Spyros Fountas and Ioannis Vasilakoglou},\n keywords = {Weed identification, Deep learning, Transfer learning, Open data, Precision agriculture},\n abstract = {Reducing the use of pesticides through selective spraying is an important component towards a more sustainable computer-assisted agriculture. Weed identification at early growth stage contributes to reduced herbicide rates. However, while computer vision alongside deep learning have overcome the performance of approaches that use hand-crafted features, there are still some open challenges in the development of a reliable automatic plant identification system. These type of systems have to take into account different sources of variability, such as growth stages and soil conditions, with the added constraint of the limited size of usual datasets. This study proposes a novel crop/weed identification system that relies on a combination of fine-tuning pre-trained convolutional networks (Xception, Inception-Resnet, VGNets, Mobilenet and Densenet) with the \u201ctraditional\u201d machine learning classifiers (Support Vector Machines, XGBoost and Logistic Regression) trained with the previously deep extracted features. The aim of this approach was to avoid overfitting and to obtain a robust and consistent performance. To evaluate this approach, an open access dataset of two crop [tomato (Solanum lycopersicum L.) and cotton (Gossypium hirsutum L.)] and two weed species [black nightshade (Solanum nigrum L.) and velvetleaf (Abutilon theophrasti Medik.)] was generated. The pictures were taken by different production sites across Greece under natural variable light conditions from RGB cameras. The results revealed that a combination of fine-tuned Densenet and Support Vector Machine achieved a micro F1 score of 99.29% with a very low performance difference between train and test sets. Other evaluated approaches also obtained repeatedly more than 95% F1 score. Additionally, our results analysis provides some heuristics for designing transfer-learning based systems to avoid overfitting without decreasing performance.}\n}"
|
| 25 |
+
},
|
| 26 |
+
"sugarbeet_weed_segmentation": {
|
| 27 |
+
"license": "GPL-3.0",
|
| 28 |
+
"citation": "@ARTICLE{8115245,\n author={I. Sa and Z. Chen and M. Popovi\u0107 and R. Khanna and F. Liebisch and J. Nieto and R. Siegwart},\n journal={IEEE Robotics and Automation Letters},\n title={weedNet: Dense Semantic Weed Classification Using Multispectral Images and MAV for Smart Farming},\n year={2018},\n volume={3},\n number={1},\n pages={588-595},\n keywords={agriculture;agrochemicals;autonomous aerial vehicles;control engineering computing;convolution;crops;feature extraction;image classification;learning (artificial intelligence);neural nets;vegetation;MAV;SegNet;convolutional neural network;crop health;crop management;curve classification metrics;dense semantic classes;dense semantic weed classification;encoder-decoder;input image channels;multispectral images;selective weed treatment;vegetation index;weed detection;Agriculture;Cameras;Image segmentation;Robots;Semantics;Training;Vegetation mapping;Aerial systems;agricultural automation;applications;robotics in agriculture and forestry},\n doi={10.1109/LRA.2017.2774979},\n ISSN={},\n month={Jan}\n}"
|
| 29 |
+
},
|
| 30 |
+
"rangeland_weeds_australia": {
|
| 31 |
+
"license": "CC BY-SA 4.0",
|
| 32 |
+
"citation": "@Article{Olsen2019,\n author={Olsen, Alex and Konovalov, Dmitry A. and Philippa, Bronson and Ridd, Peter and Wood, Jake C. and Johns, Jamie and Banks, Wesley and Girgenti, Benjamin and Kenny, Owen and Whinney, James and Calvert, Brendan and Azghadi, Mostafa Rahimi and White, Ronald D.},\n title={DeepWeeds: A Multiclass Weed Species Image Dataset for Deep Learning},\n journal={Scientific Reports},\n year={2019},\n month={Feb},\n day={14},\n volume={9},\n number={1},\n pages={2058},\n abstract={Robotic weed control has seen increased research of late with its potential for boosting productivity in agriculture. Majority of works focus on developing robotics for croplands, ignoring the weed management problems facing rangeland stock farmers. Perhaps the greatest obstacle to widespread uptake of robotic weed control is the robust classification of weed species in their natural environment. The unparalleled successes of deep learning make it an ideal candidate for recognising various weed species in the complex rangeland environment. This work contributes the first large, public, multiclass image dataset of weed species from the Australian rangelands; allowing for the development of robust classification methods to make robotic weed control viable. The DeepWeeds dataset consists of 17,509 labelled images of eight nationally significant weed species native to eight locations across northern Australia. This paper presents a baseline for classification performance on the dataset using the benchmark deep learning models, Inception-v3 and ResNet-50. These models achieved an average classification accuracy of 95.1{\\%} and 95.7{\\%}, respectively. We also demonstrate real time performance of the ResNet-50 architecture, with an average inference time of 53.4 ms per image. These strong results bode well for future field implementation of robotic weed control methods in the Australian rangelands.},\n issn={2045-2322},\n doi={10.1038/s41598-018-38343-3},\n url={https://doi.org/10.1038/s41598-018-38343-3}\n}"
|
| 33 |
+
},
|
| 34 |
+
"fruit_detection_worldwide": {
|
| 35 |
+
"license": "",
|
| 36 |
+
"citation": "@Article{s16081222,\n AUTHOR = {Sa, Inkyu and Ge, Zongyuan and Dayoub, Feras and Upcroft, Ben and Perez, Tristan and McCool, Chris},\n TITLE = {DeepFruits: A Fruit Detection System Using Deep Neural Networks},\n JOURNAL = {Sensors},\n VOLUME = {16},\n YEAR = {2016},\n NUMBER = {8},\n ARTICLE-NUMBER = {1222},\n URL = {https://www.mdpi.com/1424-8220/16/8/1222},\n ISSN = {1424-8220},\n ABSTRACT = {This paper presents a novel approach to fruit detection using deep convolutional neural networks. The aim is to build an accurate, fast and reliable fruit detection system, which is a vital element of an autonomous agricultural robotic platform; it is a key element for fruit yield estimation and automated harvesting. Recent work in deep neural networks has led to the development of a state-of-the-art object detector termed Faster Region-based CNN (Faster R-CNN). We adapt this model, through transfer learning, for the task of fruit detection using imagery obtained from two modalities: colour (RGB) and Near-Infrared (NIR). Early and late fusion methods are explored for combining the multi-modal (RGB and NIR) information. This leads to a novel multi-modal Faster R-CNN model, which achieves state-of-the-art results compared to prior work with the F1 score, which takes into account both precision and recall performances improving from 0 . 807 to 0 . 838 for the detection of sweet pepper. In addition to improved accuracy, this approach is also much quicker to deploy for new fruits, as it requires bounding box annotation rather than pixel-level annotation (annotating bounding boxes is approximately an order of magnitude quicker to perform). The model is retrained to perform the detection of seven fruits, with the entire process taking four hours to annotate and train the new model per fruit.},\n DOI = {10.3390/s16081222}\n}"
|
| 37 |
+
},
|
| 38 |
+
"leaf_counting_denmark": {
|
| 39 |
+
"license": "CC BY-SA 4.0",
|
| 40 |
+
"citation": "@Article{s18051580,\n author = {Teimouri, Nima and Dyrmann, Mads and Nielsen, Per Rydahl and Mathiassen, Solvejg Kopp and Somerville, Gayle J. and J\u00f8rgensen, Rasmus Nyholm},\n title = {Weed Growth Stage Estimator Using Deep Convolutional Neural Networks},\n journal = {Sensors},\n volume = {18},\n year = {2018},\n number = {5},\n url = {http://www.mdpi.com/1424-8220/18/5/1580},\n issn = {1424-8220}\n}"
|
| 41 |
+
},
|
| 42 |
+
"apple_detection_usa": {
|
| 43 |
+
"license": "",
|
| 44 |
+
"citation": "@article{karkee2019apple,\n title={Apple Dataset Benchmark from Orchard Environment in Modern Fruiting Wall},\n author={Karkee, Manoj and Bhusal, Santosh and Zhang, Qin},\n year={2019}\n}"
|
| 45 |
+
},
|
| 46 |
+
"mango_detection_australia": {
|
| 47 |
+
"license": "",
|
| 48 |
+
"citation": "@Misc{Koirala2019,\n author={Koirala, Anand and Walsh, Kerry and Wang, Z. and McCarthy, C.},\n title={MangoYOLO data set},\n year={2019},\n month={2021},\n day={10-19},\n publisher={Central Queensland University},\n keywords={Mango images; Fruit detection; Yield estimation; Mango; Agricultural Land Management; Horticultural Crop Growth and Development},\n abstract={Datasets and directories are structured similar to the PASCAL VOC dataset, avoiding the need to change scripts already available, with the detection frameworks ready to parse PASCAL VOC annotations into their format. The sub-directory JPEGImages consist of 1730 images (612x512 pixels) used for train, test and validation. Each image has at least one annotated fruit. The sub-directory Annotations consists of all the annotation files (record of bounding box coordinates for each image) in xml format and have the same name as the image name. The sub-directory Main consists of the text file that contains image names (without extension) used for train, test and validation. Training set (train.txt) lists 1300 train images Validation set (val.txt) lists 130 validation images Test set (test.txt) lists 300 test images Each image has an XML annotation file (filename = image name) and each image set (training validation and test set) has associated text files (train.txt, val.txt and test.txt) containing the list of image names to be used for training and testing. The XML annotation file contains the image attributes (name, width, height), the object attributes (class name, object bounding box co-ordinates (xmin, ymin, xmax, ymax)). (xmin, ymin) and (xmax, ymax) are the pixel co-ordinates of the bounding box's top-left corner and bottom-right corner respectively.},\n note={CC-BY-4.0},\n url={https://figshare.com/articles/dataset/MangoYOLO_data_set/13450661, https://researchdata.edu.au/mangoyolo-set},\n language={English}\n}"
|
| 49 |
+
},
|
| 50 |
+
"tomato_ripeness_detection": {
|
| 51 |
+
"license": "CC BY-NC-SA 4.0",
|
| 52 |
+
"citation": ""
|
| 53 |
+
},
|
| 54 |
+
"apple_flower_segmentation": {
|
| 55 |
+
"license": "US Public Domain",
|
| 56 |
+
"citation": "@ARTICLE{8392727,\n author={Dias, Philipe A. and Tabb, Amy and Medeiros, Henry},\n journal={IEEE Robotics and Automation Letters}, \n title={Multispecies Fruit Flower Detection Using a Refined Semantic Segmentation Network}, \n year={2018},\n volume={3},\n number={4},\n pages={3003-3010},\n doi={10.1109/LRA.2018.2849498}}"
|
| 57 |
+
},
|
| 58 |
+
"apple_segmentation_minnesota": {
|
| 59 |
+
"license": "MIT",
|
| 60 |
+
"citation": "@misc{hani2019minneapple,\n title={MinneApple: A Benchmark Dataset for Apple Detection and Segmentation},\n author={Nicolai H\u00e4ni and Pravakar Roy and Volkan Isler}\n year={2019},\n eprint={1909.06441},\n archivePrefix={arXiv},\n primaryClass={cs.CV}\n}"
|
| 61 |
+
},
|
| 62 |
+
"rice_seedling_segmentation": {
|
| 63 |
+
"license": "",
|
| 64 |
+
"citation": "@Article{electronics9101602,\n AUTHOR = {Khan, Abbas and Ilyas, Talha and Umraiz, Muhammad and Mannan, Zubaer Ibna and Kim, Hyongsuk},\n TITLE = {CED-Net: Crops and Weeds Segmentation for Smart Farming Using a Small Cascaded Encoder-Decoder Architecture},\n JOURNAL = {Electronics},\n VOLUME = {9},\n YEAR = {2020},\n NUMBER = {10},\n ARTICLE-NUMBER = {1602},\n URL = {https://www.mdpi.com/2079-9292/9/10/1602},\n ISSN = {2079-9292},\n ABSTRACT = {Convolutional neural networks (CNNs) have achieved state-of-the-art performance in numerous aspects of human life and the agricultural sector is no exception. One of the main objectives of deep learning for smart farming is to identify the precise location of weeds and crops on farmland. In this paper, we propose a semantic segmentation method based on a cascaded encoder-decoder network, namely CED-Net, to differentiate weeds from crops. The existing architectures for weeds and crops segmentation are quite deep, with millions of parameters that require longer training time. To overcome such limitations, we propose an idea of training small networks in cascade to obtain coarse-to-fine predictions, which are then combined to produce the final results. Evaluation of the proposed network and comparison with other state-of-the-art networks are conducted using four publicly available datasets: rice seeding and weed dataset, BoniRob dataset, carrot crop vs. weed dataset, and a paddy–millet dataset. The experimental results and their comparisons proclaim that the proposed network outperforms state-of-the-art architectures, such as U-Net, SegNet, FCN-8s, and DeepLabv3, over intersection over union (IoU), F1-score, sensitivity, true detection rate, and average precision comparison metrics by utilizing only (1/5.74 × U-Net), (1/5.77 × SegNet), (1/3.04 × FCN-8s), and (1/3.24 × DeepLabv3) fractions of total parameters.},\n DOI = {10.3390/electronics9101602}\n}"
|
| 65 |
+
},
|
| 66 |
+
"plant_village_classification": {
|
| 67 |
+
"license": "",
|
| 68 |
+
"citation": "@article{DBLP:journals/corr/HughesS15,\n author = {David P. Hughes and\n Marcel Salath{'{e} } },\n title = {An open access repository of images on plant health to enable the\n development of mobile disease diagnostics through machine\n learning and crowdsourcing},\n journal = {CoRR},\n volume = {abs/1511.08060},\n year = {2015},\n url = {http://arxiv.org/abs/1511.08060},\n archivePrefix = {arXiv},\n eprint = {1511.08060},\n timestamp = {Mon, 13 Aug 2018 16:48:21 +0200},\n biburl = {https://dblp.org/rec/bib/journals/corr/HughesS15},\n bibsource = {dblp computer science bibliography, https://dblp.org}\n}"
|
| 69 |
+
},
|
| 70 |
+
"plant_doc_classification": {
|
| 71 |
+
"license": "CC BY-SA 4.0",
|
| 72 |
+
"citation": "@inproceedings{10.1145/3371158.3371196,\n author = {Singh, Davinder and Jain, Naman and Jain, Pranjali and Kayal, Pratik and Kumawat, Sudhakar and Batra, Nipun},\n title = {PlantDoc: A Dataset for Visual Plant Disease Detection},\n year = {2020},\n isbn = {9781450377386},\n publisher = {Association for Computing Machinery},\n address = {New York, NY, USA},\n url = {https://doi.org/10.1145/3371158.3371196},\n doi = {10.1145/3371158.3371196},\n booktitle = {Proceedings of the 7th ACM IKDD CoDS and 25th COMAD},\n pages = {249–253},\n numpages = {5},\n keywords = {Deep Learning, Object Detection, Image Classification},\n location = {Hyderabad, India},\n series = {CoDS COMAD 2020}\n }"
|
| 73 |
+
},
|
| 74 |
+
"autonomous_greenhouse_regression": {
|
| 75 |
+
"license": "CC BY-SA 4.0",
|
| 76 |
+
"citation": "@misc{https://doi.org/10.4121/15023088.v1,\n doi = {10.4121/15023088.V1},\n url = {https://data.4tu.nl/articles/_/15023088/1},\n author = {Hemming, S. (Silke) and de Zwart, H.F. (Feije) and Elings, A. (Anne) and bijlaard, monique and Marrewijk, van, Bart and Petropoulou, Anna},\n keywords = {Horticultural Crops, Mechanical Engineering, FOS: Mechanical engineering, Artificial Intelligence and Image Processing, FOS: Computer and information sciences, Horticultural Production, FOS: Agriculture, forestry and fisheries, Autonomous Greenhouse Challenge, autonomous greenhouse, Artificial Intelligence, image processing, computer vision, Horticulture, Lettuce, sensors, non-destructive sensing},\n title = {3rd Autonomous Greenhouse Challenge: Online Challenge Lettuce Images},\n publisher = {4TU.ResearchData},\n year = {2021},\n copyright = {Creative Commons Attribution 4.0 International}\n}"
|
| 77 |
+
},
|
| 78 |
+
"grape_detection_syntheticday": {
|
| 79 |
+
"license": "",
|
| 80 |
+
"citation": "@ARTICLE{10.3389/fpls.2019.01185,\n \nAUTHOR={Bailey, Brian N.}, \n\t \nTITLE={Helios: A Scalable 3D Plant and Environmental Biophysical Modeling Framework}, \n\t\nJOURNAL={Frontiers in Plant Science}, \n\t\nVOLUME={10}, \n\t\nYEAR={2019}, \n\t \nURL={https://www.frontiersin.org/article/10.3389/fpls.2019.01185}, \n\t\nDOI={10.3389/fpls.2019.01185}, \n\t\nISSN={1664-462X}, \n \nABSTRACT={This article presents an overview of Helios, a new three-dimensional (3D) plant and environmental modeling framework. Helios is a model coupling framework designed to provide maximum flexibility in integrating and running arbitrary 3D environmental system models. Users interact with Helios through a well-documented open-source C++ API. Version 1.0 comes with model plug-ins for radiation transport, the surface energy balance, stomatal conductance, photosynthesis, solar position, and procedural tree generation. Additional plug-ins are also available for visualizing model geometry and data and for processing and integrating LiDAR scanning data. Many of the plug-ins perform calculations on the graphics processing unit, which allows for efficient simulation of very large domains with high detail. An example modeling study is presented in which leaf-level heterogeneity in water usage and photosynthesis of an orchard is examined to understand how this leaf-scale variability contributes to whole-tree and -canopy fluxes.}\n}"
|
| 81 |
+
},
|
| 82 |
+
"grape_detection_californiaday": {
|
| 83 |
+
"license": "",
|
| 84 |
+
"citation": "@misc{GrapeDay,\n author = {Plant AI and Biophysics Lab},\n title = {Grape Detection 2019 Day},\n year = {2019},\n url = {https://github.com/plant-ai-biophysics-lab/AgML} \n "
|
| 85 |
+
},
|
| 86 |
+
"grape_detection_californianight": {
|
| 87 |
+
"license": "",
|
| 88 |
+
"citation": "@misc{GrapeNight,\n author = {Plant AI and Biophysics Lab},\n title = {Grape Detection 2020 Night},\n year = {2020},\n url = {https://github.com/plant-ai-biophysics-lab/AgML} \n "
|
| 89 |
+
},
|
| 90 |
+
"guava_disease_pakistan": {
|
| 91 |
+
"license": "",
|
| 92 |
+
"citation": "@article{Rauf_Lali_2021, \n title={A Guava Fruits and Leaves Dataset for Detection and Classification of Guava Diseases through Machine Learning}, \n volume={1}, \n url={https://data.mendeley.com/datasets/s8x6jn5cvr/1}, \n DOI={10.17632/s8x6jn5cvr.1}, \n abstractNote={(1) Plant diseases are the primary cause of reduced productivity in agriculture, which results in economic losses. Guava is a big source of nutrients for humans all over the world. Guava diseases, on the other hand, harm the yield and quality of the crop. (2) For the identification and classification of plant diseases, computer vision and image processing methods have been commonly used. (3) The dataset includes an image gallery of healthy and unhealthy Guava fruits and leaves that could be used by researchers to adopt advanced computer vision techniques to protect plants from disease. Dot, Canker, Mummification, and Rust are the diseases targeted in the data sets. (4) The dataset contains 306 images of healthy and unhealthy images for both Guava fruits and leaves collectively. Each image contains 6000 * 4000 dimensions with 300 dpi resolution. (5) All images were acquired from the tropical areas of Pakistan under the supervision of Prof. Dr. Ikramullah Lali. (6) All images were annotated manually by the domain expert such as For Guava fruits and leaves; Dot (76), Canker (77), Mummification (83), and Rust (70) Note: The data labeling was manual and can be updated by automatic labeling through machine learning. In the meantime, the authors can also use the data set for the clustering problem.}, \n author={Rauf, Hafiz Tayyab and Lali, Muhammad Ikram Ullah}, \n year={2021}, month={Apr} \n}\n"
|
| 93 |
+
},
|
| 94 |
+
"apple_detection_spain": {
|
| 95 |
+
"license": "",
|
| 96 |
+
"citation": "@article{GENEMOLA2019104289,\ntitle = {KFuji RGB-DS database: Fuji apple multi-modal images for fruit detection with color, depth and range-corrected IR data},\njournal = {Data in Brief},\nvolume = {25},\npages = {104289},\nyear = {2019},\nissn = {2352-3409},\ndoi = {https://doi.org/10.1016/j.dib.2019.104289},\nurl = {https://www.sciencedirect.com/science/article/pii/S2352340919306432},\nauthor = {Jordi Gené-Mola and Verónica Vilaplana and Joan R. Rosell-Polo and Josep-Ramon Morros and Javier Ruiz-Hidalgo and Eduard Gregorio},\nkeywords = {Multi-modal dataset, Fruit detection, Depth cameras, RGB-D, Fruit reflectance, Fuji apple},\nabstract = {This article contains data related to the research article entitle “Multi-modal Deep Learning for Fruit Detection Using RGB-D Cameras and their Radiometric Capabilities” [1]. The development of reliable fruit detection and localization systems is essential for future sustainable agronomic management of high-value crops. RGB-D sensors have shown potential for fruit detection and localization since they provide 3D information with color data. However, the lack of substantial datasets is a barrier for exploiting the use of these sensors. This article presents the KFuji RGB-DS database which is composed by 967 multi-modal images of Fuji apples on trees captured using Microsoft Kinect v2 (Microsoft, Redmond, WA, USA). Each image contains information from 3 different modalities: color (RGB), depth (D) and range corrected IR intensity (S). Ground truth fruit locations were manually annotated, labeling a total of 12,839 apples in all the dataset. The current dataset is publicly available at http://www.grap.udl.cat/publicacions/datasets.html.}\n}"
|
| 97 |
+
},
|
| 98 |
+
"apple_detection_drone_brazil": {
|
| 99 |
+
"license": "CC BY-SA 4.0",
|
| 100 |
+
"citation": "@article{DBLP:journals/corr/abs-2110-12331,\n author = {Thiago T. Santos and\n Luciano Gebler},\n title = {A methodology for detection and localization of fruits in apples orchards\n from aerial images},\n journal = {CoRR},\n volume = {abs/2110.12331},\n year = {2021},\n url = {https://arxiv.org/abs/2110.12331},\n eprinttype = {arXiv},\n eprint = {2110.12331},\n timestamp = {Thu, 28 Oct 2021 15:25:31 +0200},\n biburl = {https://dblp.org/rec/journals/corr/abs-2110-12331.bib},\n bibsource = {dblp computer science bibliography, https://dblp.org}\n}"
|
| 101 |
+
},
|
| 102 |
+
"plant_doc_detection": {
|
| 103 |
+
"license": "CC BY-SA 4.0",
|
| 104 |
+
"citation": "@inproceedings{10.1145/3371158.3371196,\n author = {Singh, Davinder and Jain, Naman and Jain, Pranjali and Kayal, Pratik and Kumawat, Sudhakar and Batra, Nipun},\n title = {PlantDoc: A Dataset for Visual Plant Disease Detection},\n year = {2020},\n isbn = {9781450377386},\n publisher = {Association for Computing Machinery},\n address = {New York, NY, USA},\n url = {https://doi.org/10.1145/3371158.3371196},\n doi = {10.1145/3371158.3371196},\n booktitle = {Proceedings of the 7th ACM IKDD CoDS and 25th COMAD},\n pages = {249–253},\n numpages = {5},\n keywords = {Deep Learning, Object Detection, Image Classification},\n location = {Hyderabad, India},\n series = {CoDS COMAD 2020}\n }"
|
| 105 |
+
},
|
| 106 |
+
"wheat_head_counting": {
|
| 107 |
+
"license": "CC BY-SA 4.0",
|
| 108 |
+
"citation": "@article{david2020global,\n title={Global Wheat Head Detection (GWHD) dataset: a large and diverse dataset of high-resolution RGB-labelled images to develop and benchmark wheat head detection methods},\n author={David, Etienne and Madec, Simon and Sadeghi-Tehran, Pouria and Aasen, Helge and Zheng, Bangyou and Liu, Shouyang and Kirchgessner, Norbert and Ishikawa, Goro and Nagasawa, Koichi and Badhon, Minhajul A and others},\n journal={Plant Phenomics},\n volume={2020},\n year={2020},\n publisher={Science Partner Journal}\n }"
|
| 109 |
+
},
|
| 110 |
+
"peachpear_flower_segmentation": {
|
| 111 |
+
"license": "US Public Domain",
|
| 112 |
+
"citation": "@ARTICLE{8392727,\n author={Dias, Philipe A. and Tabb, Amy and Medeiros, Henry},\n journal={IEEE Robotics and Automation Letters}, \n title={Multispecies Fruit Flower Detection Using a Refined Semantic Segmentation Network}, \n year={2018},\n volume={3},\n number={4},\n pages={3003-3010},\n doi={10.1109/LRA.2018.2849498}}"
|
| 113 |
+
},
|
| 114 |
+
"red_grapes_and_leaves_segmentation": {
|
| 115 |
+
"license": "",
|
| 116 |
+
"citation": "@inproceedings{kalampokas2020semantic,\n title={Semantic segmentation of vineyard images using convolutional neural networks},\n author={Kalampokas, Theofanis and Tziridis, Konstantinos and Nikolaou, Alexandros and Vrochidou, Eleni and Papakostas, George A and Pachidis, Theodore and Kaburlasos, Vassilis G},\n booktitle={International Conference on Engineering Applications of Neural Networks},\n pages={292--303},\n year={2020},\n organization={Springer}}"
|
| 117 |
+
},
|
| 118 |
+
"white_grapes_and_leaves_segmentation": {
|
| 119 |
+
"license": "",
|
| 120 |
+
"citation": "@inproceedings{kalampokas2020semantic,\n title={Semantic segmentation of vineyard images using convolutional neural networks},\n author={Kalampokas, Theofanis and Tziridis, Konstantinos and Nikolaou, Alexandros and Vrochidou, Eleni and Papakostas, George A and Pachidis, Theodore and Kaburlasos, Vassilis G},\n booktitle={International Conference on Engineering Applications of Neural Networks},\n pages={292--303},\n year={2020},\n organization={Springer}}"
|
| 121 |
+
},
|
| 122 |
+
"ghai_romaine_detection": {
|
| 123 |
+
"license": "CC BY-SA 4.0",
|
| 124 |
+
"citation": ""
|
| 125 |
+
},
|
| 126 |
+
"ghai_green_cabbage_detection": {
|
| 127 |
+
"license": "CC BY-SA 4.0",
|
| 128 |
+
"citation": ""
|
| 129 |
+
},
|
| 130 |
+
"ghai_iceberg_lettuce_detection": {
|
| 131 |
+
"license": "CC BY-SA 4.0",
|
| 132 |
+
"citation": ""
|
| 133 |
+
},
|
| 134 |
+
"riseholme_strawberry_classification_2021": {
|
| 135 |
+
"license": "",
|
| 136 |
+
"citation": "@inproceedings{CWSC21,\n title={Self-supervised Representation Learning for Reliable Robotic Monitoring of Fruit Anomalies},\n author={Choi, Taeyeong and Would, Owen and Salazar-Gomez, Adrian and Cielniak, Grzegorz},\n booktitle={2022 International Conference on Robotics and Automation (ICRA)},\n pages={2266--2272},\n year={2022},\n organization={IEEE}\n}"
|
| 137 |
+
},
|
| 138 |
+
"ghai_broccoli_detection": {
|
| 139 |
+
"license": "CC BY-SA 4.0",
|
| 140 |
+
"citation": ""
|
| 141 |
+
},
|
| 142 |
+
"bean_synthetic_earlygrowth_aerial": {
|
| 143 |
+
"license": "MIT",
|
| 144 |
+
"citation": "@ARTICLE{10.3389/fpls.2019.01185,\n \nAUTHOR={Bailey, Brian N.}, \n\t \nTITLE={Helios: A Scalable 3D Plant and Environmental Biophysical Modeling Framework}, \n\t\nJOURNAL={Frontiers in Plant Science}, \n\t\nVOLUME={10}, \n\t\nYEAR={2019}, \n\t \nURL={https://www.frontiersin.org/article/10.3389/fpls.2019.01185}, \n\t\nDOI={10.3389/fpls.2019.01185}, \n\t\nISSN={1664-462X}, \n \nABSTRACT={This article presents an overview of Helios, a new three-dimensional (3D) plant and environmental modeling framework. Helios is a model coupling framework designed to provide maximum flexibility in integrating and running arbitrary 3D environmental system models. Users interact with Helios through a well-documented open-source C++ API. Version 1.0 comes with model plug-ins for radiation transport, the surface energy balance, stomatal conductance, photosynthesis, solar position, and procedural tree generation. Additional plug-ins are also available for visualizing model geometry and data and for processing and integrating LiDAR scanning data. Many of the plug-ins perform calculations on the graphics processing unit, which allows for efficient simulation of very large domains with high detail. An example modeling study is presented in which leaf-level heterogeneity in water usage and photosynthesis of an orchard is examined to understand how this leaf-scale variability contributes to whole-tree and -canopy fluxes.}\n}"
|
| 145 |
+
},
|
| 146 |
+
"ghai_strawberry_fruit_detection": {
|
| 147 |
+
"license": "CC BY-SA 4.0",
|
| 148 |
+
"citation": ""
|
| 149 |
+
},
|
| 150 |
+
"vegann_multicrop_presence_segmentation": {
|
| 151 |
+
"license": "CC BY-SA 4.0",
|
| 152 |
+
"citation": " @article{Madec_Irfan_Velumani_Baret_David_Daubige_Samatan_Serouart_Smith_James_et al._2023, title={VegAnn, Vegetation Annotation of multi-crop RGB images acquired under diverse conditions for segmentation}, volume={10}, ISSN={2052-4463}, url={https://www.nature.com/articles/s41597-023-02098-y}, DOI={10.1038/s41597-023-02098-y}, abstractNote={Abstract\n \n Applying deep learning to images of cropping systems provides new knowledge and insights in research and commercial applications. Semantic segmentation or pixel-wise classification, of RGB images acquired at the ground level, into vegetation and background is a critical step in the estimation of several canopy traits. Current state of the art methodologies based on convolutional neural networks (CNNs) are trained on datasets acquired under controlled or indoor environments. These models are unable to generalize to real-world images and hence need to be fine-tuned using new labelled datasets. This motivated the creation of the VegAnn -\n Veg\n etation\n Ann\n otation - dataset, a collection of 3775 multi-crop RGB images acquired for different phenological stages using different systems and platforms in diverse illumination conditions. We anticipate that VegAnn will help improving segmentation algorithm performances, facilitate benchmarking and promote large-scale crop vegetation segmentation research.}, number={1}, journal={Scientific Data}, author={Madec, Simon and Irfan, Kamran and Velumani, Kaaviya and Baret, Frederic and David, Etienne and Daubige, Gaetan and Samatan, Lucas Bernigaud and Serouart, Mario and Smith, Daniel and James, Chrisbin and Camacho, Fernando and Guo, Wei and De Solan, Benoit and Chapman, Scott C. and Weiss, Marie}, year={2023}, month=may, pages={302}, language={en} }\n"
|
| 153 |
+
},
|
| 154 |
+
"corn_maize_leaf_disease": {
|
| 155 |
+
"license": "",
|
| 156 |
+
"citation": "Singh D, Jain N, Jain P, Kayal P, Kumawat S, Batra N. PlantDoc: a dataset for visual plant disease detection. InProceedings of the 7th ACM IKDD CoDS and 25th COMAD 2020 Jan 5 (pp. 249-253)."
|
| 157 |
+
},
|
| 158 |
+
"tomato_leaf_disease": {
|
| 159 |
+
"license": "CC0: Public Domain",
|
| 160 |
+
"citation": ""
|
| 161 |
+
},
|
| 162 |
+
"vine_virus_photo_dataset": {
|
| 163 |
+
"license": "Apache 2.0",
|
| 164 |
+
"citation": ""
|
| 165 |
+
},
|
| 166 |
+
"embrapa_wgisd_grape_detection": {
|
| 167 |
+
"license": "CC BY-NC 4.0",
|
| 168 |
+
"citation": ""
|
| 169 |
+
},
|
| 170 |
+
"growliflower_cauliflower_segmentation": {
|
| 171 |
+
"license": "",
|
| 172 |
+
"citation": "Kierdorf, Jana & Junker-Frohn, Laura & Delaney, Mike & Olave, Mariele & Burkart, Andreas & Jaenicke, Hannah & Muller, Onno & Roscher, Ribana. (2022). GrowliFlower: An image time‐series dataset for GROWth analysis of cauLIFLOWER. Journal of Field Robotics. 40. 10.1002/rob.22122. "
|
| 173 |
+
},
|
| 174 |
+
"strawberry_detection_2023": {
|
| 175 |
+
"license": "CC BY 4.0",
|
| 176 |
+
"citation": ""
|
| 177 |
+
},
|
| 178 |
+
"strawberry_detection_2022": {
|
| 179 |
+
"license": "CC BY 4.0",
|
| 180 |
+
"citation": ""
|
| 181 |
+
},
|
| 182 |
+
"almond_harvest_2021": {
|
| 183 |
+
"license": "Apache 2.0",
|
| 184 |
+
"citation": ""
|
| 185 |
+
},
|
| 186 |
+
"almond_bloom_2023": {
|
| 187 |
+
"license": "Apache 2.0",
|
| 188 |
+
"citation": ""
|
| 189 |
+
},
|
| 190 |
+
"gemini_flower_detection_2022": {
|
| 191 |
+
"license": "Apache 2.0",
|
| 192 |
+
"citation": ""
|
| 193 |
+
},
|
| 194 |
+
"gemini_leaf_detection_2022": {
|
| 195 |
+
"license": "Apache 2.0",
|
| 196 |
+
"citation": ""
|
| 197 |
+
},
|
| 198 |
+
"gemini_pod_detection_2022": {
|
| 199 |
+
"license": "Apache 2.0",
|
| 200 |
+
"citation": ""
|
| 201 |
+
},
|
| 202 |
+
"gemini_plant_detection_2022": {
|
| 203 |
+
"license": "Apache 2.0",
|
| 204 |
+
"citation": ""
|
| 205 |
+
},
|
| 206 |
+
"paddy_disease_classification": {
|
| 207 |
+
"license": "CC BY 4.0",
|
| 208 |
+
"citation": "Petchiammal A, Briskline Kiruba S, Murugan D, Pandarasamy Arjunan. (2022). Paddy Doctor: A Visual Image Dataset for Automated Paddy Disease Classification and Benchmarking. IEEE Dataport. https://dx.doi.org/10.21227/hz4v-af08"
|
| 209 |
+
},
|
| 210 |
+
"onion_leaf_classification": {
|
| 211 |
+
"license": "CC BY 4.0",
|
| 212 |
+
"citation": "Aishwarya, M.P & Reddy, A.. (2024). Dataset of Chilli and Onion Plant Leaf Images for Classification and Detection. Data in Brief. 54. 110524. 10.1016/j.dib.2024.110524. "
|
| 213 |
+
},
|
| 214 |
+
"chilli_leaf_classification": {
|
| 215 |
+
"license": "CC BY 4.0",
|
| 216 |
+
"citation": "Aishwarya, M.P & Reddy, A.. (2024). Dataset of Chilli and Onion Plant Leaf Images for Classification and Detection. Data in Brief. 54. 110524. 10.1016/j.dib.2024.110524. "
|
| 217 |
+
},
|
| 218 |
+
"orange_leaf_disease_classification": {
|
| 219 |
+
"license": "CC BY 4.0",
|
| 220 |
+
"citation": "Emon, Yousuf Rayhan; Ahad, Md Taimur (2023), “Multi-format open-source sweet orange leaf dataset for disease detection, classification, and analysis.”, Mendeley Data, V1, doi: 10.17632/f7cr74mwpj.1"
|
| 221 |
+
},
|
| 222 |
+
"papaya_leaf_disease_classification": {
|
| 223 |
+
"license": "CC BY 4.0",
|
| 224 |
+
"citation": "Sarker, Arpita ; Mustofa, Sumaya; Ahad, Md Taimur (2023), “BDPapayaLeaf: A annotation based image dataset of papaya leaf disease.”, Mendeley Data, V1, doi: 10.17632/p997fvf526.1"
|
| 225 |
+
},
|
| 226 |
+
"blackgram_plant_leaf_disease_classification": {
|
| 227 |
+
"license": "CC BY 4.0",
|
| 228 |
+
"citation": "Talasila, Srinivas; Rawal, Kirti; Sethi, Gaurav; MSS, Sanjay; M, Surya Prakash Reddy (2022), “Blackgram Plant Leaf Disease Dataset”, Mendeley Data, V3, doi: 10.17632/zfcv9fmrgv.3"
|
| 229 |
+
},
|
| 230 |
+
"arabica_coffee_leaf_disease_classification": {
|
| 231 |
+
"license": "CC BY 4.0",
|
| 232 |
+
"citation": "@article{JEPKOECH2021107142, title = {Arabica coffee leaf images dataset for coffee leaf disease detection and classification}, journal = {Data in Brief}, volume = {36}, pages = {107142}, year = {2021}, issn = {2352-3409}, doi = {https://doi.org/10.1016/j.dib.2021.107142}, url = {https://www.sciencedirect.com/science/article/pii/S2352340921004261}, author = {Jennifer Jepkoech and David Muchangi Mugo and Benson K. Kenduiywo and Edna Chebet Too}}"
|
| 233 |
+
},
|
| 234 |
+
"banana_leaf_disease_classification": {
|
| 235 |
+
"license": "CC BY 4.0",
|
| 236 |
+
"citation": "hailu, yordanos (2021), “Banana Leaf Disease Images”, Mendeley Data, V1, doi: 10.17632/rjykr62kdh.1"
|
| 237 |
+
},
|
| 238 |
+
"coconut_tree_disease_classification": {
|
| 239 |
+
"license": "CC BY 4.0",
|
| 240 |
+
"citation": "PATIL, Kailas; Thite, Sandip; Suryawanshi, Yogesh; chumchu, prawit (2023), “Coconut Tree Disease Dataset”, Mendeley Data, V1, doi: 10.17632/gh56wbsnj5.1"
|
| 241 |
+
},
|
| 242 |
+
"rice_leaf_disease_classification": {
|
| 243 |
+
"license": "",
|
| 244 |
+
"citation": ""
|
| 245 |
+
},
|
| 246 |
+
"tea_leaf_disease_classification": {
|
| 247 |
+
"license": "CC BY-NC 4.0",
|
| 248 |
+
"citation": "@article{BALASUNDARAM2025103784, title = {Tea leaf disease detection using segment anything model and deep convolutional neural networks}, journal = {Results in Engineering}, volume = {25}, pages = {103784}, year = {2025}, issn = {2590-1230}, doi = {https://doi.org/10.1016/j.rineng.2024.103784}, url = {https://www.sciencedirect.com/science/article/pii/S2590123024020279}, author = {Ananthakrishnan Balasundaram and Prem Sundaresan and Aryan Bhavsar and Mishti Mattu and Muthu Subash Kavitha and Ayesha Shaik}}"
|
| 249 |
+
},
|
| 250 |
+
"betel_leaf_disease_classification": {
|
| 251 |
+
"license": "CC BY 4.0",
|
| 252 |
+
"citation": "Rashid, Mohammad Rifat Ahmmad; Hossain, Md. Miskat ; Biswas, Joy ; Majumder, Hredoy (2024), “Betel Leaf Image Dataset from Bangladesh”, Mendeley Data, V2, doi: 10.17632/g7fpgj57wc.2"
|
| 253 |
+
},
|
| 254 |
+
"java_plum_leaf_disease_classification": {
|
| 255 |
+
"license": "CC BY 4.0",
|
| 256 |
+
"citation": "Bhowmik, Auvick Chandra; Ahad, Taimur (2024), “Java Plum Leaf Disease Dataset”, Mendeley Data, V3, doi: 10.17632/43d75vptz4.3"
|
| 257 |
+
},
|
| 258 |
+
"sunflower_disease_classification": {
|
| 259 |
+
"license": "CC BY 4.0",
|
| 260 |
+
"citation": "Rajbongshi, Aditya; Sara, Umme ; Akter, Bonna ; Shakil, Rashiduzzaman ; Sazzad, Sadia (2022), “Sun Flower Fruits and Leaves dataset for Sunflower Disease Classification through Machine Learning and Deep Learning”, Mendeley Data, V1, doi: 10.17632/b83hmrzth8.1"
|
| 261 |
+
},
|
| 262 |
+
"cucumber_disease_classification": {
|
| 263 |
+
"license": "CC BY 4.0",
|
| 264 |
+
"citation": "Sultana, Nusrat; Shorif, Sumaita Binte ; Akter, Morium ; Uddin, Mohammad Shorif (2022), “Cucumber Disease Recognition Dataset”, Mendeley Data, V1, doi: 10.17632/y6d3z6f8z9.1"
|
| 265 |
+
},
|
| 266 |
+
"soybean_insect_classification": {
|
| 267 |
+
"license": "CC BY 4.0",
|
| 268 |
+
"citation": "Mignoni, Maria Eloisa (2021), “Images of Soybean Leaves”, Mendeley Data, V1, doi: 10.17632/bycbh73438.1"
|
| 269 |
+
}
|
| 270 |
+
}
|
AgML/source/agml/_assets/viz_colormaps.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"default": [
|
| 3 |
+
[0, 255, 0],
|
| 4 |
+
[255, 0, 0],
|
| 5 |
+
[0, 0, 255],
|
| 6 |
+
[255, 255, 0],
|
| 7 |
+
[255, 0, 255],
|
| 8 |
+
[0, 255, 255]
|
| 9 |
+
],
|
| 10 |
+
"agriculture": [
|
| 11 |
+
[0, 255, 0],
|
| 12 |
+
[50, 168, 82],
|
| 13 |
+
[42, 84, 24],
|
| 14 |
+
[17, 71, 4],
|
| 15 |
+
[57, 66, 53],
|
| 16 |
+
[181, 204, 171]
|
| 17 |
+
]
|
| 18 |
+
}
|
AgML/source/agml/_helios/helios_install.sh
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
# This script will almost certainly not be run manually, and instead
|
| 5 |
+
# be called by the AgML Helios module. So, we can't rely on using the
|
| 6 |
+
# existing parent directory to install Helios. Instead, we need to get
|
| 7 |
+
# the path of this actual file itself, and then
|
| 8 |
+
PATH_TO_ME="$(readlink -nf "$0")"
|
| 9 |
+
INSTALL_PATH="$(dirname "$(dirname "$PATH_TO_ME")")/_helios/Helios"
|
| 10 |
+
|
| 11 |
+
# Install or Update Helios, depending on whether the directory for Helios
|
| 12 |
+
# already exists. While the actual Python installation script which calls
|
| 13 |
+
# this shell script has slightly more complex logic (for figuring out
|
| 14 |
+
# version Helios is on, and in turn, whether it needs an update or not),
|
| 15 |
+
# this simply installs/updates based on the existence of the directory.
|
| 16 |
+
if [ ! -d "$INSTALL_PATH" ]; then
|
| 17 |
+
git clone -b master https://github.com/PlantSimulationLab/Helios.git "$INSTALL_PATH"
|
| 18 |
+
else
|
| 19 |
+
ORIGINAL_DIR="$PWD"
|
| 20 |
+
cd "$INSTALL_PATH"
|
| 21 |
+
git pull https://github.com/PlantSimulationLab/Helios.git master
|
| 22 |
+
cd "$ORIGINAL_DIR" || echo "Issue when trying to update Helios. Please report this to the AgML team."; exit
|
| 23 |
+
fi
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
|
AgML/source/agml/_internal/__init__.py
ADDED
|
File without changes
|
AgML/source/agml/_internal/preprocess.py
ADDED
|
@@ -0,0 +1,1609 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 UC Davis Plant AI and Biophysics Lab
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
"""
|
| 16 |
+
Preprocessing code for AgML public data sources.
|
| 17 |
+
This file stores the preprocessing code used to preprocess a public
|
| 18 |
+
dataset when added to AgML's public data sources.
|
| 19 |
+
If you want to use this preprocessing code, run `pip install agml[dev]`
|
| 20 |
+
to install the necessary preprocessing packages.
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
import argparse
|
| 24 |
+
import csv
|
| 25 |
+
import glob
|
| 26 |
+
import json
|
| 27 |
+
import os
|
| 28 |
+
import shutil
|
| 29 |
+
import sys
|
| 30 |
+
|
| 31 |
+
import cv2
|
| 32 |
+
import numpy as np
|
| 33 |
+
import pandas as pd
|
| 34 |
+
from PIL import Image
|
| 35 |
+
|
| 36 |
+
from agml._internal.process_utils import (
|
| 37 |
+
convert_bbox_to_coco,
|
| 38 |
+
convert_xmls_to_cocojson,
|
| 39 |
+
get_coco_annotation_from_obj,
|
| 40 |
+
get_image_info,
|
| 41 |
+
get_label2id,
|
| 42 |
+
move_segmentation_dataset,
|
| 43 |
+
read_txt_file,
|
| 44 |
+
)
|
| 45 |
+
from agml.utils.data import load_public_sources
|
| 46 |
+
from agml.utils.io import create_dir, get_dir_list, get_file_list, nested_dir_list
|
| 47 |
+
from agml.utils.logging import tqdm
|
| 48 |
+
|
| 49 |
+
def yolo_to_coco_bbox(x_center, y_center, width, height, img_width, img_height):
|
| 50 |
+
"""Convert YOLO format (x_center, y_center, width, height) to COCO format (xmin, ymin, width, height)."""
|
| 51 |
+
xmin = (x_center - (width / 2)) * img_width
|
| 52 |
+
ymin = (y_center - (height / 2)) * img_height
|
| 53 |
+
width = width * img_width
|
| 54 |
+
height = height * img_height
|
| 55 |
+
return [xmin, ymin, width, height]
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
class PublicDataPreprocessor(object):
|
| 59 |
+
"""Internal data preprocessing class.
|
| 60 |
+
|
| 61 |
+
Parameters
|
| 62 |
+
----------
|
| 63 |
+
data_dir : str
|
| 64 |
+
The directory with a folder `original` and `processed` to hold
|
| 65 |
+
the original and processed datasets, respectively.
|
| 66 |
+
"""
|
| 67 |
+
|
| 68 |
+
def __init__(self, data_dir):
|
| 69 |
+
self.data_dir = os.path.abspath(data_dir)
|
| 70 |
+
self.data_original_dir = os.path.join(self.data_dir, "original")
|
| 71 |
+
self.data_processed_dir = os.path.join(self.data_dir, "processed")
|
| 72 |
+
self.data_sources = load_public_sources()
|
| 73 |
+
|
| 74 |
+
def preprocess(self, dataset_name):
|
| 75 |
+
"""Preprocesses the provided dataset.
|
| 76 |
+
Parameters
|
| 77 |
+
----------
|
| 78 |
+
dataset_name : str
|
| 79 |
+
name of dataset to preprocess
|
| 80 |
+
"""
|
| 81 |
+
getattr(self, dataset_name)(dataset_name)
|
| 82 |
+
|
| 83 |
+
def vine_virus_photo_dataset(self, dataset_name):
|
| 84 |
+
"""Preprocesses the Vine Virus Photo Dataset."""
|
| 85 |
+
# Get the dataset directory directly (no need for 'original' directory)
|
| 86 |
+
base_path = self.data_dir
|
| 87 |
+
classes = sorted([d for d in os.listdir(base_path) if os.path.isdir(os.path.join(base_path, d))])
|
| 88 |
+
|
| 89 |
+
# Create output directory
|
| 90 |
+
output_path = os.path.join(self.data_processed_dir, dataset_name)
|
| 91 |
+
if not os.path.exists(output_path):
|
| 92 |
+
os.makedirs(output_path)
|
| 93 |
+
|
| 94 |
+
# Create subdirectories for each class inside the output directory
|
| 95 |
+
for cls in classes:
|
| 96 |
+
class_output_path = os.path.join(output_path, cls)
|
| 97 |
+
if not os.path.exists(class_output_path):
|
| 98 |
+
os.makedirs(class_output_path)
|
| 99 |
+
|
| 100 |
+
# Process and copy the dataset images to the processed directory
|
| 101 |
+
for cls in classes:
|
| 102 |
+
class_path = os.path.join(base_path, cls)
|
| 103 |
+
for img in os.listdir(class_path):
|
| 104 |
+
if img.endswith(("jpg", "png", "jpeg", "JPG")):
|
| 105 |
+
img_path = os.path.join(class_path, img)
|
| 106 |
+
shutil.copyfile(img_path, os.path.join(output_path, cls, img))
|
| 107 |
+
|
| 108 |
+
print(f"Dataset {dataset_name} has been preprocessed and saved to {output_path}")
|
| 109 |
+
|
| 110 |
+
def corn_maize_leaf_disease(self, dataset_name):
|
| 111 |
+
"""Preprocesses the Corn or Maize Leaf Disease Dataset."""
|
| 112 |
+
# Get the dataset directory directly (no need for 'original' directory)
|
| 113 |
+
base_path = self.data_dir
|
| 114 |
+
classes = sorted([d for d in os.listdir(base_path) if os.path.isdir(os.path.join(base_path, d))])
|
| 115 |
+
|
| 116 |
+
# Create output directory
|
| 117 |
+
output_path = os.path.join(self.data_processed_dir, dataset_name)
|
| 118 |
+
if not os.path.exists(output_path):
|
| 119 |
+
os.makedirs(output_path)
|
| 120 |
+
|
| 121 |
+
# Create subdirectories for each class inside the output directory
|
| 122 |
+
for cls in classes:
|
| 123 |
+
class_output_path = os.path.join(output_path, cls)
|
| 124 |
+
if not os.path.exists(class_output_path):
|
| 125 |
+
os.makedirs(class_output_path)
|
| 126 |
+
|
| 127 |
+
# Process and copy the dataset images to the processed directory
|
| 128 |
+
for cls in classes:
|
| 129 |
+
class_path = os.path.join(base_path, cls)
|
| 130 |
+
for img in os.listdir(class_path):
|
| 131 |
+
if img.endswith(("jpg", "png", "jpeg", "JPG")):
|
| 132 |
+
img_path = os.path.join(class_path, img)
|
| 133 |
+
|
| 134 |
+
# Open the image using Pillow
|
| 135 |
+
with Image.open(img_path) as image:
|
| 136 |
+
# Convert image to a NumPy array
|
| 137 |
+
img_array = np.array(image)
|
| 138 |
+
|
| 139 |
+
# Ensure the image is in range [0, 255] and dtype is uint8
|
| 140 |
+
if img_array.dtype != np.uint8:
|
| 141 |
+
# If the image is in float [0-1], scale it to [0-255]
|
| 142 |
+
img_array = (img_array * 255).astype(np.uint8)
|
| 143 |
+
|
| 144 |
+
# Convert back to PIL Image to save
|
| 145 |
+
processed_image = Image.fromarray(img_array)
|
| 146 |
+
|
| 147 |
+
if processed_image.mode == "RGBA":
|
| 148 |
+
processed_image = processed_image.convert("RGB")
|
| 149 |
+
|
| 150 |
+
# Save the processed image to the output directory
|
| 151 |
+
processed_image.save(os.path.join(output_path, cls, img))
|
| 152 |
+
|
| 153 |
+
print(f"Dataset {dataset_name} has been preprocessed and saved to {output_path}")
|
| 154 |
+
|
| 155 |
+
def tomato_leaf_disease(self, dataset_name):
|
| 156 |
+
"""Preprocesses the Tomato Leaf Disease Dataset."""
|
| 157 |
+
# Get the dataset directory directly (no need for 'original' directory)
|
| 158 |
+
base_path = self.data_dir
|
| 159 |
+
classes = sorted([d for d in os.listdir(base_path) if os.path.isdir(os.path.join(base_path, d))])
|
| 160 |
+
|
| 161 |
+
# Create output directory
|
| 162 |
+
output_path = os.path.join(self.data_processed_dir, dataset_name)
|
| 163 |
+
if not os.path.exists(output_path):
|
| 164 |
+
os.makedirs(output_path)
|
| 165 |
+
|
| 166 |
+
# Create subdirectories for each class inside the output directory
|
| 167 |
+
for cls in classes:
|
| 168 |
+
class_output_path = os.path.join(output_path, cls)
|
| 169 |
+
if not os.path.exists(class_output_path):
|
| 170 |
+
os.makedirs(class_output_path)
|
| 171 |
+
|
| 172 |
+
# Process and copy the dataset images to the processed directory
|
| 173 |
+
for cls in classes:
|
| 174 |
+
class_path = os.path.join(base_path, cls)
|
| 175 |
+
for img in os.listdir(class_path):
|
| 176 |
+
if img.endswith(("jpg", "png", "jpeg", "JPG")):
|
| 177 |
+
img_path = os.path.join(class_path, img)
|
| 178 |
+
|
| 179 |
+
# Open the image using Pillow
|
| 180 |
+
with Image.open(img_path) as image:
|
| 181 |
+
# Convert image to a NumPy array
|
| 182 |
+
img_array = np.array(image)
|
| 183 |
+
|
| 184 |
+
# Ensure the image is in range [0, 255] and dtype is uint8
|
| 185 |
+
if img_array.dtype != np.uint8:
|
| 186 |
+
# If the image is in float [0-1], scale it to [0-255]
|
| 187 |
+
img_array = (img_array * 255).astype(np.uint8)
|
| 188 |
+
|
| 189 |
+
# Convert back to PIL Image to save
|
| 190 |
+
processed_image = Image.fromarray(img_array)
|
| 191 |
+
|
| 192 |
+
if processed_image.mode == "RGBA":
|
| 193 |
+
processed_image = processed_image.convert("RGB")
|
| 194 |
+
|
| 195 |
+
# Save the processed image to the output directory
|
| 196 |
+
processed_image.save(os.path.join(output_path, cls, img))
|
| 197 |
+
|
| 198 |
+
print(f"Dataset {dataset_name} has been preprocessed and saved to {output_path}")
|
| 199 |
+
|
| 200 |
+
def bean_disease_uganda(self, dataset_name):
|
| 201 |
+
# Get the dataset classes and paths
|
| 202 |
+
base_path = os.path.join(self.data_original_dir, dataset_name)
|
| 203 |
+
dirs = ["train", "validation", "test"]
|
| 204 |
+
classes = sorted(os.listdir(os.path.join(base_path, dirs[0])))[1:]
|
| 205 |
+
|
| 206 |
+
# Construct output directories
|
| 207 |
+
output = os.path.join(self.data_processed_dir, dataset_name)
|
| 208 |
+
os.makedirs(output, exist_ok=True)
|
| 209 |
+
for cls in classes:
|
| 210 |
+
os.makedirs(os.path.join(output, cls), exist_ok=True)
|
| 211 |
+
|
| 212 |
+
# Move the dataset
|
| 213 |
+
for dir_ in dirs:
|
| 214 |
+
for cls in classes:
|
| 215 |
+
path = os.path.join(base_path, dir_, cls)
|
| 216 |
+
for p in os.listdir(path):
|
| 217 |
+
if p.endswith("jpg") or p.endswith("png"):
|
| 218 |
+
img = os.path.join(base_path, dir_, cls, p)
|
| 219 |
+
shutil.copyfile(img, os.path.join(output, cls, p))
|
| 220 |
+
|
| 221 |
+
def leaf_counting_denmark(self, dataset_name):
|
| 222 |
+
pass
|
| 223 |
+
|
| 224 |
+
def plant_seedlings_aarhus(self, dataset_name):
|
| 225 |
+
pass
|
| 226 |
+
|
| 227 |
+
def crop_weeds_greece(self, dataset_name):
|
| 228 |
+
pass
|
| 229 |
+
|
| 230 |
+
def rangeland_weeds_australia(self, dataset_name):
|
| 231 |
+
# Get the file information.
|
| 232 |
+
dataset_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 233 |
+
images = get_file_list(os.path.join(dataset_dir, "images"))
|
| 234 |
+
df = pd.read_csv(os.path.join(dataset_dir, "labels.csv"))
|
| 235 |
+
|
| 236 |
+
# Construct the new structure.
|
| 237 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 238 |
+
unique_labels = np.unique(df["Species"])
|
| 239 |
+
for unique_label in unique_labels:
|
| 240 |
+
os.makedirs(os.path.join(processed_dir, unique_label.title()), exist_ok=True)
|
| 241 |
+
for file in tqdm(images, desc="Moving Images", file=sys.stdout):
|
| 242 |
+
save_dir = df.loc[df["Filename"] == os.path.basename(file)]["Species"].values[0].title()
|
| 243 |
+
shutil.copyfile(
|
| 244 |
+
os.path.join(dataset_dir, "images", file),
|
| 245 |
+
os.path.join(processed_dir, save_dir, os.path.basename(file)),
|
| 246 |
+
)
|
| 247 |
+
|
| 248 |
+
def fruit_detection_worldwide(self, dataset_name):
|
| 249 |
+
# Get the dataset directory
|
| 250 |
+
dataset_dir = os.path.join(self.data_original_dir, dataset_name, "datasets")
|
| 251 |
+
|
| 252 |
+
# Get folder list
|
| 253 |
+
dataset_folders = get_dir_list(dataset_dir)
|
| 254 |
+
label2id = get_label2id(dataset_folders)
|
| 255 |
+
anno_data_all = []
|
| 256 |
+
for folder in dataset_folders:
|
| 257 |
+
annotations = ["test_RGB.txt", "train_RGB.txt"]
|
| 258 |
+
dataset_path = os.path.join(dataset_dir, folder)
|
| 259 |
+
# @TODO: Make separate json files for train and test?
|
| 260 |
+
for anno_file_name in annotations:
|
| 261 |
+
# Read annotations
|
| 262 |
+
try:
|
| 263 |
+
anno_data = read_txt_file(os.path.join(dataset_path, anno_file_name))
|
| 264 |
+
except:
|
| 265 |
+
try:
|
| 266 |
+
anno_data = read_txt_file(os.path.join(dataset_path, anno_file_name + ".txt"))
|
| 267 |
+
except Exception as e:
|
| 268 |
+
raise e
|
| 269 |
+
|
| 270 |
+
# Concat fruit name at head of line
|
| 271 |
+
for i, anno in enumerate(anno_data):
|
| 272 |
+
# Change to test path if the text file is test
|
| 273 |
+
if "test" in anno_file_name and "TRAIN" in anno[0]:
|
| 274 |
+
anno_data[i][0] = anno[0].replace("TRAIN", "TEST")
|
| 275 |
+
anno_data[i][0] = os.path.join(dataset_path, anno_data[i][0])
|
| 276 |
+
|
| 277 |
+
anno_data_all += anno_data
|
| 278 |
+
|
| 279 |
+
# Process annotation files
|
| 280 |
+
save_dir_anno = os.path.join(self.data_processed_dir, dataset_name, "annotations")
|
| 281 |
+
create_dir(save_dir_anno)
|
| 282 |
+
output_json_file = os.path.join(save_dir_anno, "instances.json")
|
| 283 |
+
|
| 284 |
+
general_info = {
|
| 285 |
+
"description": "fruits dataset",
|
| 286 |
+
"url": "https://drive.google.com/drive/folders/1CmsZb1caggLRN7ANfika8WuPiywo4mBb",
|
| 287 |
+
"version": "1.0",
|
| 288 |
+
"year": 2018,
|
| 289 |
+
"contributor": "Inkyu Sa",
|
| 290 |
+
"date_created": "2018/11/12",
|
| 291 |
+
}
|
| 292 |
+
|
| 293 |
+
# Process image files
|
| 294 |
+
output_img_path = os.path.join(self.data_processed_dir, dataset_name, "images")
|
| 295 |
+
create_dir(output_img_path)
|
| 296 |
+
|
| 297 |
+
convert_bbox_to_coco(anno_data_all, label2id, output_json_file, output_img_path, general_info)
|
| 298 |
+
|
| 299 |
+
def apple_detection_usa(self, dataset_name, fix=False):
|
| 300 |
+
# Just a quick fix to clip over-sized bounding boxes.
|
| 301 |
+
if fix:
|
| 302 |
+
# Load in the annotations.
|
| 303 |
+
dataset_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 304 |
+
with open(os.path.join(dataset_dir, "annotations.json"), "r") as f:
|
| 305 |
+
annotations = json.load(f)
|
| 306 |
+
|
| 307 |
+
# Get the images and all of their heights/widths.
|
| 308 |
+
images = annotations["images"]
|
| 309 |
+
image_id_content_map = {}
|
| 310 |
+
for image in images:
|
| 311 |
+
image_id_content_map[image["id"]] = (image["height"], image["width"])
|
| 312 |
+
|
| 313 |
+
# Load all of the annotations.
|
| 314 |
+
new_annotations = []
|
| 315 |
+
for a in annotations["annotations"]:
|
| 316 |
+
new_a = a.copy()
|
| 317 |
+
height, width = image_id_content_map[a["image_id"]]
|
| 318 |
+
(x, y, w, h) = a["bbox"]
|
| 319 |
+
x1, y1, x2, y2 = x, y, x + w, y + h
|
| 320 |
+
x1 = np.clip(x1, 0, width)
|
| 321 |
+
x2 = np.clip(x2, 0, width)
|
| 322 |
+
y1 = np.clip(y1, 0, height)
|
| 323 |
+
y2 = np.clip(y2, 0, height)
|
| 324 |
+
new_a["bbox"] = [int(i) for i in [x1, y1, x2 - x1, y2 - y1]]
|
| 325 |
+
new_annotations.append(new_a)
|
| 326 |
+
|
| 327 |
+
# Save the annotations.
|
| 328 |
+
annotations["annotations"] = new_annotations
|
| 329 |
+
with open(os.path.join(dataset_dir, "annotations.json"), "w") as f:
|
| 330 |
+
json.dump(annotations, f)
|
| 331 |
+
return
|
| 332 |
+
|
| 333 |
+
# resize the dataset
|
| 334 |
+
resize = 1.0
|
| 335 |
+
|
| 336 |
+
# Read public_datasources.json to get class information
|
| 337 |
+
category_info = self.data_sources[dataset_name]["classes"]
|
| 338 |
+
labels_str = []
|
| 339 |
+
labels_ids = []
|
| 340 |
+
for info in category_info:
|
| 341 |
+
labels_str.append(category_info[info])
|
| 342 |
+
labels_ids.append(int(info))
|
| 343 |
+
|
| 344 |
+
label2id = dict(zip(labels_str, labels_ids))
|
| 345 |
+
|
| 346 |
+
# Task 1: Image classification
|
| 347 |
+
dataset_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 348 |
+
obj_Detection_data = os.path.join(dataset_dir, "Dataset")
|
| 349 |
+
|
| 350 |
+
# get folders
|
| 351 |
+
plant_folders = nested_dir_list(obj_Detection_data)
|
| 352 |
+
|
| 353 |
+
# do tasks along folders
|
| 354 |
+
anno_data_all = []
|
| 355 |
+
for folder in plant_folders:
|
| 356 |
+
# Get image file and xml file
|
| 357 |
+
full_path = os.path.join(obj_Detection_data, folder)
|
| 358 |
+
all_files = get_file_list(full_path)
|
| 359 |
+
anno_files = [x for x in all_files if "txt" in x]
|
| 360 |
+
for anno_file in anno_files:
|
| 361 |
+
anno_line = []
|
| 362 |
+
anno_path = os.path.join(full_path, anno_file)
|
| 363 |
+
# Opening annotation file
|
| 364 |
+
anno_data = read_txt_file(anno_path, delimiter=",")[0]
|
| 365 |
+
|
| 366 |
+
for i, anno in enumerate(anno_data):
|
| 367 |
+
new_anno = [os.path.join(dataset_dir, anno_data[i][0])]
|
| 368 |
+
# Add bbox count
|
| 369 |
+
# Update image file path to abs path
|
| 370 |
+
bbox_cnt = int((len(anno_data[i]) - 1) / 4)
|
| 371 |
+
new_anno.append(str(bbox_cnt))
|
| 372 |
+
for idx in range(bbox_cnt):
|
| 373 |
+
xmin = int(anno[1 + 4 * idx])
|
| 374 |
+
ymin = int(anno[1 + 4 * idx + 1])
|
| 375 |
+
w = int(anno[1 + 4 * idx + 2])
|
| 376 |
+
h = int(anno[1 + 4 * idx + 3])
|
| 377 |
+
|
| 378 |
+
new_anno.append(str(xmin)) # xmin
|
| 379 |
+
new_anno.append(str(ymin)) # ymin
|
| 380 |
+
new_anno.append(str(xmin + w)) # xmax
|
| 381 |
+
new_anno.append(str(ymin + h)) # ymax
|
| 382 |
+
new_anno.append(str(1)) # label
|
| 383 |
+
anno_data[i] = new_anno
|
| 384 |
+
anno_data_all += anno_data
|
| 385 |
+
|
| 386 |
+
# Process annotation files
|
| 387 |
+
save_dir_anno = os.path.join(self.data_processed_dir, dataset_name, "annotations")
|
| 388 |
+
create_dir(save_dir_anno)
|
| 389 |
+
output_json_file = os.path.join(save_dir_anno, "instances.json")
|
| 390 |
+
|
| 391 |
+
general_info = {
|
| 392 |
+
"description": "apple dataset",
|
| 393 |
+
"url": "https://research.libraries.wsu.edu:8443/xmlui/handle/2376/17721",
|
| 394 |
+
"version": "1.0",
|
| 395 |
+
"year": 2019,
|
| 396 |
+
"contributor": "Bhusal, Santosh, Karkee, Manoj, Zhang, Qin",
|
| 397 |
+
"date_created": "2019/04/20",
|
| 398 |
+
}
|
| 399 |
+
|
| 400 |
+
# Process image files
|
| 401 |
+
output_img_path = os.path.join(self.data_processed_dir, dataset_name, "images")
|
| 402 |
+
create_dir(output_img_path)
|
| 403 |
+
convert_bbox_to_coco(
|
| 404 |
+
anno_data_all,
|
| 405 |
+
label2id,
|
| 406 |
+
output_json_file,
|
| 407 |
+
output_img_path,
|
| 408 |
+
general_info,
|
| 409 |
+
None,
|
| 410 |
+
None,
|
| 411 |
+
get_label_from_folder=False,
|
| 412 |
+
resize=resize,
|
| 413 |
+
add_foldername=True,
|
| 414 |
+
)
|
| 415 |
+
|
| 416 |
+
def mango_detection_australia(self, dataset_name):
|
| 417 |
+
# resize the dataset
|
| 418 |
+
resize = 1.0
|
| 419 |
+
|
| 420 |
+
# Read public_datasources.json to get class information
|
| 421 |
+
datasource_file = os.path.join(os.path.dirname(__file__), "../_assets/public_datasources.json")
|
| 422 |
+
with open(datasource_file) as f:
|
| 423 |
+
data = json.load(f)
|
| 424 |
+
category_info = data[dataset_name]["crop_types"]
|
| 425 |
+
labels_str = []
|
| 426 |
+
labels_ids = []
|
| 427 |
+
for info in category_info:
|
| 428 |
+
labels_str.append(category_info[info])
|
| 429 |
+
labels_ids.append(int(info))
|
| 430 |
+
|
| 431 |
+
name_converter = dict(zip(["M"], ["mango"])) # src -> dst
|
| 432 |
+
label2id = dict(zip(labels_str, labels_ids))
|
| 433 |
+
|
| 434 |
+
dataset_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 435 |
+
ann_dir = os.path.join(dataset_dir, "VOCDevkit/VOC2007/Annotations")
|
| 436 |
+
|
| 437 |
+
# Get image file and xml file
|
| 438 |
+
all_files = get_file_list(ann_dir)
|
| 439 |
+
anno_files = [os.path.join(ann_dir, x) for x in all_files if "xml" in x]
|
| 440 |
+
img_files = [x.replace(".xml", ".jpg").replace("Annotations", "JPEGImages") for x in anno_files]
|
| 441 |
+
|
| 442 |
+
# Process annotation files
|
| 443 |
+
save_dir_anno = os.path.join(self.data_processed_dir, dataset_name, "annotations")
|
| 444 |
+
create_dir(save_dir_anno)
|
| 445 |
+
output_json_file = os.path.join(save_dir_anno, "instances.json")
|
| 446 |
+
|
| 447 |
+
# Process image files
|
| 448 |
+
output_img_path = os.path.join(self.data_processed_dir, dataset_name, "images")
|
| 449 |
+
create_dir(output_img_path)
|
| 450 |
+
|
| 451 |
+
general_info = {
|
| 452 |
+
"description": "MangoYOLO data set",
|
| 453 |
+
"url": "https://researchdata.edu.au/mangoyolo-set/1697505",
|
| 454 |
+
"version": "1.0",
|
| 455 |
+
"year": 2019,
|
| 456 |
+
"contributor": "Anand Koirala, Kerry Walsh, Z Wang, C McCarthy",
|
| 457 |
+
"date_created": "2019/02/25",
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
convert_xmls_to_cocojson(
|
| 461 |
+
general_info,
|
| 462 |
+
annotation_paths=anno_files,
|
| 463 |
+
img_paths=img_files,
|
| 464 |
+
label2id=label2id,
|
| 465 |
+
name_converter=name_converter,
|
| 466 |
+
output_jsonpath=output_json_file,
|
| 467 |
+
output_imgpath=output_img_path,
|
| 468 |
+
extract_num_from_imgid=True,
|
| 469 |
+
)
|
| 470 |
+
|
| 471 |
+
def tomato_ripeness_detection(self, dataset_name):
|
| 472 |
+
pass
|
| 473 |
+
|
| 474 |
+
def cotton_seedling_counting(self, dataset_name):
|
| 475 |
+
# Get all of the relevant data
|
| 476 |
+
dataset_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 477 |
+
image_dir = os.path.join(dataset_dir, "Images")
|
| 478 |
+
images = sorted([os.path.join(image_dir, i) for i in os.listdir(image_dir)])
|
| 479 |
+
with open(os.path.join(dataset_dir, "Images.json"), "r") as f:
|
| 480 |
+
annotations = json.load(f)
|
| 481 |
+
|
| 482 |
+
# Get all of the unique labels
|
| 483 |
+
labels = []
|
| 484 |
+
for label_set in annotations["frames"].values():
|
| 485 |
+
for individual_set in label_set:
|
| 486 |
+
labels.extend(individual_set["tags"])
|
| 487 |
+
labels = np.unique(labels).tolist()
|
| 488 |
+
label2id = get_label2id(labels) # noqa
|
| 489 |
+
|
| 490 |
+
# Extract all of the bounding boxes and images
|
| 491 |
+
image_data = []
|
| 492 |
+
annotation_data = []
|
| 493 |
+
valid_paths = [] # some paths are not in the annotations, track the ones which are
|
| 494 |
+
for indx, (img_path, annotation) in enumerate(
|
| 495 |
+
zip(
|
| 496 |
+
tqdm(images, file=sys.stdout, desc="Generating Data"),
|
| 497 |
+
annotations["frames"].values(),
|
| 498 |
+
)
|
| 499 |
+
):
|
| 500 |
+
image_data.append(get_image_info(img_path, indx))
|
| 501 |
+
valid_paths.append(img_path)
|
| 502 |
+
for a_set in annotation:
|
| 503 |
+
formatted_set = [
|
| 504 |
+
a_set["x1"],
|
| 505 |
+
a_set["y1"],
|
| 506 |
+
a_set["x2"],
|
| 507 |
+
a_set["y2"],
|
| 508 |
+
label2id[a_set["tags"][0]],
|
| 509 |
+
]
|
| 510 |
+
base_annotation_data = get_coco_annotation_from_obj(formatted_set, a_set["name"])
|
| 511 |
+
base_annotation_data["image_id"] = indx + 1
|
| 512 |
+
annotation_data.append(base_annotation_data)
|
| 513 |
+
|
| 514 |
+
# Set up the annotation dictionary
|
| 515 |
+
all_annotation_data = {
|
| 516 |
+
"images": [],
|
| 517 |
+
"type": "instances",
|
| 518 |
+
"annotations": [],
|
| 519 |
+
"categories": [],
|
| 520 |
+
"info": {
|
| 521 |
+
"description": "cotton seedling counting dataset",
|
| 522 |
+
"url": "https://figshare.com/s/616956f8633c17ceae9b",
|
| 523 |
+
"version": "1.0",
|
| 524 |
+
"year": 2019,
|
| 525 |
+
"contributor": "Yu Jiang",
|
| 526 |
+
"date_created": "2019/11/23",
|
| 527 |
+
},
|
| 528 |
+
}
|
| 529 |
+
|
| 530 |
+
# Populate the annotation dictionary
|
| 531 |
+
for label, label_id in label2id.items():
|
| 532 |
+
category_info = {"supercategory": "none", "id": label_id, "name": label}
|
| 533 |
+
all_annotation_data["categories"].append(category_info)
|
| 534 |
+
all_annotation_data["images"] = image_data
|
| 535 |
+
all_annotation_data["annotations"] = annotation_data
|
| 536 |
+
|
| 537 |
+
# Recreate the dataset and zip it
|
| 538 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 539 |
+
processed_img_dir = os.path.join(processed_dir, "images")
|
| 540 |
+
if os.path.exists(processed_dir):
|
| 541 |
+
shutil.rmtree(processed_dir)
|
| 542 |
+
os.makedirs(processed_dir, exist_ok=True)
|
| 543 |
+
os.makedirs(processed_img_dir, exist_ok=True)
|
| 544 |
+
for path in images:
|
| 545 |
+
if path not in valid_paths:
|
| 546 |
+
continue
|
| 547 |
+
shutil.copyfile(path, os.path.join(processed_img_dir, os.path.basename(path)))
|
| 548 |
+
with open(os.path.join(processed_dir, "annotations.json"), "w") as f:
|
| 549 |
+
json.dump(all_annotation_data, f, indent=4)
|
| 550 |
+
|
| 551 |
+
# Zip the dataset
|
| 552 |
+
shutil.make_archive(processed_dir, "zip", os.path.dirname(processed_dir))
|
| 553 |
+
|
| 554 |
+
def apple_flower_segmentation(self, dataset_name):
|
| 555 |
+
# Get all of the relevant data.
|
| 556 |
+
dataset_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 557 |
+
apple_a_dir = os.path.join(dataset_dir, "FlowerImages")
|
| 558 |
+
apple_a_images = os.listdir(apple_a_dir)
|
| 559 |
+
apple_a_label_dir = os.path.join(dataset_dir, "AppleA_Labels")
|
| 560 |
+
apple_a_labels = os.listdir(apple_a_label_dir)
|
| 561 |
+
apple_b_dir = os.path.join(dataset_dir, "AppleB")
|
| 562 |
+
apple_b_images = os.listdir(apple_b_dir)
|
| 563 |
+
apple_b_label_dir = os.path.join(dataset_dir, "AppleB_Labels")
|
| 564 |
+
apple_b_labels = os.listdir(apple_b_label_dir)
|
| 565 |
+
|
| 566 |
+
# Map image filenames with their corresponding labels.
|
| 567 |
+
fname_map_a, fname_map_b = {}, {}
|
| 568 |
+
for fname in apple_a_images:
|
| 569 |
+
fname_id = str(int(float(os.path.splitext(fname)[0].split("_")[-1]))) + ".png"
|
| 570 |
+
if fname_id in apple_a_labels:
|
| 571 |
+
fname_map_a[os.path.join(apple_a_dir, fname)] = os.path.join(apple_a_label_dir, fname_id)
|
| 572 |
+
for fname in apple_b_images:
|
| 573 |
+
fname_id = str(int(float(os.path.splitext(fname)[0].split("_")[-1]))) + ".png"
|
| 574 |
+
if fname_id in apple_b_labels:
|
| 575 |
+
fname_map_b[os.path.join(apple_b_dir, fname)] = os.path.join(apple_b_label_dir, fname_id)
|
| 576 |
+
|
| 577 |
+
# Process and move the images.
|
| 578 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 579 |
+
os.makedirs(processed_dir, exist_ok=True)
|
| 580 |
+
processed_image_dir = os.path.join(processed_dir, "images")
|
| 581 |
+
os.makedirs(processed_image_dir, exist_ok=True)
|
| 582 |
+
processed_annotation_dir = os.path.join(processed_dir, "annotations")
|
| 583 |
+
os.makedirs(processed_annotation_dir, exist_ok=True)
|
| 584 |
+
for image_path, label_path in tqdm(fname_map_a.items(), desc="Processing Part A", file=sys.stdout):
|
| 585 |
+
image = cv2.resize(cv2.imread(image_path), (2074, 1382))
|
| 586 |
+
label = cv2.resize(cv2.imread(label_path), (2074, 1382)) // 255
|
| 587 |
+
label_path = os.path.basename(label_path)
|
| 588 |
+
out_image_path = os.path.join(processed_image_dir, label_path)
|
| 589 |
+
out_label_path = os.path.join(processed_annotation_dir, label_path)
|
| 590 |
+
cv2.imwrite(out_image_path.replace(".png", ".jpg"), image)
|
| 591 |
+
cv2.imwrite(out_label_path, label)
|
| 592 |
+
for image_path, label_path in tqdm(fname_map_b.items(), desc="Processing Part B", file=sys.stdout):
|
| 593 |
+
image = cv2.resize(cv2.imread(image_path), (2074, 1382))
|
| 594 |
+
label = cv2.resize(cv2.imread(label_path), (2074, 1382)) // 255
|
| 595 |
+
label_path = os.path.basename(label_path)
|
| 596 |
+
out_image_path = os.path.join(processed_image_dir, label_path)
|
| 597 |
+
out_label_path = os.path.join(processed_annotation_dir, label_path)
|
| 598 |
+
cv2.imwrite(out_image_path.replace(".png", ".jpg"), image)
|
| 599 |
+
cv2.imwrite(out_label_path, label)
|
| 600 |
+
|
| 601 |
+
def sugarbeet_weed_segmentation(self, dataset_name):
|
| 602 |
+
# Get all of the relevant data
|
| 603 |
+
dataset_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 604 |
+
train_dir = os.path.join(dataset_dir, "train")
|
| 605 |
+
train_images = sorted(get_file_list(train_dir))
|
| 606 |
+
annotation_dir = os.path.join(dataset_dir, "trainannot") # noqa
|
| 607 |
+
annotation_images = sorted(get_file_list(annotation_dir))
|
| 608 |
+
|
| 609 |
+
# Move the images to the new directory
|
| 610 |
+
move_segmentation_dataset(
|
| 611 |
+
self.data_processed_dir,
|
| 612 |
+
dataset_name,
|
| 613 |
+
train_images,
|
| 614 |
+
annotation_images,
|
| 615 |
+
train_dir,
|
| 616 |
+
annotation_dir,
|
| 617 |
+
)
|
| 618 |
+
|
| 619 |
+
def carrot_weeds_germany(self, dataset_name):
|
| 620 |
+
# Get all of the relevant data.
|
| 621 |
+
dataset_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 622 |
+
train_dir = os.path.join(dataset_dir, "images")
|
| 623 |
+
train_images = sorted(get_file_list(train_dir))
|
| 624 |
+
annotation_dir = os.path.join(dataset_dir, "annotations")
|
| 625 |
+
annotation_images = sorted(get_file_list(annotation_dir, ext="png"))
|
| 626 |
+
|
| 627 |
+
# Move the images to the new directory.
|
| 628 |
+
def _annotation_preprocess_fn(annotation_path, out_path):
|
| 629 |
+
an_img = cv2.cvtColor(cv2.imread(annotation_path), cv2.COLOR_BGR2RGB)
|
| 630 |
+
crop, weed = (0, 255, 0), (255, 0, 0)
|
| 631 |
+
out_annotation = np.zeros(shape=an_img.shape[:-1])
|
| 632 |
+
crop_indices = np.stack(np.where(np.all(an_img == crop, axis=-1))).T
|
| 633 |
+
weed_indices = np.stack(np.where(np.all(an_img == weed, axis=-1))).T
|
| 634 |
+
for indxs in crop_indices:
|
| 635 |
+
out_annotation[indxs[0]][indxs[1]] = 1
|
| 636 |
+
for indxs in weed_indices:
|
| 637 |
+
out_annotation[indxs[0]][indxs[1]] = 2
|
| 638 |
+
return cv2.imwrite(out_path, out_annotation.astype(np.int8))
|
| 639 |
+
|
| 640 |
+
move_segmentation_dataset(
|
| 641 |
+
self.data_processed_dir,
|
| 642 |
+
dataset_name,
|
| 643 |
+
train_images,
|
| 644 |
+
annotation_images,
|
| 645 |
+
train_dir,
|
| 646 |
+
annotation_dir,
|
| 647 |
+
annotation_preprocess_fn=_annotation_preprocess_fn,
|
| 648 |
+
)
|
| 649 |
+
|
| 650 |
+
def apple_segmentation_minnesota(self, dataset_name):
|
| 651 |
+
# Get all of the relevant data.
|
| 652 |
+
dataset_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 653 |
+
train_dir = os.path.join(dataset_dir, "train", "images")
|
| 654 |
+
train_images = sorted(get_file_list(train_dir))
|
| 655 |
+
masks_dir = os.path.join(dataset_dir, "train", "masks")
|
| 656 |
+
mask_images = sorted(get_file_list(masks_dir))
|
| 657 |
+
|
| 658 |
+
# Move the images to the new directory.
|
| 659 |
+
def _annotation_preprocess_fn(annotation_path, out_path):
|
| 660 |
+
mask = cv2.imread(annotation_path, cv2.IMREAD_GRAYSCALE)
|
| 661 |
+
ids = np.unique(mask)[1:]
|
| 662 |
+
masks = mask == ids[:, np.newaxis, np.newaxis]
|
| 663 |
+
masks = masks.astype(np.int32)
|
| 664 |
+
if len(masks) == 1:
|
| 665 |
+
mask = mask
|
| 666 |
+
elif len(masks) >= 2:
|
| 667 |
+
mask = np.logical_or(masks[0], masks[1])
|
| 668 |
+
if len(masks) > 2:
|
| 669 |
+
for mask_ in masks[2:]:
|
| 670 |
+
mask = np.logical_or(mask, mask_)
|
| 671 |
+
mask = mask.astype(np.int32)
|
| 672 |
+
return cv2.imwrite(out_path, mask)
|
| 673 |
+
|
| 674 |
+
move_segmentation_dataset(
|
| 675 |
+
self.data_processed_dir,
|
| 676 |
+
dataset_name,
|
| 677 |
+
train_images,
|
| 678 |
+
mask_images,
|
| 679 |
+
train_dir,
|
| 680 |
+
masks_dir,
|
| 681 |
+
annotation_preprocess_fn=_annotation_preprocess_fn,
|
| 682 |
+
)
|
| 683 |
+
|
| 684 |
+
def rice_seedling_segmentation(self, dataset_name, fix=False):
|
| 685 |
+
# Re-mapping labels to remove the `Background` class.
|
| 686 |
+
if fix:
|
| 687 |
+
data_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 688 |
+
annotations = sorted(
|
| 689 |
+
[os.path.join(data_dir, "annotations", i) for i in os.listdir(os.path.join(data_dir, "annotations"))]
|
| 690 |
+
)
|
| 691 |
+
os.makedirs(os.path.join(data_dir, "new_annotations"))
|
| 692 |
+
|
| 693 |
+
# Create the remap.
|
| 694 |
+
for annotation in tqdm(annotations):
|
| 695 |
+
a = cv2.imread(annotation)
|
| 696 |
+
a[a == 2] = 0
|
| 697 |
+
a[a == 3] = 2
|
| 698 |
+
cv2.imwrite(
|
| 699 |
+
os.path.join(data_dir, "new_annotations", os.path.basename(annotation)),
|
| 700 |
+
a,
|
| 701 |
+
)
|
| 702 |
+
return
|
| 703 |
+
|
| 704 |
+
# Get all of the relevant data.
|
| 705 |
+
data_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 706 |
+
images = sorted(glob.glob(os.path.join(data_dir, "image_*.jpg")))
|
| 707 |
+
labels = sorted(glob.glob(os.path.join(data_dir, "Label_*.png")))
|
| 708 |
+
images = [os.path.basename(p) for p in images]
|
| 709 |
+
labels = [os.path.basename(p) for p in labels]
|
| 710 |
+
|
| 711 |
+
# Move the images to the new directory.
|
| 712 |
+
move_segmentation_dataset(self.data_processed_dir, dataset_name, images, labels, data_dir, data_dir)
|
| 713 |
+
|
| 714 |
+
def sugarcane_damage_usa(self, dataset_name):
|
| 715 |
+
pass
|
| 716 |
+
|
| 717 |
+
def soybean_weed_uav_brazil(self, dataset_name):
|
| 718 |
+
pass
|
| 719 |
+
|
| 720 |
+
def plant_village_classification(self, dataset_name):
|
| 721 |
+
pass
|
| 722 |
+
|
| 723 |
+
def autonomous_greenhouse_regression(self, dataset_name):
|
| 724 |
+
# Get all of the data paths.
|
| 725 |
+
dataset_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 726 |
+
image_dir = os.path.join(dataset_dir, "RGBImages")
|
| 727 |
+
depth_dir = os.path.join(dataset_dir, "DepthImages")
|
| 728 |
+
with open(os.path.join(dataset_dir, "dataset.json"), "r") as f:
|
| 729 |
+
contents = json.load(f)
|
| 730 |
+
|
| 731 |
+
# Construct the output annotation JSON file.
|
| 732 |
+
out = []
|
| 733 |
+
for sample in contents["labels"].values():
|
| 734 |
+
out.append(
|
| 735 |
+
{
|
| 736 |
+
"image": sample["rgb_image_path"],
|
| 737 |
+
"depth_image": sample["depth_image_path"],
|
| 738 |
+
"outputs": {
|
| 739 |
+
"regression": sample["regression_outputs"],
|
| 740 |
+
"classification": sample["classification_outputs"]["Variety"],
|
| 741 |
+
},
|
| 742 |
+
}
|
| 743 |
+
)
|
| 744 |
+
|
| 745 |
+
# Copy the images over.
|
| 746 |
+
out_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 747 |
+
out_image_dir = os.path.join(out_dir, "images")
|
| 748 |
+
os.makedirs(out_image_dir, exist_ok=True)
|
| 749 |
+
out_depth_dir = os.path.join(out_dir, "depth_images")
|
| 750 |
+
os.makedirs(out_depth_dir, exist_ok=True)
|
| 751 |
+
for image in tqdm(os.listdir(image_dir), desc="Moving Images", file=sys.stdout):
|
| 752 |
+
shutil.copyfile(os.path.join(image_dir, image), os.path.join(out_image_dir, image))
|
| 753 |
+
for depth in tqdm(os.listdir(depth_dir), desc="Moving Depth Images", file=sys.stdout):
|
| 754 |
+
shutil.copyfile(os.path.join(depth_dir, depth), os.path.join(out_depth_dir, depth))
|
| 755 |
+
|
| 756 |
+
# Save the annotation file.
|
| 757 |
+
with open(os.path.join(out_dir, "annotations.json"), "w") as f:
|
| 758 |
+
json.dump(out, f)
|
| 759 |
+
|
| 760 |
+
def guava_disease_pakistan(self, dataset_name):
|
| 761 |
+
# Get all of the images.
|
| 762 |
+
dataset_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 763 |
+
classes = os.listdir(dataset_dir)
|
| 764 |
+
all_images = []
|
| 765 |
+
for cls in classes:
|
| 766 |
+
all_images.extend([os.path.join(dataset_dir, cls, i) for i in os.listdir(os.path.join(dataset_dir, cls))])
|
| 767 |
+
|
| 768 |
+
# Resize all of the images.
|
| 769 |
+
out_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 770 |
+
os.makedirs(out_dir, exist_ok=True)
|
| 771 |
+
for cls in classes:
|
| 772 |
+
os.makedirs(os.path.join(out_dir, cls), exist_ok=True)
|
| 773 |
+
for image in tqdm(all_images, "Resizing Images"):
|
| 774 |
+
out_image = image.replace("/original/", "/processed/")
|
| 775 |
+
im = cv2.imread(image, cv2.IMREAD_UNCHANGED)
|
| 776 |
+
im = cv2.resize(im, (im.shape[1] // 5, im.shape[0] // 5), cv2.INTER_LINEAR)
|
| 777 |
+
cv2.imwrite(out_image, im)
|
| 778 |
+
|
| 779 |
+
def apple_detection_spain(self, dataset_name):
|
| 780 |
+
# resize the dataset
|
| 781 |
+
resize = 1.0
|
| 782 |
+
|
| 783 |
+
# Read public_datasources.json to get class information
|
| 784 |
+
datasource_file = os.path.join(os.path.dirname(__file__), "../_assets/public_datasources.json")
|
| 785 |
+
with open(datasource_file) as f:
|
| 786 |
+
data = json.load(f)
|
| 787 |
+
category_info = data[dataset_name]["crop_types"]
|
| 788 |
+
labels_str = []
|
| 789 |
+
labels_ids = []
|
| 790 |
+
for info in category_info:
|
| 791 |
+
labels_str.append(category_info[info])
|
| 792 |
+
labels_ids.append(int(info))
|
| 793 |
+
|
| 794 |
+
name_converter = dict(zip(["Poma"], ["apple"])) # src -> dst
|
| 795 |
+
label2id = dict(zip(labels_str, labels_ids))
|
| 796 |
+
|
| 797 |
+
dataset_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 798 |
+
ann_dir = os.path.join(dataset_dir, "preprocessed data/square_annotations1")
|
| 799 |
+
|
| 800 |
+
# Get image file and xml file
|
| 801 |
+
all_files = get_file_list(ann_dir)
|
| 802 |
+
anno_files = [os.path.join(ann_dir, x) for x in all_files if "xml" in x]
|
| 803 |
+
img_files = [x.replace(".xml", "hr.jpg").replace("square_annotations1", "images") for x in anno_files]
|
| 804 |
+
|
| 805 |
+
# Process annotation files
|
| 806 |
+
save_dir_anno = os.path.join(self.data_processed_dir, dataset_name, "annotations")
|
| 807 |
+
create_dir(save_dir_anno)
|
| 808 |
+
output_json_file = os.path.join(save_dir_anno, "instances.json")
|
| 809 |
+
|
| 810 |
+
# Process image files
|
| 811 |
+
output_img_path = os.path.join(self.data_processed_dir, dataset_name, "images")
|
| 812 |
+
create_dir(output_img_path)
|
| 813 |
+
|
| 814 |
+
general_info = {
|
| 815 |
+
"description": "KFuji RGB-DS database",
|
| 816 |
+
"url": "http://www.grap.udl.cat/en/publications/KFuji_RGBDS_database.html",
|
| 817 |
+
"version": "1.0",
|
| 818 |
+
"year": 2018,
|
| 819 |
+
"contributor": "Gené-Mola J, Vilaplana V, Rosell-Polo JR, Morros JR, Ruiz-Hidalgo J, Gregorio E",
|
| 820 |
+
"date_created": "2018/10/19",
|
| 821 |
+
}
|
| 822 |
+
|
| 823 |
+
convert_xmls_to_cocojson(
|
| 824 |
+
general_info,
|
| 825 |
+
annotation_paths=anno_files,
|
| 826 |
+
img_paths=img_files,
|
| 827 |
+
label2id=label2id,
|
| 828 |
+
name_converter=name_converter,
|
| 829 |
+
output_jsonpath=output_json_file,
|
| 830 |
+
output_imgpath=output_img_path,
|
| 831 |
+
extract_num_from_imgid=True,
|
| 832 |
+
)
|
| 833 |
+
|
| 834 |
+
def apple_detection_drone_brazil(self, dataset_name):
|
| 835 |
+
# Get the data directory and rename it if necessary.
|
| 836 |
+
dataset_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 837 |
+
if not os.path.exists(dataset_dir):
|
| 838 |
+
fallback = os.path.join(self.data_original_dir, "thsant-add256-68d2f88") # noqa
|
| 839 |
+
if os.path.exists(fallback):
|
| 840 |
+
os.rename(fallback, dataset_dir)
|
| 841 |
+
|
| 842 |
+
# Get all of the images which have valid annotations.
|
| 843 |
+
with open(os.path.join(dataset_dir, "all.json"), "r") as f:
|
| 844 |
+
original_annotations = json.load(f)
|
| 845 |
+
valid_annotations = {k: v for k, v in original_annotations.items() if v != []}
|
| 846 |
+
|
| 847 |
+
# Construct the `images` part of the COCO JSON.
|
| 848 |
+
image_coco = []
|
| 849 |
+
image_id_map = {}
|
| 850 |
+
image_dir = os.path.join(dataset_dir, "images")
|
| 851 |
+
for idx, image_name in tqdm(
|
| 852 |
+
enumerate(valid_annotations.keys()),
|
| 853 |
+
desc="Parsing Images",
|
| 854 |
+
total=len(valid_annotations),
|
| 855 |
+
):
|
| 856 |
+
height, width = cv2.imread(os.path.join(image_dir, image_name)).shape[:2]
|
| 857 |
+
image_coco.append({"file_name": image_name, "height": height, "width": width, "id": idx})
|
| 858 |
+
image_id_map[image_name] = idx
|
| 859 |
+
|
| 860 |
+
# Construct the `annotations` part of the COCO JSON.
|
| 861 |
+
annotation_idx = 0
|
| 862 |
+
annotation_coco = []
|
| 863 |
+
for image_name, annotation_list in valid_annotations.items():
|
| 864 |
+
for annotation in annotation_list:
|
| 865 |
+
# Coordinates are in form (center_x, center_y, radius). We convert
|
| 866 |
+
# these to (top left x, top left y, width, height)
|
| 867 |
+
x_c, y_c, r = annotation["cx"], annotation["cy"], annotation["r"]
|
| 868 |
+
x, y = x_c - r, y_c - r
|
| 869 |
+
w = h = r * 2
|
| 870 |
+
annotation_coco.append(
|
| 871 |
+
{
|
| 872 |
+
"area": w * h,
|
| 873 |
+
"iscrowd": 0,
|
| 874 |
+
"bbox": [x, y, w, h],
|
| 875 |
+
"category_id": 1,
|
| 876 |
+
"ignore": 0,
|
| 877 |
+
"segmentation": 0,
|
| 878 |
+
"image_id": image_id_map[image_name],
|
| 879 |
+
"id": annotation_idx,
|
| 880 |
+
}
|
| 881 |
+
)
|
| 882 |
+
annotation_idx += 1
|
| 883 |
+
|
| 884 |
+
# Set up the annotation dictionary.
|
| 885 |
+
category_info = [{"supercategory": "none", "id": 1, "name": "apple"}]
|
| 886 |
+
all_annotation_data = {
|
| 887 |
+
"images": image_coco,
|
| 888 |
+
"type": "instances",
|
| 889 |
+
"annotations": annotation_coco,
|
| 890 |
+
"categories": category_info,
|
| 891 |
+
"info": {
|
| 892 |
+
"description": "apple detection dataset with drone imagery",
|
| 893 |
+
"url": "https://github.com/thsant/add256/tree/zenodo-1.0",
|
| 894 |
+
"version": "1.0",
|
| 895 |
+
"year": 2021,
|
| 896 |
+
"contributor": "Thiago T. Santos and Luciano Gebler",
|
| 897 |
+
"date_created": "2021/10/2021",
|
| 898 |
+
},
|
| 899 |
+
}
|
| 900 |
+
|
| 901 |
+
# Recreate the dataset and zip it
|
| 902 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 903 |
+
processed_img_dir = os.path.join(processed_dir, "images")
|
| 904 |
+
if os.path.exists(processed_dir):
|
| 905 |
+
shutil.rmtree(processed_dir)
|
| 906 |
+
os.makedirs(processed_dir, exist_ok=True)
|
| 907 |
+
os.makedirs(processed_img_dir, exist_ok=True)
|
| 908 |
+
for path in tqdm(valid_annotations.keys(), desc="Moving Images"):
|
| 909 |
+
full_path = os.path.join(image_dir, path)
|
| 910 |
+
shutil.copyfile(full_path, os.path.join(processed_img_dir, os.path.basename(path)))
|
| 911 |
+
with open(os.path.join(processed_dir, "annotations.json"), "w") as f:
|
| 912 |
+
json.dump(all_annotation_data, f)
|
| 913 |
+
|
| 914 |
+
def plant_doc_classification(self, dataset_name):
|
| 915 |
+
category_info = self.data_sources[dataset_name]["classes"]
|
| 916 |
+
|
| 917 |
+
# paths to original files
|
| 918 |
+
dataset_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 919 |
+
train_dir = os.path.join(dataset_dir, "train")
|
| 920 |
+
test_dir = os.path.join(dataset_dir, "test")
|
| 921 |
+
|
| 922 |
+
# make output dir
|
| 923 |
+
output = os.path.join(self.data_processed_dir, dataset_name)
|
| 924 |
+
os.makedirs(output)
|
| 925 |
+
|
| 926 |
+
for key in category_info:
|
| 927 |
+
category = category_info[key]
|
| 928 |
+
|
| 929 |
+
# make output dir for each crop type
|
| 930 |
+
output_catg_dir = os.path.join(output, category)
|
| 931 |
+
os.makedirs(output_catg_dir)
|
| 932 |
+
|
| 933 |
+
# put train and test images of same category into same folder
|
| 934 |
+
train_catg_dir = os.path.join(train_dir, category)
|
| 935 |
+
test_catg_dir = os.path.join(test_dir, category)
|
| 936 |
+
|
| 937 |
+
for img_name in get_file_list(train_catg_dir):
|
| 938 |
+
img = os.path.join(train_catg_dir, img_name)
|
| 939 |
+
shutil.copyfile(img, os.path.join(output_catg_dir, img_name))
|
| 940 |
+
|
| 941 |
+
if os.path.exists(test_catg_dir):
|
| 942 |
+
for img_name in get_file_list(test_catg_dir):
|
| 943 |
+
img = os.path.join(test_catg_dir, img_name)
|
| 944 |
+
shutil.copyfile(img, os.path.join(output_catg_dir, img_name))
|
| 945 |
+
|
| 946 |
+
def wheat_head_counting(self, dataset_name):
|
| 947 |
+
label2id = {"Wheat Head": 1}
|
| 948 |
+
dataset_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 949 |
+
anno_files = [
|
| 950 |
+
os.path.join(dataset_dir, "competition_train.csv"),
|
| 951 |
+
os.path.join(dataset_dir, "competition_test.csv"),
|
| 952 |
+
os.path.join(dataset_dir, "competition_val.csv"),
|
| 953 |
+
]
|
| 954 |
+
|
| 955 |
+
annotations = []
|
| 956 |
+
for anno_file in anno_files:
|
| 957 |
+
with open(anno_file, "r") as file:
|
| 958 |
+
reader = csv.reader(file)
|
| 959 |
+
for row in reader:
|
| 960 |
+
img_path = os.path.join(dataset_dir, "images", row[0])
|
| 961 |
+
anno = [img_path]
|
| 962 |
+
bboxs = row[1].split(";")
|
| 963 |
+
anno.append(len(bboxs))
|
| 964 |
+
for bbox in bboxs:
|
| 965 |
+
if bbox != "no_box":
|
| 966 |
+
bbox = bbox.split(" ")
|
| 967 |
+
bbox.append("1")
|
| 968 |
+
anno.append(bbox)
|
| 969 |
+
annotations.append(anno)
|
| 970 |
+
|
| 971 |
+
# Define path to processed annotation files
|
| 972 |
+
output_json_file = os.path.join(self.data_processed_dir, dataset_name, "annotations.json")
|
| 973 |
+
|
| 974 |
+
# Create directory for processed image files
|
| 975 |
+
output_img_path = os.path.join(self.data_processed_dir, dataset_name, "images")
|
| 976 |
+
create_dir(output_img_path)
|
| 977 |
+
|
| 978 |
+
general_info = {
|
| 979 |
+
"description": "Global Wheat Head Detection (GWHD) dataset",
|
| 980 |
+
"url": "http://www.global-wheat.com/",
|
| 981 |
+
"version": "1.0",
|
| 982 |
+
"year": 2021,
|
| 983 |
+
"contributor": "David, Etienne and Madec, Simon and Sadeghi-Tehran, Pouria and Aasen, Helge and Zheng, Bangyou and Liu, Shouyang and Kirchgessner, Norbert and Ishikawa, Goro and Nagasawa, Koichi and Badhon, Minhajul A and others",
|
| 984 |
+
"date_created": "2021/7/12",
|
| 985 |
+
}
|
| 986 |
+
|
| 987 |
+
convert_bbox_to_coco(
|
| 988 |
+
annotations,
|
| 989 |
+
label2id,
|
| 990 |
+
output_json_file,
|
| 991 |
+
output_img_path,
|
| 992 |
+
general_info,
|
| 993 |
+
resize=512 / 1024,
|
| 994 |
+
)
|
| 995 |
+
|
| 996 |
+
def peachpear_flower_segmentation(self, dataset_name):
|
| 997 |
+
# Create processed directories
|
| 998 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 999 |
+
os.makedirs(processed_dir, exist_ok=True)
|
| 1000 |
+
processed_image_dir = os.path.join(processed_dir, "images")
|
| 1001 |
+
os.makedirs(processed_image_dir, exist_ok=True)
|
| 1002 |
+
processed_annotation_dir = os.path.join(processed_dir, "annotations")
|
| 1003 |
+
os.makedirs(processed_annotation_dir, exist_ok=True)
|
| 1004 |
+
|
| 1005 |
+
dataset_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 1006 |
+
|
| 1007 |
+
# Get image files
|
| 1008 |
+
img_dirs = ["Peach", "Pear"]
|
| 1009 |
+
img_paths = []
|
| 1010 |
+
for img_dir in img_dirs:
|
| 1011 |
+
img_paths += [
|
| 1012 |
+
os.path.join(dataset_dir, img_dir, file_name)
|
| 1013 |
+
for file_name in get_file_list(os.path.join(dataset_dir, img_dir))
|
| 1014 |
+
]
|
| 1015 |
+
|
| 1016 |
+
# Save all images as jpg in processed directory
|
| 1017 |
+
for img_path in img_paths:
|
| 1018 |
+
processed_path = os.path.join(processed_image_dir, img_path.split("/")[-1].replace(".bmp", ".jpg"))
|
| 1019 |
+
img = cv2.imread(img_path)
|
| 1020 |
+
cv2.imwrite(processed_path, img)
|
| 1021 |
+
|
| 1022 |
+
# Get annotation files
|
| 1023 |
+
anno_dirs = ["PeachLabels", "PearLabels"]
|
| 1024 |
+
anno_paths = []
|
| 1025 |
+
for anno_dir in anno_dirs:
|
| 1026 |
+
anno_paths += [
|
| 1027 |
+
os.path.join(dataset_dir, anno_dir, file_name)
|
| 1028 |
+
for file_name in get_file_list(os.path.join(dataset_dir, anno_dir))
|
| 1029 |
+
]
|
| 1030 |
+
|
| 1031 |
+
# Transform mask and save to processed directory
|
| 1032 |
+
for anno_path in anno_paths:
|
| 1033 |
+
img = cv2.imread(anno_path, cv2.IMREAD_GRAYSCALE)
|
| 1034 |
+
img = np.where(img[:] == 255, 1, 0)
|
| 1035 |
+
processed_path = os.path.join(processed_annotation_dir, anno_path.split("/")[-1])
|
| 1036 |
+
cv2.imwrite(processed_path, img)
|
| 1037 |
+
|
| 1038 |
+
def ghai_romaine_detection(self, dataset_name):
|
| 1039 |
+
# Create processed directories
|
| 1040 |
+
original_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 1041 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 1042 |
+
processed_image_dir = os.path.join(processed_dir, "images")
|
| 1043 |
+
os.makedirs(processed_image_dir, exist_ok=True)
|
| 1044 |
+
|
| 1045 |
+
# Move images
|
| 1046 |
+
for image in glob.glob(os.path.join(original_dir, "*.jpg")):
|
| 1047 |
+
shutil.move(image, processed_image_dir)
|
| 1048 |
+
shutil.move(
|
| 1049 |
+
os.path.join(original_dir, "coco.json"),
|
| 1050 |
+
os.path.join(processed_dir, "annotations.json"),
|
| 1051 |
+
)
|
| 1052 |
+
|
| 1053 |
+
def ghai_green_cabbage_detection(self, dataset_name):
|
| 1054 |
+
# Create processed directories
|
| 1055 |
+
original_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 1056 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 1057 |
+
processed_image_dir = os.path.join(processed_dir, "images")
|
| 1058 |
+
os.makedirs(processed_image_dir, exist_ok=True)
|
| 1059 |
+
|
| 1060 |
+
# Move images
|
| 1061 |
+
for image in glob.glob(os.path.join(original_dir, "*.jpg")):
|
| 1062 |
+
shutil.move(image, processed_image_dir)
|
| 1063 |
+
shutil.move(
|
| 1064 |
+
os.path.join(original_dir, "coco.json"),
|
| 1065 |
+
os.path.join(processed_dir, "annotations.json"),
|
| 1066 |
+
)
|
| 1067 |
+
|
| 1068 |
+
def ghai_iceberg_lettuce_detection(self, dataset_name):
|
| 1069 |
+
# Create processed directories
|
| 1070 |
+
original_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 1071 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 1072 |
+
processed_image_dir = os.path.join(processed_dir, "images")
|
| 1073 |
+
os.makedirs(processed_image_dir, exist_ok=True)
|
| 1074 |
+
|
| 1075 |
+
# Move images
|
| 1076 |
+
for image in glob.glob(os.path.join(original_dir, "*.jpg")):
|
| 1077 |
+
shutil.move(image, processed_image_dir)
|
| 1078 |
+
shutil.move(
|
| 1079 |
+
os.path.join(original_dir, "coco.json"),
|
| 1080 |
+
os.path.join(processed_dir, "annotations.json"),
|
| 1081 |
+
)
|
| 1082 |
+
|
| 1083 |
+
def riseholme_strawberry_classification_2021(self, dataset_name):
|
| 1084 |
+
# Create processed data directory.
|
| 1085 |
+
original_dir = os.path.join(self.data_original_dir, "Riseholme-2021-main", "Data")
|
| 1086 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 1087 |
+
|
| 1088 |
+
# Load all of the individual images and keep a mapping to their corresponding directory.
|
| 1089 |
+
images = {
|
| 1090 |
+
"anomalous": get_file_list(os.path.join(original_dir, "Anomalous")),
|
| 1091 |
+
**{
|
| 1092 |
+
dir_.lower(): get_file_list(os.path.join(original_dir, "Normal", dir_))
|
| 1093 |
+
for dir_ in os.listdir(os.path.join(original_dir, "Normal"))
|
| 1094 |
+
},
|
| 1095 |
+
}
|
| 1096 |
+
|
| 1097 |
+
# Create the output file structure.
|
| 1098 |
+
for class_name, image_set in images.items():
|
| 1099 |
+
class_dir = os.path.join(processed_dir, class_name)
|
| 1100 |
+
os.makedirs(class_dir, exist_ok=True)
|
| 1101 |
+
for file in image_set:
|
| 1102 |
+
shutil.copyfile(file, os.path.join(class_dir, os.path.basename(file)))
|
| 1103 |
+
|
| 1104 |
+
def ghai_broccoli_detection(self, dataset_name):
|
| 1105 |
+
# Create processed directories
|
| 1106 |
+
original_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 1107 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 1108 |
+
processed_image_dir = os.path.join(processed_dir, "images")
|
| 1109 |
+
os.makedirs(processed_image_dir, exist_ok=True)
|
| 1110 |
+
|
| 1111 |
+
# Move images
|
| 1112 |
+
for image in tqdm(glob.glob(os.path.join(original_dir, "*.jpg"))):
|
| 1113 |
+
shutil.move(image, processed_image_dir)
|
| 1114 |
+
shutil.move(
|
| 1115 |
+
os.path.join(original_dir, "coco.json"),
|
| 1116 |
+
os.path.join(processed_dir, "annotations.json"),
|
| 1117 |
+
)
|
| 1118 |
+
|
| 1119 |
+
def ghai_strawberry_fruit_detection(self, dataset_name):
|
| 1120 |
+
# Create processed directories
|
| 1121 |
+
original_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 1122 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 1123 |
+
processed_image_dir = os.path.join(processed_dir, "images")
|
| 1124 |
+
os.makedirs(processed_image_dir, exist_ok=True)
|
| 1125 |
+
|
| 1126 |
+
# Move images
|
| 1127 |
+
for image in tqdm(glob.glob(os.path.join(original_dir, "*.jpg"))):
|
| 1128 |
+
shutil.move(image, processed_image_dir)
|
| 1129 |
+
shutil.move(
|
| 1130 |
+
os.path.join(original_dir, "coco.json"),
|
| 1131 |
+
os.path.join(processed_dir, "annotations.json"),
|
| 1132 |
+
)
|
| 1133 |
+
|
| 1134 |
+
def vegann_multicrop_presence_segmentation(self, dataset_name):
|
| 1135 |
+
# Create processed directories
|
| 1136 |
+
original_dir = os.path.join(self.data_original_dir, dataset_name)
|
| 1137 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 1138 |
+
processed_image_dir = os.path.join(processed_dir, "images")
|
| 1139 |
+
os.makedirs(processed_image_dir, exist_ok=True)
|
| 1140 |
+
processed_annotation_dir = os.path.join(processed_dir, "annotations")
|
| 1141 |
+
os.makedirs(processed_annotation_dir, exist_ok=True)
|
| 1142 |
+
|
| 1143 |
+
# Move images
|
| 1144 |
+
for image in tqdm(glob.glob(os.path.join(original_dir, "images", "*.png"))):
|
| 1145 |
+
shutil.copyfile(image, os.path.join(processed_image_dir, os.path.basename(image)))
|
| 1146 |
+
|
| 1147 |
+
# Read annotations
|
| 1148 |
+
for annotation_file in tqdm(glob.glob(os.path.join(original_dir, "annotations", "*.png"))):
|
| 1149 |
+
annotation = cv2.imread(annotation_file, cv2.IMREAD_UNCHANGED)
|
| 1150 |
+
annotation = np.where(annotation == 255, 1, 0)
|
| 1151 |
+
cv2.imwrite(
|
| 1152 |
+
os.path.join(processed_annotation_dir, os.path.basename(annotation_file)),
|
| 1153 |
+
annotation,
|
| 1154 |
+
)
|
| 1155 |
+
|
| 1156 |
+
# Read the CSV file containing the splits
|
| 1157 |
+
split_csv = pd.read_csv(os.path.join(original_dir, "VegAnn_dataset.csv"), sep=";")
|
| 1158 |
+
|
| 1159 |
+
# Get the `Name` and `TVT-split{n}` columns for each n, and save the splits to a folder
|
| 1160 |
+
splits_folder = os.path.join(processed_dir, ".splits")
|
| 1161 |
+
os.makedirs(splits_folder, exist_ok=True)
|
| 1162 |
+
column_pairs = [["Name", f"TVT-split{i}"] for i in range(1, 5 + 1)]
|
| 1163 |
+
|
| 1164 |
+
splits = {}
|
| 1165 |
+
for column_pair in column_pairs:
|
| 1166 |
+
columns = split_csv[column_pair]
|
| 1167 |
+
train_images = columns[columns[column_pair[1]] == "Training"]["Name"]
|
| 1168 |
+
test_images = columns[columns[column_pair[1]] == "Test"]["Name"]
|
| 1169 |
+
splits[column_pair[1]] = {
|
| 1170 |
+
"train": {os.path.join("images", i): os.path.join("annotations", i) for i in train_images},
|
| 1171 |
+
"val": {},
|
| 1172 |
+
"test": {os.path.join("images", i): os.path.join("annotations", i) for i in test_images},
|
| 1173 |
+
}
|
| 1174 |
+
|
| 1175 |
+
# Save each split to a JSON file
|
| 1176 |
+
for split_name, split in splits.items():
|
| 1177 |
+
with open(os.path.join(splits_folder, f"{split_name}.json"), "w") as f:
|
| 1178 |
+
json.dump(split, f)
|
| 1179 |
+
|
| 1180 |
+
def embrapa_wgisd_grape_detection(self, dataset_name):
|
| 1181 |
+
"""Preprocesses your grape dataset (Chardonnay, PinotGris, PinotNoir) from YOLO format to COCO format."""
|
| 1182 |
+
base_path = os.path.join(self.data_original_dir)
|
| 1183 |
+
|
| 1184 |
+
# Get all the dataset folders (Chardonnay, PinotGris, PinotNoir)
|
| 1185 |
+
dataset_folders = ['Chardonnay', 'PinotGris', 'PinotNoir']
|
| 1186 |
+
|
| 1187 |
+
# Prepare the COCO annotation dictionary
|
| 1188 |
+
coco_annotation = {
|
| 1189 |
+
"images": [],
|
| 1190 |
+
"annotations": [],
|
| 1191 |
+
"categories": [{
|
| 1192 |
+
"id": 1, # Category ID for the object (e.g., grape)
|
| 1193 |
+
"name": "grape", # You can change this to match your dataset's object
|
| 1194 |
+
"supercategory": "fruit"
|
| 1195 |
+
}]
|
| 1196 |
+
}
|
| 1197 |
+
|
| 1198 |
+
annotation_id = 1
|
| 1199 |
+
image_id = 1
|
| 1200 |
+
|
| 1201 |
+
# Create the output directories for processed images and annotations
|
| 1202 |
+
output_base_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 1203 |
+
output_img_dir = os.path.join(output_base_dir, 'images')
|
| 1204 |
+
os.makedirs(output_img_dir, exist_ok=True)
|
| 1205 |
+
|
| 1206 |
+
# Iterate through each dataset folder (Chardonnay, PinotGris, PinotNoir)
|
| 1207 |
+
for folder in dataset_folders:
|
| 1208 |
+
images_dir = os.path.join(base_path, folder, 'images')
|
| 1209 |
+
labels_dir = os.path.join(base_path, folder, 'labels')
|
| 1210 |
+
|
| 1211 |
+
# Check if the directories exist
|
| 1212 |
+
if not os.path.exists(images_dir) or not os.path.exists(labels_dir):
|
| 1213 |
+
print(f"Error: Images or labels directory does not exist in {images_dir} or {labels_dir}")
|
| 1214 |
+
continue
|
| 1215 |
+
|
| 1216 |
+
# Create output directory for this folder inside the processed folder
|
| 1217 |
+
output_folder_img_dir = os.path.join(output_img_dir, folder)
|
| 1218 |
+
os.makedirs(output_folder_img_dir, exist_ok=True)
|
| 1219 |
+
|
| 1220 |
+
# Process all images and their corresponding YOLO labels
|
| 1221 |
+
for img_file in tqdm(os.listdir(images_dir), desc=f"Processing images for {folder}"):
|
| 1222 |
+
if img_file.endswith(('jpg', 'jpeg', 'png')):
|
| 1223 |
+
image_path = os.path.join(images_dir, img_file)
|
| 1224 |
+
label_file = img_file.replace('.jpg', '.txt').replace('.jpeg', '.txt').replace('.png', '.txt')
|
| 1225 |
+
label_path = os.path.join(labels_dir, label_file)
|
| 1226 |
+
|
| 1227 |
+
# Read the image to get its dimensions
|
| 1228 |
+
img = cv2.imread(image_path)
|
| 1229 |
+
if img is None:
|
| 1230 |
+
print(f"Error: Could not open image file {image_path}")
|
| 1231 |
+
continue
|
| 1232 |
+
img_height, img_width = img.shape[:2]
|
| 1233 |
+
|
| 1234 |
+
# Add image information to COCO structure
|
| 1235 |
+
image_info = {
|
| 1236 |
+
"file_name": f"{folder}/{img_file}", # Include folder name in file path
|
| 1237 |
+
"height": img_height,
|
| 1238 |
+
"width": img_width,
|
| 1239 |
+
"id": image_id
|
| 1240 |
+
}
|
| 1241 |
+
coco_annotation['images'].append(image_info)
|
| 1242 |
+
|
| 1243 |
+
# Read the YOLO label file and convert to COCO format
|
| 1244 |
+
if os.path.exists(label_path):
|
| 1245 |
+
with open(label_path, 'r') as f:
|
| 1246 |
+
lines = f.readlines()
|
| 1247 |
+
|
| 1248 |
+
# Prepare annotations in COCO format
|
| 1249 |
+
for line in lines:
|
| 1250 |
+
elements = line.strip().split()
|
| 1251 |
+
class_id = int(elements[0]) # class_id from YOLO
|
| 1252 |
+
x_center, y_center, bbox_width, bbox_height = map(float, elements[1:])
|
| 1253 |
+
|
| 1254 |
+
# Convert to COCO format bounding box
|
| 1255 |
+
bbox = yolo_to_coco_bbox(x_center, y_center, bbox_width, bbox_height, img_width, img_height)
|
| 1256 |
+
|
| 1257 |
+
annotation = {
|
| 1258 |
+
"image_id": image_id, # Reference to the image ID
|
| 1259 |
+
"bbox": bbox, # COCO bounding box [xmin, ymin, width, height]
|
| 1260 |
+
"category_id": 1, # Assuming a single category "grape"
|
| 1261 |
+
"id": annotation_id, # Unique annotation ID
|
| 1262 |
+
"area": bbox[2] * bbox[3], # width * height
|
| 1263 |
+
"iscrowd": 0,
|
| 1264 |
+
"segmentation": []
|
| 1265 |
+
}
|
| 1266 |
+
coco_annotation['annotations'].append(annotation)
|
| 1267 |
+
annotation_id += 1
|
| 1268 |
+
else:
|
| 1269 |
+
print(f"Warning: No label file found for {img_file}")
|
| 1270 |
+
|
| 1271 |
+
# Copy the image to the processed directory
|
| 1272 |
+
shutil.copyfile(image_path, os.path.join(output_folder_img_dir, img_file))
|
| 1273 |
+
|
| 1274 |
+
# Increment image ID
|
| 1275 |
+
image_id += 1
|
| 1276 |
+
|
| 1277 |
+
# Save the final COCO annotations to the correct path inside the processed folder
|
| 1278 |
+
output_json_file = os.path.join(output_base_dir, 'annotations.json')
|
| 1279 |
+
with open(output_json_file, 'w') as json_file:
|
| 1280 |
+
json.dump(coco_annotation, json_file, indent=4)
|
| 1281 |
+
|
| 1282 |
+
print(f"COCO annotations saved to {output_json_file}")
|
| 1283 |
+
|
| 1284 |
+
def plant_doc_detection(self, dataset_name):
|
| 1285 |
+
# Resize the dataset (if necessary)
|
| 1286 |
+
resize = 1.0
|
| 1287 |
+
|
| 1288 |
+
# Read public_datasources.json to get class information
|
| 1289 |
+
datasource_file = os.path.join(os.path.dirname(__file__), "../_assets/public_datasources.json")
|
| 1290 |
+
with open(datasource_file) as f:
|
| 1291 |
+
data = json.load(f)
|
| 1292 |
+
category_info = data[dataset_name]['classes'] # This will give us the class information
|
| 1293 |
+
labels_str = []
|
| 1294 |
+
labels_ids = []
|
| 1295 |
+
for info in category_info:
|
| 1296 |
+
labels_str.append(category_info[info])
|
| 1297 |
+
labels_ids.append(int(info))
|
| 1298 |
+
|
| 1299 |
+
# No name conversion in this case, unless you need to remap class names
|
| 1300 |
+
name_converter = None
|
| 1301 |
+
label2id = dict(zip(labels_str, labels_ids)) # Map class names to their respective IDs
|
| 1302 |
+
|
| 1303 |
+
# Set paths to dataset and annotations
|
| 1304 |
+
dataset_dir = os.path.join(self.data_original_dir)
|
| 1305 |
+
ann_dir = dataset_dir # Both images and XMLs are in the same directory
|
| 1306 |
+
|
| 1307 |
+
# Get image file and xml file
|
| 1308 |
+
all_files = os.listdir(ann_dir)
|
| 1309 |
+
anno_files = [os.path.join(ann_dir, x) for x in all_files if x.endswith("xml")]
|
| 1310 |
+
img_files = [x.replace(".xml", ".jpg") for x in anno_files] # Assuming images are in JPG format
|
| 1311 |
+
|
| 1312 |
+
# # Process annotation files
|
| 1313 |
+
# save_dir_anno = os.path.join(self.data_processed_dir, dataset_name, 'annotations')
|
| 1314 |
+
# create_dir(save_dir_anno)
|
| 1315 |
+
# output_json_file = os.path.join(save_dir_anno, 'instances.json')
|
| 1316 |
+
|
| 1317 |
+
# Process image files
|
| 1318 |
+
output_img_path = os.path.join(self.data_processed_dir, dataset_name, 'images')
|
| 1319 |
+
create_dir(output_img_path)
|
| 1320 |
+
|
| 1321 |
+
# General information for the COCO JSON format
|
| 1322 |
+
general_info = {
|
| 1323 |
+
"description": "PlantDoc Object Detection Dataset",
|
| 1324 |
+
"url": "https://github.com/pratikkayal/PlantDoc-Object-Detection-Dataset",
|
| 1325 |
+
"version": "1.0",
|
| 1326 |
+
"year": 2024,
|
| 1327 |
+
"contributor": "PlantDoc",
|
| 1328 |
+
"date_created": "2024/10/17"
|
| 1329 |
+
}
|
| 1330 |
+
|
| 1331 |
+
# Save the COCO JSON file directly in the processed directory
|
| 1332 |
+
output_json_file = os.path.join(self.data_processed_dir, dataset_name, 'annotations.json')
|
| 1333 |
+
|
| 1334 |
+
# Convert the XML annotations to COCO format using your existing function
|
| 1335 |
+
convert_xmls_to_cocojson(
|
| 1336 |
+
general_info=general_info,
|
| 1337 |
+
annotation_paths=anno_files,
|
| 1338 |
+
img_paths=img_files,
|
| 1339 |
+
label2id=label2id,
|
| 1340 |
+
name_converter=name_converter,
|
| 1341 |
+
output_jsonpath=output_json_file,
|
| 1342 |
+
output_imgpath=output_img_path,
|
| 1343 |
+
extract_num_from_imgid=False
|
| 1344 |
+
)
|
| 1345 |
+
|
| 1346 |
+
print(f"Preprocessing completed! Annotations saved to {output_json_file}")
|
| 1347 |
+
|
| 1348 |
+
def growliflower_cauliflower_segmentation(self, dataset_name):
|
| 1349 |
+
"""
|
| 1350 |
+
Preprocess the cauliflower dataset by merging mask images and moving them to the new directory.
|
| 1351 |
+
|
| 1352 |
+
Args:
|
| 1353 |
+
self: Instance of the class where this function belongs.
|
| 1354 |
+
dataset_name (str): Name of the dataset.
|
| 1355 |
+
"""
|
| 1356 |
+
# Paths to the dataset
|
| 1357 |
+
dataset_dir = os.path.join(self.data_original_dir)
|
| 1358 |
+
images_dir = os.path.join(dataset_dir, 'images') # Folder with original images
|
| 1359 |
+
masks_dir = os.path.join(dataset_dir, 'annotations') # Folder with the mask subfolders
|
| 1360 |
+
|
| 1361 |
+
# Output directory where preprocessed data will be stored
|
| 1362 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 1363 |
+
processed_image_dir = os.path.join(processed_dir, 'images')
|
| 1364 |
+
processed_annotation_dir = os.path.join(processed_dir, 'annotations')
|
| 1365 |
+
|
| 1366 |
+
# Create output directories if they don't exist
|
| 1367 |
+
os.makedirs(processed_image_dir, exist_ok=True)
|
| 1368 |
+
os.makedirs(processed_annotation_dir, exist_ok=True)
|
| 1369 |
+
|
| 1370 |
+
# Define the mask class mappings (assign unique labels to each type)
|
| 1371 |
+
mask_classes = {
|
| 1372 |
+
'maskLeaves': 1,
|
| 1373 |
+
'maskPlants': 2,
|
| 1374 |
+
'maskStems': 3,
|
| 1375 |
+
'maskVoid': 4
|
| 1376 |
+
}
|
| 1377 |
+
|
| 1378 |
+
# Get the list of image filenames
|
| 1379 |
+
image_files = sorted(os.listdir(images_dir))
|
| 1380 |
+
|
| 1381 |
+
for idx, image_file in enumerate(tqdm(image_files, desc="Processing Cauliflower Dataset")):
|
| 1382 |
+
image_name = os.path.splitext(image_file)[0] # Get the base image name without extension
|
| 1383 |
+
image_path = os.path.join(images_dir, image_file)
|
| 1384 |
+
|
| 1385 |
+
# Find the corresponding masks for each class
|
| 1386 |
+
mask_paths = {}
|
| 1387 |
+
for mask_class in mask_classes.keys():
|
| 1388 |
+
# Build mask filenames with both naming conventions
|
| 1389 |
+
mask_filename_no_plants = f"{image_name}_Label_NoPlants_{mask_class}.png"
|
| 1390 |
+
mask_filename = f"{image_name}_Label_{mask_class}.png"
|
| 1391 |
+
|
| 1392 |
+
# Set the correct mask path
|
| 1393 |
+
mask_path_no_plants = os.path.join(masks_dir, mask_class, mask_filename_no_plants)
|
| 1394 |
+
mask_path = os.path.join(masks_dir, mask_class, mask_filename)
|
| 1395 |
+
|
| 1396 |
+
if os.path.exists(mask_path_no_plants):
|
| 1397 |
+
mask_paths[mask_class] = mask_path_no_plants
|
| 1398 |
+
else:
|
| 1399 |
+
mask_paths[mask_class] = mask_path
|
| 1400 |
+
|
| 1401 |
+
# Load the original image to get its shape (we need the height and width)
|
| 1402 |
+
orig_image = cv2.imread(image_path)
|
| 1403 |
+
if orig_image is None:
|
| 1404 |
+
print(f"Warning: Unable to read image {image_path}")
|
| 1405 |
+
continue
|
| 1406 |
+
image_shape = orig_image.shape[:2] # (height, width)
|
| 1407 |
+
|
| 1408 |
+
# Initialize the merged mask as a blank image (background class 0)
|
| 1409 |
+
merged_mask = np.zeros(image_shape, dtype=np.uint8)
|
| 1410 |
+
|
| 1411 |
+
# Visualize and debug individual masks, if needed
|
| 1412 |
+
individual_masks = {}
|
| 1413 |
+
|
| 1414 |
+
for mask_name, class_value in mask_classes.items():
|
| 1415 |
+
mask = cv2.imread(mask_paths[mask_name], cv2.IMREAD_GRAYSCALE)
|
| 1416 |
+
if mask is None:
|
| 1417 |
+
print(f"Warning: Unable to read mask {mask_paths[mask_name]}")
|
| 1418 |
+
continue
|
| 1419 |
+
individual_masks[mask_name] = mask # Store for visualization
|
| 1420 |
+
|
| 1421 |
+
# Debugging: Check unique values in each mask
|
| 1422 |
+
print(f"{mask_name} unique values for {image_name}: {np.unique(mask)}")
|
| 1423 |
+
|
| 1424 |
+
# Binarize the mask for leaf mask based on the value 60
|
| 1425 |
+
if mask_name == 'maskLeaves':
|
| 1426 |
+
binarized_mask = np.where(mask == 60, 1, 0).astype(np.uint8)
|
| 1427 |
+
else:
|
| 1428 |
+
# For other masks, threshold based on the condition > 60
|
| 1429 |
+
binarized_mask = np.where(mask > 60, 1, 0).astype(np.uint8)
|
| 1430 |
+
# Merge logic: void mask only applies where there's no other mask
|
| 1431 |
+
if class_value == 4: # Void class
|
| 1432 |
+
merged_mask[(merged_mask == 0) & (binarized_mask > 0)] = class_value
|
| 1433 |
+
else:
|
| 1434 |
+
merged_mask[(binarized_mask > 0)] = class_value
|
| 1435 |
+
|
| 1436 |
+
# Debugging Step: Check unique values in the merged mask
|
| 1437 |
+
unique_values = np.unique(merged_mask)
|
| 1438 |
+
print(f"Image {idx+1}/{len(image_files)}: {image_file} - Unique mask values: {unique_values}")
|
| 1439 |
+
|
| 1440 |
+
# Save the original image and the merged mask to the new directory
|
| 1441 |
+
out_image_path = os.path.join(processed_image_dir, image_file)
|
| 1442 |
+
out_mask_path = os.path.join(processed_annotation_dir, f"{image_name}.png")
|
| 1443 |
+
|
| 1444 |
+
cv2.imwrite(out_image_path, orig_image)
|
| 1445 |
+
cv2.imwrite(out_mask_path, merged_mask)
|
| 1446 |
+
|
| 1447 |
+
def strawberry_detection_2023(self, dataset_name):
|
| 1448 |
+
# Create processed directories
|
| 1449 |
+
original_dir = os.path.join(self.data_original_dir)
|
| 1450 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 1451 |
+
processed_image_dir = os.path.join(processed_dir, 'images')
|
| 1452 |
+
os.makedirs(processed_image_dir, exist_ok = True)
|
| 1453 |
+
# Move images
|
| 1454 |
+
for image in tqdm(glob.glob(os.path.join(original_dir, '*.jpg'))):
|
| 1455 |
+
shutil.move(image, processed_image_dir)
|
| 1456 |
+
shutil.move(os.path.join(original_dir, 'coco.json'),
|
| 1457 |
+
os.path.join(processed_dir, 'annotations.json'))
|
| 1458 |
+
|
| 1459 |
+
def strawberry_detection_2022(self, dataset_name):
|
| 1460 |
+
# Create processed directories
|
| 1461 |
+
original_dir = os.path.join(self.data_original_dir)
|
| 1462 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 1463 |
+
processed_image_dir = os.path.join(processed_dir, 'images')
|
| 1464 |
+
os.makedirs(processed_image_dir, exist_ok = True)
|
| 1465 |
+
# Move images
|
| 1466 |
+
for image in tqdm(glob.glob(os.path.join(original_dir, '*.jpg'))):
|
| 1467 |
+
shutil.move(image, processed_image_dir)
|
| 1468 |
+
shutil.move(os.path.join(original_dir, 'coco.json'),
|
| 1469 |
+
os.path.join(processed_dir, 'annotations.json'))
|
| 1470 |
+
|
| 1471 |
+
def almond_harvest_2021(self, dataset_name):
|
| 1472 |
+
# Create processed directories
|
| 1473 |
+
original_dir = os.path.join(self.data_original_dir)
|
| 1474 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 1475 |
+
processed_image_dir = os.path.join(processed_dir, 'images')
|
| 1476 |
+
os.makedirs(processed_image_dir, exist_ok = True)
|
| 1477 |
+
# Move images
|
| 1478 |
+
for image in tqdm(glob.glob(os.path.join(original_dir, '*.jpg'))):
|
| 1479 |
+
shutil.move(image, processed_image_dir)
|
| 1480 |
+
shutil.move(os.path.join(original_dir, 'coco.json'),
|
| 1481 |
+
os.path.join(processed_dir, 'annotations.json'))
|
| 1482 |
+
|
| 1483 |
+
def almond_bloom_2023(self, dataset_name):
|
| 1484 |
+
# Create processed directories
|
| 1485 |
+
original_dir = os.path.join(self.data_original_dir)
|
| 1486 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 1487 |
+
processed_image_dir = os.path.join(processed_dir, 'images')
|
| 1488 |
+
os.makedirs(processed_image_dir, exist_ok = True)
|
| 1489 |
+
# Move images
|
| 1490 |
+
for image in tqdm(glob.glob(os.path.join(original_dir, '*.jpg'))):
|
| 1491 |
+
shutil.move(image, processed_image_dir)
|
| 1492 |
+
shutil.move(os.path.join(original_dir, 'coco.json'),
|
| 1493 |
+
os.path.join(processed_dir, 'annotations.json'))
|
| 1494 |
+
|
| 1495 |
+
def gemini_flower_detection_2022(self, dataset_name):
|
| 1496 |
+
original_dir = os.path.join(self.data_original_dir)
|
| 1497 |
+
print(original_dir)
|
| 1498 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 1499 |
+
processed_image_dir = os.path.join(processed_dir, 'images')
|
| 1500 |
+
os.makedirs(processed_image_dir, exist_ok = True)
|
| 1501 |
+
# Move images
|
| 1502 |
+
for image in tqdm(glob.glob(os.path.join(original_dir, 'images', '*.jpg'))):
|
| 1503 |
+
shutil.move(image, processed_image_dir)
|
| 1504 |
+
shutil.move(os.path.join(original_dir, 'coco.json'),
|
| 1505 |
+
os.path.join(processed_dir, 'annotations.json'))
|
| 1506 |
+
|
| 1507 |
+
def gemini_leaf_detection_2022(self, dataset_name):
|
| 1508 |
+
original_dir = os.path.join(self.data_original_dir)
|
| 1509 |
+
print(original_dir)
|
| 1510 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 1511 |
+
processed_image_dir = os.path.join(processed_dir, 'images')
|
| 1512 |
+
os.makedirs(processed_image_dir, exist_ok = True)
|
| 1513 |
+
# Move images
|
| 1514 |
+
for image in tqdm(glob.glob(os.path.join(original_dir, 'images', '*.jpg'))):
|
| 1515 |
+
shutil.move(image, processed_image_dir)
|
| 1516 |
+
shutil.move(os.path.join(original_dir, 'coco.json'),
|
| 1517 |
+
os.path.join(processed_dir, 'annotations.json'))
|
| 1518 |
+
|
| 1519 |
+
def gemini_pod_detection_2022(self, dataset_name):
|
| 1520 |
+
original_dir = os.path.join(self.data_original_dir)
|
| 1521 |
+
print(original_dir)
|
| 1522 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 1523 |
+
processed_image_dir = os.path.join(processed_dir, 'images')
|
| 1524 |
+
os.makedirs(processed_image_dir, exist_ok = True)
|
| 1525 |
+
# Move images
|
| 1526 |
+
for image in tqdm(glob.glob(os.path.join(original_dir, 'images', '*.jpg'))):
|
| 1527 |
+
shutil.move(image, processed_image_dir)
|
| 1528 |
+
shutil.move(os.path.join(original_dir, 'coco.json'),
|
| 1529 |
+
os.path.join(processed_dir, 'annotations.json'))
|
| 1530 |
+
|
| 1531 |
+
def gemini_plant_detection_2022(self, dataset_name):
|
| 1532 |
+
original_dir = os.path.join(self.data_original_dir)
|
| 1533 |
+
print(original_dir)
|
| 1534 |
+
processed_dir = os.path.join(self.data_processed_dir, dataset_name)
|
| 1535 |
+
processed_image_dir = os.path.join(processed_dir, 'images')
|
| 1536 |
+
os.makedirs(processed_image_dir, exist_ok = True)
|
| 1537 |
+
# Move images
|
| 1538 |
+
for image in tqdm(glob.glob(os.path.join(original_dir, 'images', '*.jpg'))):
|
| 1539 |
+
shutil.move(image, processed_image_dir)
|
| 1540 |
+
shutil.move(os.path.join(original_dir, 'coco.json'),
|
| 1541 |
+
os.path.join(processed_dir, 'annotations.json'))
|
| 1542 |
+
|
| 1543 |
+
def paddy_disease_classification(self, dataset_name):
|
| 1544 |
+
pass
|
| 1545 |
+
|
| 1546 |
+
def onion_leaf_classification(self, dataset_name):
|
| 1547 |
+
pass
|
| 1548 |
+
|
| 1549 |
+
def chilli_leaf_classification(self, dataset_name):
|
| 1550 |
+
pass
|
| 1551 |
+
|
| 1552 |
+
def orange_leaf_disease_classification(self, dataset_name):
|
| 1553 |
+
pass
|
| 1554 |
+
|
| 1555 |
+
def papaya_leaf_disease_classification(self, dataset_name):
|
| 1556 |
+
pass
|
| 1557 |
+
|
| 1558 |
+
def blackgram_plant_leaf_disease_classification(self, dataset_name):
|
| 1559 |
+
pass
|
| 1560 |
+
|
| 1561 |
+
def arabica_coffee_leaf_disease_classification(self, dataset_name):
|
| 1562 |
+
pass
|
| 1563 |
+
|
| 1564 |
+
def banana_leaf_disease_classification(self, dataset_name):
|
| 1565 |
+
pass
|
| 1566 |
+
|
| 1567 |
+
def coconut_tree_disease_classification(self, dataset_name):
|
| 1568 |
+
pass
|
| 1569 |
+
|
| 1570 |
+
def rice_leaf_disease_classification(self, dataset_name):
|
| 1571 |
+
pass
|
| 1572 |
+
|
| 1573 |
+
def tea_leaf_disease_classification(self, dataset_name):
|
| 1574 |
+
pass
|
| 1575 |
+
|
| 1576 |
+
def betel_leaf_disease_classification(self, dataset_name):
|
| 1577 |
+
pass
|
| 1578 |
+
|
| 1579 |
+
def java_plum_leaf_disease_classification(self, dataset_name):
|
| 1580 |
+
pass
|
| 1581 |
+
|
| 1582 |
+
def sunflower_disease_classification(self, dataset_name):
|
| 1583 |
+
pass
|
| 1584 |
+
|
| 1585 |
+
def cucumber_disease_classification(self, dataset_name):
|
| 1586 |
+
pass
|
| 1587 |
+
|
| 1588 |
+
def soybean_insect_classification(self, dataset_name):
|
| 1589 |
+
pass
|
| 1590 |
+
|
| 1591 |
+
if __name__ == '__main__':
|
| 1592 |
+
# Initialize program arguments.
|
| 1593 |
+
ap = argparse.ArgumentParser()
|
| 1594 |
+
ap.add_argument(
|
| 1595 |
+
"--data_dir",
|
| 1596 |
+
type=str,
|
| 1597 |
+
default="../../data_new",
|
| 1598 |
+
help="The directory containing two sub-directories, " "`original` and `processed`, with the data.",
|
| 1599 |
+
)
|
| 1600 |
+
ap.add_argument("--dataset", type=str, help="The dataset to process.")
|
| 1601 |
+
args = ap.parse_args()
|
| 1602 |
+
|
| 1603 |
+
# Execute the preprocessing.
|
| 1604 |
+
p = PublicDataPreprocessor(os.path.abspath(args.data_dir))
|
| 1605 |
+
print("Processing dataset")
|
| 1606 |
+
p.preprocess(args.dataset)
|
| 1607 |
+
print("Converting dataset")
|
| 1608 |
+
# os.chdir(f'{args.data_dir}/processed')
|
| 1609 |
+
# os.system(f'zip -r {args.dataset}.zip {args.dataset} -x ".*" -x "__MACOSX"')
|
AgML/source/agml/_internal/process_utils.py
ADDED
|
@@ -0,0 +1,576 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 UC Davis Plant AI and Biophysics Lab
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
"""
|
| 16 |
+
Preprocess utilities for the code in `preprocess.py`.
|
| 17 |
+
"""
|
| 18 |
+
|
| 19 |
+
import os
|
| 20 |
+
import sys
|
| 21 |
+
import csv
|
| 22 |
+
import json
|
| 23 |
+
import shutil
|
| 24 |
+
from typing import Dict, List
|
| 25 |
+
import xml.etree.ElementTree as ET
|
| 26 |
+
|
| 27 |
+
import cv2
|
| 28 |
+
import numpy as np
|
| 29 |
+
|
| 30 |
+
from PIL import Image
|
| 31 |
+
from skimage import measure
|
| 32 |
+
from shapely.geometry import Polygon, MultiPolygon
|
| 33 |
+
|
| 34 |
+
from agml.utils.logging import tqdm
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def read_txt_file(file_name, delimiter=" ", header=False):
|
| 38 |
+
with open(file_name, newline="\n") as txt_file:
|
| 39 |
+
txt_reader = csv.reader(txt_file, delimiter=delimiter)
|
| 40 |
+
txt_lines = []
|
| 41 |
+
headline = None
|
| 42 |
+
for idx, line in enumerate(txt_reader):
|
| 43 |
+
if header and idx == 0:
|
| 44 |
+
headline = line
|
| 45 |
+
continue
|
| 46 |
+
line = [x.strip() for x in line if x.strip()] # To remove blank elements
|
| 47 |
+
txt_lines.append(line)
|
| 48 |
+
|
| 49 |
+
return txt_lines, headline
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def get_label2id(labels_str: str) -> Dict[str, int]:
|
| 53 |
+
"""id is 1 start"""
|
| 54 |
+
labels_ids = list(range(1, len(labels_str) + 1))
|
| 55 |
+
return dict(zip(labels_str, labels_ids))
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def get_annpaths(
|
| 59 |
+
ann_dir_path: str = None, ann_ids_path: str = None, ext: str = "", annpaths_list_path: str = None
|
| 60 |
+
) -> List[str]:
|
| 61 |
+
# If wanting to use annotation paths list
|
| 62 |
+
if annpaths_list_path is not None:
|
| 63 |
+
with open(annpaths_list_path, "r") as f:
|
| 64 |
+
ann_paths = f.read().split()
|
| 65 |
+
return ann_paths
|
| 66 |
+
|
| 67 |
+
# If wanting to use annotation ids list
|
| 68 |
+
ext_with_dot = "." + ext if ext != "" else ""
|
| 69 |
+
with open(ann_ids_path, "r") as f:
|
| 70 |
+
ann_ids = f.read().split()
|
| 71 |
+
ann_paths = [os.path.join(ann_dir_path, aid + ext_with_dot) for aid in ann_ids]
|
| 72 |
+
return ann_paths
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def get_image_info_from_annoline(annotation_root, idx, resize=1.0, add_foldername=False):
|
| 76 |
+
filename = annotation_root[0].split("/")[-1]
|
| 77 |
+
try:
|
| 78 |
+
img = cv2.imread(annotation_root[0])
|
| 79 |
+
|
| 80 |
+
if resize != 1.0:
|
| 81 |
+
dsize = (int(img.shape[1] * resize), int(img.shape[0] * resize))
|
| 82 |
+
img = cv2.resize(img, dsize)
|
| 83 |
+
|
| 84 |
+
size = img.shape
|
| 85 |
+
width = size[1]
|
| 86 |
+
height = size[0]
|
| 87 |
+
|
| 88 |
+
if add_foldername:
|
| 89 |
+
filename = "{folder}_{img_name}".format(
|
| 90 |
+
folder=annotation_root[0].split("/")[-2], img_name=annotation_root[0].split("/")[-1]
|
| 91 |
+
)
|
| 92 |
+
|
| 93 |
+
image_info = {
|
| 94 |
+
"file_name": filename,
|
| 95 |
+
"height": height,
|
| 96 |
+
"width": width,
|
| 97 |
+
"id": idx, # Use image order
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
except Exception as e:
|
| 101 |
+
print(e)
|
| 102 |
+
print("Cannot open {file}".format(file=annotation_root[0]))
|
| 103 |
+
image_info = None
|
| 104 |
+
img = None
|
| 105 |
+
|
| 106 |
+
return image_info, img
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
def get_image_info(annotation_root, idx, resize=1.0, add_foldername=False):
|
| 110 |
+
path = annotation_root.findtext("path")
|
| 111 |
+
if path is None or True:
|
| 112 |
+
filename = annotation_root.findtext("filename")
|
| 113 |
+
else:
|
| 114 |
+
filename = os.path.basename(path)
|
| 115 |
+
|
| 116 |
+
try:
|
| 117 |
+
img = cv2.imread(filename)
|
| 118 |
+
|
| 119 |
+
if resize != 1.0:
|
| 120 |
+
dsize = [int(img.shape[1] * resize), int(img.shape[0] * resize)]
|
| 121 |
+
img = cv2.resize(img, dsize)
|
| 122 |
+
|
| 123 |
+
size = img.shape
|
| 124 |
+
width = size[1]
|
| 125 |
+
height = size[0]
|
| 126 |
+
|
| 127 |
+
if add_foldername:
|
| 128 |
+
filename = "{folder}_{img_name}".format(folder=filename.split("/")[-2], img_name=filename.split("/")[-1])
|
| 129 |
+
|
| 130 |
+
image_info = {
|
| 131 |
+
"file_name": filename.split("/")[-1],
|
| 132 |
+
"height": height,
|
| 133 |
+
"width": width,
|
| 134 |
+
"id": idx, # Use image order
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
except Exception as e:
|
| 138 |
+
print(e)
|
| 139 |
+
print("Cannot open {file}".format(file=annotation_root[0]))
|
| 140 |
+
image_info = None
|
| 141 |
+
img = None
|
| 142 |
+
|
| 143 |
+
return image_info, img
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
# Sourced from https://github.com/roboflow-ai/voc2coco.git
|
| 147 |
+
def get_coco_annotation_from_annoline(obj, resize=1.0):
|
| 148 |
+
# Try the sub-label first
|
| 149 |
+
category_id = int(obj[4])
|
| 150 |
+
xmin = int(float(obj[0]) * resize)
|
| 151 |
+
ymin = int(float(obj[1]) * resize)
|
| 152 |
+
xmax = int(float(obj[2]) * resize)
|
| 153 |
+
ymax = int(float(obj[3]) * resize)
|
| 154 |
+
assert xmax > xmin and ymax > ymin, f"Box size error !: (xmin, ymin, xmax, ymax): {xmin, ymin, xmax, ymax}"
|
| 155 |
+
o_width = xmax - xmin + 1
|
| 156 |
+
o_height = ymax - ymin + 1
|
| 157 |
+
return {
|
| 158 |
+
"area": o_width * o_height,
|
| 159 |
+
"iscrowd": 0,
|
| 160 |
+
"bbox": [xmin, ymin, o_width, o_height],
|
| 161 |
+
"category_id": category_id,
|
| 162 |
+
"ignore": 0,
|
| 163 |
+
"segmentation": [], # This script is not for segmentation
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
def get_coco_annotation_from_obj(obj, label2id, name_converter=None):
|
| 168 |
+
# Try to sub-label first
|
| 169 |
+
label = obj.findtext("subname")
|
| 170 |
+
if label is None:
|
| 171 |
+
label = obj.findtext("name")
|
| 172 |
+
if name_converter:
|
| 173 |
+
if label in name_converter:
|
| 174 |
+
label = name_converter[label]
|
| 175 |
+
if label not in label2id:
|
| 176 |
+
return []
|
| 177 |
+
category_id = label2id[label]
|
| 178 |
+
|
| 179 |
+
bndbox = obj.find("bndbox")
|
| 180 |
+
if bndbox is None:
|
| 181 |
+
bndbox = obj.find("bbox")
|
| 182 |
+
if bndbox is None:
|
| 183 |
+
return None
|
| 184 |
+
|
| 185 |
+
xmin = int(float(bndbox.findtext("xmin"))) - 1
|
| 186 |
+
ymin = int(float(bndbox.findtext("ymin"))) - 1
|
| 187 |
+
xmax = int(float(bndbox.findtext("xmax")))
|
| 188 |
+
ymax = int(float(bndbox.findtext("ymax")))
|
| 189 |
+
assert xmax > xmin and ymax > ymin, f"Box size error !: (xmin, ymin, xmax, ymax): {xmin, ymin, xmax, ymax}"
|
| 190 |
+
o_width = xmax - xmin
|
| 191 |
+
o_height = ymax - ymin
|
| 192 |
+
return {
|
| 193 |
+
"area": o_width * o_height,
|
| 194 |
+
"iscrowd": 0,
|
| 195 |
+
"bbox": [xmin, ymin, o_width, o_height],
|
| 196 |
+
"category_id": category_id,
|
| 197 |
+
"ignore": 0,
|
| 198 |
+
"segmentation": [], # This script is not for segmentation
|
| 199 |
+
}
|
| 200 |
+
|
| 201 |
+
|
| 202 |
+
def convert_bbox_to_coco(
|
| 203 |
+
annotation: List[str],
|
| 204 |
+
label2id: Dict[str, int],
|
| 205 |
+
output_jsonpath: str,
|
| 206 |
+
output_imgpath: str,
|
| 207 |
+
general_info,
|
| 208 |
+
image_id_list=None,
|
| 209 |
+
bnd_id_list=None,
|
| 210 |
+
get_label_from_folder=False,
|
| 211 |
+
resize=1.0,
|
| 212 |
+
add_foldername=False,
|
| 213 |
+
extract_num_from_imgid=False,
|
| 214 |
+
):
|
| 215 |
+
"""
|
| 216 |
+
Annotation Format
|
| 217 |
+
-----------------
|
| 218 |
+
"image name" "the number of bounding boxes(bb)" "x1" "y1" "x2" "y2" "label" "score" "x1" "y1" "x2" "y2" ...
|
| 219 |
+
|
| 220 |
+
For example, the following line:
|
| 221 |
+
|
| 222 |
+
TRAIN_RGB/n12710693_12225.png 5 515 68 759 285 2 1.000 624 347 868 582 2 1.000 480 488 693 712 2 1.000 44 433 268 657 2 1.000 112 198 342 401 2 1.000
|
| 223 |
+
|
| 224 |
+
will become:
|
| 225 |
+
|
| 226 |
+
image name=TRAIN_RGB/n12710693_12225.png
|
| 227 |
+
the number of bb=5
|
| 228 |
+
x1=515
|
| 229 |
+
y1=68
|
| 230 |
+
x2=759
|
| 231 |
+
y2=285
|
| 232 |
+
label=2 "0=background, 1=capsicum, 2=rockmelon..."
|
| 233 |
+
score=1.000
|
| 234 |
+
|
| 235 |
+
Reference: https://drive.google.com/drive/folders/1CmsZb1caggLRN7ANfika8WuPiywo4mBb
|
| 236 |
+
"""
|
| 237 |
+
output_json_dict = {"images": [], "type": "instances", "annotations": [], "categories": [], "info": general_info}
|
| 238 |
+
|
| 239 |
+
# TODO: Use multi thread to boost up the speed
|
| 240 |
+
print("Converting annotations into COCO JSON and process the images")
|
| 241 |
+
for img_idx, anno_line in enumerate(tqdm(annotation)):
|
| 242 |
+
if image_id_list:
|
| 243 |
+
img_unique_id = image_id_list[img_idx]
|
| 244 |
+
else:
|
| 245 |
+
if extract_num_from_imgid:
|
| 246 |
+
filename = anno_line[0].split("/")[-1]
|
| 247 |
+
img_unique_id = int("".join(filter(str.isdigit, filename)))
|
| 248 |
+
else:
|
| 249 |
+
img_unique_id = img_idx + 1
|
| 250 |
+
|
| 251 |
+
img_info, img = get_image_info_from_annoline(
|
| 252 |
+
annotation_root=anno_line, idx=img_unique_id, resize=resize, add_foldername=add_foldername
|
| 253 |
+
)
|
| 254 |
+
|
| 255 |
+
if img_info:
|
| 256 |
+
output_json_dict["images"].append(img_info)
|
| 257 |
+
|
| 258 |
+
bbox_cnt = int(anno_line[1])
|
| 259 |
+
if bbox_cnt > 0:
|
| 260 |
+
ann_reshape = np.reshape(anno_line[2:], (bbox_cnt, -1))
|
| 261 |
+
for bnd_idx, obj in enumerate(ann_reshape):
|
| 262 |
+
if get_label_from_folder:
|
| 263 |
+
# Change label based on folder
|
| 264 |
+
try:
|
| 265 |
+
category_name = anno_line[0].split("/")[-3]
|
| 266 |
+
if category_name not in label2id:
|
| 267 |
+
raise
|
| 268 |
+
except:
|
| 269 |
+
try:
|
| 270 |
+
category_name = anno_line[0].split("/")[-2]
|
| 271 |
+
if category_name not in label2id:
|
| 272 |
+
raise
|
| 273 |
+
except Exception as e:
|
| 274 |
+
raise e
|
| 275 |
+
|
| 276 |
+
if len(obj) < 5:
|
| 277 |
+
obj = np.append(obj, label2id[category_name])
|
| 278 |
+
else:
|
| 279 |
+
obj[4] = label2id[category_name]
|
| 280 |
+
else:
|
| 281 |
+
pass
|
| 282 |
+
|
| 283 |
+
try:
|
| 284 |
+
ann = get_coco_annotation_from_annoline(obj=obj, resize=resize)
|
| 285 |
+
except:
|
| 286 |
+
ann = None
|
| 287 |
+
|
| 288 |
+
if ann:
|
| 289 |
+
if bnd_id_list:
|
| 290 |
+
bnd_idx = bnd_id_list[img_idx][bnd_idx]
|
| 291 |
+
else:
|
| 292 |
+
bnd_idx + 1 # noqa
|
| 293 |
+
ann.update({"image_id": img_info["id"], "id": bnd_idx})
|
| 294 |
+
output_json_dict["annotations"].append(ann)
|
| 295 |
+
|
| 296 |
+
img_name = img_info["file_name"]
|
| 297 |
+
dest_path = os.path.join(output_imgpath, img_name)
|
| 298 |
+
try:
|
| 299 |
+
if resize == 1.0:
|
| 300 |
+
shutil.copyfile(anno_line[0], dest_path)
|
| 301 |
+
else:
|
| 302 |
+
cv2.imwrite(dest_path, img)
|
| 303 |
+
except: # Cannot copy the image file
|
| 304 |
+
pass
|
| 305 |
+
|
| 306 |
+
else: # Not valid image => Delete from annotation
|
| 307 |
+
pass
|
| 308 |
+
|
| 309 |
+
for label, label_id in label2id.items():
|
| 310 |
+
category_info = {"supercategory": "none", "id": label_id, "name": label}
|
| 311 |
+
output_json_dict["categories"].append(category_info)
|
| 312 |
+
|
| 313 |
+
with open(output_jsonpath, "w") as f:
|
| 314 |
+
output_json = json.dumps(output_json_dict)
|
| 315 |
+
f.write(output_json)
|
| 316 |
+
|
| 317 |
+
return output_json_dict
|
| 318 |
+
|
| 319 |
+
|
| 320 |
+
def convert_xmls_to_cocojson(
|
| 321 |
+
general_info,
|
| 322 |
+
annotation_paths: List[str],
|
| 323 |
+
img_paths: List[str],
|
| 324 |
+
label2id: Dict[str, int],
|
| 325 |
+
name_converter,
|
| 326 |
+
output_jsonpath: str,
|
| 327 |
+
output_imgpath: str,
|
| 328 |
+
extract_num_from_imgid: bool = True,
|
| 329 |
+
):
|
| 330 |
+
"""Converts the XML annotation format into COCO JSON."""
|
| 331 |
+
output_json_dict = {"images": [], "type": "instances", "annotations": [], "categories": [], "info": general_info}
|
| 332 |
+
bnd_id = 1 # START_BOUNDING_BOX_ID, TODO input as args ?
|
| 333 |
+
print("Start converting !")
|
| 334 |
+
for img_idx, a_path in enumerate(tqdm(annotation_paths)):
|
| 335 |
+
# Read annotation xml
|
| 336 |
+
ann_tree = ET.parse(a_path)
|
| 337 |
+
ann_root = ann_tree.getroot()
|
| 338 |
+
|
| 339 |
+
if extract_num_from_imgid:
|
| 340 |
+
filename = a_path.split("/")[-1]
|
| 341 |
+
img_unique_id = int("".join(filter(str.isdigit, filename)))
|
| 342 |
+
else:
|
| 343 |
+
img_unique_id = img_idx + 1
|
| 344 |
+
|
| 345 |
+
if len(img_paths) == len(annotation_paths):
|
| 346 |
+
ann_root.find("filename").text = img_paths[img_idx]
|
| 347 |
+
|
| 348 |
+
img_info, img = get_image_info(annotation_root=ann_root, idx=img_unique_id, resize=1.0, add_foldername=False)
|
| 349 |
+
output_json_dict["images"].append(img_info)
|
| 350 |
+
|
| 351 |
+
for obj in ann_root.findall("object"):
|
| 352 |
+
ann = get_coco_annotation_from_obj(obj=obj, label2id=label2id, name_converter=name_converter)
|
| 353 |
+
if ann:
|
| 354 |
+
ann.update({"image_id": img_info["id"], "id": bnd_id})
|
| 355 |
+
output_json_dict["annotations"].append(ann)
|
| 356 |
+
bnd_id = bnd_id + 1
|
| 357 |
+
|
| 358 |
+
# Process images
|
| 359 |
+
img_name = img_info["file_name"]
|
| 360 |
+
dest_path = os.path.join(output_imgpath, img_name)
|
| 361 |
+
try:
|
| 362 |
+
cv2.imwrite(dest_path, img)
|
| 363 |
+
except: # Cannot copy the image file
|
| 364 |
+
pass
|
| 365 |
+
|
| 366 |
+
for label, label_id in label2id.items():
|
| 367 |
+
category_info = {"supercategory": "none", "id": label_id, "name": label}
|
| 368 |
+
output_json_dict["categories"].append(category_info)
|
| 369 |
+
|
| 370 |
+
with open(output_jsonpath, "w") as f:
|
| 371 |
+
output_json = json.dumps(output_json_dict)
|
| 372 |
+
f.write(output_json)
|
| 373 |
+
|
| 374 |
+
|
| 375 |
+
# Reference: https://www.immersivelimit.com/create-coco-annotations-from-scratch
|
| 376 |
+
def create_sub_masks(mask_image):
|
| 377 |
+
width, height = mask_image.size
|
| 378 |
+
|
| 379 |
+
# Initialize a dictionary of sub-masks indexed by RGB colors
|
| 380 |
+
sub_masks = {}
|
| 381 |
+
for x in range(width):
|
| 382 |
+
for y in range(height):
|
| 383 |
+
# Get the RGB values of the pixel
|
| 384 |
+
pixel = mask_image.getpixel((x, y))[:3]
|
| 385 |
+
|
| 386 |
+
# If the pixel is not black...
|
| 387 |
+
if pixel != (0, 0, 0):
|
| 388 |
+
# Check to see if we've created a sub-mask...
|
| 389 |
+
pixel_str = str(pixel)
|
| 390 |
+
sub_mask = sub_masks.get(pixel_str)
|
| 391 |
+
if sub_mask is None:
|
| 392 |
+
# Create a sub-mask (one bit per pixel) and add to the dictionary
|
| 393 |
+
# Note: we add 1 pixel of padding in each direction
|
| 394 |
+
# because the contours module doesn't handle cases
|
| 395 |
+
# where pixels bleed to the edge of the image
|
| 396 |
+
sub_masks[pixel_str] = Image.new("1", (width + 2, height + 2))
|
| 397 |
+
|
| 398 |
+
# Set the pixel value to 1 (default is 0), accounting for padding
|
| 399 |
+
sub_masks[pixel_str].putpixel((x + 1, y + 1), 1)
|
| 400 |
+
|
| 401 |
+
return sub_masks
|
| 402 |
+
|
| 403 |
+
|
| 404 |
+
# Reference: https://www.immersivelimit.com/create-coco-annotations-from-scratch
|
| 405 |
+
def create_sub_mask_annotation(sub_mask, image_id, category_id, annotation_id, is_crowd):
|
| 406 |
+
# Find contours (boundary lines) around each sub-mask
|
| 407 |
+
# Note: there could be multiple contours if the object
|
| 408 |
+
# is partially occluded. (E.g. an elephant behind a tree)
|
| 409 |
+
contours = measure.find_contours(sub_mask, 0.5, positive_orientation="low")
|
| 410 |
+
|
| 411 |
+
segmentations = []
|
| 412 |
+
polygons = []
|
| 413 |
+
for contour in contours:
|
| 414 |
+
# Flip from (row, col) representation to (x, y)
|
| 415 |
+
# and subtract the padding pixel
|
| 416 |
+
for i in range(len(contour)):
|
| 417 |
+
row, col = contour[i]
|
| 418 |
+
contour[i] = (col - 1, row - 1)
|
| 419 |
+
|
| 420 |
+
# Make a polygon and simplify it
|
| 421 |
+
poly = Polygon(contour)
|
| 422 |
+
poly = poly.simplify(1.0, preserve_topology=False)
|
| 423 |
+
polygons.append(poly)
|
| 424 |
+
segmentation = np.array(poly.exterior.coords).ravel().tolist()
|
| 425 |
+
segmentations.append(segmentation)
|
| 426 |
+
|
| 427 |
+
# Combine the polygons to calculate the bounding box and area
|
| 428 |
+
multi_poly = MultiPolygon(polygons)
|
| 429 |
+
x, y, max_x, max_y = multi_poly.bounds
|
| 430 |
+
width = max_x - x
|
| 431 |
+
height = max_y - y
|
| 432 |
+
bbox = (x, y, width, height)
|
| 433 |
+
area = multi_poly.area
|
| 434 |
+
|
| 435 |
+
annotation = {
|
| 436 |
+
"segmentation": segmentations,
|
| 437 |
+
"iscrowd": is_crowd,
|
| 438 |
+
"image_id": image_id,
|
| 439 |
+
"category_id": category_id,
|
| 440 |
+
"id": annotation_id,
|
| 441 |
+
"bbox": bbox,
|
| 442 |
+
"area": area,
|
| 443 |
+
}
|
| 444 |
+
|
| 445 |
+
return annotation
|
| 446 |
+
|
| 447 |
+
|
| 448 |
+
def create_sub_mask_annotation_per_bbox(sub_mask, image_id, category_id, annotation_id, is_crowd):
|
| 449 |
+
# Find contours (boundary lines) around each sub-mask
|
| 450 |
+
# Note: there could be multiple contours if the object
|
| 451 |
+
# is partially occluded. (E.g. an elephant behind a tree)
|
| 452 |
+
sub_mask_np = np.array(sub_mask)
|
| 453 |
+
contours = measure.find_contours(sub_mask_np, 0.5, positive_orientation="low")
|
| 454 |
+
|
| 455 |
+
segmentations = []
|
| 456 |
+
polygons = []
|
| 457 |
+
annotations = []
|
| 458 |
+
for idx, contour in enumerate(contours):
|
| 459 |
+
# Flip from (row, col) representation to (x, y)
|
| 460 |
+
# and subtract the padding pixel
|
| 461 |
+
for i in range(len(contour)):
|
| 462 |
+
row, col = contour[i]
|
| 463 |
+
contour[i] = (col - 1, row - 1)
|
| 464 |
+
|
| 465 |
+
# Make a polygon and simplify it
|
| 466 |
+
poly = Polygon(contour)
|
| 467 |
+
poly = poly.simplify(1.0, preserve_topology=False)
|
| 468 |
+
polygons.append(poly)
|
| 469 |
+
segmentation = np.array(poly.exterior.coords).ravel().tolist()
|
| 470 |
+
segmentations.append(segmentation)
|
| 471 |
+
|
| 472 |
+
if poly.area > 0:
|
| 473 |
+
# Combine the polygons to calculate the bounding box and area
|
| 474 |
+
multi_poly = MultiPolygon([poly])
|
| 475 |
+
x, y, max_x, max_y = multi_poly.bounds
|
| 476 |
+
width = max_x - x
|
| 477 |
+
height = max_y - y
|
| 478 |
+
bbox = (x, y, width, height)
|
| 479 |
+
area = multi_poly.area
|
| 480 |
+
|
| 481 |
+
annotations.append(
|
| 482 |
+
{
|
| 483 |
+
"segmentation": [segmentation],
|
| 484 |
+
"iscrowd": is_crowd,
|
| 485 |
+
"image_id": image_id,
|
| 486 |
+
"category_id": category_id,
|
| 487 |
+
"id": annotation_id + idx,
|
| 488 |
+
"bbox": bbox,
|
| 489 |
+
"area": area,
|
| 490 |
+
}
|
| 491 |
+
)
|
| 492 |
+
|
| 493 |
+
return annotations
|
| 494 |
+
|
| 495 |
+
|
| 496 |
+
def mask_annotation_per_bbox(anno_line, image_id, category_id, annotation_id, is_crowd):
|
| 497 |
+
# Find contours (boundary lines) around each sub-mask
|
| 498 |
+
# Note: there could be multiple contours if the object
|
| 499 |
+
# is partially occluded. (E.g. an elephant behind a tree)
|
| 500 |
+
segmentations = []
|
| 501 |
+
polygons = []
|
| 502 |
+
annotations = []
|
| 503 |
+
mask_data = json.loads(anno_line[5])
|
| 504 |
+
|
| 505 |
+
if len(mask_data["all_points_x"]) > 3:
|
| 506 |
+
# Flip from (row, col) representation to (x, y)
|
| 507 |
+
# and subtract the padding pixel
|
| 508 |
+
contour = []
|
| 509 |
+
for i in range(len(mask_data["all_points_x"])):
|
| 510 |
+
contour.append([int(mask_data["all_points_x"][i]), int(mask_data["all_points_y"][i])])
|
| 511 |
+
|
| 512 |
+
contour = np.array(contour)
|
| 513 |
+
# Make a polygon and simplify it
|
| 514 |
+
poly = Polygon(contour)
|
| 515 |
+
poly = poly.simplify(1.0, preserve_topology=False)
|
| 516 |
+
polygons.append(poly)
|
| 517 |
+
# Only need the contours, not the polygon itself:
|
| 518 |
+
# segmentation = np.array(poly.exterior.coords).ravel().tolist()
|
| 519 |
+
segmentation = contour.ravel().tolist()
|
| 520 |
+
|
| 521 |
+
segmentations.append(segmentation)
|
| 522 |
+
|
| 523 |
+
if poly.area > 0:
|
| 524 |
+
# Combine the polygons to calculate the bounding box and area
|
| 525 |
+
x, y, max_x, max_y = poly.bounds
|
| 526 |
+
width = max_x - x
|
| 527 |
+
height = max_y - y
|
| 528 |
+
bbox = (x, y, width, height)
|
| 529 |
+
area = poly.area
|
| 530 |
+
|
| 531 |
+
annotation = {
|
| 532 |
+
"segmentation": [segmentation],
|
| 533 |
+
"iscrowd": is_crowd,
|
| 534 |
+
"image_id": image_id,
|
| 535 |
+
"category_id": category_id,
|
| 536 |
+
"id": annotation_id,
|
| 537 |
+
"bbox": bbox,
|
| 538 |
+
"area": area,
|
| 539 |
+
}
|
| 540 |
+
annotations.append(annotation)
|
| 541 |
+
|
| 542 |
+
return annotations
|
| 543 |
+
|
| 544 |
+
|
| 545 |
+
def move_segmentation_dataset(
|
| 546 |
+
out_dir,
|
| 547 |
+
dataset_name,
|
| 548 |
+
train_images,
|
| 549 |
+
annotation_images,
|
| 550 |
+
train_dir,
|
| 551 |
+
annotation_dir,
|
| 552 |
+
train_preprocess_fn=None,
|
| 553 |
+
annotation_preprocess_fn=None,
|
| 554 |
+
):
|
| 555 |
+
"""Moves segmentation images and annotations to a new location."""
|
| 556 |
+
processed_dir = os.path.join(out_dir, dataset_name)
|
| 557 |
+
os.makedirs(processed_dir, exist_ok=True)
|
| 558 |
+
processed_image_dir = os.path.join(processed_dir, "images")
|
| 559 |
+
os.makedirs(processed_image_dir, exist_ok=True)
|
| 560 |
+
processed_annotation_dir = os.path.join(processed_dir, "annotations")
|
| 561 |
+
os.makedirs(processed_annotation_dir, exist_ok=True)
|
| 562 |
+
for image_path, annotation_path in zip(
|
| 563 |
+
tqdm(train_images, desc="Processing Images", file=sys.stdout), annotation_images
|
| 564 |
+
):
|
| 565 |
+
orig_image_path = os.path.join(train_dir, image_path)
|
| 566 |
+
orig_annotation_path = os.path.join(annotation_dir, annotation_path)
|
| 567 |
+
out_image_path = os.path.join(processed_image_dir, image_path)
|
| 568 |
+
out_label_path = os.path.join(processed_annotation_dir, annotation_path)
|
| 569 |
+
if train_preprocess_fn is None:
|
| 570 |
+
shutil.copyfile(orig_image_path, out_image_path)
|
| 571 |
+
else:
|
| 572 |
+
train_preprocess_fn(orig_image_path, out_image_path)
|
| 573 |
+
if annotation_preprocess_fn is None:
|
| 574 |
+
shutil.copyfile(orig_annotation_path, out_label_path)
|
| 575 |
+
else:
|
| 576 |
+
annotation_preprocess_fn(orig_annotation_path, out_label_path)
|
AgML/source/agml/_internal/s3internal.py
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 UC Davis Plant AI and Biophysics Lab
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
"""
|
| 16 |
+
Internal class for interacting with the AgML public dataset S3 bucket.
|
| 17 |
+
"""
|
| 18 |
+
|
| 19 |
+
import json
|
| 20 |
+
import os
|
| 21 |
+
import sys
|
| 22 |
+
import warnings
|
| 23 |
+
import zipfile
|
| 24 |
+
|
| 25 |
+
import boto3
|
| 26 |
+
import botocore.exceptions
|
| 27 |
+
|
| 28 |
+
from agml.utils.logging import tqdm
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
class InternalAgMLS3API(object):
|
| 32 |
+
"""
|
| 33 |
+
Internal API for interaction with the dataset S3 bucket.
|
| 34 |
+
|
| 35 |
+
*Note*: This class should only be used by the AgML developers.
|
| 36 |
+
"""
|
| 37 |
+
|
| 38 |
+
def __init__(self):
|
| 39 |
+
# Read in metadata for data sources file
|
| 40 |
+
self.data_srcs_path = os.path.join(
|
| 41 |
+
os.path.dirname(os.path.dirname(__file__)),
|
| 42 |
+
"_assets",
|
| 43 |
+
"public_datasources.json",
|
| 44 |
+
)
|
| 45 |
+
with open(self.data_srcs_path) as f:
|
| 46 |
+
self.data_srcs = json.load(f)
|
| 47 |
+
|
| 48 |
+
# Define s3 bucket URI
|
| 49 |
+
self.agdata_s3_uri = "https://s3.us-west-1.amazonaws.com/agdata-data/"
|
| 50 |
+
|
| 51 |
+
# Initialize attribute for storing dataset download path
|
| 52 |
+
self.dataset_download_path = None
|
| 53 |
+
|
| 54 |
+
@property
|
| 55 |
+
def data_sources(self):
|
| 56 |
+
"""Returns a list of AgML public data sources."""
|
| 57 |
+
return list(self.data_srcs.keys())
|
| 58 |
+
|
| 59 |
+
def upload_dataset(self, dataset_name, dataset_dir):
|
| 60 |
+
"""
|
| 61 |
+
Uploads dataset to agdata-data s3 file storage.
|
| 62 |
+
|
| 63 |
+
Parameters
|
| 64 |
+
----------
|
| 65 |
+
dataset_name : str
|
| 66 |
+
name of dataset (without '.zip') -- for list of datasets run self.data_srcs.keys()
|
| 67 |
+
dataset_dir : str
|
| 68 |
+
path to directory where dataset is stored
|
| 69 |
+
"""
|
| 70 |
+
# Establish connection with s3 via boto
|
| 71 |
+
self.s3 = boto3.client("s3")
|
| 72 |
+
|
| 73 |
+
# Setup progress bar
|
| 74 |
+
self.pg = tqdm(
|
| 75 |
+
total=os.stat(os.path.abspath(os.path.join(dataset_dir, dataset_name + ".zip"))).st_size,
|
| 76 |
+
file=sys.stdout,
|
| 77 |
+
desc=f"Uploading {dataset_name}",
|
| 78 |
+
)
|
| 79 |
+
|
| 80 |
+
# Upload data to agdata-data bucket
|
| 81 |
+
try:
|
| 82 |
+
with open(os.path.join(dataset_dir, dataset_name + ".zip"), "rb") as data:
|
| 83 |
+
self.s3.upload_fileobj(
|
| 84 |
+
Fileobj=data,
|
| 85 |
+
Bucket="agdata-data",
|
| 86 |
+
Key="datasets/" + dataset_name + ".zip",
|
| 87 |
+
Callback=lambda x: self.pg.update(x),
|
| 88 |
+
)
|
| 89 |
+
except:
|
| 90 |
+
warnings.warn(
|
| 91 |
+
f"Upload of {dataset_name} unsuccessful. You may not have permission "
|
| 92 |
+
f"to upload to the agdata-data s3 bucket.",
|
| 93 |
+
category=UserWarning,
|
| 94 |
+
)
|
| 95 |
+
finally:
|
| 96 |
+
self.pg.close()
|
| 97 |
+
|
| 98 |
+
def upload_model(self, model_name, model_dir):
|
| 99 |
+
"""Uploads model to agdata-data s3 file storage.
|
| 100 |
+
|
| 101 |
+
Parameters
|
| 102 |
+
----------
|
| 103 |
+
model_name : str
|
| 104 |
+
name of model (without '.pth')
|
| 105 |
+
model_dir : str
|
| 106 |
+
path to directory where model is stored
|
| 107 |
+
"""
|
| 108 |
+
# Establish connection with s3 via boto
|
| 109 |
+
self.s3 = boto3.client("s3")
|
| 110 |
+
|
| 111 |
+
# Setup progress bar
|
| 112 |
+
self.pg = tqdm(
|
| 113 |
+
total=os.stat(os.path.abspath(os.path.join(model_dir, model_name + ".pth"))).st_size,
|
| 114 |
+
file=sys.stdout,
|
| 115 |
+
desc=f"Uploading {model_name}",
|
| 116 |
+
)
|
| 117 |
+
|
| 118 |
+
# Upload data to agdata-data bucket
|
| 119 |
+
try:
|
| 120 |
+
with open(os.path.join(model_dir, model_name + ".pth"), "rb") as data:
|
| 121 |
+
self.s3.upload_fileobj(
|
| 122 |
+
Fileobj=data,
|
| 123 |
+
Bucket="agdata-data",
|
| 124 |
+
Key="models/" + model_name + ".pth",
|
| 125 |
+
Callback=lambda x: self.pg.update(x),
|
| 126 |
+
)
|
| 127 |
+
except:
|
| 128 |
+
warnings.warn(
|
| 129 |
+
f"Upload of {model_name} unsuccessful. You may not have permission "
|
| 130 |
+
f"to upload to the agdata-data s3 bucket.",
|
| 131 |
+
category=UserWarning,
|
| 132 |
+
)
|
| 133 |
+
finally:
|
| 134 |
+
self.pg.close()
|
| 135 |
+
|
| 136 |
+
def download_dataset(self, dataset_name, dest_dir):
|
| 137 |
+
"""
|
| 138 |
+
Downloads dataset from agdata-data s3 file storage.
|
| 139 |
+
|
| 140 |
+
Parameters
|
| 141 |
+
----------
|
| 142 |
+
dataset_name : str
|
| 143 |
+
name of dataset to download
|
| 144 |
+
dest_dir : str
|
| 145 |
+
path for saving downloaded dataset
|
| 146 |
+
"""
|
| 147 |
+
# Validate the dataset name.
|
| 148 |
+
if dataset_name not in self.data_sources:
|
| 149 |
+
raise ValueError(f"Invalid dataset '{dataset_name}.'")
|
| 150 |
+
|
| 151 |
+
# Establish connection with s3 via boto
|
| 152 |
+
self.s3 = boto3.client("s3")
|
| 153 |
+
self.s3_resource = boto3.resource("s3")
|
| 154 |
+
|
| 155 |
+
# Setup progress bar
|
| 156 |
+
try:
|
| 157 |
+
self.pg = tqdm(
|
| 158 |
+
total=float(self.s3_resource.ObjectSummary(bucket_name="agdata-data", key=dataset_name + ".zip").size),
|
| 159 |
+
file=sys.stdout,
|
| 160 |
+
desc=f"Downloading {dataset_name}",
|
| 161 |
+
)
|
| 162 |
+
except botocore.exceptions.ClientError as ce:
|
| 163 |
+
if "Not Found" in str(ce):
|
| 164 |
+
raise ValueError(
|
| 165 |
+
f"The dataset '{dataset_name}' could not be found in "
|
| 166 |
+
f"the bucket, perhaps it has not been uploaded yet."
|
| 167 |
+
)
|
| 168 |
+
raise ce
|
| 169 |
+
|
| 170 |
+
# File path of zipped dataset
|
| 171 |
+
self.dataset_download_path = os.path.join(dest_dir, dataset_name + ".zip")
|
| 172 |
+
|
| 173 |
+
# Upload data to agdata-data bucket
|
| 174 |
+
with open(self.dataset_download_path, "wb") as data:
|
| 175 |
+
self.s3.download_fileobj(
|
| 176 |
+
Bucket="agdata-data",
|
| 177 |
+
Key=dataset_name + ".zip",
|
| 178 |
+
Fileobj=data,
|
| 179 |
+
Callback=lambda x: self.pg.update(x),
|
| 180 |
+
)
|
| 181 |
+
self.pg.close()
|
| 182 |
+
|
| 183 |
+
# Unzip downloaded dataset
|
| 184 |
+
with zipfile.ZipFile(self.dataset_download_path, "r") as z:
|
| 185 |
+
z.printdir()
|
| 186 |
+
print("Extracting files...")
|
| 187 |
+
z.extractall(path=dest_dir)
|
| 188 |
+
print("Done!")
|
| 189 |
+
|
| 190 |
+
# Delete zipped file
|
| 191 |
+
os.remove(self.dataset_download_path)
|
AgML/source/agml/_internal/syntheticdata.py
ADDED
|
@@ -0,0 +1,756 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
import csv
|
| 3 |
+
import copy
|
| 4 |
+
import os
|
| 5 |
+
import numpy as np
|
| 6 |
+
from dict2xml import dict2xml
|
| 7 |
+
import platform
|
| 8 |
+
import subprocess
|
| 9 |
+
import sys
|
| 10 |
+
|
| 11 |
+
from skimage.io import imread, imshow
|
| 12 |
+
import skimage
|
| 13 |
+
from skimage.morphology import closing
|
| 14 |
+
import imantics
|
| 15 |
+
import pandas as pd
|
| 16 |
+
import matplotlib.pyplot as plt
|
| 17 |
+
import xml.etree.ElementTree as ET
|
| 18 |
+
|
| 19 |
+
HELIOS_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), "_helios/Helios")
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
class HeliosDataGenerator(object):
|
| 23 |
+
def __init__(self, path_helios_dir=HELIOS_PATH):
|
| 24 |
+
self.path_canopygen_header = os.path.join(path_helios_dir, "plugins/canopygenerator/include/CanopyGenerator.h")
|
| 25 |
+
self.path_canopygen_cpp = os.path.join(path_helios_dir, "plugins/canopygenerator/src/CanopyGenerator.cpp")
|
| 26 |
+
self.path_cmakelists = os.path.join(
|
| 27 |
+
os.path.dirname(os.path.dirname(__file__)),
|
| 28 |
+
"_helios/Helios/projects/SyntheticImageAnnotation/CMakeLists.txt",
|
| 29 |
+
)
|
| 30 |
+
self.path_main_cpp = os.path.join(
|
| 31 |
+
os.path.dirname(os.path.dirname(__file__)), "_helios/Helios/projects/SyntheticImageAnnotation/main.cpp"
|
| 32 |
+
)
|
| 33 |
+
|
| 34 |
+
self.path_lidar_cpp = os.path.join(path_helios_dir, "plugins/lidar/src/LiDAR.cpp")
|
| 35 |
+
self.canopy_types = self.get_canopy_types()
|
| 36 |
+
self.canopy_params = self.get_canopy_params()
|
| 37 |
+
self.canopy_param_ranges = self.set_initial_canopy_param_ranges()
|
| 38 |
+
self.lidar_params = self.get_lidar_params()
|
| 39 |
+
self.lidar_param_ranges = self.set_initial_lidar_param_ranges()
|
| 40 |
+
self.camera_params = self.get_camera_params()
|
| 41 |
+
self.camera_param_ranges = self.set_initial_camera_param_ranges()
|
| 42 |
+
|
| 43 |
+
def get_canopy_types(self):
|
| 44 |
+
"""
|
| 45 |
+
Find all occurrences of 'struct' in canopygen_header_txt.
|
| 46 |
+
Parse canopy type from struct occurrences.
|
| 47 |
+
Generate a list of canopy types.
|
| 48 |
+
"""
|
| 49 |
+
|
| 50 |
+
# Read CanopyGenerator.h to define potential canopy types
|
| 51 |
+
with open(self.path_canopygen_header) as f:
|
| 52 |
+
canopygen_header_txt = f.readlines()
|
| 53 |
+
|
| 54 |
+
# Generate list of canopy types
|
| 55 |
+
canopy_types = []
|
| 56 |
+
search_term = "struct "
|
| 57 |
+
length_search_term = len(search_term)
|
| 58 |
+
for i, string in enumerate(canopygen_header_txt):
|
| 59 |
+
if search_term in string:
|
| 60 |
+
canopy_types.append(string[length_search_term:].split("Parameters{")[0])
|
| 61 |
+
|
| 62 |
+
return canopy_types
|
| 63 |
+
|
| 64 |
+
def set_seed(self, seed):
|
| 65 |
+
np.random.seed(seed)
|
| 66 |
+
|
| 67 |
+
def get_canopy_params(self):
|
| 68 |
+
# Flag for parsing
|
| 69 |
+
param_flag = 0
|
| 70 |
+
|
| 71 |
+
# Initialize canopy parameters dictionary
|
| 72 |
+
canopy_params = {}
|
| 73 |
+
|
| 74 |
+
# Read CanopyGenerator.cpp to define potential canopy types
|
| 75 |
+
with open(self.path_canopygen_cpp) as f:
|
| 76 |
+
canopygen_header_txt = f.readlines()
|
| 77 |
+
|
| 78 |
+
# Find parameters for each canopy type
|
| 79 |
+
for canopy_type in self.canopy_types:
|
| 80 |
+
# Find first line of parameter definition in cpp file
|
| 81 |
+
search_term = canopy_type + "Parameters::"
|
| 82 |
+
|
| 83 |
+
for i, string in enumerate(canopygen_header_txt):
|
| 84 |
+
if param_flag == 1:
|
| 85 |
+
if string != "\n" and string != "}\n" and string != " \n":
|
| 86 |
+
line = string.split(";\n")[0]
|
| 87 |
+
key, value = line.split(" = ")
|
| 88 |
+
|
| 89 |
+
if "(" in value:
|
| 90 |
+
value = value.split("(")[1].split(")")[0].replace(",", " ")
|
| 91 |
+
|
| 92 |
+
canopy_params[canopy_type][key.strip()] = (
|
| 93 |
+
value.strip().strip('"').replace("\n", "").replace(";", "").replace(".f", "0")
|
| 94 |
+
)
|
| 95 |
+
|
| 96 |
+
if len(canopy_params[canopy_type][key.strip()]) == 1:
|
| 97 |
+
canopy_params[canopy_type][key.strip()] = canopy_params[canopy_type][key.strip()][0]
|
| 98 |
+
|
| 99 |
+
if "M_PI" in value:
|
| 100 |
+
new_val = float(value.split("*")[0]) * 3.14159
|
| 101 |
+
canopy_params[canopy_type][key.strip()] = str(new_val)
|
| 102 |
+
|
| 103 |
+
if search_term in string:
|
| 104 |
+
canopy_params[canopy_type] = {}
|
| 105 |
+
param_flag = 1
|
| 106 |
+
|
| 107 |
+
if "}" in string and param_flag == 1:
|
| 108 |
+
param_flag = 0
|
| 109 |
+
|
| 110 |
+
return canopy_params
|
| 111 |
+
|
| 112 |
+
def get_lidar_params(self):
|
| 113 |
+
# Flag for parsing
|
| 114 |
+
param_flag = 0
|
| 115 |
+
|
| 116 |
+
# Initialize canopy parameters dictionary
|
| 117 |
+
lidar_params = {}
|
| 118 |
+
|
| 119 |
+
# Read LiDAR.cpp to find parameters
|
| 120 |
+
with open(self.path_lidar_cpp) as f:
|
| 121 |
+
LiDAR_txt = f.readlines()
|
| 122 |
+
|
| 123 |
+
# Find Metadata line of parameter definition in cpp file
|
| 124 |
+
search_term = "ScanMetadata::ScanMetadata"
|
| 125 |
+
|
| 126 |
+
for i, string in enumerate(LiDAR_txt):
|
| 127 |
+
if param_flag == 1:
|
| 128 |
+
if (
|
| 129 |
+
string != "\n"
|
| 130 |
+
and string != "}\n"
|
| 131 |
+
and string != " \n"
|
| 132 |
+
and string != " //Copy arguments into structure variables\n"
|
| 133 |
+
):
|
| 134 |
+
line = string.split(";\n")[0]
|
| 135 |
+
key = line.split(" = ")
|
| 136 |
+
# Initialization of values from Helios -- Need to read this values from c++
|
| 137 |
+
if key[0].strip() == "origin":
|
| 138 |
+
lidar_params[key[0].strip()] = "0 0 0"
|
| 139 |
+
elif key[0].strip() == "Ntheta":
|
| 140 |
+
lidar_params["size"] = "250"
|
| 141 |
+
elif key[0].strip() == "thetaMin":
|
| 142 |
+
lidar_params[key[0].strip()] = "0"
|
| 143 |
+
elif key[0].strip() == "thetaMax":
|
| 144 |
+
lidar_params[key[0].strip()] = "180"
|
| 145 |
+
elif key[0].strip() == "Nphi":
|
| 146 |
+
lidar_params["size"] = lidar_params["size"] + " 450"
|
| 147 |
+
elif key[0].strip() == "phiMin":
|
| 148 |
+
lidar_params[key[0].strip()] = "0"
|
| 149 |
+
elif key[0].strip() == "phiMax":
|
| 150 |
+
lidar_params[key[0].strip()] = "360"
|
| 151 |
+
elif key[0].strip() == "exitDiameter":
|
| 152 |
+
lidar_params[key[0].strip()] = "0"
|
| 153 |
+
elif key[0].strip() == "beamDivergence":
|
| 154 |
+
lidar_params[key[0].strip()] = "0"
|
| 155 |
+
elif key[0].strip() == "columnFormat":
|
| 156 |
+
lidar_params["ASCII_format"] = "x y z"
|
| 157 |
+
|
| 158 |
+
if "ScanMetadata::ScanMetadata" in string:
|
| 159 |
+
param_flag = 1
|
| 160 |
+
|
| 161 |
+
if "}" in string and param_flag == 1:
|
| 162 |
+
param_flag = 0
|
| 163 |
+
return lidar_params
|
| 164 |
+
|
| 165 |
+
def get_camera_params(self):
|
| 166 |
+
# Initialize canopy parameters dictionary
|
| 167 |
+
camera_params = {}
|
| 168 |
+
|
| 169 |
+
# Initialization of image resolution and camera position
|
| 170 |
+
camera_params["image_resolution"] = "600 400"
|
| 171 |
+
camera_params["camera_lookat"] = "0 0 1"
|
| 172 |
+
camera_params["camera_position"] = "0 -2 1"
|
| 173 |
+
|
| 174 |
+
return camera_params
|
| 175 |
+
|
| 176 |
+
def set_initial_lidar_param_ranges(self):
|
| 177 |
+
lidar_param_ranges = copy.deepcopy(self.lidar_params)
|
| 178 |
+
|
| 179 |
+
# Check if parameter is a path or number; this assumes that all strings will be paths
|
| 180 |
+
for i in lidar_param_ranges.keys():
|
| 181 |
+
if i == "ASCII_format":
|
| 182 |
+
val = lidar_param_ranges[i]
|
| 183 |
+
lidar_param_ranges[i] = [(val.split(" ")[j].replace("f", "0")) for j in range(len(val.split()))]
|
| 184 |
+
else:
|
| 185 |
+
val = lidar_param_ranges[i]
|
| 186 |
+
lidar_param_ranges[i] = [float(val.split(" ")[j].replace("f", "0")) for j in range(len(val.split()))]
|
| 187 |
+
|
| 188 |
+
return lidar_param_ranges
|
| 189 |
+
|
| 190 |
+
def set_initial_canopy_param_ranges(self):
|
| 191 |
+
canopy_param_ranges = copy.deepcopy(self.canopy_params)
|
| 192 |
+
|
| 193 |
+
# Check if parameter is a path or number; this assumes that all strings will be paths
|
| 194 |
+
for i in canopy_param_ranges.keys():
|
| 195 |
+
for key in list(canopy_param_ranges[i]):
|
| 196 |
+
val = canopy_param_ranges[i][key]
|
| 197 |
+
if val.isalpha() or "/" in val or ":" in val:
|
| 198 |
+
canopy_param_ranges[i].pop(key)
|
| 199 |
+
else:
|
| 200 |
+
canopy_param_ranges[i][key] = [
|
| 201 |
+
[float(val.split(" ")[j].replace("f", "0")), float(val.split(" ")[j].replace("f", "0"))]
|
| 202 |
+
for j in range(len(val.split()))
|
| 203 |
+
]
|
| 204 |
+
|
| 205 |
+
return canopy_param_ranges
|
| 206 |
+
|
| 207 |
+
def set_initial_camera_param_ranges(self):
|
| 208 |
+
camera_param_ranges = copy.deepcopy(self.camera_params)
|
| 209 |
+
|
| 210 |
+
# Check if parameter is a path or number; this assumes that all strings will be paths
|
| 211 |
+
for i in camera_param_ranges.keys():
|
| 212 |
+
val = camera_param_ranges[i]
|
| 213 |
+
camera_param_ranges[i] = [float(val.split(" ")[j]) for j in range(len(val.split()))]
|
| 214 |
+
|
| 215 |
+
return camera_param_ranges
|
| 216 |
+
|
| 217 |
+
def generate_one_datapair(self, canopy_type, simulation_type, export_format="xml"):
|
| 218 |
+
"""
|
| 219 |
+
Find all occurrences of 'struct' in canopygen_header_txt.
|
| 220 |
+
Parse canopy type from struct occurrences.
|
| 221 |
+
Generate a list of canopy types.
|
| 222 |
+
|
| 223 |
+
Args:
|
| 224 |
+
canopy_type (string): the selected canopy type for the synthetic images
|
| 225 |
+
It should contain a out_channels attribute, which indicates the number of output
|
| 226 |
+
channels that each feature map has (and it should be the same for all feature maps).
|
| 227 |
+
The backbone should return a single Tensor or and OrderedDict[Tensor].
|
| 228 |
+
simulation_type (string): choose between RGB only and Lidar mode using 'rgb' or 'lidar'
|
| 229 |
+
export_format (string): default is xml for Helios
|
| 230 |
+
"""
|
| 231 |
+
|
| 232 |
+
assert canopy_type in self.canopy_types, "Canopy type not available."
|
| 233 |
+
|
| 234 |
+
assert export_format in ["xml", "csv", "json"], "Only xml, csv and json export formats are possible."
|
| 235 |
+
|
| 236 |
+
canopy_params_filtered = {k: v for k, v in self.canopy_params.items() if k.startswith(canopy_type)}
|
| 237 |
+
|
| 238 |
+
canopy_params_filtered[canopy_type + "Parameters"] = canopy_params_filtered.pop(canopy_type)
|
| 239 |
+
|
| 240 |
+
canopy_params_filtered["Ground"] = {
|
| 241 |
+
"origin": "0 0 0",
|
| 242 |
+
"extent": "10 10",
|
| 243 |
+
"texture_subtiles": "10 10",
|
| 244 |
+
"texture_subpatches": "1 1",
|
| 245 |
+
"ground_texture_file": "plugins/canopygenerator/textures/dirt.jpg",
|
| 246 |
+
"rotation": "0",
|
| 247 |
+
}
|
| 248 |
+
|
| 249 |
+
canopy_params_filtered = {"canopygenerator": canopy_params_filtered}
|
| 250 |
+
|
| 251 |
+
if simulation_type == "lidar":
|
| 252 |
+
canopy_params_filtered["scan"] = self.lidar_params
|
| 253 |
+
|
| 254 |
+
if simulation_type == "rgb":
|
| 255 |
+
canopy_params_filtered[""] = self.camera_params
|
| 256 |
+
|
| 257 |
+
canopy_params_filtered = {"helios": canopy_params_filtered}
|
| 258 |
+
from pprint import pprint
|
| 259 |
+
# print(canopy_params_filtered)
|
| 260 |
+
|
| 261 |
+
if not os.path.exists(
|
| 262 |
+
os.path.join(
|
| 263 |
+
os.path.dirname(os.path.dirname(__file__)), "_helios/Helios/projects/SyntheticImageAnnotation/xml"
|
| 264 |
+
)
|
| 265 |
+
):
|
| 266 |
+
os.makedirs(
|
| 267 |
+
os.path.join(
|
| 268 |
+
os.path.dirname(os.path.dirname(__file__)), "_helios/Helios/projects/SyntheticImageAnnotation/xml"
|
| 269 |
+
)
|
| 270 |
+
)
|
| 271 |
+
|
| 272 |
+
if export_format == "xml":
|
| 273 |
+
with open(
|
| 274 |
+
os.path.join(
|
| 275 |
+
os.path.dirname(os.path.dirname(__file__)),
|
| 276 |
+
"_helios/Helios/projects/SyntheticImageAnnotation/xml/tmp_canopy_params_image.xml",
|
| 277 |
+
),
|
| 278 |
+
"w",
|
| 279 |
+
) as f:
|
| 280 |
+
f.write(dict2xml(canopy_params_filtered))
|
| 281 |
+
|
| 282 |
+
def generate_data(
|
| 283 |
+
self, n_imgs, canopy_type, simulation_type, annotation_type, label_elements="none", output_directory=".."
|
| 284 |
+
):
|
| 285 |
+
"""
|
| 286 |
+
Given the path to the output of Helios, this method can be used to convert the data to a more standard format such as COCO JSON
|
| 287 |
+
|
| 288 |
+
Args:
|
| 289 |
+
n_imgs (int): The number of images that to be generated
|
| 290 |
+
canopy_type (string): the selected canopy type for the synthetic images
|
| 291 |
+
simulation_type (string): choose between RGB only and Lidar mode using 'rgb' or 'lidar'
|
| 292 |
+
annotation_type (string): choose between semantic segmentation, object detection, and instance segmentation as 'semantic', 'object', and 'instance'.
|
| 293 |
+
output_directory (string) (optional): optionally you may pass in a custom path to save the Helios output to the custom path
|
| 294 |
+
|
| 295 |
+
"""
|
| 296 |
+
output_directory = os.path.abspath(output_directory)
|
| 297 |
+
|
| 298 |
+
assert simulation_type in ["rgb", "lidar"], "Simulation type unavailable."
|
| 299 |
+
|
| 300 |
+
assert annotation_type in ["semantic", "object", "instance", "none"], "Annotation type unavailable."
|
| 301 |
+
|
| 302 |
+
Labels = label_elements.replace(" ", "").split(",")
|
| 303 |
+
|
| 304 |
+
for j in range(len(Labels)):
|
| 305 |
+
assert Labels[j] in ["trunk", "leaves", "fruits", "branches", "ground", "none"], "Label type unavailable"
|
| 306 |
+
|
| 307 |
+
param_ranges = self.canopy_param_ranges[canopy_type]
|
| 308 |
+
|
| 309 |
+
camera_ranges = self.camera_param_ranges
|
| 310 |
+
|
| 311 |
+
if simulation_type == "lidar":
|
| 312 |
+
lidar_ranges = copy.deepcopy(self.lidar_param_ranges)
|
| 313 |
+
|
| 314 |
+
# LiDAR parameters
|
| 315 |
+
for key in lidar_ranges:
|
| 316 |
+
# param_vals=lidar_params[key].split(' ')
|
| 317 |
+
arr = [lidar_ranges[key][i] for i in range(len(lidar_ranges[key]))]
|
| 318 |
+
string_arr = [str(a) for a in arr]
|
| 319 |
+
self.lidar_params[key] = " ".join(string_arr)
|
| 320 |
+
# Mutiple LiDAR
|
| 321 |
+
LiDARs = []
|
| 322 |
+
for i in range(len(lidar_ranges["origin"])):
|
| 323 |
+
for key in lidar_ranges:
|
| 324 |
+
if key == "origin":
|
| 325 |
+
arr = [lidar_ranges[key][i] for i in range(len(lidar_ranges[key]))]
|
| 326 |
+
arr = arr[i]
|
| 327 |
+
string_arr = [str(a) for a in arr]
|
| 328 |
+
self.lidar_params[key] = " ".join(string_arr)
|
| 329 |
+
A = copy.deepcopy(self.lidar_params)
|
| 330 |
+
LiDARs.append(A)
|
| 331 |
+
self.lidar_params = LiDARs
|
| 332 |
+
|
| 333 |
+
if simulation_type == "rgb":
|
| 334 |
+
# Camera parameters
|
| 335 |
+
for key in camera_ranges:
|
| 336 |
+
arr = [camera_ranges[key][i] for i in range(len(camera_ranges[key]))]
|
| 337 |
+
string_arr = [str(a).replace(",", "").replace("[", " ").replace("]", " ") for a in arr]
|
| 338 |
+
self.camera_params[key] = " ".join(string_arr)
|
| 339 |
+
|
| 340 |
+
for n in range(n_imgs):
|
| 341 |
+
params = self.canopy_params[canopy_type]
|
| 342 |
+
# lidar_params = self.lidar_params
|
| 343 |
+
|
| 344 |
+
# Context parameters
|
| 345 |
+
for key in param_ranges:
|
| 346 |
+
print(param_ranges[key])
|
| 347 |
+
arr = [
|
| 348 |
+
np.random.uniform(param_ranges[key][i][0], param_ranges[key][i][1])
|
| 349 |
+
for i in range(len(param_ranges[key]))
|
| 350 |
+
]
|
| 351 |
+
string_arr = [str(a) for a in arr]
|
| 352 |
+
params[key] = " ".join(string_arr)
|
| 353 |
+
self.canopy_params[canopy_type] = params
|
| 354 |
+
print(self.canopy_params[canopy_type])
|
| 355 |
+
|
| 356 |
+
self.generate_one_datapair(canopy_type, simulation_type)
|
| 357 |
+
|
| 358 |
+
# Re-write tags of XML to have the expected Helios input
|
| 359 |
+
tree = ET.parse(
|
| 360 |
+
os.path.join(
|
| 361 |
+
os.path.dirname(os.path.dirname(__file__)),
|
| 362 |
+
"_helios/Helios/projects/SyntheticImageAnnotation/xml",
|
| 363 |
+
"tmp_canopy_params_image.xml",
|
| 364 |
+
)
|
| 365 |
+
)
|
| 366 |
+
root = tree.getroot()
|
| 367 |
+
for child in root:
|
| 368 |
+
if child.tag == "camera_position":
|
| 369 |
+
child.tag = "globaldata_vec3"
|
| 370 |
+
child.set("label", "camera_position")
|
| 371 |
+
if child.tag == "camera_lookat":
|
| 372 |
+
child.tag = "globaldata_vec3"
|
| 373 |
+
child.set("label", "camera_lookat")
|
| 374 |
+
if child.tag == "image_resolution":
|
| 375 |
+
child.tag = "globaldata_int2"
|
| 376 |
+
child.set("label", "image_resolution")
|
| 377 |
+
|
| 378 |
+
tree.write(
|
| 379 |
+
os.path.join(
|
| 380 |
+
os.path.dirname(os.path.dirname(__file__)),
|
| 381 |
+
"_helios/Helios/projects/SyntheticImageAnnotation/xml",
|
| 382 |
+
"tmp_canopy_params_image.xml",
|
| 383 |
+
)
|
| 384 |
+
)
|
| 385 |
+
|
| 386 |
+
# Modify cmake file for rgb versus lidar simulation
|
| 387 |
+
with open(self.path_cmakelists) as f:
|
| 388 |
+
cmakelists_txt = f.readlines()
|
| 389 |
+
|
| 390 |
+
for i, string in enumerate(cmakelists_txt):
|
| 391 |
+
if "set( PLUGINS " in string and simulation_type == "lidar":
|
| 392 |
+
cmakelists_txt[i] = 'set( PLUGINS "lidar;visualizer;canopygenerator;syntheticannotation" )\n'
|
| 393 |
+
|
| 394 |
+
if "set( PLUGINS " in string and simulation_type == "rgb":
|
| 395 |
+
cmakelists_txt[i] = 'set( PLUGINS "visualizer;canopygenerator;syntheticannotation" )\n'
|
| 396 |
+
|
| 397 |
+
# and write everything back
|
| 398 |
+
with open(self.path_cmakelists, "w") as f:
|
| 399 |
+
f.writelines(cmakelists_txt)
|
| 400 |
+
|
| 401 |
+
# Modify maincpp file for rgb versus lidar simulation
|
| 402 |
+
# with open(self.path_main_cpp) as f:
|
| 403 |
+
# main_cpp = f.readlines()
|
| 404 |
+
|
| 405 |
+
# Define paths for CMAKE compilation and output files
|
| 406 |
+
current_directory = os.getcwd()
|
| 407 |
+
build_dir = os.path.join(current_directory, "Helios/projects/SyntheticImageAnnotation/build")
|
| 408 |
+
if output_directory == "":
|
| 409 |
+
output_dir = os.path.join(current_directory, "Helios/projects/SyntheticImageAnnotation/output")
|
| 410 |
+
else:
|
| 411 |
+
assert os.path.isdir(output_directory), "Please, introduce a valid directory"
|
| 412 |
+
output_dir = output_directory + "/output"
|
| 413 |
+
point_cloud_dir = os.path.join(current_directory, output_dir + "/point_cloud/")
|
| 414 |
+
images_dir = os.path.join(current_directory, output_dir + "/images/")
|
| 415 |
+
|
| 416 |
+
if not os.path.exists(build_dir):
|
| 417 |
+
os.makedirs(build_dir)
|
| 418 |
+
|
| 419 |
+
if not os.path.exists(output_dir):
|
| 420 |
+
os.makedirs(output_dir)
|
| 421 |
+
|
| 422 |
+
if simulation_type == "lidar":
|
| 423 |
+
if not os.path.exists(point_cloud_dir):
|
| 424 |
+
os.makedirs(point_cloud_dir)
|
| 425 |
+
|
| 426 |
+
if simulation_type == "rgb":
|
| 427 |
+
if not os.path.exists(images_dir):
|
| 428 |
+
os.makedirs(images_dir)
|
| 429 |
+
|
| 430 |
+
exe = os.path.join(build_dir, "SyntheticImageAnnotation")
|
| 431 |
+
|
| 432 |
+
# Modify main.cpp file for compilation in LIDAR and RGB case
|
| 433 |
+
"""
|
| 434 |
+
print('Generation synthetic data: #' + str(n))
|
| 435 |
+
for i, string in enumerate(main_cpp):
|
| 436 |
+
|
| 437 |
+
# Managing annotation types requested by user
|
| 438 |
+
if 'annotation.disableSemanticSegmentation();' in string and 'semantic' not in annotation_type:
|
| 439 |
+
main_cpp[i] = ' annotation.disableSemanticSegmentation();\n'
|
| 440 |
+
|
| 441 |
+
if 'annotation.disableSemanticSegmentation();' in string and 'semantic' in annotation_type:
|
| 442 |
+
main_cpp[i] = ' //annotation.disableSemanticSegmentation();\n'
|
| 443 |
+
|
| 444 |
+
if 'annotation.disableObjectDetection();' in string and 'object' not in annotation_type:
|
| 445 |
+
main_cpp[i] = ' annotation.disableObjectDetection();\n'
|
| 446 |
+
|
| 447 |
+
if 'annotation.disableObjectDetection();' in string and 'object' in annotation_type:
|
| 448 |
+
main_cpp[i] = ' //annotation.disableObjectDetection();\n'
|
| 449 |
+
|
| 450 |
+
if 'annotation.disableInstanceSegmentation();' in string and 'instance' not in annotation_type:
|
| 451 |
+
main_cpp[i] = ' annotation.disableInstanceSegmentation();\n'
|
| 452 |
+
|
| 453 |
+
if 'annotation.disableInstanceSegmentation();' in string and 'instance' in annotation_type:
|
| 454 |
+
main_cpp[i] = ' //annotation.disableInstanceSegmentation();\n'
|
| 455 |
+
|
| 456 |
+
# Managing LiDAR versus rgb request by user
|
| 457 |
+
if '#include "L' in string and simulation_type == 'lidar':
|
| 458 |
+
main_cpp[i] = '#include "LiDAR.h"\n'
|
| 459 |
+
|
| 460 |
+
if '#include "L' in string and simulation_type == 'rgb':
|
| 461 |
+
main_cpp[i] = '//#include "LiDAR.h"\n'
|
| 462 |
+
|
| 463 |
+
if 'flag=' in string and simulation_type == 'lidar':
|
| 464 |
+
main_cpp[i] = 'bool flag=true;\n'
|
| 465 |
+
|
| 466 |
+
if 'flag=' in string and simulation_type == 'rgb':
|
| 467 |
+
main_cpp[i] = 'bool flag=false;\n'
|
| 468 |
+
|
| 469 |
+
if 'LiDARcloud lidarcloud' in string and simulation_type == 'lidar':
|
| 470 |
+
main_cpp[i] = ' LiDARcloud lidarcloud;\n'
|
| 471 |
+
|
| 472 |
+
if 'LiDARcloud lidarcloud' in string and simulation_type == 'rgb':
|
| 473 |
+
main_cpp[i] = ' //LiDARcloud lidarcloud;\n'
|
| 474 |
+
|
| 475 |
+
if 'lidarcloud.loadXML' in string and simulation_type == 'lidar':
|
| 476 |
+
main_cpp[i] = ' lidarcloud.loadXML("../xml/tmp_canopy_params_image.xml");\n'
|
| 477 |
+
|
| 478 |
+
if 'lidarcloud.loadXML' in string and simulation_type == 'rgb':
|
| 479 |
+
main_cpp[i] = ' //lidarcloud.loadXML("../xml/tmp_canopy_params_image.xml");\n'
|
| 480 |
+
|
| 481 |
+
if 'lidarcloud.syntheticScan' in string and simulation_type == 'lidar':
|
| 482 |
+
main_cpp[i] = ' lidarcloud.syntheticScan( &context);\n'
|
| 483 |
+
|
| 484 |
+
if 'lidarcloud.syntheticScan' in string and simulation_type == 'rgb':
|
| 485 |
+
main_cpp[i] = ' //lidarcloud.syntheticScan( &context);\n'
|
| 486 |
+
|
| 487 |
+
#
|
| 488 |
+
if 'lidarcloud.exportPointCloud' in string and simulation_type == 'lidar':
|
| 489 |
+
main_cpp[i] = ' lidarcloud.exportPointCloud( "' + output_dir + '/point_cloud/synthetic_scan_' + str(
|
| 490 |
+
n) + '.xyz" );\n'
|
| 491 |
+
|
| 492 |
+
if 'lidarcloud.exportPointCloud' in string and simulation_type == 'rgb':
|
| 493 |
+
main_cpp[
|
| 494 |
+
i] = ' //lidarcloud.exportPointCloud( "' + output_dir + '/point_cloud/synthetic_scan_' + str(
|
| 495 |
+
n) + '.xyz" );\n'
|
| 496 |
+
|
| 497 |
+
# Change output directory -- if requested
|
| 498 |
+
|
| 499 |
+
if 'annotation.render(' in string and simulation_type == 'rgb':
|
| 500 |
+
main_cpp[i] = ' annotation.render( "' + images_dir + '" );\n'
|
| 501 |
+
|
| 502 |
+
# Choose elements to label
|
| 503 |
+
for k in Labels:
|
| 504 |
+
|
| 505 |
+
if 'annotation.labelPrimitives(cgen.getTrunkUUIDs(p)' in string and simulation_type == 'rgb' and 'trunk' in Labels:
|
| 506 |
+
main_cpp[i] = ' annotation.labelPrimitives(cgen.getTrunkUUIDs(p), "trunks");\n'
|
| 507 |
+
elif 'annotation.labelPrimitives(cgen.getTrunkUUIDs(p)' in string and simulation_type == 'rgb' and 'trunk' not in Labels:
|
| 508 |
+
main_cpp[i] = ' //annotation.labelPrimitives(cgen.getTrunkUUIDs(p), "trunks");\n'
|
| 509 |
+
|
| 510 |
+
if 'annotation.labelPrimitives(cgen.getBranchUUIDs(p)' in string and simulation_type == 'rgb' and 'branches' in Labels:
|
| 511 |
+
main_cpp[i] = ' annotation.labelPrimitives(cgen.getBranchUUIDs(p), "branches");\n'
|
| 512 |
+
elif 'annotation.labelPrimitives(cgen.getBranchUUIDs(p)' in string and simulation_type == 'rgb' and 'branches' not in Labels:
|
| 513 |
+
main_cpp[i] = ' //annotation.labelPrimitives(cgen.getBranchUUIDs(p), "branches");\n'
|
| 514 |
+
|
| 515 |
+
if 'annotation.labelPrimitives(cgen.getLeafUUIDs(p)' in string and simulation_type == 'rgb' and 'leaves' in Labels:
|
| 516 |
+
main_cpp[i] = ' annotation.labelPrimitives(cgen.getLeafUUIDs(p), "leaves");\n'
|
| 517 |
+
elif 'annotation.labelPrimitives(cgen.getLeafUUIDs(p)' in string and simulation_type == 'rgb' and 'leaves' not in Labels:
|
| 518 |
+
main_cpp[i] = ' //annotation.labelPrimitives(cgen.getLeafUUIDs(p), "leaves");\n'
|
| 519 |
+
|
| 520 |
+
if 'annotation.labelPrimitives( flatten(fruitUUIDs.at(c))' in string and simulation_type == 'rgb' and 'fruits' in Labels:
|
| 521 |
+
main_cpp[i] = ' annotation.labelPrimitives( flatten(fruitUUIDs.at(c)), "clusters" );\n'
|
| 522 |
+
elif 'annotation.labelPrimitives( flatten(fruitUUIDs.at(c))' in string and simulation_type == 'rgb' and 'fruits' not in Labels:
|
| 523 |
+
main_cpp[i] = ' //annotation.labelPrimitives( flatten(fruitUUIDs.at(c)), "clusters" );\n'
|
| 524 |
+
|
| 525 |
+
|
| 526 |
+
|
| 527 |
+
# and write everything back
|
| 528 |
+
with open(self.path_main_cpp, 'w') as f:
|
| 529 |
+
f.writelines(main_cpp)
|
| 530 |
+
"""
|
| 531 |
+
|
| 532 |
+
default_xml_path = os.path.join(
|
| 533 |
+
os.path.dirname(os.path.dirname(__file__)),
|
| 534 |
+
"_helios/Helios/projects/SyntheticImageAnnotation/xml",
|
| 535 |
+
"tmp_canopy_params_image.xml",
|
| 536 |
+
)
|
| 537 |
+
str_to_write = f"{annotation_type}\n{simulation_type}\n{' '.join(Labels)}\n{default_xml_path}\n{images_dir}"
|
| 538 |
+
with open(
|
| 539 |
+
os.path.join(
|
| 540 |
+
os.path.dirname(os.path.dirname(__file__)),
|
| 541 |
+
"_helios/Helios/projects/SyntheticImageAnnotation/config.txt",
|
| 542 |
+
),
|
| 543 |
+
"w",
|
| 544 |
+
) as f:
|
| 545 |
+
f.write(str_to_write)
|
| 546 |
+
|
| 547 |
+
# System call to helios @DARIO
|
| 548 |
+
# current_directory = os.getcwd()
|
| 549 |
+
helios_directory = os.path.join(os.path.dirname(os.path.dirname(__file__)), "_helios")
|
| 550 |
+
build_dir = os.path.join(helios_directory, "Helios/projects/SyntheticImageAnnotation/build")
|
| 551 |
+
output_dir = os.path.join(helios_directory, "Helios/projects/SyntheticImageAnnotation/output")
|
| 552 |
+
point_cloud_dir = os.path.join(
|
| 553 |
+
helios_directory, "Helios/projects/SyntheticImageAnnotation/output/point_cloud/"
|
| 554 |
+
)
|
| 555 |
+
images_dir = os.path.join(helios_directory, "Helios/projects/SyntheticImageAnnotation/output/images/")
|
| 556 |
+
|
| 557 |
+
if not os.path.exists(build_dir):
|
| 558 |
+
os.makedirs(build_dir)
|
| 559 |
+
|
| 560 |
+
if not os.path.exists(output_dir):
|
| 561 |
+
os.makedirs(output_dir)
|
| 562 |
+
|
| 563 |
+
if simulation_type == "lidar":
|
| 564 |
+
if not os.path.exists(point_cloud_dir):
|
| 565 |
+
os.makedirs(point_cloud_dir)
|
| 566 |
+
|
| 567 |
+
if simulation_type == "rgb":
|
| 568 |
+
if not os.path.exists(images_dir):
|
| 569 |
+
os.makedirs(images_dir)
|
| 570 |
+
|
| 571 |
+
exe = os.path.join(build_dir, "SyntheticImageAnnotation")
|
| 572 |
+
|
| 573 |
+
cmake_args = ["-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=" + build_dir]
|
| 574 |
+
cmake_args += ["-G", "Unix Makefiles"]
|
| 575 |
+
# current_directory = os.getcwd()
|
| 576 |
+
helios_directory = os.path.join(os.path.dirname(os.path.dirname(__file__)), "_helios")
|
| 577 |
+
build_dir = os.path.join(helios_directory, "Helios/projects/SyntheticImageAnnotation/build")
|
| 578 |
+
output_dir = os.path.join(helios_directory, "Helios/projects/SyntheticImageAnnotation/output")
|
| 579 |
+
point_cloud_dir = os.path.join(
|
| 580 |
+
helios_directory, "Helios/projects/SyntheticImageAnnotation/output/point_cloud/"
|
| 581 |
+
)
|
| 582 |
+
images_dir = os.path.join(helios_directory, "Helios/projects/SyntheticImageAnnotation/output/images/")
|
| 583 |
+
|
| 584 |
+
if not os.path.exists(build_dir):
|
| 585 |
+
os.makedirs(build_dir)
|
| 586 |
+
|
| 587 |
+
if not os.path.exists(output_dir):
|
| 588 |
+
os.makedirs(output_dir)
|
| 589 |
+
|
| 590 |
+
if simulation_type == "lidar":
|
| 591 |
+
if not os.path.exists(point_cloud_dir):
|
| 592 |
+
os.makedirs(point_cloud_dir)
|
| 593 |
+
|
| 594 |
+
if n == 0:
|
| 595 |
+
subprocess.run(["cmake", ".."] + cmake_args, cwd=build_dir, check=True)
|
| 596 |
+
subprocess.run(["cmake", "--build", "."], cwd=build_dir, check=True)
|
| 597 |
+
|
| 598 |
+
subprocess.run(
|
| 599 |
+
[
|
| 600 |
+
exe,
|
| 601 |
+
"/Users/amoghjoshi/Documents/Amogh/Programs/Python/AgML/agml/_helios/Helios/projects/SyntheticImageAnnotation/config.txt",
|
| 602 |
+
output_dir,
|
| 603 |
+
],
|
| 604 |
+
cwd=build_dir,
|
| 605 |
+
)
|
| 606 |
+
|
| 607 |
+
# self.convert_data() # Conversion to standard formats @PRANAV
|
| 608 |
+
|
| 609 |
+
def convert_data(self, Frames_path, annotation_format="instance_segmentation"):
|
| 610 |
+
"""
|
| 611 |
+
Given the path to the output of Helios, this method can be used to convert the data to a more standard format such as COCO JSON
|
| 612 |
+
|
| 613 |
+
Args:
|
| 614 |
+
annotation_format (string): choose between 'instance_segmentation', 'object_detection', or 'panoptic_segmentation'
|
| 615 |
+
Frames_path (string): Specify the path to the output of Helios
|
| 616 |
+
|
| 617 |
+
"""
|
| 618 |
+
|
| 619 |
+
if annotation_format == "object_detection":
|
| 620 |
+
pass # YOLO @PRANAV
|
| 621 |
+
if annotation_format == "semantic_segmentation":
|
| 622 |
+
pass # single channel + mapping @PRANAV
|
| 623 |
+
if annotation_format == "instance_segmentation" or annotation_format == "object_detection":
|
| 624 |
+
# data_path = sorted(os.listdir(data_path))
|
| 625 |
+
frames_view = sorted(os.listdir(Frames_path))
|
| 626 |
+
# Initialize a list of label numpy arrays
|
| 627 |
+
# imgs = []
|
| 628 |
+
# npy_arrs = []
|
| 629 |
+
images = []
|
| 630 |
+
if not os.path.exists("./train_images/"):
|
| 631 |
+
os.mkdir("./train_images/")
|
| 632 |
+
for i, frame in enumerate(frames_view):
|
| 633 |
+
if frame == ".DS_Store":
|
| 634 |
+
continue
|
| 635 |
+
|
| 636 |
+
else:
|
| 637 |
+
# Generate labels and append to list
|
| 638 |
+
image, mask, pixel_ID = self.generate_npy_arr(Frames_path, Frames_path + frame + "/")
|
| 639 |
+
plt.imsave("./train_images/" + frame + ".jpeg", image)
|
| 640 |
+
|
| 641 |
+
strel = skimage.morphology.selem.disk(2)
|
| 642 |
+
|
| 643 |
+
# %% Convert masks to COCO for detectron implementation.
|
| 644 |
+
|
| 645 |
+
mapping = pd.read_csv(
|
| 646 |
+
Frames_path + frame + "/" + "ID_mapping.txt", delim_whitespace=True, names=["ID", "Class"]
|
| 647 |
+
)
|
| 648 |
+
|
| 649 |
+
category = imantics.Category(
|
| 650 |
+
mapping["Class"].iloc[pixel_ID], color=imantics.Color([255, 0, 0])
|
| 651 |
+
) # color for debug only
|
| 652 |
+
c = 0
|
| 653 |
+
|
| 654 |
+
im2 = imantics.Image(
|
| 655 |
+
image_array=image, path="data/train_images/" + frame + ".jpeg", id=i
|
| 656 |
+
) # imantics image object
|
| 657 |
+
|
| 658 |
+
for i in range(mask.shape[2]): # create the polygons for each slice
|
| 659 |
+
if annotation_format == "instance_segmentation":
|
| 660 |
+
poly = imantics.Mask(closing(mask[:, :, i], strel)).polygons()
|
| 661 |
+
ann = imantics.Annotation(image=im2, category=category, polygons=poly, id=c)
|
| 662 |
+
box = imantics.Mask(closing(mask[:, :, i], strel)).bbox()
|
| 663 |
+
# print(box)
|
| 664 |
+
|
| 665 |
+
if annotation_format == "object_detection":
|
| 666 |
+
box = imantics.Mask(closing(mask[:, :, i], strel)).bbox()
|
| 667 |
+
ann = imantics.Annotation(image=im2, category=category, bbox=box, id=c)
|
| 668 |
+
# print(box)
|
| 669 |
+
c += 1
|
| 670 |
+
|
| 671 |
+
if np.sum(mask[:, :, i]) > 1300:
|
| 672 |
+
im2.add(ann) # add the polygon to the image object
|
| 673 |
+
print(box)
|
| 674 |
+
|
| 675 |
+
images.append(im2) # collect the image objects after they get polygons
|
| 676 |
+
# %% Create Imantics dataset and export
|
| 677 |
+
ds = imantics.Dataset(name="coco", images=images)
|
| 678 |
+
obj = ds.coco()
|
| 679 |
+
with open("trainval.json", "w") as json_file:
|
| 680 |
+
json.dump(obj, json_file)
|
| 681 |
+
# json_file.close()
|
| 682 |
+
# obj=obj.clear()
|
| 683 |
+
# del obj, ds, json_file, images
|
| 684 |
+
|
| 685 |
+
# COCO json @PRANAV
|
| 686 |
+
if annotation_format == "panoptic_segmentation":
|
| 687 |
+
pass
|
| 688 |
+
if annotation_format == "regression":
|
| 689 |
+
pass
|
| 690 |
+
|
| 691 |
+
def generate_npy_arr(self, Frames_path, frames_view_path):
|
| 692 |
+
Frame_paths = frames_view_path
|
| 693 |
+
|
| 694 |
+
# Grab dimensions
|
| 695 |
+
render = imread(frames_view_path + "/RGB_rendering" + ".jpeg")
|
| 696 |
+
render_xy_shape = (render.shape[0], render.shape[1])
|
| 697 |
+
# print(render_xy_shape)
|
| 698 |
+
|
| 699 |
+
# Number of instances
|
| 700 |
+
frames_list = []
|
| 701 |
+
exclude_files = ["RGB_rendering.jpeg", "pixelID_combined.txt", "ID_mapping.txt"]
|
| 702 |
+
frames_files = [x for x in os.listdir(frames_view_path) if x not in exclude_files]
|
| 703 |
+
frames_list.append(frames_files)
|
| 704 |
+
n_instances = [len(frame) for frame in frames_list]
|
| 705 |
+
|
| 706 |
+
# Initialize numpy array of shape (x, y, n_instances)
|
| 707 |
+
npy_arr = np.zeros(
|
| 708 |
+
shape=(render_xy_shape[0], render_xy_shape[1], n_instances[0]), dtype=np.bool_
|
| 709 |
+
) # Make boolean dtype
|
| 710 |
+
|
| 711 |
+
# Read frames as a list
|
| 712 |
+
bboxes = []
|
| 713 |
+
frames = []
|
| 714 |
+
i = 0
|
| 715 |
+
for file_grape_arr in os.listdir(frames_view_path):
|
| 716 |
+
if file_grape_arr == ".DS_Store":
|
| 717 |
+
continue
|
| 718 |
+
|
| 719 |
+
if file_grape_arr == "pixelID_combined.txt":
|
| 720 |
+
continue
|
| 721 |
+
|
| 722 |
+
if file_grape_arr == "ID_mapping.txt":
|
| 723 |
+
continue
|
| 724 |
+
|
| 725 |
+
if file_grape_arr == "RGB_rendering.jpeg":
|
| 726 |
+
continue
|
| 727 |
+
|
| 728 |
+
if file_grape_arr == "rectangular_labels.txt":
|
| 729 |
+
continue
|
| 730 |
+
|
| 731 |
+
else:
|
| 732 |
+
# Extract pixel id based off name of the file. We want the number between _ and .
|
| 733 |
+
|
| 734 |
+
pixel_id_tmp = int(file_grape_arr.split("_")[1].split(".")[0])
|
| 735 |
+
# print(pixel_id_tmp)
|
| 736 |
+
|
| 737 |
+
# Load bounding box coordinates from file
|
| 738 |
+
bbox_tmp = np.loadtxt(frames_view_path + file_grape_arr, max_rows=1)
|
| 739 |
+
bbox_tmp = [int(bbox_tmp[i]) for i in range(0, 4)]
|
| 740 |
+
bbox = np.copy(bbox_tmp)
|
| 741 |
+
bbox[3] = render_xy_shape[0] - bbox_tmp[2]
|
| 742 |
+
bbox[2] = render_xy_shape[0] - bbox_tmp[3]
|
| 743 |
+
|
| 744 |
+
# print(bbox_tmp)
|
| 745 |
+
|
| 746 |
+
# Load pixel positions from file
|
| 747 |
+
grape_arr_tmp = np.loadtxt(frames_view_path + file_grape_arr, skiprows=1, ndmin=2)
|
| 748 |
+
|
| 749 |
+
#
|
| 750 |
+
grape_arr_tmp = grape_arr_tmp == pixel_id_tmp
|
| 751 |
+
|
| 752 |
+
npy_arr[bbox[2] : (bbox[3] + 1), bbox[0] : (bbox[1] + 1), i] = grape_arr_tmp
|
| 753 |
+
|
| 754 |
+
i += 1
|
| 755 |
+
|
| 756 |
+
return render, npy_arr, pixel_id_tmp
|
AgML/source/agml/_internal/utils.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 UC Davis Plant AI and Biophysics Lab
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
"""
|
| 16 |
+
Methods for checking the dataset information in AgML.
|
| 17 |
+
"""
|
| 18 |
+
|
| 19 |
+
import os
|
| 20 |
+
import pickle
|
| 21 |
+
|
| 22 |
+
from agml.utils.io import recursive_dirname
|
| 23 |
+
|
| 24 |
+
_PERSONAL_ACCESS_TOKEN = None
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def shape_info_file_contents():
|
| 28 |
+
with open(
|
| 29 |
+
os.path.join(recursive_dirname(__file__, 2), "_assets", "shape_info.pickle"),
|
| 30 |
+
"rb",
|
| 31 |
+
) as f:
|
| 32 |
+
return pickle.load(f)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def set_git_personal_access_token(token):
|
| 36 |
+
global _PERSONAL_ACCESS_TOKEN
|
| 37 |
+
_PERSONAL_ACCESS_TOKEN = token
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def get_personal_access_token():
|
| 41 |
+
global _PERSONAL_ACCESS_TOKEN
|
| 42 |
+
return _PERSONAL_ACCESS_TOKEN
|
AgML/source/agml/backend/__init__.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 UC Davis Plant AI and Biophysics Lab
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
"""
|
| 16 |
+
Controls the AgML backend system.
|
| 17 |
+
|
| 18 |
+
The first part of the backend is the backend deep learning library.
|
| 19 |
+
The backend, one of {TensorFlow, PyTorch}, primarily exists for internal
|
| 20 |
+
purposes, e.g. figuring out which methods to use in the data module or
|
| 21 |
+
the actual model configuring/training modules.
|
| 22 |
+
|
| 23 |
+
Secondly, the backend controls the loading/saving procedure for files within
|
| 24 |
+
AgML, specifically data loaded or generated from the data module.
|
| 25 |
+
"""
|
| 26 |
+
|
| 27 |
+
from . import experimental
|
| 28 |
+
from .config import (
|
| 29 |
+
clear_all_datasets,
|
| 30 |
+
data_save_path,
|
| 31 |
+
downloaded_datasets,
|
| 32 |
+
model_save_path,
|
| 33 |
+
set_data_save_path,
|
| 34 |
+
set_model_save_path,
|
| 35 |
+
set_synthetic_save_path,
|
| 36 |
+
synthetic_data_save_path,
|
| 37 |
+
)
|
| 38 |
+
from .random import set_seed
|
| 39 |
+
from .tftorch import get_backend, set_backend
|
AgML/source/agml/backend/config.py
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 UC Davis Plant AI and Biophysics Lab
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
import json
|
| 16 |
+
import logging
|
| 17 |
+
import os
|
| 18 |
+
import shutil
|
| 19 |
+
from pathlib import Path
|
| 20 |
+
|
| 21 |
+
from agml.utils.logging import log
|
| 22 |
+
|
| 23 |
+
# The super base save directory for AgML. This is the overriding base
|
| 24 |
+
# save directory and default original save directory. This is saved here
|
| 25 |
+
# because the default path to save datasets to can be overridden by
|
| 26 |
+
# `set_dataset_save_path()`, but we need to keep the super directory to
|
| 27 |
+
# access the config file which stores this information in the first place.
|
| 28 |
+
SUPER_BASE_DIR = Path(os.getenv("AGML_CONFIG_DIR", os.path.join(os.path.expanduser("~"), ".agml")))
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
# This is the path to the saved datasets. By default, this saves to
|
| 32 |
+
# SUPER_BASE_DIR/datasets, but can be overridden. The value of this
|
| 33 |
+
# is set upon the instantiation of the module (see below code).
|
| 34 |
+
DATASET_SAVE_DIR: str
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
# This is similar to `DATASET_SAVE_DIR`, but is for synthetically generated
|
| 38 |
+
# datasets using Helios. By default, this will be SUPER_BASE_DIR/synthetic,
|
| 39 |
+
# but it can be overridden. The value is set upon instantiation of the module.
|
| 40 |
+
SYNTHETIC_SAVE_DIR: str
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
# This is the path to any downloaded models. By default, this saves to
|
| 44 |
+
# SUPER_BASE_DIR/models, but can be overridden. The value is set upon
|
| 45 |
+
# instantiation of the module (see the below code).
|
| 46 |
+
MODEL_SAVE_DIR: str
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
# Loads the configuration info. We don't cache this since it may
|
| 50 |
+
# change if the user decides to change the path. This method
|
| 51 |
+
# also runs upon the first import of AgML to set it properly.
|
| 52 |
+
def _load_config_info():
|
| 53 |
+
global DATASET_SAVE_DIR, SYNTHETIC_SAVE_DIR, MODEL_SAVE_DIR
|
| 54 |
+
try:
|
| 55 |
+
with open(os.path.join(SUPER_BASE_DIR, "config.json"), "r") as f:
|
| 56 |
+
contents = json.load(f)
|
| 57 |
+
DATASET_SAVE_DIR = contents["data_path"]
|
| 58 |
+
SYNTHETIC_SAVE_DIR = contents["synthetic_data_path"]
|
| 59 |
+
MODEL_SAVE_DIR = contents["model_path"]
|
| 60 |
+
except (OSError, KeyError):
|
| 61 |
+
with open(os.path.join(SUPER_BASE_DIR, "config.json"), "w") as f:
|
| 62 |
+
json.dump(
|
| 63 |
+
{
|
| 64 |
+
"data_path": os.path.join(SUPER_BASE_DIR, "datasets"),
|
| 65 |
+
"synthetic_data_path": os.path.join(SUPER_BASE_DIR, "synthetic"),
|
| 66 |
+
"model_path": os.path.join(SUPER_BASE_DIR, "models"),
|
| 67 |
+
},
|
| 68 |
+
f,
|
| 69 |
+
)
|
| 70 |
+
_load_config_info()
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
_load_config_info()
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def data_save_path():
|
| 77 |
+
"""Returns the default dataset save path for AgML."""
|
| 78 |
+
global DATASET_SAVE_DIR
|
| 79 |
+
return DATASET_SAVE_DIR
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def set_data_save_path(location=None):
|
| 83 |
+
"""Sets the default dataset save path for AgML.
|
| 84 |
+
Changing the data save path using this method permanently changes
|
| 85 |
+
the data save path for all future sessions, until it is changed
|
| 86 |
+
or switched back to the original. If you just want to download one
|
| 87 |
+
dataset to a different path, use the `dataset_path` argument.
|
| 88 |
+
Parameters
|
| 89 |
+
----------
|
| 90 |
+
location : str
|
| 91 |
+
The location to save the data to.
|
| 92 |
+
Returns
|
| 93 |
+
-------
|
| 94 |
+
The fully expanded location.
|
| 95 |
+
"""
|
| 96 |
+
global SUPER_BASE_DIR
|
| 97 |
+
if location is None or location == "reset":
|
| 98 |
+
location = os.path.join(SUPER_BASE_DIR, "datasets")
|
| 99 |
+
location = os.path.expanduser(location)
|
| 100 |
+
if not os.path.exists(location) and not os.path.isdir(location):
|
| 101 |
+
raise NotADirectoryError(f"The provided destination {location} does " f"not exist, or is not a directory.")
|
| 102 |
+
_update_config("data_path", os.path.realpath(os.path.abspath(location)))
|
| 103 |
+
return
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
def synthetic_data_save_path():
|
| 107 |
+
"""Returns the default synthetic data save path for AgML."""
|
| 108 |
+
global SYNTHETIC_SAVE_DIR
|
| 109 |
+
return SYNTHETIC_SAVE_DIR
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
def set_synthetic_save_path(location=None):
|
| 113 |
+
"""Sets the default synthetic data save path for AgML.
|
| 114 |
+
Changing the data save path using this method permanently changes
|
| 115 |
+
the data save path for all future sessions, until it is changed
|
| 116 |
+
or switched back to the original. If you just want to download one
|
| 117 |
+
dataset to a different path, use the `dataset_path` argument.
|
| 118 |
+
Parameters
|
| 119 |
+
----------
|
| 120 |
+
location : str
|
| 121 |
+
The location to save the data to.
|
| 122 |
+
Returns
|
| 123 |
+
-------
|
| 124 |
+
The fully expanded location.
|
| 125 |
+
"""
|
| 126 |
+
global SUPER_BASE_DIR
|
| 127 |
+
if location is None or location == "reset":
|
| 128 |
+
location = os.path.join(SUPER_BASE_DIR, "synthetic")
|
| 129 |
+
location = os.path.expanduser(location)
|
| 130 |
+
if not os.path.exists(location) and not os.path.isdir(location):
|
| 131 |
+
raise NotADirectoryError(f"The provided destination {location} does " f"not exist, or is not a directory.")
|
| 132 |
+
_update_config("synthetic_data_path", os.path.realpath(os.path.abspath(location)))
|
| 133 |
+
return
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
def model_save_path():
|
| 137 |
+
"""Returns the default model save path for AgML."""
|
| 138 |
+
global MODEL_SAVE_DIR
|
| 139 |
+
return MODEL_SAVE_DIR
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
def set_model_save_path(location=None):
|
| 143 |
+
"""Sets the default model save path for AgML.
|
| 144 |
+
Changing the data save path using this method permanently changes
|
| 145 |
+
the data save path for all future sessions, until it is changed
|
| 146 |
+
or switched back to the original.
|
| 147 |
+
Parameters
|
| 148 |
+
----------
|
| 149 |
+
location : str
|
| 150 |
+
The location to save the model to.
|
| 151 |
+
Returns
|
| 152 |
+
-------
|
| 153 |
+
The fully expanded location.
|
| 154 |
+
"""
|
| 155 |
+
global SUPER_BASE_DIR
|
| 156 |
+
if location is None or location == "reset":
|
| 157 |
+
location = os.path.join(SUPER_BASE_DIR, "models")
|
| 158 |
+
location = os.path.expanduser(location)
|
| 159 |
+
if not os.path.exists(location) and not os.path.isdir(location):
|
| 160 |
+
raise NotADirectoryError(f"The provided destination {location} does " f"not exist, or is not a directory.")
|
| 161 |
+
_update_config("model_path", os.path.realpath(os.path.abspath(location)))
|
| 162 |
+
return
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
def _get_config(param):
|
| 166 |
+
"""Update the configuration file with a new parameter."""
|
| 167 |
+
global SUPER_BASE_DIR
|
| 168 |
+
with open(os.path.join(SUPER_BASE_DIR, "config.json"), "r") as f:
|
| 169 |
+
contents = json.load(f)
|
| 170 |
+
if param not in contents.keys():
|
| 171 |
+
return None
|
| 172 |
+
return contents[param]
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
def _update_config(param, value):
|
| 176 |
+
"""Update the configuration file with a new parameter."""
|
| 177 |
+
global SUPER_BASE_DIR
|
| 178 |
+
with open(os.path.join(SUPER_BASE_DIR, "config.json"), "r") as f:
|
| 179 |
+
contents = json.load(f)
|
| 180 |
+
contents[param] = value
|
| 181 |
+
with open(os.path.join(SUPER_BASE_DIR, "config.json"), "w") as f:
|
| 182 |
+
json.dump(contents, f)
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
def clear_all_datasets():
|
| 186 |
+
"""Deletes all of the datasets within the AgML local storage."""
|
| 187 |
+
log("Entering AgML interactive dataset deletion mode.", logging.WARNING)
|
| 188 |
+
msg_format = "\033[91m{0}\033[0m"
|
| 189 |
+
if not input(msg_format.format("Please confirm that you want to delete datasets: [y|n] ")) == "y":
|
| 190 |
+
print("Aborting dataset deletion.")
|
| 191 |
+
local_datasets = os.listdir(data_save_path())
|
| 192 |
+
deleted_datasets = []
|
| 193 |
+
for dataset in local_datasets:
|
| 194 |
+
if not os.path.isdir(os.path.join(data_save_path(), dataset)):
|
| 195 |
+
continue
|
| 196 |
+
if not input(msg_format.format(f"Delete dataset '{dataset}'? [y|n] ")) == "y":
|
| 197 |
+
continue
|
| 198 |
+
shutil.rmtree(os.path.join(data_save_path(), dataset))
|
| 199 |
+
deleted_datasets.append(dataset)
|
| 200 |
+
print(f"Deleted datasets {deleted_datasets}.")
|
| 201 |
+
log("Exiting AgML interactive dataset deletion mode.", logging.WARNING)
|
| 202 |
+
|
| 203 |
+
|
| 204 |
+
def downloaded_datasets():
|
| 205 |
+
"""Lists downloaded datasets in ~/.agml/datasets"""
|
| 206 |
+
return [d for d in os.listdir(data_save_path()) if os.path.isdir(os.path.join(data_save_path(), d))]
|
AgML/source/agml/backend/experimental.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 UC Davis Plant AI and Biophysics Lab
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""Experimental features in AgML, these may be added or removed permanently."""
|
| 15 |
+
|
| 16 |
+
from agml.framework import AgMLSerializable
|
| 17 |
+
|
| 18 |
+
__all__ = ["allow_nested_data_splitting"]
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
class AgMLExperimentalFeatureWrapper(AgMLSerializable):
|
| 22 |
+
"""Stores all of the feature values."""
|
| 23 |
+
|
| 24 |
+
_NESTED_SPLITTING = False
|
| 25 |
+
|
| 26 |
+
def __init__(self):
|
| 27 |
+
raise ValueError("This class should not be instantiated!")
|
| 28 |
+
|
| 29 |
+
@classmethod
|
| 30 |
+
def allow_nested_data_splitting(cls, value: bool) -> None:
|
| 31 |
+
"""Enables/disables nested splitting of `AgMLDataLoader`s.
|
| 32 |
+
|
| 33 |
+
This method can be used to either enable or disable a feature which
|
| 34 |
+
allows an sub-AgMLDataLoader which has been split to a custom data
|
| 35 |
+
split to be split again. This is an experimental feature, which
|
| 36 |
+
would allow for multiple levels of nested splits (e.g., you could
|
| 37 |
+
have a `loader.train_data.val_data.test_data`).
|
| 38 |
+
|
| 39 |
+
Parameters
|
| 40 |
+
----------
|
| 41 |
+
value : bool
|
| 42 |
+
Whether to enable or disable the feature.
|
| 43 |
+
|
| 44 |
+
Notes
|
| 45 |
+
-----
|
| 46 |
+
This method must be called at the start of each script in order
|
| 47 |
+
to function, otherwise it will default to `False`.
|
| 48 |
+
"""
|
| 49 |
+
if not isinstance(value, bool):
|
| 50 |
+
raise TypeError("Expected either True or False.")
|
| 51 |
+
cls._NESTED_SPLITTING = value
|
| 52 |
+
|
| 53 |
+
@classmethod
|
| 54 |
+
def nested_splitting(cls):
|
| 55 |
+
return cls._NESTED_SPLITTING
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
# While the `AgMLExperimentalFeatureWrapper` class controls the actual values,
|
| 59 |
+
# we expose each of its toggle methods as part of the `agml.backend` API.
|
| 60 |
+
allow_nested_data_splitting = AgMLExperimentalFeatureWrapper.allow_nested_data_splitting
|
AgML/source/agml/backend/random.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 UC Davis Plant AI and Biophysics Lab
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from agml.backend.tftorch import get_backend, tf, torch
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def set_seed(seed=None):
|
| 19 |
+
"""Sets a new random seed. If None, uses a random seed."""
|
| 20 |
+
import random
|
| 21 |
+
|
| 22 |
+
random.seed(seed)
|
| 23 |
+
import numpy as np
|
| 24 |
+
|
| 25 |
+
np.random.seed(seed)
|
| 26 |
+
if get_backend() == "torch":
|
| 27 |
+
torch.random.manual_seed(seed)
|
| 28 |
+
elif get_backend() == "tensorflow":
|
| 29 |
+
tf.random.set_seed(seed)
|
AgML/source/agml/backend/tftorch.py
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 UC Davis Plant AI and Biophysics Lab
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
"""
|
| 16 |
+
This part of the backend controls the AgML methods where either
|
| 17 |
+
TensorFlow or PyTorch methods can be used, and prevents unnecessary
|
| 18 |
+
importing of either library (which takes a significant amount of time).
|
| 19 |
+
"""
|
| 20 |
+
|
| 21 |
+
import functools
|
| 22 |
+
import importlib
|
| 23 |
+
import inspect
|
| 24 |
+
import logging
|
| 25 |
+
import types
|
| 26 |
+
|
| 27 |
+
# Suppress any irrelevant warnings which will pop up from either backend.
|
| 28 |
+
import warnings
|
| 29 |
+
|
| 30 |
+
import numpy as np
|
| 31 |
+
|
| 32 |
+
from agml.utils.image import consistent_shapes
|
| 33 |
+
from agml.utils.logging import log
|
| 34 |
+
|
| 35 |
+
warnings.filterwarnings("ignore", category=UserWarning, message=".*Named tensors.*Triggered internally.*")
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
class StrictBackendError(ValueError):
|
| 39 |
+
def __init__(self, message=None, change=None, obj=None):
|
| 40 |
+
if message is None:
|
| 41 |
+
message = (
|
| 42 |
+
f"Backend was manually set to "
|
| 43 |
+
f"'{get_backend()}', but got an object "
|
| 44 |
+
f"from backend '{change}': {obj}."
|
| 45 |
+
)
|
| 46 |
+
super(StrictBackendError, self).__init__(message)
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
# Check if TensorFlow and PyTorch exist in the environment.
|
| 50 |
+
_HAS_TENSORFLOW: bool
|
| 51 |
+
_HAS_TORCH: bool
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
@functools.lru_cache(maxsize=None)
|
| 55 |
+
def _check_tf_torch():
|
| 56 |
+
global _HAS_TENSORFLOW, _HAS_TORCH
|
| 57 |
+
try:
|
| 58 |
+
import tensorflow
|
| 59 |
+
except ImportError:
|
| 60 |
+
_HAS_TENSORFlOW = False
|
| 61 |
+
else:
|
| 62 |
+
_HAS_TENSORFLOW = True
|
| 63 |
+
try:
|
| 64 |
+
import torch
|
| 65 |
+
except ImportError:
|
| 66 |
+
_HAS_TORCH = False
|
| 67 |
+
else:
|
| 68 |
+
_HAS_TORCH = True
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
# Default backend is PyTorch.
|
| 72 |
+
_BACKEND = None
|
| 73 |
+
_USER_SET_BACKEND = False
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def get_backend():
|
| 77 |
+
"""Returns the current AgML backend."""
|
| 78 |
+
return _BACKEND
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
def set_backend(backend):
|
| 82 |
+
"""Change the AgML backend for the current session.
|
| 83 |
+
|
| 84 |
+
By default, AgML uses PyTorch as a backend, but it is
|
| 85 |
+
compatible with both TensorFlow and PyTorch. AgML can
|
| 86 |
+
also automatically inference the backend from the
|
| 87 |
+
different parameters passed into `AgMLDataLoader` and
|
| 88 |
+
other internal library methods.
|
| 89 |
+
|
| 90 |
+
This method allows a user to automatically set the backend.
|
| 91 |
+
"""
|
| 92 |
+
global _USER_SET_BACKEND, _BACKEND
|
| 93 |
+
# Check whether the user has modified the backend.
|
| 94 |
+
mod = inspect.getmodule(inspect.stack()[1][0])
|
| 95 |
+
if mod is None: # IPython shell
|
| 96 |
+
_USER_SET_BACKEND = True
|
| 97 |
+
elif "agml." not in mod.__name__:
|
| 98 |
+
_USER_SET_BACKEND = True
|
| 99 |
+
|
| 100 |
+
# If the backend is the same, don't do anything.
|
| 101 |
+
if backend == _BACKEND:
|
| 102 |
+
return
|
| 103 |
+
|
| 104 |
+
_check_tf_torch()
|
| 105 |
+
if backend not in ["tensorflow", "tf", "torch", "pytorch"]:
|
| 106 |
+
raise ValueError(f"Invalid backend: {backend}.")
|
| 107 |
+
if backend in ["tensorflow", "tf"] and _BACKEND != "tensorflow":
|
| 108 |
+
if not _HAS_TENSORFLOW:
|
| 109 |
+
raise ImportError(
|
| 110 |
+
"TensorFlow not found on system, cannot be used as " "backend. Try running `pip install tensorflow`."
|
| 111 |
+
)
|
| 112 |
+
_BACKEND = "tf"
|
| 113 |
+
log("Switched backend to TensorFlow.", level=logging.INFO)
|
| 114 |
+
elif backend in ["torch", "pytorch"] and _BACKEND != "torch":
|
| 115 |
+
if not _HAS_TORCH:
|
| 116 |
+
raise ImportError(
|
| 117 |
+
"PyTorch not found on system, cannot be used as " "backend. Try running `pip install torch`."
|
| 118 |
+
)
|
| 119 |
+
_BACKEND = "torch"
|
| 120 |
+
log("Switched backend to PyTorch.", level=logging.INFO)
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
def user_changed_backend():
|
| 124 |
+
"""Returns whether the backend has been manually changed."""
|
| 125 |
+
return _USER_SET_BACKEND
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
# Ported from https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/util/lazy_loader.py
|
| 129 |
+
class LazyLoader(types.ModuleType):
|
| 130 |
+
"""Lazily import a module, mainly to avoid pulling in large dependencies."""
|
| 131 |
+
|
| 132 |
+
def __init__(self, local_name, parent_module_globals, name):
|
| 133 |
+
self._local_name = local_name
|
| 134 |
+
self._parent_module_globals = parent_module_globals
|
| 135 |
+
super(LazyLoader, self).__init__(name)
|
| 136 |
+
|
| 137 |
+
def _load(self):
|
| 138 |
+
"""Load the module and insert it into the parent's globals."""
|
| 139 |
+
# Import the target module and insert it into the parent's namespace.
|
| 140 |
+
module = importlib.import_module(self.__name__)
|
| 141 |
+
self._parent_module_globals[self._local_name] = module
|
| 142 |
+
|
| 143 |
+
# Update this object's dict so that if someone keeps a reference to the
|
| 144 |
+
# LazyLoader, lookups are efficient (__getattr__ is only called on lookups
|
| 145 |
+
# that fail).
|
| 146 |
+
self.__dict__.update(module.__dict__)
|
| 147 |
+
return module
|
| 148 |
+
|
| 149 |
+
def __getattr__(self, item):
|
| 150 |
+
module = self._load()
|
| 151 |
+
return getattr(module, item)
|
| 152 |
+
|
| 153 |
+
def __dir__(self):
|
| 154 |
+
module = self._load()
|
| 155 |
+
return dir(module)
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
# Load TensorFlow and PyTorch lazily to prevent pulling them in when unnecessary.
|
| 159 |
+
torch = LazyLoader("torch", globals(), "torch")
|
| 160 |
+
torch_data = LazyLoader("torch_data", globals(), "torch.utils.data")
|
| 161 |
+
torchvision = LazyLoader("torchvision", globals(), "torchvision")
|
| 162 |
+
tf = LazyLoader("tensorflow", globals(), "tensorflow")
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
######### GENERAL METHODS #########
|
| 166 |
+
|
| 167 |
+
|
| 168 |
+
def _convert_image_to_torch(image):
|
| 169 |
+
"""Converts an image (np.ndarray) to a torch Tensor."""
|
| 170 |
+
if isinstance(image, (list, tuple)):
|
| 171 |
+
return torch.tensor(image)
|
| 172 |
+
if isinstance(image, torch.Tensor) or image.ndim == 4:
|
| 173 |
+
if image.shape[0] == 1 and image.shape[-1] <= 3 and image.ndim == 4:
|
| 174 |
+
return torch.from_numpy(image).permute(0, 3, 1, 2).float()
|
| 175 |
+
return image
|
| 176 |
+
if image.ndim == 3:
|
| 177 |
+
if image.shape[0] > image.shape[-1]:
|
| 178 |
+
return torch.from_numpy(image).permute(2, 0, 1).float()
|
| 179 |
+
elif image.ndim == 2:
|
| 180 |
+
return torch.from_numpy(image)
|
| 181 |
+
return torch.from_numpy(image).float()
|
| 182 |
+
|
| 183 |
+
|
| 184 |
+
def _postprocess_torch_annotation(image):
|
| 185 |
+
"""Post-processes a spatially augmented torch annotation."""
|
| 186 |
+
try:
|
| 187 |
+
if image.dtype.is_floating_point:
|
| 188 |
+
image = (image * 255).int()
|
| 189 |
+
except AttributeError:
|
| 190 |
+
pass
|
| 191 |
+
return image
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
def as_scalar(inp):
|
| 195 |
+
"""Converts an input value to a scalar."""
|
| 196 |
+
if isinstance(inp, (int, float)):
|
| 197 |
+
return inp
|
| 198 |
+
if np.isscalar(inp):
|
| 199 |
+
return inp.item()
|
| 200 |
+
if isinstance(inp, np.ndarray):
|
| 201 |
+
return inp.item()
|
| 202 |
+
if isinstance(inp, torch.Tensor):
|
| 203 |
+
return inp.item()
|
| 204 |
+
if isinstance(inp, tf.Tensor):
|
| 205 |
+
return inp.numpy()
|
| 206 |
+
raise TypeError(f"Unsupported variable type {type(inp)}.")
|
| 207 |
+
|
| 208 |
+
|
| 209 |
+
def scalar_unpack(inp):
|
| 210 |
+
"""Unpacks a 1-d array into a list of scalars."""
|
| 211 |
+
return [as_scalar(item) for item in inp]
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
def is_array_like(inp, no_list=False):
|
| 215 |
+
"""Determines if an input is a np.ndarray, torch.Tensor, or tf.Tensor."""
|
| 216 |
+
if isinstance(inp, (list, tuple)): # no need to import tensorflow for this
|
| 217 |
+
if no_list:
|
| 218 |
+
return False
|
| 219 |
+
return True
|
| 220 |
+
if isinstance(inp, np.ndarray):
|
| 221 |
+
return True
|
| 222 |
+
if isinstance(inp, torch.Tensor):
|
| 223 |
+
return True
|
| 224 |
+
if isinstance(inp, tf.Tensor):
|
| 225 |
+
return True
|
| 226 |
+
return False
|
| 227 |
+
|
| 228 |
+
|
| 229 |
+
def convert_to_batch(images):
|
| 230 |
+
"""Converts a set of images to a batch."""
|
| 231 |
+
# If `images` is already an array type, nothing to do.
|
| 232 |
+
if is_array_like(images):
|
| 233 |
+
return images
|
| 234 |
+
|
| 235 |
+
# NumPy Arrays.
|
| 236 |
+
if isinstance(images[0], np.ndarray):
|
| 237 |
+
if not consistent_shapes(images):
|
| 238 |
+
images = np.array(images, dtype=object)
|
| 239 |
+
log(
|
| 240 |
+
"Created a batch of images with different "
|
| 241 |
+
"shapes. If you want the shapes to be consistent, "
|
| 242 |
+
"run `loader.resize_images('auto')`."
|
| 243 |
+
)
|
| 244 |
+
else:
|
| 245 |
+
images = np.array(images)
|
| 246 |
+
return images
|
| 247 |
+
|
| 248 |
+
# Torch Tensors.
|
| 249 |
+
if isinstance(images[0], torch.Tensor):
|
| 250 |
+
if not consistent_shapes(images):
|
| 251 |
+
images = [image.numpy() for image in images]
|
| 252 |
+
images = np.array(images, dtype=object)
|
| 253 |
+
log(
|
| 254 |
+
"Created a batch of images with different "
|
| 255 |
+
"shapes. If you want the shapes to be consistent, "
|
| 256 |
+
"run `loader.resize_images('auto')`."
|
| 257 |
+
)
|
| 258 |
+
else:
|
| 259 |
+
images = torch.stack(images)
|
| 260 |
+
return images
|
| 261 |
+
|
| 262 |
+
# TensorFlow Tensors.
|
| 263 |
+
if isinstance(images[0], tf.Tensor):
|
| 264 |
+
if not consistent_shapes(images):
|
| 265 |
+
images = tf.ragged.stack(images)
|
| 266 |
+
log(
|
| 267 |
+
"Created a batch of images with different "
|
| 268 |
+
"shapes. If you want the shapes to be consistent, "
|
| 269 |
+
"run `loader.resize_images('auto')`."
|
| 270 |
+
)
|
| 271 |
+
else:
|
| 272 |
+
images = tf.stack(images)
|
| 273 |
+
return images
|
| 274 |
+
|
| 275 |
+
|
| 276 |
+
######### AGMLDATALOADER METHODS #########
|
| 277 |
+
|
| 278 |
+
|
| 279 |
+
class AgMLObject(object):
|
| 280 |
+
"""Base class for the `AgMLDataLoader` to enable inheritance.
|
| 281 |
+
|
| 282 |
+
This class solves a bug which arises when trying to dynamically
|
| 283 |
+
inherit from `tf.keras.utils.Sequence` and/or `torch.utils.data.Dataset`.
|
| 284 |
+
The fact that the `AgMLDataLoader` has this `AgMLObject` as a subclass
|
| 285 |
+
enables it to be able to handle dynamic inheritance. This is the sole
|
| 286 |
+
purpose of this subclass, it does not have any features.
|
| 287 |
+
"""
|
| 288 |
+
|
| 289 |
+
|
| 290 |
+
def _add_dataset_to_mro(inst, mode):
|
| 291 |
+
"""Adds the relevant backend class to the `AgMLDataLoader` MRO.
|
| 292 |
+
|
| 293 |
+
This allows for the loader to dynamically inherent from the
|
| 294 |
+
`tf.keras.utils.Sequence` and `torch.utils.data.Dataset`.
|
| 295 |
+
"""
|
| 296 |
+
if mode == "tf":
|
| 297 |
+
if not get_backend() == "tf":
|
| 298 |
+
if user_changed_backend():
|
| 299 |
+
raise StrictBackendError(change="tf", obj=inst)
|
| 300 |
+
set_backend("tf")
|
| 301 |
+
if tf.keras.utils.Sequence not in inst.__class__.__bases__:
|
| 302 |
+
inst.__class__.__bases__ += (tf.keras.utils.Sequence,)
|
| 303 |
+
if mode == "torch":
|
| 304 |
+
if not get_backend() == "torch":
|
| 305 |
+
if user_changed_backend():
|
| 306 |
+
raise StrictBackendError(change="torch", obj=inst)
|
| 307 |
+
if torch_data.Dataset not in inst.__class__.__bases__:
|
| 308 |
+
inst.__class__.__bases__ += (torch_data.Dataset,)
|
| 309 |
+
|
| 310 |
+
|
| 311 |
+
def collate_fn_basic(batch):
|
| 312 |
+
images = torch.stack([i[0] for i in batch], dim=0)
|
| 313 |
+
coco = tuple(zip(*[i[1] for i in batch]))
|
| 314 |
+
return images, coco
|
| 315 |
+
|
| 316 |
+
|
| 317 |
+
def collate_fn_efficientdet(batch):
|
| 318 |
+
"""Collates items together into a batch."""
|
| 319 |
+
images, targets = tuple(zip(*batch))
|
| 320 |
+
images = torch.stack(images)
|
| 321 |
+
images = images.float()
|
| 322 |
+
|
| 323 |
+
boxes = [target["bboxes"].float() for target in targets]
|
| 324 |
+
labels = [target["labels"].float() for target in targets]
|
| 325 |
+
img_size = torch.stack([target["img_size"] for target in targets]).float()
|
| 326 |
+
img_scale = torch.stack([target["img_scale"] for target in targets]).float()
|
| 327 |
+
|
| 328 |
+
annotations = {
|
| 329 |
+
"bbox": boxes,
|
| 330 |
+
"cls": labels,
|
| 331 |
+
"img_size": img_size,
|
| 332 |
+
"img_scale": img_scale,
|
| 333 |
+
}
|
| 334 |
+
return images, annotations, targets
|
AgML/source/agml/data/__init__.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 UC Davis Plant AI and Biophysics Lab
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from . import experimental, exporters, extensions
|
| 16 |
+
from .image_loader import ImageLoader
|
| 17 |
+
from .loader import AgMLDataLoader
|
| 18 |
+
from .point_cloud import PointCloud
|
| 19 |
+
from .public import download_public_dataset, public_data_sources, source
|
| 20 |
+
from .tools import coco_to_bboxes, convert_bbox_format
|
AgML/source/agml/data/builder.py
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 UC Davis Plant AI and Biophysics Lab
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
import json
|
| 16 |
+
import os
|
| 17 |
+
import re
|
| 18 |
+
import sys
|
| 19 |
+
|
| 20 |
+
from agml.backend.config import data_save_path
|
| 21 |
+
from agml.framework import AgMLSerializable
|
| 22 |
+
from agml.utils.downloads import download_dataset
|
| 23 |
+
from agml.utils.io import get_dir_list, get_file_list, is_image_file
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
class DataBuilder(AgMLSerializable):
|
| 27 |
+
"""Builds an internal representation format of AgML data.
|
| 28 |
+
|
| 29 |
+
This class doesn't affect the state of the `AgMLDataLoader`, but
|
| 30 |
+
instead generates an internal representation of the data content
|
| 31 |
+
of a dataset. This allows for all data to be loaded in a standard
|
| 32 |
+
format and streamlined into the `DataManager`.
|
| 33 |
+
|
| 34 |
+
Primarily, this class attempts to locate the dataset and if unable
|
| 35 |
+
to do so, it downloads the dataset from the public bucket. Then,
|
| 36 |
+
it creates a mapping between the images and annotations which is
|
| 37 |
+
used by the `DataManager` inside the `AgMLDataLoader`.
|
| 38 |
+
"""
|
| 39 |
+
|
| 40 |
+
serializable = frozenset(("name", "labels_for_image", "data", "info", "dataset_root", "data_length"))
|
| 41 |
+
|
| 42 |
+
def __init__(self, info, dataset_path, overwrite):
|
| 43 |
+
# Attempt to locate or download the dataset.
|
| 44 |
+
self._info = info
|
| 45 |
+
self._name = info.name
|
| 46 |
+
self._configure_dataset(dataset_path=dataset_path, overwrite=overwrite)
|
| 47 |
+
self._data = None
|
| 48 |
+
self._data_length = None
|
| 49 |
+
self._labels_for_image = None
|
| 50 |
+
|
| 51 |
+
@classmethod
|
| 52 |
+
def from_data(cls, contents, info, root, builder=None):
|
| 53 |
+
"""Initializes the `DataBuilder` from a pre-built set of data.
|
| 54 |
+
|
| 55 |
+
This is mainly used when running `AgMLDataLoader.split`, to create
|
| 56 |
+
a `DataManager` with a split of data. Functionally, it disables
|
| 57 |
+
all of the actual generation protocols of the `DataBuilder` and
|
| 58 |
+
just pre-assigns all of the values to it.
|
| 59 |
+
"""
|
| 60 |
+
obj = super(DataBuilder, cls).__new__(cls)
|
| 61 |
+
obj._name = info.name
|
| 62 |
+
obj._info = info
|
| 63 |
+
obj._dataset_root = root
|
| 64 |
+
obj._data = contents[0]
|
| 65 |
+
obj._data_length = len(obj._data)
|
| 66 |
+
obj._labels_for_image = contents[1]
|
| 67 |
+
if builder is not None:
|
| 68 |
+
if hasattr(builder, "_default_coco_annotations"):
|
| 69 |
+
obj._default_coco_annotations = DataBuilder._regenerate_coco_annotations(
|
| 70 |
+
builder._default_coco_annotations, obj._data
|
| 71 |
+
)
|
| 72 |
+
return obj
|
| 73 |
+
|
| 74 |
+
@staticmethod
|
| 75 |
+
def _regenerate_coco_annotations(coco, data):
|
| 76 |
+
"""Regenerates COCO annotations from a reduced set."""
|
| 77 |
+
image_coco = []
|
| 78 |
+
annotation_coco = []
|
| 79 |
+
image_id_tracker = 0
|
| 80 |
+
|
| 81 |
+
# Update the list of image paths.
|
| 82 |
+
for c in coco["images"]:
|
| 83 |
+
if c["file_name"] in list(data.keys()):
|
| 84 |
+
c["image_id"] = image_id_tracker
|
| 85 |
+
image_coco.append(c)
|
| 86 |
+
image_id_tracker += 1
|
| 87 |
+
|
| 88 |
+
# Update the image IDs for the annotations
|
| 89 |
+
for image_id, (_, annotation) in enumerate(data.items()):
|
| 90 |
+
for a in annotation:
|
| 91 |
+
a["id"] = image_id
|
| 92 |
+
annotation_coco.extend(annotation)
|
| 93 |
+
|
| 94 |
+
# Update the complete COCO dictionary.
|
| 95 |
+
ret_coco = coco.copy()
|
| 96 |
+
ret_coco["images"] = image_coco
|
| 97 |
+
ret_coco["annotations"] = annotation_coco
|
| 98 |
+
return ret_coco
|
| 99 |
+
|
| 100 |
+
@property
|
| 101 |
+
def dataset_root(self):
|
| 102 |
+
return self._dataset_root
|
| 103 |
+
|
| 104 |
+
def _configure_dataset(self, **kwargs):
|
| 105 |
+
"""Finds and configures the dataset into the loader."""
|
| 106 |
+
# Check if the user wants to overwrite the existing dataset,
|
| 107 |
+
# and resolve the potentially provided custom dataset path.
|
| 108 |
+
overwrite = kwargs.get("overwrite", False)
|
| 109 |
+
if kwargs.get("dataset_path", None):
|
| 110 |
+
kwargs["dataset_path"] = os.path.realpath(os.path.expanduser(kwargs["dataset_path"]))
|
| 111 |
+
|
| 112 |
+
# If a custom dataset has been provided, then we assume the directory
|
| 113 |
+
# provided is the root of the dataset, e.g., if /root/datasets/dir
|
| 114 |
+
# is provided, then dir doesn't necessarily need to be the name of
|
| 115 |
+
# the dataset, but it is assumed to be its root. Note that if no path
|
| 116 |
+
# is given, then we check similarly to the default path for datasets,
|
| 117 |
+
# e.g., if there is a directory with the provided name in the custom path.
|
| 118 |
+
#
|
| 119 |
+
# No downloading phase for custom datasets, as there is nothing to do.
|
| 120 |
+
if self._info.is_custom_dataset:
|
| 121 |
+
if kwargs.get("dataset_path", False):
|
| 122 |
+
path = kwargs.get("dataset_path")
|
| 123 |
+
if os.path.exists(path):
|
| 124 |
+
self._dataset_root = path
|
| 125 |
+
return
|
| 126 |
+
|
| 127 |
+
elif os.path.exists(os.path.join(data_save_path(), self._name)):
|
| 128 |
+
self._dataset_root = os.path.join(data_save_path(), self._name)
|
| 129 |
+
return
|
| 130 |
+
|
| 131 |
+
# Otherwise, we don't know what to do.
|
| 132 |
+
raise OSError(
|
| 133 |
+
f"Could not find a directory for the dataset {self._name}. "
|
| 134 |
+
f"Dataset path given: {kwargs.get('dataset_path', None)}"
|
| 135 |
+
)
|
| 136 |
+
|
| 137 |
+
# If the user doesn't want to overwrite the existing contents,
|
| 138 |
+
# first check whether the dataset already exists. If so, then set
|
| 139 |
+
# the dataset root and return without doing any downloading.
|
| 140 |
+
#
|
| 141 |
+
# Note that the `dataset_path` is resolved as follows: If the path
|
| 142 |
+
# ends with the name of the dataset, e.g., `/root/datasets/<name>`,
|
| 143 |
+
# then we pop '<name>' from the end of the path in order to prevent
|
| 144 |
+
# the dataset from being downloaded to `/root/datasets/<name>/<name>`.
|
| 145 |
+
if not overwrite:
|
| 146 |
+
if kwargs.get("dataset_path", False):
|
| 147 |
+
path = kwargs.get("dataset_path")
|
| 148 |
+
if (os.path.basename(path) == self._name and os.path.exists(path)) or os.path.exists(
|
| 149 |
+
os.path.join(path, self._name)
|
| 150 |
+
):
|
| 151 |
+
if os.path.basename(path) != self._name:
|
| 152 |
+
path = os.path.join(path, self._name)
|
| 153 |
+
self._dataset_root = path
|
| 154 |
+
return
|
| 155 |
+
|
| 156 |
+
elif os.path.exists(os.path.join(data_save_path(), self._name)):
|
| 157 |
+
self._dataset_root = os.path.join(data_save_path(), self._name)
|
| 158 |
+
return
|
| 159 |
+
|
| 160 |
+
# If the user wants to overwrite, or the dataset doesn't exist
|
| 161 |
+
# at the path, then we create the root in the same way, except
|
| 162 |
+
# we just also download the dataset to the path.
|
| 163 |
+
else:
|
| 164 |
+
if kwargs.get("dataset_path", False):
|
| 165 |
+
path = kwargs.get("dataset_path")
|
| 166 |
+
if (os.path.basename(path) == self._name and os.path.exists(path)) or os.path.exists(
|
| 167 |
+
os.path.join(path, self._name)
|
| 168 |
+
):
|
| 169 |
+
if os.path.basename(path) != self._name:
|
| 170 |
+
path = os.path.join(path, self._name)
|
| 171 |
+
print(f"[AgML Download]: Overwriting dataset at " f"{os.path.join(path)}")
|
| 172 |
+
if os.path.basename(path) != self._name:
|
| 173 |
+
path = os.path.join(path, self._name)
|
| 174 |
+
self._dataset_root = path
|
| 175 |
+
|
| 176 |
+
elif os.path.exists(os.path.join(data_save_path(), self._name)):
|
| 177 |
+
self._dataset_root = os.path.join(data_save_path(), self._name)
|
| 178 |
+
sys.stderr.write(f"[AgML Download]: Overwriting dataset at " f"{os.path.join(self._dataset_root)}")
|
| 179 |
+
|
| 180 |
+
# Performs the actual downloading of the dataset.
|
| 181 |
+
if kwargs.get("dataset_path", False):
|
| 182 |
+
download_path = kwargs["dataset_path"]
|
| 183 |
+
if os.path.basename(download_path) != self._name:
|
| 184 |
+
download_path = os.path.join(download_path, self._name)
|
| 185 |
+
else:
|
| 186 |
+
download_path = os.path.join(data_save_path(), self._name)
|
| 187 |
+
sys.stderr.write(f"[AgML Download]: Downloading dataset " f"`{self._name}` to {download_path}.")
|
| 188 |
+
download_dataset(self._name, download_path)
|
| 189 |
+
self._dataset_root = download_path
|
| 190 |
+
|
| 191 |
+
def _generate_contents(self, task):
|
| 192 |
+
"""Dispatches to a content generation method for the provided task."""
|
| 193 |
+
if self._data is not None:
|
| 194 |
+
return
|
| 195 |
+
if task == "image_classification":
|
| 196 |
+
self._generate_image_classification_data()
|
| 197 |
+
elif task == "image_regression":
|
| 198 |
+
self._generate_image_regression_data()
|
| 199 |
+
elif task == "object_detection":
|
| 200 |
+
self._generate_object_detection_data()
|
| 201 |
+
else:
|
| 202 |
+
self._generate_semantic_segmentation_data()
|
| 203 |
+
|
| 204 |
+
def get_contents(self):
|
| 205 |
+
"""Extracts the internal representation of the data content."""
|
| 206 |
+
# Create the internal content representation of the dataset.
|
| 207 |
+
self._generate_contents(self._info.tasks.ml)
|
| 208 |
+
|
| 209 |
+
# Update the length of the data in the metadata dictionary for
|
| 210 |
+
# custom datasets, since they may not be providing the total number.
|
| 211 |
+
self._data_length = len(self._data)
|
| 212 |
+
if self._info._metadata.get("n_images", None) is None:
|
| 213 |
+
self._info._metadata["n_images"] = str(self._data_length)
|
| 214 |
+
return self._data
|
| 215 |
+
|
| 216 |
+
def export_contents(self, export_format):
|
| 217 |
+
"""Returns the raw contents of the loader."""
|
| 218 |
+
# We start by constructing a default mapping.
|
| 219 |
+
contents = self.get_contents()
|
| 220 |
+
|
| 221 |
+
# For a COCO JSON dictionary, we have to make the full paths.
|
| 222 |
+
if self._info.tasks.ml == "object_detection":
|
| 223 |
+
paths, coco = contents.keys(), contents.values()
|
| 224 |
+
paths = [os.path.join(self._dataset_root, "images", i) for i in paths]
|
| 225 |
+
contents = dict({k: v for k, v in zip(paths, coco)})
|
| 226 |
+
|
| 227 |
+
# If the export format is `None`, we return the default mapping.
|
| 228 |
+
if export_format is None:
|
| 229 |
+
return contents
|
| 230 |
+
|
| 231 |
+
# If the export format is `arrays`, return the keys and
|
| 232 |
+
# the values of the mapping as two independent arrays.
|
| 233 |
+
if export_format == "arrays":
|
| 234 |
+
return list(contents.keys()), list(contents.values())
|
| 235 |
+
|
| 236 |
+
# A special case for COCO JSON dictionaries.
|
| 237 |
+
if export_format == "coco":
|
| 238 |
+
if self._info.tasks.ml != "object_detection":
|
| 239 |
+
raise ValueError("The `coco` export format is " "only for object detection tasks.")
|
| 240 |
+
return self._default_coco_annotations
|
| 241 |
+
|
| 242 |
+
# The following methods actually generate the content mappings for
|
| 243 |
+
# the different tasks. In essence, for each image path, `image`, a
|
| 244 |
+
# mapping is generated with a corresponding annotation, such as a
|
| 245 |
+
# label for image classification, mask for semantic segmentation, or
|
| 246 |
+
# a COCO JSON dictionary for object detection.
|
| 247 |
+
|
| 248 |
+
def _generate_image_classification_data(self):
|
| 249 |
+
"""Loads image classification data for the `directory_names` format.
|
| 250 |
+
|
| 251 |
+
In this format, images are organized by class where the directory
|
| 252 |
+
they are placed in corresponds to their label in the dataset.
|
| 253 |
+
"""
|
| 254 |
+
image_label_mapping = {}
|
| 255 |
+
candidate_dirs = get_dir_list(self._dataset_root)
|
| 256 |
+
for dir_ in candidate_dirs:
|
| 257 |
+
if dir_.startswith("."):
|
| 258 |
+
continue
|
| 259 |
+
dir_path = os.path.join(self._dataset_root, dir_)
|
| 260 |
+
if len(get_file_list(dir_path)) == 0:
|
| 261 |
+
continue
|
| 262 |
+
for file_ in get_file_list(dir_path):
|
| 263 |
+
file_ = os.path.join(dir_path, file_)
|
| 264 |
+
image_label_mapping[file_] = self._info.class_to_num[dir_]
|
| 265 |
+
self._data = image_label_mapping
|
| 266 |
+
|
| 267 |
+
def _generate_image_regression_data(self):
|
| 268 |
+
"""Loads image regression data for the loader.
|
| 269 |
+
|
| 270 |
+
In this format, there are input images in an `images` folder as
|
| 271 |
+
well as other image formats in other various `*_images` folders,
|
| 272 |
+
and an `annotations.json` file containing the regression outputs.
|
| 273 |
+
"""
|
| 274 |
+
with open(os.path.join(self._dataset_root, "annotations.json"), "r") as f:
|
| 275 |
+
annotations = json.load(f)
|
| 276 |
+
content_mapping = {"inputs": [], "outputs": []}
|
| 277 |
+
annotation_types = set(list(self._info.class_to_num.keys()))
|
| 278 |
+
annotation_types.remove("regression")
|
| 279 |
+
for sample in annotations:
|
| 280 |
+
for k, v in sample.items():
|
| 281 |
+
if is_image_file(v):
|
| 282 |
+
sample[k] = os.path.join(self._dataset_root, f"{k}s", v)
|
| 283 |
+
content_mapping["inputs"].append({k: v for k, v in sample.items() if re.match("(.*?)image", k)})
|
| 284 |
+
out = {"regression": list(sample["outputs"]["regression"].values())}
|
| 285 |
+
out.update(
|
| 286 |
+
{k: self._info.class_to_num[k][v] for k, v in sample["outputs"].items() if k in annotation_types}
|
| 287 |
+
)
|
| 288 |
+
content_mapping["outputs"].append(out)
|
| 289 |
+
self._data = content_mapping
|
| 290 |
+
|
| 291 |
+
def _generate_semantic_segmentation_data(self):
|
| 292 |
+
"""Loads semantic segmentation data for the loader.
|
| 293 |
+
|
| 294 |
+
Image data is loaded from an `images` directory, and pixel-wise
|
| 295 |
+
annotated images are loaded from an `annotations` directory.
|
| 296 |
+
"""
|
| 297 |
+
image_dir = os.path.join(self._dataset_root, "images")
|
| 298 |
+
annotation_dir = os.path.join(self._dataset_root, "annotations")
|
| 299 |
+
images, annotations = (
|
| 300 |
+
sorted(get_file_list(image_dir)),
|
| 301 |
+
sorted(get_file_list(annotation_dir)),
|
| 302 |
+
)
|
| 303 |
+
image_annotation_map = {}
|
| 304 |
+
for image_path, annotation_path in zip(images, annotations):
|
| 305 |
+
image_annotation_map[os.path.join(image_dir, image_path)] = os.path.join(annotation_dir, annotation_path)
|
| 306 |
+
self._data = image_annotation_map
|
| 307 |
+
|
| 308 |
+
def _generate_object_detection_data(self):
|
| 309 |
+
"""Generates object detection data for the loader.
|
| 310 |
+
|
| 311 |
+
Image data is loaded from an `images` directory, and the COCO
|
| 312 |
+
JSON annotations are loaded from an `annotations.json` file.
|
| 313 |
+
"""
|
| 314 |
+
with open(os.path.join(self._dataset_root, "annotations.json")) as f:
|
| 315 |
+
self._default_coco_annotations = json.load(f)
|
| 316 |
+
coco_annotations = self._default_coco_annotations
|
| 317 |
+
image_id_mapping = {}
|
| 318 |
+
for img_meta in coco_annotations["images"]:
|
| 319 |
+
image_id_mapping[img_meta["id"]] = img_meta["file_name"]
|
| 320 |
+
coco_map = {fname: [] for fname in image_id_mapping.values()}
|
| 321 |
+
image_category_map = {k: [] for k in coco_map.keys()}
|
| 322 |
+
for a_meta in coco_annotations["annotations"]:
|
| 323 |
+
image_category_map[image_id_mapping[a_meta["image_id"]]].append(a_meta["category_id"])
|
| 324 |
+
coco_map[image_id_mapping[a_meta["image_id"]]].append(a_meta)
|
| 325 |
+
self._labels_for_image = image_category_map
|
| 326 |
+
self._data = coco_map
|
AgML/source/agml/data/experimental.py
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 UC Davis Plant AI and Biophysics Lab
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
"""
|
| 16 |
+
Experimental data utilities that are in development.
|
| 17 |
+
"""
|
| 18 |
+
|
| 19 |
+
import functools
|
| 20 |
+
|
| 21 |
+
import numpy as np
|
| 22 |
+
|
| 23 |
+
__all__ = ["generate_keras_segmentation_dual_transform"]
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def generate_keras_segmentation_dual_transform(*layers):
|
| 27 |
+
"""Generates a `dual_transform` pipeline from Keras preprocessing layers.
|
| 28 |
+
|
| 29 |
+
This method takes in Keras preprocessing layers and generates a
|
| 30 |
+
transformation pipeline for the `dual_transform` argument in
|
| 31 |
+
*semantic segmentation* loaders, which applies the transform in the
|
| 32 |
+
same fashion to both the image and annotation.
|
| 33 |
+
|
| 34 |
+
This is due to the fact that TensorFlow has its operation-level
|
| 35 |
+
random states different than its module-level random state, so
|
| 36 |
+
the layers need to have their seeds manually set in order to work.
|
| 37 |
+
|
| 38 |
+
In essence, for each of the preprocessing layers passed, this
|
| 39 |
+
method conducts the following operations:
|
| 40 |
+
|
| 41 |
+
> def preprocessing_transform(image, annotation):
|
| 42 |
+
> layer = functools.partial(KerasPreprocessingLayer, **kwargs)
|
| 43 |
+
> seed = np.random.randint(BUFFER_SIZE) # up to sys.maxsize
|
| 44 |
+
> image = layer(image, seed = seed)
|
| 45 |
+
> annotation = layer(annotation, seed = seed)
|
| 46 |
+
> return image, annotation
|
| 47 |
+
|
| 48 |
+
It then repeats this transform for all of the preprocessing layers
|
| 49 |
+
passed, and returns a method which has this behavior wrapped into
|
| 50 |
+
it and can perform it when the preprocessing is actually conducted.
|
| 51 |
+
|
| 52 |
+
Parameters
|
| 53 |
+
----------
|
| 54 |
+
layers : Any
|
| 55 |
+
Either a Sequential model with preprocessing layers, or a
|
| 56 |
+
set of instantiated preprocessing layers.
|
| 57 |
+
|
| 58 |
+
Returns
|
| 59 |
+
-------
|
| 60 |
+
"""
|
| 61 |
+
import tensorflow as tf
|
| 62 |
+
|
| 63 |
+
if len(layers) == 1:
|
| 64 |
+
if isinstance(layers[0], tf.keras.Sequential):
|
| 65 |
+
layers = layers[0].layers
|
| 66 |
+
|
| 67 |
+
# These methods perform the behavior indicated in the
|
| 68 |
+
# code snippet above (for each of the layers given).
|
| 69 |
+
def _single_preprocessing_layer_base(layer_, build_dict):
|
| 70 |
+
def _internal(image, annotation, seed):
|
| 71 |
+
instantiated_layer = functools.partial(layer_, **build_dict)
|
| 72 |
+
seed_update = {}
|
| 73 |
+
if seed is not None:
|
| 74 |
+
seed_update["seed"] = seed
|
| 75 |
+
image = instantiated_layer(**seed_update)(image)
|
| 76 |
+
annotation = instantiated_layer(**seed_update)(annotation)
|
| 77 |
+
return image, annotation
|
| 78 |
+
|
| 79 |
+
return _internal
|
| 80 |
+
|
| 81 |
+
preprocessing_methods, use_seeds = [], []
|
| 82 |
+
for layer in layers:
|
| 83 |
+
config = layer.get_config()
|
| 84 |
+
if "seed" in config:
|
| 85 |
+
config.pop("seed")
|
| 86 |
+
use_seeds.append(True)
|
| 87 |
+
else:
|
| 88 |
+
use_seeds.append(False)
|
| 89 |
+
preprocessing_methods.append(_single_preprocessing_layer_base(layer.__class__, config))
|
| 90 |
+
|
| 91 |
+
def _execute_preprocessing(layers_, use_seeds_):
|
| 92 |
+
def _execute(image, annotation):
|
| 93 |
+
for p_layer, seed_ in zip(layers_, use_seeds_):
|
| 94 |
+
seed = np.random.randint(2147483647) if seed_ else None
|
| 95 |
+
image, annotation = p_layer(image, annotation, seed=seed)
|
| 96 |
+
return image, annotation
|
| 97 |
+
|
| 98 |
+
return _execute
|
| 99 |
+
|
| 100 |
+
return _execute_preprocessing(preprocessing_methods, use_seeds)
|
AgML/source/agml/data/exporters/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
from .yolo import export_yolo
|
AgML/source/agml/data/exporters/tensorflow.py
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 UC Davis Plant AI and Biophysics Lab
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from agml.backend.tftorch import tf
|
| 16 |
+
from agml.data.managers.training import TrainState
|
| 17 |
+
from agml.data.object import DataObject
|
| 18 |
+
from agml.utils.logging import log
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
class TFExporter(object):
|
| 22 |
+
"""Exports an `AgMLDataLoader` as a `tf.data.Dataset`.
|
| 23 |
+
|
| 24 |
+
This class manages the methods and conversions between `AgMLDataLoader`
|
| 25 |
+
parameters, managers, and methods, into TensorFlow native methods.
|
| 26 |
+
"""
|
| 27 |
+
|
| 28 |
+
def __init__(self, task, builder):
|
| 29 |
+
self._task = task
|
| 30 |
+
self._builder = builder
|
| 31 |
+
|
| 32 |
+
def digest_transforms(self, transforms, resizing):
|
| 33 |
+
"""Parses the transforms for the `AgMLDataLoader`."""
|
| 34 |
+
self._transforms = {k: state for k, state in transforms.items()}
|
| 35 |
+
self._size = resizing if resizing is not None else (512, 512)
|
| 36 |
+
|
| 37 |
+
def assign_state(self, state):
|
| 38 |
+
"""Updates the training state for the `tf.data.Dataset`."""
|
| 39 |
+
if state in [
|
| 40 |
+
TrainState.EVAL,
|
| 41 |
+
TrainState.EVAL_TF,
|
| 42 |
+
TrainState.EVAL_TORCH,
|
| 43 |
+
TrainState.FALSE,
|
| 44 |
+
]:
|
| 45 |
+
self._state = "eval"
|
| 46 |
+
else:
|
| 47 |
+
self._state = "train"
|
| 48 |
+
|
| 49 |
+
def _build_from_contents_by_type(self, builder):
|
| 50 |
+
"""Parses the provided mapping into a valid set of contents."""
|
| 51 |
+
if self._task == "image_classification":
|
| 52 |
+
ds = self._build_image_classification(builder)
|
| 53 |
+
return ds.map(self._image_classification_load)
|
| 54 |
+
elif self._task == "semantic_segmentation":
|
| 55 |
+
ds = self._build_semantic_segmentation(builder)
|
| 56 |
+
return ds.map(self._semantic_segmentation_load)
|
| 57 |
+
else:
|
| 58 |
+
ds = self._build_object_detection(builder)
|
| 59 |
+
return ds.map(self._object_detection_load)
|
| 60 |
+
|
| 61 |
+
def _apply_resizing_by_type(self, ds):
|
| 62 |
+
"""Applies resizing based on the task."""
|
| 63 |
+
if self._task == "image_classification":
|
| 64 |
+
return ds.map(self._image_classification_resize)
|
| 65 |
+
elif self._task == "semantic_segmentation":
|
| 66 |
+
return ds.map(self._semantic_segmentation_resize)
|
| 67 |
+
else:
|
| 68 |
+
return ds.map(self._object_detection_resize)
|
| 69 |
+
|
| 70 |
+
def build(self, batch_size=None):
|
| 71 |
+
"""Builds the `tf.data.Dataset` using the provided parameters."""
|
| 72 |
+
# Construct the dataset from the contents.
|
| 73 |
+
ds = self._build_from_contents_by_type(self._builder)
|
| 74 |
+
|
| 75 |
+
# Apply the digested transforms and resizing.
|
| 76 |
+
ds = self._apply_resizing_by_type(ds)
|
| 77 |
+
if self._state != "eval":
|
| 78 |
+
# No transforms for object detection, since it is near impossible
|
| 79 |
+
# for TensorFlow's graph mode to use COCO JSON dictionaries.
|
| 80 |
+
if self._task == "object_detection":
|
| 81 |
+
if len(self._transforms) != 0:
|
| 82 |
+
log(
|
| 83 |
+
"Got transforms when exporting an `AgMLDataLoader`"
|
| 84 |
+
"to a `tf.data.Dataset`. These transforms will not be "
|
| 85 |
+
"applied. To use transforms in TensorFlow, use the "
|
| 86 |
+
"`as_keras_sequence()` method instead."
|
| 87 |
+
)
|
| 88 |
+
else:
|
| 89 |
+
tfm = self._apply_transforms
|
| 90 |
+
if len(self._transforms) != 0:
|
| 91 |
+
ds = ds.map(tfm)
|
| 92 |
+
|
| 93 |
+
# Apply batching and prefetching, then return the dataset.
|
| 94 |
+
if batch_size is not None:
|
| 95 |
+
ds = ds.batch(batch_size)
|
| 96 |
+
ds = ds.prefetch(batch_size)
|
| 97 |
+
return ds
|
| 98 |
+
|
| 99 |
+
# The following methods are used to parse the input
|
| 100 |
+
# contents into valid methods for the loaders.
|
| 101 |
+
|
| 102 |
+
@staticmethod
|
| 103 |
+
def _build_image_classification(builder):
|
| 104 |
+
images, labels = builder.export_contents(export_format="arrays")
|
| 105 |
+
images, labels = tf.constant(images), tf.constant(labels)
|
| 106 |
+
ds = tf.data.Dataset.from_tensor_slices((images, labels))
|
| 107 |
+
return ds.shuffle(len(images))
|
| 108 |
+
|
| 109 |
+
@staticmethod
|
| 110 |
+
def _build_semantic_segmentation(builder):
|
| 111 |
+
images, masks = builder.export_contents(export_format="arrays")
|
| 112 |
+
images, masks = tf.constant(images), tf.constant(masks)
|
| 113 |
+
ds = tf.data.Dataset.from_tensor_slices((images, masks))
|
| 114 |
+
return ds.shuffle(len(images))
|
| 115 |
+
|
| 116 |
+
@staticmethod
|
| 117 |
+
def _build_object_detection(builder):
|
| 118 |
+
images, annotations = builder.export_contents(export_format="arrays")
|
| 119 |
+
images = tf.constant(images)
|
| 120 |
+
processed_annotations = [DataObject._parse_coco(a) for a in annotations]
|
| 121 |
+
features = {
|
| 122 |
+
"bbox": [],
|
| 123 |
+
"category_id": [],
|
| 124 |
+
"area": [],
|
| 125 |
+
"image_id": [],
|
| 126 |
+
"iscrowd": [],
|
| 127 |
+
"segmentation": [],
|
| 128 |
+
}
|
| 129 |
+
for a_set in processed_annotations:
|
| 130 |
+
for feature in features.keys():
|
| 131 |
+
features[feature].append(a_set[feature]) # noqa
|
| 132 |
+
for feature in features.keys():
|
| 133 |
+
features[feature] = tf.ragged.constant(features[feature])
|
| 134 |
+
feature_ds = tf.data.Dataset.from_tensor_slices(features)
|
| 135 |
+
ds = tf.data.Dataset.zip((tf.data.Dataset.from_tensor_slices(images), feature_ds))
|
| 136 |
+
return ds.shuffle(len(images))
|
| 137 |
+
|
| 138 |
+
# The following methods are used for loading images and
|
| 139 |
+
# annotations for each of the different types of tasks.
|
| 140 |
+
|
| 141 |
+
@staticmethod
|
| 142 |
+
@tf.function
|
| 143 |
+
def _image_classification_load(image, label):
|
| 144 |
+
image = tf.cast(tf.image.decode_jpeg(tf.io.read_file(image)), tf.float32) / 255.0
|
| 145 |
+
return image, tf.convert_to_tensor(label)
|
| 146 |
+
|
| 147 |
+
@staticmethod
|
| 148 |
+
@tf.function
|
| 149 |
+
def _semantic_segmentation_load(image, mask):
|
| 150 |
+
image = tf.cast(tf.image.decode_jpeg(tf.io.read_file(image)), tf.float32) / 255.0
|
| 151 |
+
mask = tf.image.decode_jpeg(tf.io.read_file(mask))
|
| 152 |
+
return image, mask
|
| 153 |
+
|
| 154 |
+
@staticmethod
|
| 155 |
+
@tf.function
|
| 156 |
+
def _object_detection_load(image, coco):
|
| 157 |
+
image = tf.cast(tf.image.decode_jpeg(tf.io.read_file(image)), tf.float32) / 255.0
|
| 158 |
+
ret_coco = coco.copy()
|
| 159 |
+
for key in coco.keys():
|
| 160 |
+
try:
|
| 161 |
+
ret_coco[key] = coco[key].to_tensor()
|
| 162 |
+
except:
|
| 163 |
+
pass
|
| 164 |
+
return image, ret_coco
|
| 165 |
+
|
| 166 |
+
# The following methods apply resizing to the data.
|
| 167 |
+
|
| 168 |
+
def _image_classification_resize(self, image, label):
|
| 169 |
+
image = (tf.image.resize(image, self._size, method="nearest"), tf.float32)
|
| 170 |
+
return image, label
|
| 171 |
+
|
| 172 |
+
def _semantic_segmentation_resize(self, image, mask):
|
| 173 |
+
image = tf.cast(tf.image.resize(image, self._size, method="nearest"), tf.float32)
|
| 174 |
+
mask = tf.cast(tf.image.resize(mask, self._size, method="nearest"), tf.float32)
|
| 175 |
+
return image, mask
|
| 176 |
+
|
| 177 |
+
def _object_detection_resize(self, image, coco):
|
| 178 |
+
# Helper for the `tf.py_function` for object detection.
|
| 179 |
+
def _resize_image_and_bboxes(image, coco_boxes):
|
| 180 |
+
nonlocal size
|
| 181 |
+
y_scale, x_scale = image.shape[0:2]
|
| 182 |
+
stack_boxes = tf.stack(
|
| 183 |
+
[
|
| 184 |
+
coco_boxes[:, 0] / x_scale,
|
| 185 |
+
coco_boxes[:, 1] / y_scale,
|
| 186 |
+
coco_boxes[:, 2] / x_scale,
|
| 187 |
+
coco_boxes[:, 3] / y_scale,
|
| 188 |
+
],
|
| 189 |
+
axis=-1,
|
| 190 |
+
)
|
| 191 |
+
image = tf.cast(tf.image.resize(image, size), tf.float32)
|
| 192 |
+
y_new, x_new = image.shape[0:2]
|
| 193 |
+
new_stack = tf.cast(
|
| 194 |
+
tf.stack(
|
| 195 |
+
[
|
| 196 |
+
stack_boxes[:, 0] * x_new,
|
| 197 |
+
stack_boxes[:, 1] * y_new,
|
| 198 |
+
stack_boxes[:, 2] * x_new,
|
| 199 |
+
stack_boxes[:, 3] * y_new,
|
| 200 |
+
],
|
| 201 |
+
axis=-1,
|
| 202 |
+
),
|
| 203 |
+
tf.int32,
|
| 204 |
+
)
|
| 205 |
+
areas = new_stack[:, 2] * new_stack[:, 3]
|
| 206 |
+
return image, new_stack, areas
|
| 207 |
+
|
| 208 |
+
# The actual resizing can't take place in graph mode, so we
|
| 209 |
+
# dispatch to a `tf.py_function` to do the resizing, then
|
| 210 |
+
# re-assign the values back to the COCO JSON dictionary.
|
| 211 |
+
size = self._size
|
| 212 |
+
image, ret_coco_boxes, ret_areas = tf.py_function(
|
| 213 |
+
_resize_image_and_bboxes,
|
| 214 |
+
[image, coco["bbox"]],
|
| 215 |
+
[tf.float32, tf.int32, tf.int32],
|
| 216 |
+
)
|
| 217 |
+
coco["bbox"] = ret_coco_boxes
|
| 218 |
+
coco["area"] = ret_areas
|
| 219 |
+
return image, coco
|
| 220 |
+
|
| 221 |
+
# The following method manages the application of transforms.
|
| 222 |
+
|
| 223 |
+
def _apply_transforms(self, image, annotation):
|
| 224 |
+
# Helper for the `tf.py_function` for most transforms.
|
| 225 |
+
def _py_apply(img, ann):
|
| 226 |
+
nonlocal transforms
|
| 227 |
+
img, ann = img.numpy(), ann.numpy()
|
| 228 |
+
for key, state in transforms.items():
|
| 229 |
+
if key == "transform":
|
| 230 |
+
for t in state:
|
| 231 |
+
img = t(img)
|
| 232 |
+
elif key == "target_transform":
|
| 233 |
+
for t in state:
|
| 234 |
+
ann = t(ann)
|
| 235 |
+
else:
|
| 236 |
+
for t in state:
|
| 237 |
+
img, ann = t(img, ann)
|
| 238 |
+
|
| 239 |
+
return img, ann
|
| 240 |
+
|
| 241 |
+
# The actual transforming can't take place in graph mode
|
| 242 |
+
# (in most cases), so we dispatch and reassign.
|
| 243 |
+
transforms = self._transforms
|
| 244 |
+
image, annotation = tf.py_function(_py_apply, [image, annotation], [tf.float32, tf.int32])
|
| 245 |
+
return image, annotation
|
AgML/source/agml/data/exporters/yolo.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import shutil
|
| 3 |
+
|
| 4 |
+
import yaml
|
| 5 |
+
|
| 6 |
+
import agml
|
| 7 |
+
from agml.utils.general import flatten
|
| 8 |
+
from agml.utils.logging import log
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def convert_annotations_to_yolo_list(annotation_dict, image_shape, annotation_remapper):
|
| 12 |
+
yolo_list = []
|
| 13 |
+
height, width = image_shape
|
| 14 |
+
for annotation in annotation_dict:
|
| 15 |
+
x, y, w, h = annotation["bbox"]
|
| 16 |
+
x_center = x + w / 2
|
| 17 |
+
y_center = y + h / 2
|
| 18 |
+
|
| 19 |
+
# scale XYWH to [0, 1]
|
| 20 |
+
yolo_list.append(
|
| 21 |
+
[
|
| 22 |
+
annotation_remapper[annotation["category_id"]],
|
| 23 |
+
x_center / width,
|
| 24 |
+
y_center / height,
|
| 25 |
+
w / width,
|
| 26 |
+
h / width,
|
| 27 |
+
]
|
| 28 |
+
)
|
| 29 |
+
return yolo_list
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def export_yolo(dataset, yolo_path=None):
|
| 33 |
+
"""Exports an object detection dataset to YOLO format, ready-to-use for YOLO training.
|
| 34 |
+
|
| 35 |
+
This method will export an AgML dataset to the YOLO format, given its name and the
|
| 36 |
+
desired output location. This is so that the data is prepared within the YOLO format -
|
| 37 |
+
however, this does not translate to *integration* with the YOLO training pipeline.
|
| 38 |
+
Instead, this will simply enable you to add the dataset path to the YOLO training
|
| 39 |
+
configuration (and all other preprocessing steps are abstracted away in that same
|
| 40 |
+
pipeline, not requiring AgML).
|
| 41 |
+
|
| 42 |
+
Note that you can also use this function to export a custom dataset - in this case,
|
| 43 |
+
rather than passing in the name of a dataset simply pass in an AgMLDataLoader with
|
| 44 |
+
the dataset (and this will work for multi-dataset datasets, as well as dataset splits).
|
| 45 |
+
|
| 46 |
+
If you provide a path to a YOLO implementation, this function will automatically write
|
| 47 |
+
the corresponding files (including the `dataset.yaml` file). However, if an empty path,
|
| 48 |
+
no path, or a non-YOLO path is provided, the function will simply create a new directory
|
| 49 |
+
and write the files within a `metadata` directory there.
|
| 50 |
+
|
| 51 |
+
Additionally, if the data is already split, then `train.txt`, `val.txt`, and `test.txt`
|
| 52 |
+
files will be written to the data directory, which contain the split paths.
|
| 53 |
+
|
| 54 |
+
Parameters
|
| 55 |
+
----------
|
| 56 |
+
dataset : {str, AgMLDataLoader}
|
| 57 |
+
The name of the dataset to export to YOLO format, or an AgMLDataLoader object.
|
| 58 |
+
yolo_path : str
|
| 59 |
+
The path to the directory where the YOLO-formatted dataset will be saved.
|
| 60 |
+
|
| 61 |
+
"""
|
| 62 |
+
# if a name is provided, load the dataset
|
| 63 |
+
if isinstance(dataset, str):
|
| 64 |
+
loader = agml.data.AgMLDataLoader(dataset)
|
| 65 |
+
else:
|
| 66 |
+
loader = dataset
|
| 67 |
+
|
| 68 |
+
if yolo_path is None:
|
| 69 |
+
yolo_path = os.path.join(os.getcwd(), f"{loader.name}_yolo_export")
|
| 70 |
+
if not os.path.exists(os.path.join(yolo_path, "data")):
|
| 71 |
+
log("YOLO Export Tool did not receive a valid YOLO path. Creating a new directory for the export.")
|
| 72 |
+
|
| 73 |
+
yolo_data_path = os.path.join(yolo_path, "datasets", loader.name)
|
| 74 |
+
output_image_dir = os.path.join(yolo_data_path, "images")
|
| 75 |
+
output_annotation_dir = os.path.join(yolo_data_path, "labels")
|
| 76 |
+
os.makedirs(output_image_dir, exist_ok=True)
|
| 77 |
+
os.makedirs(output_annotation_dir, exist_ok=True)
|
| 78 |
+
|
| 79 |
+
# create the dataset YAML
|
| 80 |
+
yaml_dump = {"path": yolo_data_path, "names": loader.num_to_class}
|
| 81 |
+
|
| 82 |
+
# AgML indexes object detection datasets from 1 -> N, so reindex from 0 -> N-1
|
| 83 |
+
class_mapper = {i: i - 1 for i in yaml_dump["names"]}
|
| 84 |
+
yaml_dump["names"] = {i - 1: name for i, name in yaml_dump["names"].items()}
|
| 85 |
+
|
| 86 |
+
# get the height/width for all the images for normalization purposes
|
| 87 |
+
if loader.IS_MULTI_DATASET:
|
| 88 |
+
image_info = flatten(
|
| 89 |
+
[sub_loader._builder._default_coco_annotations["images"] for sub_loader in loader._loaders]
|
| 90 |
+
) # noqa
|
| 91 |
+
else:
|
| 92 |
+
image_info = loader._builder._default_coco_annotations["images"]
|
| 93 |
+
image_info = {image["file_name"]: (image["height"], image["width"]) for image in image_info}
|
| 94 |
+
|
| 95 |
+
# compatibility for content format for multi-dataset loaders
|
| 96 |
+
if not loader.IS_MULTI_DATASET:
|
| 97 |
+
loader_contents = {loader.name: loader.export_contents(export_format=None)}
|
| 98 |
+
else:
|
| 99 |
+
loader_contents = loader.export_contents(export_format=None)
|
| 100 |
+
|
| 101 |
+
# check for data splits and get a list of images in each split
|
| 102 |
+
all_split_images = {}
|
| 103 |
+
if loader._is_split_generated():
|
| 104 |
+
for split_name in ["train", "val", "test"]:
|
| 105 |
+
split_content = getattr(loader, f"_{split_name}_content")
|
| 106 |
+
if not loader.IS_MULTI_DATASET:
|
| 107 |
+
split_content = {loader.name: split_content}
|
| 108 |
+
|
| 109 |
+
# skip empty splits by checking the contents
|
| 110 |
+
if all(i is None for i in split_content.values()):
|
| 111 |
+
continue
|
| 112 |
+
|
| 113 |
+
split_images = flatten(
|
| 114 |
+
[
|
| 115 |
+
[f"{curr_name}_{os.path.basename(image)}" for image in curr_split]
|
| 116 |
+
for curr_name, curr_split in split_content.items()
|
| 117 |
+
]
|
| 118 |
+
)
|
| 119 |
+
all_split_images[split_name] = split_images
|
| 120 |
+
else:
|
| 121 |
+
# if no split generated, put all in `train`
|
| 122 |
+
all_split_images["train"] = flatten(
|
| 123 |
+
[
|
| 124 |
+
[f"{loader.name}_{os.path.basename(image)}" for image in curr_split]
|
| 125 |
+
for curr_split in loader_contents.values()
|
| 126 |
+
]
|
| 127 |
+
)
|
| 128 |
+
|
| 129 |
+
# write the text files containing the split contents
|
| 130 |
+
for split_name, split_images in all_split_images.items():
|
| 131 |
+
split_images = [os.path.join(output_image_dir, image) for image in split_images]
|
| 132 |
+
with open(os.path.join(yolo_data_path, f"{split_name}.txt"), "w") as f:
|
| 133 |
+
f.write("\n".join(split_images))
|
| 134 |
+
|
| 135 |
+
# update the YAML file with the corresponding locs of train/val/test
|
| 136 |
+
yaml_dump[split_name] = f"{split_name}.txt"
|
| 137 |
+
|
| 138 |
+
for loader_name, loader_content in loader_contents.items():
|
| 139 |
+
for image, annotation_set in loader_content.items():
|
| 140 |
+
# convert from the default AgML format (COCO: [x, y, w, h])
|
| 141 |
+
# to YOLO format: (normalized [x_center, y_center, w, h])
|
| 142 |
+
image_shape = image_info[os.path.basename(image)]
|
| 143 |
+
new_annotation_set = convert_annotations_to_yolo_list(annotation_set, image_shape, class_mapper)
|
| 144 |
+
text_content = "\n".join([" ".join(map(str, annotation)) for annotation in new_annotation_set])
|
| 145 |
+
|
| 146 |
+
# the name of the new image is {dataset_name}_{old_name}.{ext}
|
| 147 |
+
image_name = f"{loader_name}_{os.path.basename(image)}"
|
| 148 |
+
txt_name = os.path.splitext(image_name)[0] + ".txt"
|
| 149 |
+
|
| 150 |
+
# save the image and the text file
|
| 151 |
+
shutil.copy(image, os.path.join(output_image_dir, image_name))
|
| 152 |
+
with open(os.path.join(output_annotation_dir, txt_name), "w") as f:
|
| 153 |
+
f.write(text_content)
|
| 154 |
+
|
| 155 |
+
# write the dataset.yaml file
|
| 156 |
+
os.makedirs(os.path.join(yolo_path, "data"), exist_ok=True)
|
| 157 |
+
with open(os.path.join(yolo_path, "data", "dataset.yaml"), "w") as f:
|
| 158 |
+
yaml.safe_dump(yaml_dump, f)
|
| 159 |
+
|
| 160 |
+
# log information about the dataset location
|
| 161 |
+
information = """
|
| 162 |
+
Dataset successfully exported to YOLO format.
|
| 163 |
+
|
| 164 |
+
You can find the dataset at the following location: {0}
|
| 165 |
+
The dataset metadata is stored at {1}
|
| 166 |
+
""".format(yolo_data_path, os.path.join(yolo_path, "data", "dataset.yaml"))
|
| 167 |
+
log(information)
|
| 168 |
+
|
| 169 |
+
return {
|
| 170 |
+
"dataset_path": yolo_data_path,
|
| 171 |
+
"metadata_path": os.path.join(yolo_path, "data", "dataset.yaml"),
|
| 172 |
+
}
|
AgML/source/agml/data/extensions/__init__.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 UC Davis Plant AI and Biophysics Lab
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from .cvat import restructure_cvat_annotations
|
AgML/source/agml/data/extensions/cvat.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 UC Davis Plant AI and Biophysics Lab
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
import json
|
| 16 |
+
import os
|
| 17 |
+
import shutil
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def restructure_cvat_annotations(image_dir, cvat_dir, dataset_name, output_dir=None):
|
| 21 |
+
"""
|
| 22 |
+
Restructure CVAT annotations and images into the AgML dataset format.
|
| 23 |
+
|
| 24 |
+
Parameters
|
| 25 |
+
----------
|
| 26 |
+
image_dir : str
|
| 27 |
+
Path to the directory containing the images
|
| 28 |
+
cvat_dir : str
|
| 29 |
+
Path to the directory containing the CVAT annotations
|
| 30 |
+
dataset_name : str
|
| 31 |
+
Name of the new dataset
|
| 32 |
+
output_dir : str
|
| 33 |
+
Directory where the dataset will be saved. By default, saves to `~/.agml/datasets`
|
| 34 |
+
|
| 35 |
+
Returns
|
| 36 |
+
-------
|
| 37 |
+
The path to the dataset
|
| 38 |
+
"""
|
| 39 |
+
image_dir = os.path.expanduser(image_dir)
|
| 40 |
+
cvat_dir = os.path.expanduser(cvat_dir)
|
| 41 |
+
|
| 42 |
+
# Determine the dataset path
|
| 43 |
+
if output_dir is None:
|
| 44 |
+
import agml.backend # Ensure that agml is imported
|
| 45 |
+
|
| 46 |
+
dataset_path = os.path.join(agml.backend.data_save_path(), dataset_name)
|
| 47 |
+
else:
|
| 48 |
+
dataset_path = os.path.join(output_dir, dataset_name)
|
| 49 |
+
|
| 50 |
+
images_output_dir = os.path.join(dataset_path, "images")
|
| 51 |
+
os.makedirs(images_output_dir, exist_ok=True)
|
| 52 |
+
|
| 53 |
+
# Copy images to the new dataset directory
|
| 54 |
+
for image_file in os.listdir(image_dir):
|
| 55 |
+
src_image_path = os.path.join(image_dir, image_file)
|
| 56 |
+
dst_image_path = os.path.join(images_output_dir, image_file)
|
| 57 |
+
shutil.copy2(src_image_path, dst_image_path)
|
| 58 |
+
|
| 59 |
+
# Load the CVAT annotations
|
| 60 |
+
cvat_annotations_path = os.path.join(cvat_dir, "instances_default.json")
|
| 61 |
+
with open(cvat_annotations_path, "r") as f:
|
| 62 |
+
coco = json.load(f)
|
| 63 |
+
|
| 64 |
+
# Build a mapping from base image names to actual filenames (with extensions)
|
| 65 |
+
image_files = os.listdir(image_dir)
|
| 66 |
+
base_name_to_file_name = {}
|
| 67 |
+
for file_name in image_files:
|
| 68 |
+
base_name, ext = os.path.splitext(file_name)
|
| 69 |
+
base_name_to_file_name[base_name] = file_name
|
| 70 |
+
|
| 71 |
+
# Update the 'file_name' field in each image entry to match the actual filenames
|
| 72 |
+
for image in coco.get("images", []):
|
| 73 |
+
original_file_name = image["file_name"]
|
| 74 |
+
base_name, _ = os.path.splitext(original_file_name)
|
| 75 |
+
actual_file_name = base_name_to_file_name.get(base_name)
|
| 76 |
+
|
| 77 |
+
if actual_file_name:
|
| 78 |
+
image["file_name"] = actual_file_name
|
| 79 |
+
else:
|
| 80 |
+
print(f"Warning: No matching image file found for '{original_file_name}'.")
|
| 81 |
+
# Optionally, handle this case as needed (e.g., remove the image from the list)
|
| 82 |
+
|
| 83 |
+
# Save the updated annotations to 'annotations.json' in the new dataset directory
|
| 84 |
+
annotations_output_path = os.path.join(dataset_path, "annotations.json")
|
| 85 |
+
with open(annotations_output_path, "w") as f:
|
| 86 |
+
json.dump(coco, f)
|
| 87 |
+
|
| 88 |
+
print(f"Dataset '{dataset_name}' has been created successfully at '{dataset_path}'.")
|