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.

Files changed (216) hide show
  1. {megadetector-5.0.24/megadetector.egg-info → megadetector-5.0.25}/PKG-INFO +3 -1
  2. {megadetector-5.0.24 → megadetector-5.0.25}/README-package.md +2 -0
  3. {megadetector-5.0.24 → megadetector-5.0.25}/README.md +12 -8
  4. megadetector-5.0.25/megadetector/data_management/lila/add_locations_to_island_camera_traps.py +101 -0
  5. megadetector-5.0.25/megadetector/data_management/lila/add_locations_to_nacti.py +151 -0
  6. megadetector-5.0.24/megadetector/data_management/wi_to_md.py → megadetector-5.0.25/megadetector/data_management/speciesnet_to_md.py +2 -2
  7. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/detection/run_detector.py +1 -0
  8. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/detection/run_detector_batch.py +5 -4
  9. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/compare_batch_results.py +176 -9
  10. megadetector-5.0.25/megadetector/postprocessing/create_crop_folder.py +358 -0
  11. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/postprocess_batch_results.py +2 -2
  12. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/ct_utils.py +72 -1
  13. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/directory_listing.py +3 -3
  14. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/gpu_test.py +21 -3
  15. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/md_tests.py +141 -49
  16. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/path_utils.py +34 -0
  17. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/wi_utils.py +959 -62
  18. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/visualization/visualization_utils.py +14 -3
  19. {megadetector-5.0.24 → megadetector-5.0.25/megadetector.egg-info}/PKG-INFO +3 -1
  20. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector.egg-info/SOURCES.txt +2 -1
  21. {megadetector-5.0.24 → megadetector-5.0.25}/pyproject.toml +1 -2
  22. megadetector-5.0.24/megadetector/data_management/lila/add_locations_to_island_camera_traps.py +0 -97
  23. megadetector-5.0.24/megadetector/data_management/lila/add_locations_to_nacti.py +0 -147
  24. {megadetector-5.0.24 → megadetector-5.0.25}/LICENSE +0 -0
  25. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/__init__.py +0 -0
  26. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/__init__.py +0 -0
  27. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/__init__.py +0 -0
  28. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/batch_service/__init__.py +0 -0
  29. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/batch_service/score.py +0 -0
  30. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/server.py +0 -0
  31. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/server_api_config.py +0 -0
  32. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/server_app_config.py +0 -0
  33. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/server_batch_job_manager.py +0 -0
  34. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/server_job_status_table.py +0 -0
  35. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/server_orchestration.py +0 -0
  36. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core/server_utils.py +0 -0
  37. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core_support/__init__.py +0 -0
  38. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_core_support/aggregate_results_manually.py +0 -0
  39. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_support/__init__.py +0 -0
  40. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/api_support/summarize_daily_activity.py +0 -0
  41. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/data_preparation/__init__.py +0 -0
  42. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/integration/digiKam/setup.py +0 -0
  43. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/integration/digiKam/xmp_integration.py +0 -0
  44. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/integration/eMammal/test_scripts/config_template.py +0 -0
  45. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +0 -0
  46. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +0 -0
  47. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/synchronous/__init__.py +0 -0
  48. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/synchronous/api_core/animal_detection_api/__init__.py +0 -0
  49. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/synchronous/api_core/animal_detection_api/api_backend.py +0 -0
  50. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/synchronous/api_core/animal_detection_api/api_frontend.py +0 -0
  51. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/synchronous/api_core/animal_detection_api/config.py +0 -0
  52. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/synchronous/api_core/tests/__init__.py +0 -0
  53. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/api/synchronous/api_core/tests/load_test.py +0 -0
  54. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/__init__.py +0 -0
  55. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/aggregate_classifier_probs.py +0 -0
  56. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/analyze_failed_images.py +0 -0
  57. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/cache_batchapi_outputs.py +0 -0
  58. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/create_classification_dataset.py +0 -0
  59. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/crop_detections.py +0 -0
  60. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/csv_to_json.py +0 -0
  61. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/detect_and_crop.py +0 -0
  62. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/efficientnet/__init__.py +0 -0
  63. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/efficientnet/model.py +0 -0
  64. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/efficientnet/utils.py +0 -0
  65. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/evaluate_model.py +0 -0
  66. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/identify_mislabeled_candidates.py +0 -0
  67. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/json_to_azcopy_list.py +0 -0
  68. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/json_validator.py +0 -0
  69. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/map_classification_categories.py +0 -0
  70. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/merge_classification_detection_output.py +0 -0
  71. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/prepare_classification_script.py +0 -0
  72. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/prepare_classification_script_mc.py +0 -0
  73. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/run_classifier.py +0 -0
  74. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/save_mislabeled.py +0 -0
  75. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/train_classifier.py +0 -0
  76. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/train_classifier_tf.py +0 -0
  77. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/classification/train_utils.py +0 -0
  78. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/__init__.py +0 -0
  79. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/annotations/__init__.py +0 -0
  80. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/annotations/annotation_constants.py +0 -0
  81. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/camtrap_dp_to_coco.py +0 -0
  82. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/cct_json_utils.py +0 -0
  83. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/cct_to_md.py +0 -0
  84. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/cct_to_wi.py +0 -0
  85. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/coco_to_labelme.py +0 -0
  86. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/coco_to_yolo.py +0 -0
  87. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/databases/__init__.py +0 -0
  88. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/databases/add_width_and_height_to_db.py +0 -0
  89. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/databases/combine_coco_camera_traps_files.py +0 -0
  90. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/databases/integrity_check_json_db.py +0 -0
  91. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/databases/subset_json_db.py +0 -0
  92. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/generate_crops_from_cct.py +0 -0
  93. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/get_image_sizes.py +0 -0
  94. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/add_nacti_sizes.py +0 -0
  95. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/add_timestamps_to_icct.py +0 -0
  96. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/animl_results_to_md_results.py +0 -0
  97. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/auckland_doc_test_to_json.py +0 -0
  98. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/auckland_doc_to_json.py +0 -0
  99. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/awc_to_json.py +0 -0
  100. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/bellevue_to_json.py +0 -0
  101. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/cacophony-thermal-importer.py +0 -0
  102. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/carrizo_shrubfree_2018.py +0 -0
  103. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/carrizo_trail_cam_2017.py +0 -0
  104. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/cct_field_adjustments.py +0 -0
  105. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/channel_islands_to_cct.py +0 -0
  106. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/eMammal/copy_and_unzip_emammal.py +0 -0
  107. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/eMammal/eMammal_helpers.py +0 -0
  108. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/eMammal/make_eMammal_json.py +0 -0
  109. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/ena24_to_json.py +0 -0
  110. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/filenames_to_json.py +0 -0
  111. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/helena_to_cct.py +0 -0
  112. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/idaho-camera-traps.py +0 -0
  113. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/idfg_iwildcam_lila_prep.py +0 -0
  114. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/import_desert_lion_conservation_camera_traps.py +0 -0
  115. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/jb_csv_to_json.py +0 -0
  116. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/mcgill_to_json.py +0 -0
  117. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/missouri_to_json.py +0 -0
  118. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/nacti_fieldname_adjustments.py +0 -0
  119. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/noaa_seals_2019.py +0 -0
  120. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/osu-small-animals-to-json.py +0 -0
  121. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/pc_to_json.py +0 -0
  122. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/plot_wni_giraffes.py +0 -0
  123. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/prepare_zsl_imerit.py +0 -0
  124. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/raic_csv_to_md_results.py +0 -0
  125. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/rspb_to_json.py +0 -0
  126. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/save_the_elephants_survey_A.py +0 -0
  127. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/save_the_elephants_survey_B.py +0 -0
  128. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/snapshot_safari_importer.py +0 -0
  129. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/snapshot_serengeti_lila.py +0 -0
  130. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/snapshotserengeti/make_full_SS_json.py +0 -0
  131. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/snapshotserengeti/make_per_season_SS_json.py +0 -0
  132. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/sulross_get_exif.py +0 -0
  133. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/timelapse_csv_set_to_json.py +0 -0
  134. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/ubc_to_json.py +0 -0
  135. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/umn_to_json.py +0 -0
  136. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/wellington_to_json.py +0 -0
  137. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/wi_to_json.py +0 -0
  138. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/importers/zamba_results_to_md_results.py +0 -0
  139. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/labelme_to_coco.py +0 -0
  140. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/labelme_to_yolo.py +0 -0
  141. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/__init__.py +0 -0
  142. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/create_lila_blank_set.py +0 -0
  143. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/create_lila_test_set.py +0 -0
  144. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/create_links_to_md_results_files.py +0 -0
  145. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/download_lila_subset.py +0 -0
  146. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/generate_lila_per_image_labels.py +0 -0
  147. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/get_lila_annotation_counts.py +0 -0
  148. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/get_lila_image_counts.py +0 -0
  149. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/lila_common.py +0 -0
  150. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/lila/test_lila_metadata_urls.py +0 -0
  151. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/mewc_to_md.py +0 -0
  152. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/ocr_tools.py +0 -0
  153. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/read_exif.py +0 -0
  154. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/remap_coco_categories.py +0 -0
  155. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/remove_exif.py +0 -0
  156. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/rename_images.py +0 -0
  157. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/resize_coco_dataset.py +0 -0
  158. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/wi_download_csv_to_coco.py +0 -0
  159. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/yolo_output_to_md_output.py +0 -0
  160. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/data_management/yolo_to_coco.py +0 -0
  161. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/detection/__init__.py +0 -0
  162. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/detection/process_video.py +0 -0
  163. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/detection/pytorch_detector.py +0 -0
  164. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/detection/run_inference_with_yolov5_val.py +0 -0
  165. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/detection/run_tiled_inference.py +0 -0
  166. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/detection/tf_detector.py +0 -0
  167. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/detection/video_utils.py +0 -0
  168. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/__init__.py +0 -0
  169. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/add_max_conf.py +0 -0
  170. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/categorize_detections_by_size.py +0 -0
  171. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/classification_postprocessing.py +0 -0
  172. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/combine_batch_outputs.py +0 -0
  173. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/convert_output_format.py +0 -0
  174. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/detector_calibration.py +0 -0
  175. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/load_api_results.py +0 -0
  176. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/md_to_coco.py +0 -0
  177. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/md_to_labelme.py +0 -0
  178. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/md_to_wi.py +0 -0
  179. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/merge_detections.py +0 -0
  180. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/remap_detection_categories.py +0 -0
  181. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/render_detection_confusion_matrix.py +0 -0
  182. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py +0 -0
  183. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +0 -0
  184. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +0 -0
  185. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/separate_detections_into_folders.py +0 -0
  186. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/subset_json_detector_output.py +0 -0
  187. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/top_folders_to_bottom.py +0 -0
  188. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/postprocessing/validate_batch_results.py +0 -0
  189. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/__init__.py +0 -0
  190. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +0 -0
  191. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/map_new_lila_datasets.py +0 -0
  192. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +0 -0
  193. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/preview_lila_taxonomy.py +0 -0
  194. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/retrieve_sample_image.py +0 -0
  195. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/simple_image_download.py +0 -0
  196. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/species_lookup.py +0 -0
  197. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/taxonomy_csv_checker.py +0 -0
  198. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/taxonomy_graph.py +0 -0
  199. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/taxonomy_mapping/validate_lila_category_mappings.py +0 -0
  200. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/__init__.py +0 -0
  201. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/azure_utils.py +0 -0
  202. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/process_utils.py +0 -0
  203. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/sas_blob_utils.py +0 -0
  204. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/split_locations_into_train_val.py +0 -0
  205. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/string_utils.py +0 -0
  206. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/url_utils.py +0 -0
  207. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/utils/write_html_image_list.py +0 -0
  208. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/visualization/__init__.py +0 -0
  209. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/visualization/plot_utils.py +0 -0
  210. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/visualization/render_images_with_thumbnails.py +0 -0
  211. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/visualization/visualize_db.py +0 -0
  212. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector/visualization/visualize_detector_output.py +0 -0
  213. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector.egg-info/dependency_links.txt +0 -0
  214. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector.egg-info/requires.txt +0 -0
  215. {megadetector-5.0.24 → megadetector-5.0.25}/megadetector.egg-info/top_level.txt +0 -0
  216. {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.24
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 &ldquo;teaser&rdquo; image of what MegaDetector output looks like:
20
24
 
21
25
  ![Red bounding box on fox](images/detector_example.jpg)<br/>Image credit University of Washington.
@@ -27,7 +31,7 @@ Here's a &ldquo;teaser&rdquo; 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 &ldquo;[Everything I know about machine learning and camera traps](https://agentmorris.github.io/camera-trap-ml-survey/)&rdquo;.
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/services/wildlife-camera-trap-ai-image-processing-and-management/)
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](http://www.ebd.csic.es/inicio)
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://emammal.si.edu/snapshot-usa), Smithsonian
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://wildlifeobserver.net/))
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
- Experimental code for training species classifiers on new data sets, generally trained on MegaDetector crops. Currently the main pipeline described in this folder relies on a large database of labeled images that is not publicly available; therefore, this folder is not yet set up to facilitate training of your own classifiers. However, it is useful for <i>users</i> of the classifiers that we train, and contains some useful starting points if you are going to take a "DIY" approach to training classifiers on cropped images.
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
- All that said, here's another "teaser image" of what you get at the end of training and running a classifier:
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,
@@ -96,6 +96,7 @@ model_string_to_model_version = {
96
96
  'cedar':'v1000.0.0-cedar',
97
97
  'larch':'v1000.0.0-larch',
98
98
  'default':'v5a.0.0',
99
+ 'default-model':'v5a.0.0',
99
100
  'megadetector':'v5a.0.0'
100
101
  }
101
102
 
@@ -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=0,
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 is set')
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,
@@ -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 find_equivalent_threshold(results_a,results_b,threshold_a=0.2):
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
- def get_confidence_values_for_results(images):
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 = [det['conf'] for det in im['detections']]
1647
- confidence_values.append(max(confidence_values_this_image))
1648
- return confidence_values
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 = get_confidence_values_for_results(results_a['images'])
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 = get_confidence_values_for_results(results_b['images'])
1654
- confidence_values_b = sorted(confidence_values_b)
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(...)