megadetector 5.0.24__tar.gz → 5.0.25__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.25}/PKG-INFO +3 -1
- {megadetector-5.0.24 → megadetector-5.0.25}/README-package.md +2 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/README.md +12 -8
- megadetector-5.0.25/megadetector/data_management/lila/add_locations_to_island_camera_traps.py +101 -0
- megadetector-5.0.25/megadetector/data_management/lila/add_locations_to_nacti.py +151 -0
- megadetector-5.0.24/megadetector/data_management/wi_to_md.py → megadetector-5.0.25/megadetector/data_management/speciesnet_to_md.py +2 -2
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/detection/run_detector.py +1 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/detection/run_detector_batch.py +5 -4
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/compare_batch_results.py +176 -9
- megadetector-5.0.25/megadetector/postprocessing/create_crop_folder.py +358 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/postprocess_batch_results.py +2 -2
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/ct_utils.py +72 -1
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/directory_listing.py +3 -3
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/gpu_test.py +21 -3
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/md_tests.py +141 -49
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/path_utils.py +34 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/wi_utils.py +959 -62
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/visualization/visualization_utils.py +14 -3
- {megadetector-5.0.24 → megadetector-5.0.25/megadetector.egg-info}/PKG-INFO +3 -1
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector.egg-info/SOURCES.txt +2 -1
- {megadetector-5.0.24 → megadetector-5.0.25}/pyproject.toml +1 -2
- 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-5.0.25}/LICENSE +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/batch_service/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/batch_service/score.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/server.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/server_api_config.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/server_app_config.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/server_batch_job_manager.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/server_job_status_table.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/server_orchestration.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/server_utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core_support/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core_support/aggregate_results_manually.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_support/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_support/summarize_daily_activity.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/data_preparation/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/integration/digiKam/setup.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/integration/digiKam/xmp_integration.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/integration/eMammal/test_scripts/config_template.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/synchronous/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/synchronous/api_core/animal_detection_api/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/synchronous/api_core/animal_detection_api/api_backend.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/synchronous/api_core/animal_detection_api/api_frontend.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/synchronous/api_core/animal_detection_api/config.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/synchronous/api_core/tests/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/synchronous/api_core/tests/load_test.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/aggregate_classifier_probs.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/analyze_failed_images.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/cache_batchapi_outputs.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/create_classification_dataset.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/crop_detections.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/csv_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/detect_and_crop.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/efficientnet/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/efficientnet/model.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/efficientnet/utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/evaluate_model.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/identify_mislabeled_candidates.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/json_to_azcopy_list.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/json_validator.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/map_classification_categories.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/merge_classification_detection_output.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/prepare_classification_script.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/prepare_classification_script_mc.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/run_classifier.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/save_mislabeled.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/train_classifier.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/train_classifier_tf.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/train_utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/annotations/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/annotations/annotation_constants.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/camtrap_dp_to_coco.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/cct_json_utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/cct_to_md.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/cct_to_wi.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/coco_to_labelme.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/coco_to_yolo.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/databases/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/databases/add_width_and_height_to_db.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/databases/combine_coco_camera_traps_files.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/databases/integrity_check_json_db.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/databases/subset_json_db.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/generate_crops_from_cct.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/get_image_sizes.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/add_nacti_sizes.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/add_timestamps_to_icct.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/animl_results_to_md_results.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/auckland_doc_test_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/auckland_doc_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/awc_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/bellevue_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/cacophony-thermal-importer.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/carrizo_shrubfree_2018.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/carrizo_trail_cam_2017.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/cct_field_adjustments.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/channel_islands_to_cct.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/eMammal/copy_and_unzip_emammal.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/eMammal/eMammal_helpers.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/eMammal/make_eMammal_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/ena24_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/filenames_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/helena_to_cct.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/idaho-camera-traps.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/idfg_iwildcam_lila_prep.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/import_desert_lion_conservation_camera_traps.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/jb_csv_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/mcgill_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/missouri_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/nacti_fieldname_adjustments.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/noaa_seals_2019.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/osu-small-animals-to-json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/pc_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/plot_wni_giraffes.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/prepare_zsl_imerit.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/raic_csv_to_md_results.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/rspb_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/save_the_elephants_survey_A.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/save_the_elephants_survey_B.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/snapshot_safari_importer.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/snapshot_serengeti_lila.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/snapshotserengeti/make_full_SS_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/snapshotserengeti/make_per_season_SS_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/sulross_get_exif.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/timelapse_csv_set_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/ubc_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/umn_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/wellington_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/wi_to_json.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/zamba_results_to_md_results.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/labelme_to_coco.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/labelme_to_yolo.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/create_lila_blank_set.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/create_lila_test_set.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/create_links_to_md_results_files.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/download_lila_subset.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/generate_lila_per_image_labels.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/get_lila_annotation_counts.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/get_lila_image_counts.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/lila_common.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/test_lila_metadata_urls.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/mewc_to_md.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/ocr_tools.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/read_exif.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/remap_coco_categories.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/remove_exif.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/rename_images.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/resize_coco_dataset.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/wi_download_csv_to_coco.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/yolo_output_to_md_output.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/yolo_to_coco.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/detection/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/detection/process_video.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/detection/pytorch_detector.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/detection/run_inference_with_yolov5_val.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/detection/run_tiled_inference.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/detection/tf_detector.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/detection/video_utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/add_max_conf.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/categorize_detections_by_size.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/classification_postprocessing.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/combine_batch_outputs.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/convert_output_format.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/detector_calibration.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/load_api_results.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/md_to_coco.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/md_to_labelme.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/md_to_wi.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/merge_detections.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/remap_detection_categories.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/render_detection_confusion_matrix.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/separate_detections_into_folders.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/subset_json_detector_output.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/top_folders_to_bottom.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/validate_batch_results.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/map_new_lila_datasets.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/preview_lila_taxonomy.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/retrieve_sample_image.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/simple_image_download.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/species_lookup.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/taxonomy_csv_checker.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/taxonomy_graph.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/validate_lila_category_mappings.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/azure_utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/process_utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/sas_blob_utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/split_locations_into_train_val.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/string_utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/url_utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/write_html_image_list.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/visualization/__init__.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/visualization/plot_utils.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/visualization/render_images_with_thumbnails.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/visualization/visualize_db.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/visualization/visualize_detector_output.py +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector.egg-info/dependency_links.txt +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector.egg-info/requires.txt +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/megadetector.egg-info/top_level.txt +0 -0
- {megadetector-5.0.24 → megadetector-5.0.25}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: megadetector
|
|
3
|
-
Version: 5.0.
|
|
3
|
+
Version: 5.0.25
|
|
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>
|
|
@@ -58,6 +58,8 @@ This package is a pip-installable version of the support/inference code for [Meg
|
|
|
58
58
|
|
|
59
59
|
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
60
|
|
|
61
|
+
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.
|
|
62
|
+
|
|
61
63
|
## Installation
|
|
62
64
|
|
|
63
65
|
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
|
|
|
@@ -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
|
+
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
wi_to_md.py
|
|
4
4
|
|
|
5
|
-
Converts the WI predictions.json format to MD .json format. This is just a
|
|
5
|
+
Converts the WI (SpeciesNet) predictions.json format to MD .json format. This is just a
|
|
6
6
|
command-line wrapper around utils.wi_utils.generate_md_results_from_predictions_json.
|
|
7
7
|
|
|
8
8
|
"""
|
|
@@ -20,7 +20,7 @@ def main():
|
|
|
20
20
|
|
|
21
21
|
parser = argparse.ArgumentParser()
|
|
22
22
|
parser.add_argument('predictions_json_file', action='store', type=str,
|
|
23
|
-
help='.json file to convert from predictions.json format to MD format')
|
|
23
|
+
help='.json file to convert from SpeciesNet predictions.json format to MD format')
|
|
24
24
|
parser.add_argument('md_results_file', action='store', type=str,
|
|
25
25
|
help='output file to write in MD format')
|
|
26
26
|
parser.add_argument('--base_folder', action='store', type=str, default=None,
|
|
@@ -735,7 +735,7 @@ def load_and_run_detector_batch(model_file,
|
|
|
735
735
|
"""
|
|
736
736
|
|
|
737
737
|
# Validate input arguments
|
|
738
|
-
if n_cores is None:
|
|
738
|
+
if n_cores is None or n_cores <= 0:
|
|
739
739
|
n_cores = 1
|
|
740
740
|
|
|
741
741
|
if confidence_threshold is None:
|
|
@@ -1331,13 +1331,14 @@ def main():
|
|
|
1331
1331
|
parser.add_argument(
|
|
1332
1332
|
'--ncores',
|
|
1333
1333
|
type=int,
|
|
1334
|
-
default=
|
|
1335
|
-
help='Number of cores to use for inference; only applies to CPU-based inference')
|
|
1334
|
+
default=1,
|
|
1335
|
+
help='Number of cores to use for inference; only applies to CPU-based inference (default 1)')
|
|
1336
1336
|
parser.add_argument(
|
|
1337
1337
|
'--loader_workers',
|
|
1338
1338
|
type=int,
|
|
1339
1339
|
default=default_loaders,
|
|
1340
|
-
help='Number of image loader workers to use; only relevant when --use_image_queue
|
|
1340
|
+
help='Number of image loader workers to use; only relevant when --use_image_queue ' + \
|
|
1341
|
+
'is set (default {})'.format(default_loaders))
|
|
1341
1342
|
parser.add_argument(
|
|
1342
1343
|
'--class_mapping_filename',
|
|
1343
1344
|
type=str,
|
{megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/compare_batch_results.py
RENAMED
|
@@ -138,6 +138,9 @@ class BatchComparisonOptions:
|
|
|
138
138
|
#: List of filenames to include in the comparison, or None to use all files
|
|
139
139
|
self.filenames_to_include = None
|
|
140
140
|
|
|
141
|
+
#: List of category names to include in the comparison, or None to use all categories
|
|
142
|
+
self.category_names_to_include = None
|
|
143
|
+
|
|
141
144
|
#: Compare only detections/non-detections, ignore categories (still renders categories)
|
|
142
145
|
self.class_agnostic_comparison = False
|
|
143
146
|
|
|
@@ -986,7 +989,32 @@ def _pairwise_compare_batch_results(options,output_index,pairwise_options):
|
|
|
986
989
|
if invalid_category_error:
|
|
987
990
|
|
|
988
991
|
continue
|
|
989
|
-
|
|
992
|
+
|
|
993
|
+
# Should we be restricting the comparison to only certain categories?
|
|
994
|
+
if options.category_names_to_include is not None:
|
|
995
|
+
|
|
996
|
+
# Just in case the user provided a single category instead of a list
|
|
997
|
+
if isinstance(options.category_names_to_include,str):
|
|
998
|
+
options.category_names_to_include = [options.category_names_to_include]
|
|
999
|
+
|
|
1000
|
+
category_name_to_id_a = invert_dictionary(detection_categories_a)
|
|
1001
|
+
category_name_to_id_b = invert_dictionary(detection_categories_b)
|
|
1002
|
+
category_ids_to_include_a = []
|
|
1003
|
+
category_ids_to_include_b = []
|
|
1004
|
+
|
|
1005
|
+
for category_name in options.category_names_to_include:
|
|
1006
|
+
if category_name in category_name_to_id_a:
|
|
1007
|
+
category_ids_to_include_a.append(category_name_to_id_a[category_name])
|
|
1008
|
+
if category_name in category_name_to_id_b:
|
|
1009
|
+
category_ids_to_include_b.append(category_name_to_id_b[category_name])
|
|
1010
|
+
|
|
1011
|
+
# Restrict the categories we treat as above-threshold to the set we're supposed
|
|
1012
|
+
# to be using
|
|
1013
|
+
categories_above_threshold_a = [category_id for category_id in categories_above_threshold_a if \
|
|
1014
|
+
category_id in category_ids_to_include_a]
|
|
1015
|
+
categories_above_threshold_b = [category_id for category_id in categories_above_threshold_b if \
|
|
1016
|
+
category_id in category_ids_to_include_b]
|
|
1017
|
+
|
|
990
1018
|
detection_a = (len(categories_above_threshold_a) > 0)
|
|
991
1019
|
detection_b = (len(categories_above_threshold_b) > 0)
|
|
992
1020
|
|
|
@@ -1609,7 +1637,72 @@ def n_way_comparison(filenames,
|
|
|
1609
1637
|
# ...def n_way_comparison(...)
|
|
1610
1638
|
|
|
1611
1639
|
|
|
1612
|
-
def
|
|
1640
|
+
def find_image_level_detections_above_threshold(results,threshold=0.2,category_names=None):
|
|
1641
|
+
"""
|
|
1642
|
+
Returns images in the set of MD results [results] with detections above
|
|
1643
|
+
a threshold confidence level, optionally only counting certain categories.
|
|
1644
|
+
|
|
1645
|
+
Args:
|
|
1646
|
+
results (str or dict): the set of results, either a .json filename or a results
|
|
1647
|
+
dict
|
|
1648
|
+
threshold (float, optional): the threshold used to determine the target number of
|
|
1649
|
+
detections in [results]
|
|
1650
|
+
category_names (list or str, optional): the list of category names to consider (defaults
|
|
1651
|
+
to using all categories), or the name of a single category.
|
|
1652
|
+
|
|
1653
|
+
Returns:
|
|
1654
|
+
list: the images with above-threshold detections
|
|
1655
|
+
"""
|
|
1656
|
+
if isinstance(results,str):
|
|
1657
|
+
with open(results,'r') as f:
|
|
1658
|
+
results = json.load(f)
|
|
1659
|
+
|
|
1660
|
+
category_ids_to_consider = None
|
|
1661
|
+
|
|
1662
|
+
if category_names is not None:
|
|
1663
|
+
|
|
1664
|
+
if isinstance(category_names,str):
|
|
1665
|
+
category_names = [category_names]
|
|
1666
|
+
|
|
1667
|
+
category_id_to_name = results['detection_categories']
|
|
1668
|
+
category_name_to_id = invert_dictionary(category_id_to_name)
|
|
1669
|
+
|
|
1670
|
+
category_ids_to_consider = []
|
|
1671
|
+
|
|
1672
|
+
# category_name = category_names[0]
|
|
1673
|
+
for category_name in category_names:
|
|
1674
|
+
category_id = category_name_to_id[category_name]
|
|
1675
|
+
category_ids_to_consider.append(category_id)
|
|
1676
|
+
|
|
1677
|
+
assert len(category_ids_to_consider) > 0, \
|
|
1678
|
+
'Category name list did not map to any category IDs'
|
|
1679
|
+
|
|
1680
|
+
images_above_threshold = []
|
|
1681
|
+
|
|
1682
|
+
for im in results['images']:
|
|
1683
|
+
|
|
1684
|
+
if ('detections' in im) and (im['detections'] is not None) and (len(im['detections']) > 0):
|
|
1685
|
+
confidence_values_this_image = [0]
|
|
1686
|
+
for det in im['detections']:
|
|
1687
|
+
if category_ids_to_consider is not None:
|
|
1688
|
+
if det['category'] not in category_ids_to_consider:
|
|
1689
|
+
continue
|
|
1690
|
+
confidence_values_this_image.append(det['conf'])
|
|
1691
|
+
if max(confidence_values_this_image) >= threshold:
|
|
1692
|
+
images_above_threshold.append(im)
|
|
1693
|
+
|
|
1694
|
+
# ...for each image
|
|
1695
|
+
|
|
1696
|
+
return images_above_threshold
|
|
1697
|
+
|
|
1698
|
+
# ...def find_image_level_detections_above_threshold(...)
|
|
1699
|
+
|
|
1700
|
+
|
|
1701
|
+
def find_equivalent_threshold(results_a,
|
|
1702
|
+
results_b,
|
|
1703
|
+
threshold_a=0.2,
|
|
1704
|
+
category_names=None,
|
|
1705
|
+
verbose=False):
|
|
1613
1706
|
"""
|
|
1614
1707
|
Given two sets of detector results, finds the confidence threshold for results_b
|
|
1615
1708
|
that produces the same fraction of *images* with detections as threshold_a does for
|
|
@@ -1622,6 +1715,9 @@ def find_equivalent_threshold(results_a,results_b,threshold_a=0.2):
|
|
|
1622
1715
|
dict
|
|
1623
1716
|
threshold_a (float, optional): the threshold used to determine the target number of
|
|
1624
1717
|
detections in results_a
|
|
1718
|
+
category_names (list or str, optional): the list of category names to consider (defaults
|
|
1719
|
+
to using all categories), or the name of a single category.
|
|
1720
|
+
verbose (bool, optional): enable additional debug output
|
|
1625
1721
|
|
|
1626
1722
|
Returns:
|
|
1627
1723
|
float: the threshold that - when applied to results_b - produces the same number
|
|
@@ -1629,35 +1725,106 @@ def find_equivalent_threshold(results_a,results_b,threshold_a=0.2):
|
|
|
1629
1725
|
"""
|
|
1630
1726
|
|
|
1631
1727
|
if isinstance(results_a,str):
|
|
1728
|
+
if verbose:
|
|
1729
|
+
print('Loading results from {}'.format(results_a))
|
|
1632
1730
|
with open(results_a,'r') as f:
|
|
1633
1731
|
results_a = json.load(f)
|
|
1634
1732
|
|
|
1635
1733
|
if isinstance(results_b,str):
|
|
1734
|
+
if verbose:
|
|
1735
|
+
print('Loading results from {}'.format(results_b))
|
|
1636
1736
|
with open(results_b,'r') as f:
|
|
1637
1737
|
results_b = json.load(f)
|
|
1738
|
+
|
|
1739
|
+
category_ids_to_consider_a = None
|
|
1740
|
+
category_ids_to_consider_b = None
|
|
1741
|
+
|
|
1742
|
+
if category_names is not None:
|
|
1743
|
+
|
|
1744
|
+
if isinstance(category_names,str):
|
|
1745
|
+
category_names = [category_names]
|
|
1746
|
+
|
|
1747
|
+
categories_a = results_a['detection_categories']
|
|
1748
|
+
categories_b = results_b['detection_categories']
|
|
1749
|
+
category_name_to_id_a = invert_dictionary(categories_a)
|
|
1750
|
+
category_name_to_id_b = invert_dictionary(categories_b)
|
|
1751
|
+
|
|
1752
|
+
category_ids_to_consider_a = []
|
|
1753
|
+
category_ids_to_consider_b = []
|
|
1754
|
+
|
|
1755
|
+
# category_name = category_names[0]
|
|
1756
|
+
for category_name in category_names:
|
|
1757
|
+
category_id_a = category_name_to_id_a[category_name]
|
|
1758
|
+
category_id_b = category_name_to_id_b[category_name]
|
|
1759
|
+
category_ids_to_consider_a.append(category_id_a)
|
|
1760
|
+
category_ids_to_consider_b.append(category_id_b)
|
|
1638
1761
|
|
|
1639
|
-
|
|
1762
|
+
assert len(category_ids_to_consider_a) > 0 and len(category_ids_to_consider_b) > 0, \
|
|
1763
|
+
'Category name list did not map to any category IDs in one or both detection sets'
|
|
1764
|
+
|
|
1765
|
+
def _get_confidence_values_for_results(images,category_ids_to_consider,threshold):
|
|
1766
|
+
"""
|
|
1767
|
+
Return a list of the maximum confidence value for each image in [images].
|
|
1768
|
+
Returns zero confidence for images with no detections (or no detections
|
|
1769
|
+
in the specified categories). Does not return anything for invalid images.
|
|
1770
|
+
"""
|
|
1771
|
+
|
|
1640
1772
|
confidence_values = []
|
|
1773
|
+
images_above_threshold = []
|
|
1774
|
+
|
|
1641
1775
|
for im in images:
|
|
1642
1776
|
if 'detections' in im and im['detections'] is not None:
|
|
1643
1777
|
if len(im['detections']) == 0:
|
|
1644
1778
|
confidence_values.append(0)
|
|
1645
1779
|
else:
|
|
1646
|
-
confidence_values_this_image = [
|
|
1647
|
-
|
|
1648
|
-
|
|
1780
|
+
confidence_values_this_image = []
|
|
1781
|
+
for det in im['detections']:
|
|
1782
|
+
if category_ids_to_consider is not None:
|
|
1783
|
+
if det['category'] not in category_ids_to_consider:
|
|
1784
|
+
continue
|
|
1785
|
+
confidence_values_this_image.append(det['conf'])
|
|
1786
|
+
if len(confidence_values_this_image) == 0:
|
|
1787
|
+
confidence_values.append(0)
|
|
1788
|
+
else:
|
|
1789
|
+
max_conf_value = max(confidence_values_this_image)
|
|
1790
|
+
|
|
1791
|
+
if threshold is not None and max_conf_value >= threshold:
|
|
1792
|
+
images_above_threshold.append(im)
|
|
1793
|
+
confidence_values.append(max_conf_value)
|
|
1794
|
+
# ...for each image
|
|
1795
|
+
|
|
1796
|
+
return confidence_values, images_above_threshold
|
|
1649
1797
|
|
|
1650
|
-
confidence_values_a =
|
|
1798
|
+
confidence_values_a,images_above_threshold_a = \
|
|
1799
|
+
_get_confidence_values_for_results(results_a['images'],
|
|
1800
|
+
category_ids_to_consider_a,
|
|
1801
|
+
threshold_a)
|
|
1802
|
+
|
|
1803
|
+
# ...def _get_confidence_values_for_results(...)
|
|
1804
|
+
|
|
1805
|
+
if verbose:
|
|
1806
|
+
print('For result set A, considering {} of {} images'.format(
|
|
1807
|
+
len(confidence_values_a),len(results_a['images'])))
|
|
1651
1808
|
confidence_values_a_above_threshold = [c for c in confidence_values_a if c >= threshold_a]
|
|
1652
1809
|
|
|
1653
|
-
confidence_values_b =
|
|
1654
|
-
|
|
1810
|
+
confidence_values_b,_ = _get_confidence_values_for_results(results_b['images'],
|
|
1811
|
+
category_ids_to_consider_b,
|
|
1812
|
+
threshold=None)
|
|
1813
|
+
if verbose:
|
|
1814
|
+
print('For result set B, considering {} of {} images'.format(
|
|
1815
|
+
len(confidence_values_b),len(results_b['images'])))
|
|
1816
|
+
confidence_values_b = sorted(confidence_values_b)
|
|
1655
1817
|
|
|
1656
1818
|
target_detection_fraction = len(confidence_values_a_above_threshold) / len(confidence_values_a)
|
|
1657
1819
|
|
|
1658
1820
|
detection_cutoff_index = round((1.0-target_detection_fraction) * len(confidence_values_b))
|
|
1659
1821
|
threshold_b = confidence_values_b[detection_cutoff_index]
|
|
1660
1822
|
|
|
1823
|
+
if verbose:
|
|
1824
|
+
print('{} confidence values above threshold (A)'.format(len(confidence_values_a_above_threshold)))
|
|
1825
|
+
confidence_values_b_above_threshold = [c for c in confidence_values_b if c >= threshold_b]
|
|
1826
|
+
print('{} confidence values above threshold (B)'.format(len(confidence_values_b_above_threshold)))
|
|
1827
|
+
|
|
1661
1828
|
return threshold_b
|
|
1662
1829
|
|
|
1663
1830
|
# ...def find_equivalent_threshold(...)
|