megadetector 5.0.24__tar.gz → 5.0.26__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of megadetector might be problematic. Click here for more details.
- {megadetector-5.0.24/megadetector.egg-info → megadetector-5.0.26}/PKG-INFO +6 -3
- {megadetector-5.0.24 → megadetector-5.0.26}/README-package.md +2 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/README.md +12 -8
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/cct_json_utils.py +15 -2
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/coco_to_yolo.py +53 -31
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/databases/combine_coco_camera_traps_files.py +7 -3
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/databases/integrity_check_json_db.py +2 -2
- megadetector-5.0.26/megadetector/data_management/lila/add_locations_to_island_camera_traps.py +101 -0
- megadetector-5.0.26/megadetector/data_management/lila/add_locations_to_nacti.py +151 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/lila/generate_lila_per_image_labels.py +2 -2
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/lila/test_lila_metadata_urls.py +21 -10
- megadetector-5.0.26/megadetector/data_management/remap_coco_categories.py +133 -0
- megadetector-5.0.24/megadetector/data_management/wi_to_md.py → megadetector-5.0.26/megadetector/data_management/speciesnet_to_md.py +2 -2
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/yolo_to_coco.py +45 -15
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/detection/run_detector.py +1 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/detection/run_detector_batch.py +5 -4
- megadetector-5.0.26/megadetector/postprocessing/classification_postprocessing.py +980 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/compare_batch_results.py +176 -9
- megadetector-5.0.26/megadetector/postprocessing/create_crop_folder.py +420 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/load_api_results.py +4 -1
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/md_to_coco.py +1 -1
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/postprocess_batch_results.py +158 -44
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py +3 -8
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +2 -2
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/separate_detections_into_folders.py +20 -4
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/subset_json_detector_output.py +180 -15
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/validate_batch_results.py +13 -5
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/taxonomy_mapping/map_new_lila_datasets.py +6 -6
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/taxonomy_mapping/preview_lila_taxonomy.py +3 -58
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/taxonomy_mapping/species_lookup.py +45 -2
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/utils/ct_utils.py +76 -3
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/utils/directory_listing.py +4 -4
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/utils/gpu_test.py +21 -3
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/utils/md_tests.py +142 -49
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/utils/path_utils.py +342 -19
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/utils/wi_utils.py +1286 -212
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/visualization/visualization_utils.py +16 -4
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/visualization/visualize_db.py +1 -1
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/visualization/visualize_detector_output.py +1 -4
- {megadetector-5.0.24 → megadetector-5.0.26/megadetector.egg-info}/PKG-INFO +6 -3
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector.egg-info/SOURCES.txt +2 -1
- {megadetector-5.0.24 → megadetector-5.0.26}/pyproject.toml +2 -3
- megadetector-5.0.24/megadetector/data_management/lila/add_locations_to_island_camera_traps.py +0 -97
- megadetector-5.0.24/megadetector/data_management/lila/add_locations_to_nacti.py +0 -147
- megadetector-5.0.24/megadetector/data_management/remap_coco_categories.py +0 -84
- megadetector-5.0.24/megadetector/postprocessing/classification_postprocessing.py +0 -716
- {megadetector-5.0.24 → megadetector-5.0.26}/LICENSE +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/api_core/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/api_core/batch_service/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/api_core/batch_service/score.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/api_core/server.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/api_core/server_api_config.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/api_core/server_app_config.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/api_core/server_batch_job_manager.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/api_core/server_job_status_table.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/api_core/server_orchestration.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/api_core/server_utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/api_core_support/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/api_core_support/aggregate_results_manually.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/api_support/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/api_support/summarize_daily_activity.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/data_preparation/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/integration/digiKam/setup.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/integration/digiKam/xmp_integration.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/integration/eMammal/test_scripts/config_template.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/synchronous/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/synchronous/api_core/animal_detection_api/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/synchronous/api_core/animal_detection_api/api_backend.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/synchronous/api_core/animal_detection_api/api_frontend.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/synchronous/api_core/animal_detection_api/config.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/synchronous/api_core/tests/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/api/synchronous/api_core/tests/load_test.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/aggregate_classifier_probs.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/analyze_failed_images.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/cache_batchapi_outputs.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/create_classification_dataset.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/crop_detections.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/csv_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/detect_and_crop.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/efficientnet/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/efficientnet/model.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/efficientnet/utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/evaluate_model.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/identify_mislabeled_candidates.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/json_to_azcopy_list.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/json_validator.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/map_classification_categories.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/merge_classification_detection_output.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/prepare_classification_script.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/prepare_classification_script_mc.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/run_classifier.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/save_mislabeled.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/train_classifier.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/train_classifier_tf.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/classification/train_utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/annotations/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/annotations/annotation_constants.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/camtrap_dp_to_coco.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/cct_to_md.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/cct_to_wi.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/coco_to_labelme.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/databases/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/databases/add_width_and_height_to_db.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/databases/subset_json_db.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/generate_crops_from_cct.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/get_image_sizes.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/add_nacti_sizes.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/add_timestamps_to_icct.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/animl_results_to_md_results.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/auckland_doc_test_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/auckland_doc_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/awc_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/bellevue_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/cacophony-thermal-importer.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/carrizo_shrubfree_2018.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/carrizo_trail_cam_2017.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/cct_field_adjustments.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/channel_islands_to_cct.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/eMammal/copy_and_unzip_emammal.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/eMammal/eMammal_helpers.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/eMammal/make_eMammal_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/ena24_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/filenames_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/helena_to_cct.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/idaho-camera-traps.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/idfg_iwildcam_lila_prep.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/import_desert_lion_conservation_camera_traps.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/jb_csv_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/mcgill_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/missouri_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/nacti_fieldname_adjustments.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/noaa_seals_2019.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/osu-small-animals-to-json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/pc_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/plot_wni_giraffes.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/prepare_zsl_imerit.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/raic_csv_to_md_results.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/rspb_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/save_the_elephants_survey_A.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/save_the_elephants_survey_B.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/snapshot_safari_importer.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/snapshot_serengeti_lila.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/snapshotserengeti/make_full_SS_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/snapshotserengeti/make_per_season_SS_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/sulross_get_exif.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/timelapse_csv_set_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/ubc_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/umn_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/wellington_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/wi_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/importers/zamba_results_to_md_results.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/labelme_to_coco.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/labelme_to_yolo.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/lila/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/lila/create_lila_blank_set.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/lila/create_lila_test_set.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/lila/create_links_to_md_results_files.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/lila/download_lila_subset.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/lila/get_lila_annotation_counts.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/lila/get_lila_image_counts.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/lila/lila_common.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/mewc_to_md.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/ocr_tools.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/read_exif.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/remove_exif.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/rename_images.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/resize_coco_dataset.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/wi_download_csv_to_coco.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/data_management/yolo_output_to_md_output.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/detection/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/detection/process_video.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/detection/pytorch_detector.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/detection/run_inference_with_yolov5_val.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/detection/run_tiled_inference.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/detection/tf_detector.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/detection/video_utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/add_max_conf.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/categorize_detections_by_size.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/combine_batch_outputs.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/convert_output_format.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/detector_calibration.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/md_to_labelme.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/md_to_wi.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/merge_detections.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/remap_detection_categories.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/render_detection_confusion_matrix.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/postprocessing/top_folders_to_bottom.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/taxonomy_mapping/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/taxonomy_mapping/retrieve_sample_image.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/taxonomy_mapping/simple_image_download.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/taxonomy_mapping/taxonomy_csv_checker.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/taxonomy_mapping/taxonomy_graph.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/taxonomy_mapping/validate_lila_category_mappings.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/utils/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/utils/azure_utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/utils/process_utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/utils/sas_blob_utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/utils/split_locations_into_train_val.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/utils/string_utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/utils/url_utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/utils/write_html_image_list.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/visualization/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/visualization/plot_utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector/visualization/render_images_with_thumbnails.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector.egg-info/dependency_links.txt +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector.egg-info/requires.txt +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/megadetector.egg-info/top_level.txt +0 -0
- {megadetector-5.0.24 → megadetector-5.0.26}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: megadetector
|
|
3
|
-
Version: 5.0.
|
|
3
|
+
Version: 5.0.26
|
|
4
4
|
Summary: MegaDetector is an AI model that helps conservation folks spend less time doing boring things with camera trap images.
|
|
5
5
|
Author-email: Your friendly neighborhood MegaDetector team <cameratraps@lila.science>
|
|
6
6
|
Maintainer-email: Your friendly neighborhood MegaDetector team <cameratraps@lila.science>
|
|
@@ -30,7 +30,7 @@ Project-URL: Bug Reports, https://github.com/agentmorris/MegaDetector/issues
|
|
|
30
30
|
Project-URL: Source, https://github.com/agentmorris/MegaDetector
|
|
31
31
|
Keywords: camera traps,conservation,wildlife,ai,megadetector
|
|
32
32
|
Classifier: Programming Language :: Python :: 3
|
|
33
|
-
Requires-Python:
|
|
33
|
+
Requires-Python: <3.14,>=3.9
|
|
34
34
|
Description-Content-Type: text/markdown
|
|
35
35
|
License-File: LICENSE
|
|
36
36
|
Requires-Dist: mkl==2024.0; sys_platform != "darwin"
|
|
@@ -51,6 +51,7 @@ Requires-Dist: dill
|
|
|
51
51
|
Requires-Dist: ultralytics-yolov5==0.1.1
|
|
52
52
|
Requires-Dist: yolov9pip==0.0.4
|
|
53
53
|
Requires-Dist: python-dateutil
|
|
54
|
+
Dynamic: license-file
|
|
54
55
|
|
|
55
56
|
# MegaDetector
|
|
56
57
|
|
|
@@ -58,6 +59,8 @@ This package is a pip-installable version of the support/inference code for [Meg
|
|
|
58
59
|
|
|
59
60
|
If you aren't looking for the Python package specifically, and you just want to learn more about what MegaDetector is all about, head over to the [MegaDetector repo](https://github.com/agentmorris/MegaDetector/?tab=readme-ov-file#megadetector).
|
|
60
61
|
|
|
62
|
+
If you don't want to run MegaDetector, and you just want to use the utilities in this package - postprocessing, manipulating large volumes of camera trap images, etc. - you may want to check out the [megadetector-utils](https://pypi.org/project/megadetector-utils/) package, which is identical to this one, but excludes all of the PyTorch/YOLO dependencies, and is thus approximately one zillion times smaller.
|
|
63
|
+
|
|
61
64
|
## Installation
|
|
62
65
|
|
|
63
66
|
Install with:
|
|
@@ -4,6 +4,8 @@ This package is a pip-installable version of the support/inference code for [Meg
|
|
|
4
4
|
|
|
5
5
|
If you aren't looking for the Python package specifically, and you just want to learn more about what MegaDetector is all about, head over to the [MegaDetector repo](https://github.com/agentmorris/MegaDetector/?tab=readme-ov-file#megadetector).
|
|
6
6
|
|
|
7
|
+
If you don't want to run MegaDetector, and you just want to use the utilities in this package - postprocessing, manipulating large volumes of camera trap images, etc. - you may want to check out the [megadetector-utils](https://pypi.org/project/megadetector-utils/) package, which is identical to this one, but excludes all of the PyTorch/YOLO dependencies, and is thus approximately one zillion times smaller.
|
|
8
|
+
|
|
7
9
|
## Installation
|
|
8
10
|
|
|
9
11
|
Install with:
|
|
@@ -10,12 +10,16 @@
|
|
|
10
10
|
5. [Repo contents](#repo-contents)
|
|
11
11
|
6. [Contact](#contact)
|
|
12
12
|
7. [Gratuitous camera trap picture](#gratuitous-camera-trap-picture)
|
|
13
|
+
8. [License](#license)
|
|
14
|
+
9. [Contributing](#contributing)
|
|
13
15
|
|
|
14
16
|
|
|
15
17
|
## What's MegaDetector all about?
|
|
16
18
|
|
|
17
19
|
[MegaDetector](megadetector.md) is an AI model that identifies animals, people, and vehicles in camera trap images (which also makes it useful for eliminating blank images). This model is trained on several million images from a variety of ecosystems.
|
|
18
20
|
|
|
21
|
+
MegaDetector only finds animals, it doesn't identify them to species level. If you're looking for a species classifier, check out [SpeciesNet](https://github.com/google/cameratrapai), a species classifier that plays nicely with MegaDetector.
|
|
22
|
+
|
|
19
23
|
Here's a “teaser” image of what MegaDetector output looks like:
|
|
20
24
|
|
|
21
25
|
<br/>Image credit University of Washington.
|
|
@@ -27,7 +31,7 @@ Here's a “teaser” image of what MegaDetector output looks like:
|
|
|
27
31
|
* If you're just <i>considering</i> the use of AI in your workflow, and you aren't even sure yet whether MegaDetector would be useful to you, we recommend reading the "[getting started with MegaDetector](getting-started.md)" page.
|
|
28
32
|
* If you're already familiar with MegaDetector and you're ready to run it on your data, see the [MegaDetector User Guide](megadetector.md) for instructions on running MegaDetector.
|
|
29
33
|
* If you're a programmer-type looking to use tools from this repo, check out the [MegaDetector Python package](https://pypi.org/project/megadetector/) that provides access to everything in this repo (yes, you guessed it, "pip install megadetector").
|
|
30
|
-
* If you have any questions, or you want to tell us that MegaDetector was amazing/terrible on your images, <a href="mailto:cameratraps@lila.science">email us</a>!
|
|
34
|
+
* If you have any questions, or you want to tell us that MegaDetector was amazing/terrible on your images, or you have a zillion images and you want some help digging out of that backlog, <a href="mailto:cameratraps@lila.science">email us</a>!
|
|
31
35
|
|
|
32
36
|
MegaDetector is just one of many tools that aims to make conservation biologists more efficient with AI. If you want to learn about other ways to use AI to accelerate camera trap workflows, check out our of the field, affectionately titled “[Everything I know about machine learning and camera traps](https://agentmorris.github.io/camera-trap-ml-survey/)”.
|
|
33
37
|
|
|
@@ -45,9 +49,9 @@ Here are a few of the organizations that have used MegaDetector... we're only li
|
|
|
45
49
|
* [Canadian Parks and Wilderness Society (CPAWS) Northern Alberta Chapter](https://cpawsnab.org/)
|
|
46
50
|
* [Conservation X Labs](https://conservationxlabs.com/)
|
|
47
51
|
* [Czech University of Life Sciences Prague](https://www.czu.cz/en)
|
|
48
|
-
* [Dudek Camera Trap AI Image Toolkit (AIT)](https://dudek.com/
|
|
52
|
+
* [Dudek Camera Trap AI Image Toolkit (AIT)](https://ait.dudek.com/)
|
|
49
53
|
* [EcoLogic Consultants Ltd.](https://www.consult-ecologic.com/)
|
|
50
|
-
* [Estación Biológica de Doñana](
|
|
54
|
+
* [Estación Biológica de Doñana](https://www.ebd.csic.es/)
|
|
51
55
|
* [Indigenous Desert Alliance](https://www.indigenousdesertalliance.com/)
|
|
52
56
|
* [Myall Lakes Dingo Project](https://carnivorecoexistence.info/myall-lakes-dingo-project/)
|
|
53
57
|
* [Norwegian Institute for Nature Research](https://www.nina.no/english/Home)
|
|
@@ -84,7 +88,6 @@ Here are a few of the organizations that have used MegaDetector... we're only li
|
|
|
84
88
|
* [Department of Fish and Wildlife Sciences](https://www.uidaho.edu/cnr/departments/fish-and-wildlife-sciences), University of Idaho
|
|
85
89
|
* [Department of Society & Conservation](https://www.umt.edu/environment/about/departments/socon/), W.A. Franke College of Forestry & Conservation, University of Montana
|
|
86
90
|
* [Department of Wildlife Ecology and Conservation](https://wec.ifas.ufl.edu/), University of Florida
|
|
87
|
-
* [Ecology and Conservation of Amazonian Vertebrates Research Group](https://www.researchgate.net/lab/Fernanda-Michalski-Lab-4), Federal University of Amapá
|
|
88
91
|
* [Gola Forest Programme](https://www.rspb.org.uk/our-work/conservation/projects/scientific-support-for-the-gola-forest-programme/), Royal Society for the Protection of Birds (RSPB)
|
|
89
92
|
* [Graeme Shannon's Research Group](https://wildliferesearch.co.uk/group-1), Bangor University
|
|
90
93
|
* [Grizzly Bear Recovery Program](https://www.fws.gov/office/grizzly-bear-recovery-program), U.S. Fish & Wildlife Service
|
|
@@ -102,12 +105,13 @@ Here are a few of the organizations that have used MegaDetector... we're only li
|
|
|
102
105
|
* [Santa Monica Mountains Recreation Area](https://www.nps.gov/samo/index.htm), National Park Service
|
|
103
106
|
* [Seattle Urban Carnivore Project](https://www.zoo.org/seattlecarnivores), Woodland Park Zoo
|
|
104
107
|
* [Serra dos Órgãos National Park](https://www.icmbio.gov.br/parnaserradosorgaos/), ICMBio
|
|
105
|
-
* [Snapshot USA](https://
|
|
108
|
+
* [Snapshot USA](https://www.snapshot-usa.org/), Smithsonian
|
|
106
109
|
* [TROPECOLNET project](https://www.anabenitezlopez.com/research/global-change-biology/tropecolnet/), Museo Nacional de Ciencias Naturales
|
|
107
110
|
* [Wildlife Coexistence Lab](https://wildlife.forestry.ubc.ca/), University of British Columbia
|
|
108
111
|
* [Wildlife Research](https://www.dfw.state.or.us/wildlife/research/index.asp), Oregon Department of Fish and Wildlife
|
|
109
112
|
* [Wildlife Division](https://www.michigan.gov/dnr/about/contact/wildlife), Michigan Department of Natural Resources
|
|
110
113
|
* [Kohl Wildlife Lab](https://kohlwildlifelab.com/), University of Georgia
|
|
114
|
+
* Ecology and Conservation of Amazonian Vertebrates Research Group, Federal University of Amapá
|
|
111
115
|
* Department of Ecology, TU Berlin
|
|
112
116
|
* Ghost Cat Analytics
|
|
113
117
|
* Protected Areas Unit, Canadian Wildlife Service
|
|
@@ -132,7 +136,7 @@ Here are a few of the organizations that have used MegaDetector... we're only li
|
|
|
132
136
|
* [BirdLife Malta](https://birdlifemalta.org/) ([tweet](https://x.com/BirdLife_Malta/status/1817456839862173783?t=S-KRiZ5R1-CoW8-tbYNjqQ&s=03)) ([LI post](https://www.linkedin.com/posts/birdlifemalta_worldnatureconservationday-shearwater-colony-activity-7223220656589463553-X2Mc/?utm_source=share&utm_medium=member_android))
|
|
133
137
|
* [Endangered Landscapes and Seascapes Programme](https://www.endangeredlandscapes.org/), Cambridge Conservation Initiative ([blog post](https://www.endangeredlandscapes.org/news/ai-for-wildlife-monitoring-a-real-time-alert-system-for-bears-and-wild-boars-in-romanias-carpathian-mountains/))
|
|
134
138
|
|
|
135
|
-
* [Road Ecology Center](https://roadecology.ucdavis.edu/), University of California, Davis ([Wildlife Observer Network platform](https://
|
|
139
|
+
* [Road Ecology Center](https://roadecology.ucdavis.edu/), University of California, Davis ([Wildlife Observer Network platform](https://roadecology.ucdavis.edu/research/projects/wildlife-observer-network))
|
|
136
140
|
* [The Nature Conservancy in California](https://www.nature.org/en-us/about-us/where-we-work/united-states/california/) ([Animl platform](https://github.com/tnc-ca-geo/animl-frontend)) ([story](https://www.vision-systems.com/non-factory/environment-agriculture/article/14304433/the-nature-conservancy-brings-cameras-ai-to-invasive-species-prevention))
|
|
137
141
|
* [San Diego Zoo Wildlife Alliance](https://science.sandiegozoo.org/) ([Animl R package](https://github.com/conservationtechlab/animl))
|
|
138
142
|
* [TerrOïko](https://www.terroiko.fr/) ([OCAPI platform](https://www.terroiko.fr/ocapi))
|
|
@@ -202,9 +206,9 @@ Code for hosting our models as an API, either for synchronous operation (i.e., f
|
|
|
202
206
|
|
|
203
207
|
#### megadetector/classification
|
|
204
208
|
|
|
205
|
-
|
|
209
|
+
This folder is largely deprecated thanks to the release of [SpeciesNet](https://github.com/google/cameratrapai), a species classifier that is better than any of the classifiers we ever trained with the stuff in this folder. That said, this folder contains code for training species classifiers on new data sets, generally trained on MegaDetector crops.
|
|
206
210
|
|
|
207
|
-
|
|
211
|
+
Here's another "teaser image" of what you get at the end of training and running a classifier:
|
|
208
212
|
|
|
209
213
|
<img src="images/warthog_classifications.jpg" width="700"><br/>Image credit University of Minnesota, from the Snapshot Safari program.
|
|
210
214
|
|
|
@@ -300,7 +300,10 @@ class SequenceOptions:
|
|
|
300
300
|
def __init__(self):
|
|
301
301
|
#: Images separated by <= this duration will be grouped into the same sequence.
|
|
302
302
|
self.episode_interval_seconds = 60.0
|
|
303
|
-
|
|
303
|
+
|
|
304
|
+
#: How to handle invalid datetimes: 'error' or 'none'
|
|
305
|
+
self.datetime_conversion_failure_behavior = 'none'
|
|
306
|
+
|
|
304
307
|
|
|
305
308
|
#%% Functions
|
|
306
309
|
|
|
@@ -445,7 +448,17 @@ def create_sequences(image_info,options=None):
|
|
|
445
448
|
raise ValueError('Unrecognized type for [image_info]')
|
|
446
449
|
|
|
447
450
|
# Modifies the images in place
|
|
448
|
-
_ = parse_datetimes_from_cct_image_list(image_info
|
|
451
|
+
_ = parse_datetimes_from_cct_image_list(image_info,
|
|
452
|
+
conversion_failure_behavior=options.datetime_conversion_failure_behavior)
|
|
453
|
+
|
|
454
|
+
n_invalid_datetimes = 0
|
|
455
|
+
for im in image_info:
|
|
456
|
+
if not isinstance(im['datetime'],datetime.datetime):
|
|
457
|
+
assert im['datetime'] is None, 'At this point, datetimes should be valid or None'
|
|
458
|
+
n_invalid_datetimes += 1
|
|
459
|
+
if n_invalid_datetimes > 0:
|
|
460
|
+
print('Warning: {} of {} images have invalid datetimes'.format(
|
|
461
|
+
n_invalid_datetimes,len(image_info)))
|
|
449
462
|
|
|
450
463
|
# Find all unique locations
|
|
451
464
|
locations = set()
|
|
@@ -47,6 +47,9 @@ def write_yolo_dataset_file(yolo_dataset_file,
|
|
|
47
47
|
class_list (list or str): an ordered list of class names (the first item will be class 0,
|
|
48
48
|
etc.), or the name of a text file containing an ordered list of class names (one per
|
|
49
49
|
line, starting from class zero).
|
|
50
|
+
train_folder_relative (str, optional): train folder name, used only to populate dataset.yaml
|
|
51
|
+
val_folder_relative (str, optional): val folder name, used only to populate dataset.yaml
|
|
52
|
+
test_folder_relative (str, optional): test folder name, used only to populate dataset.yaml
|
|
50
53
|
"""
|
|
51
54
|
|
|
52
55
|
# Read class names
|
|
@@ -97,7 +100,7 @@ def coco_to_yolo(input_image_folder,
|
|
|
97
100
|
category_names_to_exclude=None,
|
|
98
101
|
category_names_to_include=None,
|
|
99
102
|
write_output=True,
|
|
100
|
-
flatten_paths=
|
|
103
|
+
flatten_paths=False):
|
|
101
104
|
"""
|
|
102
105
|
Converts a COCO-formatted dataset to a YOLO-formatted dataset, optionally flattening the
|
|
103
106
|
dataset to a single folder in the process.
|
|
@@ -116,17 +119,21 @@ def coco_to_yolo(input_image_folder,
|
|
|
116
119
|
images are left alone.
|
|
117
120
|
source_format (str, optional): can be 'coco' (default) or 'coco_camera_traps'. The only difference
|
|
118
121
|
is that when source_format is 'coco_camera_traps', we treat an image with a non-bbox
|
|
119
|
-
annotation
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
annotation as a special case, i.e. that's how an empty image is indicated. The original
|
|
123
|
+
COCO standard is a little ambiguous on this issue. If source_format is 'coco', we
|
|
124
|
+
either treat images as empty or error, depending on the value of [allow_empty_annotations].
|
|
125
|
+
[allow_empty_annotations] has no effect if source_format is 'coco_camera_traps'.
|
|
126
|
+
overwrite_images (bool, optional): over-write images in the output folder if they exist
|
|
124
127
|
create_image_and_label_folder (bool, optional): whether to create separate folders called 'images' and
|
|
125
128
|
'labels' in the YOLO output folder. If create_image_and_label_folders is False,
|
|
126
129
|
a/b/c/image001.jpg will become a#b#c#image001.jpg, and the corresponding text file will
|
|
127
130
|
be a#b#c#image001.txt. If create_image_and_label_folders is True, a/b/c/image001.jpg will become
|
|
128
131
|
images/a#b#c#image001.jpg, and the corresponding text file will be
|
|
129
132
|
labels/a#b#c#image001.txt.
|
|
133
|
+
class_file_name (str, optional): .txt file (relative to the output folder) that we should
|
|
134
|
+
populate with a list of classes (or None to omit)
|
|
135
|
+
allow_empty_annotations (bool, optional): if this is False and [source_format] is 'coco',
|
|
136
|
+
we'll error on annotations that have no 'bbox' field
|
|
130
137
|
clip_boxes (bool, optional): whether to clip bounding box coordinates to the range [0,1] before
|
|
131
138
|
converting to YOLO xywh format
|
|
132
139
|
image_id_to_output_image_json_file (str, optional): an optional *output* file, to which we will write
|
|
@@ -139,12 +146,14 @@ def coco_to_yolo(input_image_folder,
|
|
|
139
146
|
category_names_to_exclude (str, optional): category names that should not be represented in the
|
|
140
147
|
YOLO output; only impacts annotations, does not prevent copying images. There's almost no reason
|
|
141
148
|
you would want to specify this and [category_names_to_include].
|
|
142
|
-
category_names_to_include (str, optional): allow-list of category names that should be represented
|
|
143
|
-
YOLO output; only impacts annotations, does not prevent copying images. There's almost
|
|
144
|
-
you would want to specify this and [category_names_to_exclude].
|
|
149
|
+
category_names_to_include (str, optional): allow-list of category names that should be represented
|
|
150
|
+
in the YOLO output; only impacts annotations, does not prevent copying images. There's almost
|
|
151
|
+
no reason you would want to specify this and [category_names_to_exclude].
|
|
145
152
|
write_output (bool, optional): determines whether we actually copy images and write annotations;
|
|
146
153
|
setting this to False mostly puts this function in "dry run" "mode. The class list
|
|
147
154
|
file is written regardless of the value of write_output.
|
|
155
|
+
flatten_paths (bool, optional): replace /'s in image filenames with [path_replacement_char],
|
|
156
|
+
which ensures that the output folder is a single flat folder.
|
|
148
157
|
|
|
149
158
|
Returns:
|
|
150
159
|
dict: information about the coco --> yolo mapping, containing at least the fields:
|
|
@@ -313,9 +322,9 @@ def coco_to_yolo(input_image_folder,
|
|
|
313
322
|
|
|
314
323
|
elif source_format == 'coco_camera_traps':
|
|
315
324
|
|
|
316
|
-
# We allow empty bbox lists in COCO camera traps; this is typically a
|
|
317
|
-
# example in a dataset that has bounding boxes, and 0 is typically
|
|
318
|
-
# category.
|
|
325
|
+
# We allow empty bbox lists in COCO camera traps files; this is typically a
|
|
326
|
+
# negative example in a dataset that has bounding boxes, and 0 is typically
|
|
327
|
+
# the empty category, which is typically 0.
|
|
319
328
|
if ann['category_id'] != 0:
|
|
320
329
|
if not printed_empty_annotation_warning:
|
|
321
330
|
printed_empty_annotation_warning = True
|
|
@@ -429,13 +438,14 @@ def coco_to_yolo(input_image_folder,
|
|
|
429
438
|
|
|
430
439
|
print('Generating class list')
|
|
431
440
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
441
|
+
if class_file_name is not None:
|
|
442
|
+
class_list_filename = os.path.join(output_folder,class_file_name)
|
|
443
|
+
with open(class_list_filename, 'w') as f:
|
|
444
|
+
print('Writing class list to {}'.format(class_list_filename))
|
|
445
|
+
for i_class in range(0,len(yolo_id_to_name)):
|
|
446
|
+
# Category IDs should range from 0..N-1
|
|
447
|
+
assert i_class in yolo_id_to_name
|
|
448
|
+
f.write(yolo_id_to_name[i_class] + '\n')
|
|
439
449
|
|
|
440
450
|
if image_id_to_output_image_json_file is not None:
|
|
441
451
|
print('Writing image ID mapping to {}'.format(image_id_to_output_image_json_file))
|
|
@@ -457,6 +467,9 @@ def coco_to_yolo(input_image_folder,
|
|
|
457
467
|
|
|
458
468
|
source_image_to_dest_image = {}
|
|
459
469
|
|
|
470
|
+
label_files_written = []
|
|
471
|
+
n_boxes_written = 0
|
|
472
|
+
|
|
460
473
|
# TODO: parallelize this loop
|
|
461
474
|
#
|
|
462
475
|
# output_info = images_to_copy[0]
|
|
@@ -471,6 +484,7 @@ def coco_to_yolo(input_image_folder,
|
|
|
471
484
|
|
|
472
485
|
source_image_to_dest_image[source_image] = dest_image
|
|
473
486
|
|
|
487
|
+
# Copy the image if necessary
|
|
474
488
|
if write_output:
|
|
475
489
|
|
|
476
490
|
os.makedirs(os.path.dirname(dest_image),exist_ok=True)
|
|
@@ -482,17 +496,24 @@ def coco_to_yolo(input_image_folder,
|
|
|
482
496
|
if (not os.path.isfile(dest_image)) or (overwrite_images):
|
|
483
497
|
shutil.copyfile(source_image,dest_image)
|
|
484
498
|
|
|
485
|
-
|
|
499
|
+
bboxes = output_info['bboxes']
|
|
500
|
+
|
|
501
|
+
# Write the annotation file if necessary
|
|
502
|
+
#
|
|
503
|
+
# Only write an annotation file if there are bounding boxes. Images with
|
|
504
|
+
# no .txt files are treated as hard negatives, at least by YOLOv5:
|
|
505
|
+
#
|
|
506
|
+
# https://github.com/ultralytics/yolov5/issues/3218
|
|
507
|
+
#
|
|
508
|
+
# I think this is also true for images with empty .txt files, but
|
|
509
|
+
# I'm using the convention suggested on that issue, i.e. hard
|
|
510
|
+
# negatives are expressed as images without .txt files.
|
|
511
|
+
if len(bboxes) > 0:
|
|
486
512
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
#
|
|
492
|
-
# I think this is also true for images with empty .txt files, but
|
|
493
|
-
# I'm using the convention suggested on that issue, i.e. hard
|
|
494
|
-
# negatives are expressed as images without .txt files.
|
|
495
|
-
if len(bboxes) > 0:
|
|
513
|
+
n_boxes_written += len(bboxes)
|
|
514
|
+
label_files_written.append(dest_txt)
|
|
515
|
+
|
|
516
|
+
if write_output:
|
|
496
517
|
|
|
497
518
|
with open(dest_txt,'w') as f:
|
|
498
519
|
|
|
@@ -501,8 +522,7 @@ def coco_to_yolo(input_image_folder,
|
|
|
501
522
|
assert len(bbox) == 5
|
|
502
523
|
s = '{} {} {} {} {}'.format(bbox[0],bbox[1],bbox[2],bbox[3],bbox[4])
|
|
503
524
|
f.write(s + '\n')
|
|
504
|
-
|
|
505
|
-
# ...if we're actually writing output
|
|
525
|
+
|
|
506
526
|
|
|
507
527
|
# ...for each image
|
|
508
528
|
|
|
@@ -510,6 +530,8 @@ def coco_to_yolo(input_image_folder,
|
|
|
510
530
|
coco_to_yolo_info['class_list_filename'] = class_list_filename
|
|
511
531
|
coco_to_yolo_info['source_image_to_dest_image'] = source_image_to_dest_image
|
|
512
532
|
coco_to_yolo_info['coco_id_to_yolo_id'] = coco_id_to_yolo_id
|
|
533
|
+
coco_to_yolo_info['label_files_written'] = label_files_written
|
|
534
|
+
coco_to_yolo_info['n_boxes_written'] = n_boxes_written
|
|
513
535
|
|
|
514
536
|
return coco_to_yolo_info
|
|
515
537
|
|
|
@@ -24,8 +24,10 @@ import sys
|
|
|
24
24
|
|
|
25
25
|
#%% Merge functions
|
|
26
26
|
|
|
27
|
-
def combine_cct_files(input_files,
|
|
28
|
-
|
|
27
|
+
def combine_cct_files(input_files,
|
|
28
|
+
output_file=None,
|
|
29
|
+
require_uniqueness=True,
|
|
30
|
+
filename_prefixes=None):
|
|
29
31
|
"""
|
|
30
32
|
Merges the list of COCO Camera Traps files [input_files] into a single
|
|
31
33
|
dictionary, optionally writing the result to [output_file].
|
|
@@ -33,8 +35,10 @@ def combine_cct_files(input_files, output_file=None, require_uniqueness=True,
|
|
|
33
35
|
Args:
|
|
34
36
|
input_files (list): paths to CCT .json files
|
|
35
37
|
output_file (str, optional): path to write merged .json file
|
|
36
|
-
require_uniqueness (bool): whether to require that the images in
|
|
38
|
+
require_uniqueness (bool, optional): whether to require that the images in
|
|
37
39
|
each input_dict be unique
|
|
40
|
+
filename_prefixes (dict, optional): dict mapping input filenames to strings
|
|
41
|
+
that should be prepended to image filenames from that source
|
|
38
42
|
|
|
39
43
|
Returns:
|
|
40
44
|
dict: the merged COCO-formatted .json dict
|
|
@@ -327,7 +327,7 @@ def integrity_check_json_db(jsonFile, options=None):
|
|
|
327
327
|
|
|
328
328
|
for i_image,result in enumerate(results):
|
|
329
329
|
if result is not None:
|
|
330
|
-
validation_errors.append(images[i_image]['file_name'],result)
|
|
330
|
+
validation_errors.append((images[i_image]['file_name'],result))
|
|
331
331
|
|
|
332
332
|
# ...for each image
|
|
333
333
|
|
|
@@ -393,7 +393,7 @@ def integrity_check_json_db(jsonFile, options=None):
|
|
|
393
393
|
elif image['_count'] > 1:
|
|
394
394
|
nMultiAnnotated += 1
|
|
395
395
|
|
|
396
|
-
print('
|
|
396
|
+
print('\nFound {} unannotated images, {} images with multiple annotations'.format(
|
|
397
397
|
nUnannotated,nMultiAnnotated))
|
|
398
398
|
|
|
399
399
|
if (len(base_dir) > 0) and options.bFindUnusedImages:
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
add_locations_to_island_camera_traps.py
|
|
4
|
+
|
|
5
|
+
The Island Conservation Camera Traps dataset had unique camera identifiers embedded
|
|
6
|
+
in filenames, but not in the proper metadata fields. This script copies that information
|
|
7
|
+
to metadata.
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
#%% Imports and constants
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
import json
|
|
15
|
+
from tqdm import tqdm
|
|
16
|
+
|
|
17
|
+
input_fn = os.path.expanduser('~/lila/metadata/island_conservation.json')
|
|
18
|
+
output_fn = os.path.expanduser('~/tmp/island_conservation.json')
|
|
19
|
+
preview_folder = os.path.expanduser('~/tmp/island_conservation_preview')
|
|
20
|
+
image_directory = os.path.expanduser('~/data/icct/public/')
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
#%% Prevent imports during testing
|
|
24
|
+
|
|
25
|
+
if False:
|
|
26
|
+
|
|
27
|
+
#%% Read input file
|
|
28
|
+
|
|
29
|
+
with open(input_fn,'r') as f:
|
|
30
|
+
d = json.load(f)
|
|
31
|
+
|
|
32
|
+
d['info']
|
|
33
|
+
d['info']['version'] = '1.01'
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
#%% Find locations
|
|
37
|
+
|
|
38
|
+
images = d['images']
|
|
39
|
+
|
|
40
|
+
locations = set()
|
|
41
|
+
|
|
42
|
+
for i_image,im in tqdm(enumerate(images),total=len(images)):
|
|
43
|
+
tokens_fn = im['file_name'].split('/')
|
|
44
|
+
tokens_id = im['id'].split('_')
|
|
45
|
+
assert tokens_fn[0] == tokens_id[0]
|
|
46
|
+
assert tokens_fn[1] == tokens_id[1]
|
|
47
|
+
location = tokens_fn[0] + '_' + tokens_fn[1]
|
|
48
|
+
im['location'] = location
|
|
49
|
+
locations.add(location)
|
|
50
|
+
|
|
51
|
+
locations = sorted(list(locations))
|
|
52
|
+
|
|
53
|
+
for s in locations:
|
|
54
|
+
print(s)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
#%% Write output file
|
|
58
|
+
|
|
59
|
+
with open(output_fn,'w') as f:
|
|
60
|
+
json.dump(d,f,indent=1)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
#%% Validate .json files
|
|
64
|
+
|
|
65
|
+
from megadetector.data_management.databases import integrity_check_json_db
|
|
66
|
+
|
|
67
|
+
options = integrity_check_json_db.IntegrityCheckOptions()
|
|
68
|
+
options.baseDir = image_directory
|
|
69
|
+
options.bCheckImageSizes = False
|
|
70
|
+
options.bCheckImageExistence = True
|
|
71
|
+
options.bFindUnusedImages = True
|
|
72
|
+
|
|
73
|
+
sorted_categories, data, error_info = integrity_check_json_db.integrity_check_json_db(output_fn, options)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
#%% Preview labels
|
|
77
|
+
|
|
78
|
+
from megadetector.visualization import visualize_db
|
|
79
|
+
|
|
80
|
+
viz_options = visualize_db.DbVizOptions()
|
|
81
|
+
viz_options.num_to_visualize = 2000
|
|
82
|
+
viz_options.trim_to_images_with_bboxes = False
|
|
83
|
+
viz_options.add_search_links = False
|
|
84
|
+
viz_options.sort_by_filename = False
|
|
85
|
+
viz_options.parallelize_rendering = True
|
|
86
|
+
viz_options.classes_to_exclude = ['test']
|
|
87
|
+
html_output_file, image_db = visualize_db.visualize_db(db_path=output_fn,
|
|
88
|
+
output_dir=preview_folder,
|
|
89
|
+
image_base_dir=image_directory,
|
|
90
|
+
options=viz_options)
|
|
91
|
+
|
|
92
|
+
from megadetector.utils import path_utils
|
|
93
|
+
path_utils.open_file(html_output_file)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
#%% Zip output file
|
|
97
|
+
|
|
98
|
+
from megadetector.utils.path_utils import zip_file
|
|
99
|
+
|
|
100
|
+
zip_file(output_fn, verbose=True)
|
|
101
|
+
assert os.path.isfile(output_fn + '.zip')
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
add_locations_to_nacti.py
|
|
4
|
+
|
|
5
|
+
As of 10.2023, NACTI metadata only has very coarse location information (e.g. "Florida"),
|
|
6
|
+
but camera IDs are embedded in filenames. This script pulls that information from filenames
|
|
7
|
+
and adds it to metadata.
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
#%% Imports and constants
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
import json
|
|
15
|
+
import shutil
|
|
16
|
+
|
|
17
|
+
from tqdm import tqdm
|
|
18
|
+
from collections import defaultdict
|
|
19
|
+
|
|
20
|
+
input_file = r'd:\lila\nacti\nacti_metadata.json.1.13\nacti_metadata.json'
|
|
21
|
+
output_file = r'g:\temp\nacti_metadata.1.14.json'
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
#%% Prevent execution during testing
|
|
25
|
+
|
|
26
|
+
if False:
|
|
27
|
+
|
|
28
|
+
#%% Read metadata
|
|
29
|
+
|
|
30
|
+
with open(input_file,'r') as f:
|
|
31
|
+
d = json.load(f)
|
|
32
|
+
|
|
33
|
+
assert d['info']['version'] == 1.13
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
#%% Map images to locations (according to the metadata)
|
|
37
|
+
|
|
38
|
+
file_name_to_original_location = {}
|
|
39
|
+
|
|
40
|
+
# im = dataset_labels['images'][0]
|
|
41
|
+
for im in tqdm(d['images']):
|
|
42
|
+
file_name_to_original_location[im['file_name']] = im['location']
|
|
43
|
+
|
|
44
|
+
original_locations = set(file_name_to_original_location.values())
|
|
45
|
+
|
|
46
|
+
print('Found {} locations in the original metadata:'.format(len(original_locations)))
|
|
47
|
+
for loc in original_locations:
|
|
48
|
+
print('[{}]'.format(loc))
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
#%% Map images to new locations
|
|
52
|
+
|
|
53
|
+
def path_to_location(relative_path):
|
|
54
|
+
|
|
55
|
+
relative_path = relative_path.replace('\\','/')
|
|
56
|
+
if relative_path in file_name_to_original_location:
|
|
57
|
+
location_name = file_name_to_original_location[relative_path]
|
|
58
|
+
if location_name == 'San Juan Mntns, Colorado':
|
|
59
|
+
# "part0/sub000/2010_Unit150_Ivan097_img0003.jpg"
|
|
60
|
+
tokens = relative_path.split('/')[-1].split('_')
|
|
61
|
+
assert tokens[1].startswith('Unit')
|
|
62
|
+
location_name = 'sanjuan_{}_{}_{}'.format(tokens[0],tokens[1],tokens[2])
|
|
63
|
+
elif location_name == 'Lebec, California':
|
|
64
|
+
# "part0/sub035/CA-03_08_13_2015_CA-03_0009738.jpg"
|
|
65
|
+
tokens = relative_path.split('/')[-1].split('_')
|
|
66
|
+
assert tokens[0].startswith('CA-') or tokens[0].startswith('TAG-')
|
|
67
|
+
location_name = 'lebec_{}'.format(tokens[0])
|
|
68
|
+
elif location_name == 'Archbold, FL':
|
|
69
|
+
# "part1/sub110/FL-01_01_25_2016_FL-01_0040421.jpg"
|
|
70
|
+
tokens = relative_path.split('/')[-1].split('_')
|
|
71
|
+
assert tokens[0].startswith('FL-')
|
|
72
|
+
location_name = 'archbold_{}'.format(tokens[0])
|
|
73
|
+
else:
|
|
74
|
+
assert location_name == ''
|
|
75
|
+
tokens = relative_path.split('/')[-1].split('_')
|
|
76
|
+
if tokens[0].startswith('CA-') or tokens[0].startswith('TAG-') or tokens[0].startswith('FL-'):
|
|
77
|
+
location_name = '{}'.format(tokens[0])
|
|
78
|
+
|
|
79
|
+
else:
|
|
80
|
+
|
|
81
|
+
location_name = 'unknown'
|
|
82
|
+
|
|
83
|
+
# print('Returning location {} for file {}'.format(location_name,relative_path))
|
|
84
|
+
|
|
85
|
+
return location_name
|
|
86
|
+
|
|
87
|
+
file_name_to_updated_location = {}
|
|
88
|
+
updated_location_to_count = defaultdict(int)
|
|
89
|
+
for im in tqdm(d['images']):
|
|
90
|
+
|
|
91
|
+
updated_location = path_to_location(im['file_name'])
|
|
92
|
+
file_name_to_updated_location[im['file_name']] = updated_location
|
|
93
|
+
updated_location_to_count[updated_location] += 1
|
|
94
|
+
|
|
95
|
+
updated_location_to_count = {k: v for k, v in sorted(updated_location_to_count.items(),
|
|
96
|
+
key=lambda item: item[1],
|
|
97
|
+
reverse=True)}
|
|
98
|
+
|
|
99
|
+
updated_locations = set(file_name_to_updated_location.values())
|
|
100
|
+
|
|
101
|
+
print('Found {} updated locations in the original metadata:'.format(len(updated_locations)))
|
|
102
|
+
for loc in updated_location_to_count:
|
|
103
|
+
print('{}: {}'.format(loc,updated_location_to_count[loc]))
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
#%% Re-write metadata
|
|
107
|
+
|
|
108
|
+
for im in d['images']:
|
|
109
|
+
im['location'] = file_name_to_updated_location[im['file_name']]
|
|
110
|
+
d['info']['version'] = 1.14
|
|
111
|
+
|
|
112
|
+
with open(output_file,'w') as f:
|
|
113
|
+
json.dump(d,f,indent=1)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
#%% For each location, sample some random images to make sure they look consistent
|
|
117
|
+
|
|
118
|
+
input_base = r'd:\lila\nacti-unzipped'
|
|
119
|
+
assert os.path.isdir(input_base)
|
|
120
|
+
|
|
121
|
+
location_to_images = defaultdict(list)
|
|
122
|
+
|
|
123
|
+
for im in d['images']:
|
|
124
|
+
location_to_images[im['location']].append(im)
|
|
125
|
+
|
|
126
|
+
n_to_sample = 10
|
|
127
|
+
import random
|
|
128
|
+
random.seed(0)
|
|
129
|
+
sampling_folder_base = r'g:\temp\nacti_samples'
|
|
130
|
+
|
|
131
|
+
for location in tqdm(location_to_images):
|
|
132
|
+
|
|
133
|
+
images_this_location = location_to_images[location]
|
|
134
|
+
if len(images_this_location) > n_to_sample:
|
|
135
|
+
images_this_location = random.sample(images_this_location,n_to_sample)
|
|
136
|
+
|
|
137
|
+
for i_image,im in enumerate(images_this_location):
|
|
138
|
+
|
|
139
|
+
fn_relative = im['file_name']
|
|
140
|
+
source_fn_abs = os.path.join(input_base,fn_relative)
|
|
141
|
+
assert os.path.isfile(source_fn_abs)
|
|
142
|
+
ext = os.path.splitext(fn_relative)[1]
|
|
143
|
+
target_fn_abs = os.path.join(sampling_folder_base,'{}/{}'.format(
|
|
144
|
+
location,'image_{}{}'.format(str(i_image).zfill(2),ext)))
|
|
145
|
+
os.makedirs(os.path.dirname(target_fn_abs),exist_ok=True)
|
|
146
|
+
shutil.copyfile(source_fn_abs,target_fn_abs)
|
|
147
|
+
|
|
148
|
+
# ...for each image
|
|
149
|
+
|
|
150
|
+
# ...for each location
|
|
151
|
+
|
|
@@ -349,7 +349,7 @@ with open(output_file,'w',encoding='utf-8',newline='') as f:
|
|
|
349
349
|
|
|
350
350
|
# ...with open()
|
|
351
351
|
|
|
352
|
-
print('
|
|
352
|
+
print('\nProcessed {} datasets'.format(len(metadata_table)))
|
|
353
353
|
|
|
354
354
|
|
|
355
355
|
#%% Read the .csv back
|
|
@@ -393,7 +393,7 @@ def check_row(row):
|
|
|
393
393
|
dataset_name_to_locations[ds_name].add(row['location_id'])
|
|
394
394
|
|
|
395
395
|
# Faster, but more annoying to debug
|
|
396
|
-
if
|
|
396
|
+
if True:
|
|
397
397
|
|
|
398
398
|
df.progress_apply(check_row, axis=1)
|
|
399
399
|
|