megadetector 5.0.3__tar.gz → 5.0.4__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 (177) hide show
  1. megadetector-5.0.4/PKG-INFO +141 -0
  2. megadetector-5.0.4/README-package.md +88 -0
  3. {megadetector-5.0.3 → megadetector-5.0.4}/README.md +1 -1
  4. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/postprocessing/md_to_labelme.py +67 -38
  5. {megadetector-5.0.3 → megadetector-5.0.4}/classification/merge_classification_detection_output.py +1 -1
  6. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/cacophony-thermal-importer.py +1 -1
  7. {megadetector-5.0.3 → megadetector-5.0.4}/detection/process_video.py +1 -1
  8. {megadetector-5.0.3 → megadetector-5.0.4}/detection/pytorch_detector.py +3 -3
  9. {megadetector-5.0.3 → megadetector-5.0.4}/detection/run_detector.py +69 -1
  10. {megadetector-5.0.3 → megadetector-5.0.4}/detection/run_detector_batch.py +8 -1
  11. {megadetector-5.0.3 → megadetector-5.0.4}/md_utils/url_utils.py +4 -3
  12. {megadetector-5.0.3 → megadetector-5.0.4}/md_visualization/visualization_utils.py +1 -1
  13. megadetector-5.0.4/megadetector.egg-info/PKG-INFO +141 -0
  14. {megadetector-5.0.3 → megadetector-5.0.4}/megadetector.egg-info/SOURCES.txt +1 -0
  15. megadetector-5.0.4/megadetector.egg-info/requires.txt +16 -0
  16. {megadetector-5.0.3 → megadetector-5.0.4}/pyproject.toml +18 -18
  17. megadetector-5.0.3/PKG-INFO +0 -295
  18. megadetector-5.0.3/megadetector.egg-info/PKG-INFO +0 -295
  19. megadetector-5.0.3/megadetector.egg-info/requires.txt +0 -16
  20. {megadetector-5.0.3 → megadetector-5.0.4}/LICENSE +0 -0
  21. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/api_core/batch_service/score.py +0 -0
  22. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/api_core/server.py +0 -0
  23. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/api_core/server_api_config.py +0 -0
  24. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/api_core/server_app_config.py +0 -0
  25. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/api_core/server_batch_job_manager.py +0 -0
  26. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/api_core/server_job_status_table.py +0 -0
  27. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/api_core/server_orchestration.py +0 -0
  28. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/api_core/server_utils.py +0 -0
  29. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/api_core_support/aggregate_results_manually.py +0 -0
  30. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/api_support/summarize_daily_activity.py +0 -0
  31. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/data_preparation/manage_local_batch.py +0 -0
  32. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/data_preparation/manage_video_batch.py +0 -0
  33. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/integration/digiKam/setup.py +0 -0
  34. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/integration/digiKam/xmp_integration.py +0 -0
  35. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/integration/eMammal/test_scripts/config_template.py +0 -0
  36. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +0 -0
  37. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +0 -0
  38. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/postprocessing/add_max_conf.py +0 -0
  39. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/postprocessing/categorize_detections_by_size.py +0 -0
  40. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/postprocessing/combine_api_outputs.py +0 -0
  41. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/postprocessing/compare_batch_results.py +0 -0
  42. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/postprocessing/convert_output_format.py +0 -0
  43. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/postprocessing/load_api_results.py +0 -0
  44. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/postprocessing/md_to_coco_starter_code.py +0 -0
  45. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/postprocessing/merge_detections.py +0 -0
  46. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/postprocessing/postprocess_batch_results.py +0 -0
  47. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/postprocessing/repeat_detection_elimination/find_repeat_detections.py +0 -0
  48. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +0 -0
  49. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/postprocessing/repeat_detection_elimination/repeat_detections_core.py +0 -0
  50. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/postprocessing/separate_detections_into_folders.py +0 -0
  51. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/postprocessing/subset_json_detector_output.py +0 -0
  52. {megadetector-5.0.3 → megadetector-5.0.4}/api/batch_processing/postprocessing/top_folders_to_bottom.py +0 -0
  53. {megadetector-5.0.3 → megadetector-5.0.4}/api/synchronous/api_core/animal_detection_api/api_backend.py +0 -0
  54. {megadetector-5.0.3 → megadetector-5.0.4}/api/synchronous/api_core/animal_detection_api/api_frontend.py +0 -0
  55. {megadetector-5.0.3 → megadetector-5.0.4}/api/synchronous/api_core/animal_detection_api/config.py +0 -0
  56. {megadetector-5.0.3 → megadetector-5.0.4}/api/synchronous/api_core/tests/load_test.py +0 -0
  57. {megadetector-5.0.3 → megadetector-5.0.4}/classification/aggregate_classifier_probs.py +0 -0
  58. {megadetector-5.0.3 → megadetector-5.0.4}/classification/analyze_failed_images.py +0 -0
  59. {megadetector-5.0.3 → megadetector-5.0.4}/classification/cache_batchapi_outputs.py +0 -0
  60. {megadetector-5.0.3 → megadetector-5.0.4}/classification/create_classification_dataset.py +0 -0
  61. {megadetector-5.0.3 → megadetector-5.0.4}/classification/crop_detections.py +0 -0
  62. {megadetector-5.0.3 → megadetector-5.0.4}/classification/csv_to_json.py +0 -0
  63. {megadetector-5.0.3 → megadetector-5.0.4}/classification/detect_and_crop.py +0 -0
  64. {megadetector-5.0.3 → megadetector-5.0.4}/classification/efficientnet/__init__.py +0 -0
  65. {megadetector-5.0.3 → megadetector-5.0.4}/classification/efficientnet/model.py +0 -0
  66. {megadetector-5.0.3 → megadetector-5.0.4}/classification/efficientnet/utils.py +0 -0
  67. {megadetector-5.0.3 → megadetector-5.0.4}/classification/evaluate_model.py +0 -0
  68. {megadetector-5.0.3 → megadetector-5.0.4}/classification/identify_mislabeled_candidates.py +0 -0
  69. {megadetector-5.0.3 → megadetector-5.0.4}/classification/json_to_azcopy_list.py +0 -0
  70. {megadetector-5.0.3 → megadetector-5.0.4}/classification/json_validator.py +0 -0
  71. {megadetector-5.0.3 → megadetector-5.0.4}/classification/map_classification_categories.py +0 -0
  72. {megadetector-5.0.3 → megadetector-5.0.4}/classification/prepare_classification_script.py +0 -0
  73. {megadetector-5.0.3 → megadetector-5.0.4}/classification/prepare_classification_script_mc.py +0 -0
  74. {megadetector-5.0.3 → megadetector-5.0.4}/classification/run_classifier.py +0 -0
  75. {megadetector-5.0.3 → megadetector-5.0.4}/classification/save_mislabeled.py +0 -0
  76. {megadetector-5.0.3 → megadetector-5.0.4}/classification/train_classifier.py +0 -0
  77. {megadetector-5.0.3 → megadetector-5.0.4}/classification/train_classifier_tf.py +0 -0
  78. {megadetector-5.0.3 → megadetector-5.0.4}/classification/train_utils.py +0 -0
  79. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/annotations/annotation_constants.py +0 -0
  80. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/cct_json_to_filename_json.py +0 -0
  81. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/cct_json_utils.py +0 -0
  82. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/cct_to_csv.py +0 -0
  83. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/cct_to_md.py +0 -0
  84. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/cct_to_wi.py +0 -0
  85. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/coco_to_yolo.py +0 -0
  86. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/databases/add_width_and_height_to_db.py +0 -0
  87. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/databases/combine_coco_camera_traps_files.py +0 -0
  88. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/databases/integrity_check_json_db.py +0 -0
  89. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/databases/remove_corrupted_images_from_db.py +0 -0
  90. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/databases/subset_json_db.py +0 -0
  91. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/generate_crops_from_cct.py +0 -0
  92. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/get_image_sizes.py +0 -0
  93. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/add_nacti_sizes.py +0 -0
  94. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/auckland_doc_test_to_json.py +0 -0
  95. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/auckland_doc_to_json.py +0 -0
  96. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/awc_to_json.py +0 -0
  97. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/bellevue_to_json.py +0 -0
  98. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/carrizo_shrubfree_2018.py +0 -0
  99. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/carrizo_trail_cam_2017.py +0 -0
  100. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/cct_field_adjustments.py +0 -0
  101. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/channel_islands_to_cct.py +0 -0
  102. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/eMammal/copy_and_unzip_emammal.py +0 -0
  103. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/eMammal/eMammal_helpers.py +0 -0
  104. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/eMammal/make_eMammal_json.py +0 -0
  105. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/ena24_to_json.py +0 -0
  106. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/filenames_to_json.py +0 -0
  107. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/helena_to_cct.py +0 -0
  108. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/idaho-camera-traps.py +0 -0
  109. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/idfg_iwildcam_lila_prep.py +0 -0
  110. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/jb_csv_to_json.py +0 -0
  111. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/mcgill_to_json.py +0 -0
  112. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/missouri_to_json.py +0 -0
  113. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/nacti_fieldname_adjustments.py +0 -0
  114. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/noaa_seals_2019.py +0 -0
  115. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/pc_to_json.py +0 -0
  116. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/plot_wni_giraffes.py +0 -0
  117. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/prepare-noaa-fish-data-for-lila.py +0 -0
  118. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/prepare_zsl_imerit.py +0 -0
  119. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/rspb_to_json.py +0 -0
  120. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/save_the_elephants_survey_A.py +0 -0
  121. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/save_the_elephants_survey_B.py +0 -0
  122. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/snapshot_safari_importer.py +0 -0
  123. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/snapshot_safari_importer_reprise.py +0 -0
  124. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/snapshot_serengeti_lila.py +0 -0
  125. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/snapshotserengeti/make_full_SS_json.py +0 -0
  126. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/snapshotserengeti/make_per_season_SS_json.py +0 -0
  127. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/sulross_get_exif.py +0 -0
  128. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/timelapse_csv_set_to_json.py +0 -0
  129. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/ubc_to_json.py +0 -0
  130. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/umn_to_json.py +0 -0
  131. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/wellington_to_json.py +0 -0
  132. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/importers/wi_to_json.py +0 -0
  133. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/lila/add_locations_to_island_camera_traps.py +0 -0
  134. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/lila/create_lila_test_set.py +0 -0
  135. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/lila/download_lila_subset.py +0 -0
  136. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/lila/generate_lila_per_image_labels.py +0 -0
  137. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/lila/get_lila_annotation_counts.py +0 -0
  138. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/lila/get_lila_image_counts.py +0 -0
  139. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/lila/lila_common.py +0 -0
  140. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/read_exif.py +0 -0
  141. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/remove_exif.py +0 -0
  142. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/yolo_output_to_md_output.py +0 -0
  143. {megadetector-5.0.3 → megadetector-5.0.4}/data_management/yolo_to_coco.py +0 -0
  144. {megadetector-5.0.3 → megadetector-5.0.4}/detection/detector_training/copy_checkpoints.py +0 -0
  145. {megadetector-5.0.3 → megadetector-5.0.4}/detection/detector_training/model_main_tf2.py +0 -0
  146. {megadetector-5.0.3 → megadetector-5.0.4}/detection/run_inference_with_yolov5_val.py +0 -0
  147. {megadetector-5.0.3 → megadetector-5.0.4}/detection/run_tiled_inference.py +0 -0
  148. {megadetector-5.0.3 → megadetector-5.0.4}/detection/tf_detector.py +0 -0
  149. {megadetector-5.0.3 → megadetector-5.0.4}/detection/video_utils.py +0 -0
  150. {megadetector-5.0.3 → megadetector-5.0.4}/md_utils/azure_utils.py +0 -0
  151. {megadetector-5.0.3 → megadetector-5.0.4}/md_utils/ct_utils.py +0 -0
  152. {megadetector-5.0.3 → megadetector-5.0.4}/md_utils/directory_listing.py +0 -0
  153. {megadetector-5.0.3 → megadetector-5.0.4}/md_utils/matlab_porting_tools.py +0 -0
  154. {megadetector-5.0.3 → megadetector-5.0.4}/md_utils/path_utils.py +0 -0
  155. {megadetector-5.0.3 → megadetector-5.0.4}/md_utils/process_utils.py +0 -0
  156. {megadetector-5.0.3 → megadetector-5.0.4}/md_utils/sas_blob_utils.py +0 -0
  157. {megadetector-5.0.3 → megadetector-5.0.4}/md_utils/string_utils.py +0 -0
  158. {megadetector-5.0.3 → megadetector-5.0.4}/md_utils/write_html_image_list.py +0 -0
  159. {megadetector-5.0.3 → megadetector-5.0.4}/md_visualization/plot_utils.py +0 -0
  160. {megadetector-5.0.3 → megadetector-5.0.4}/md_visualization/render_images_with_thumbnails.py +0 -0
  161. {megadetector-5.0.3 → megadetector-5.0.4}/md_visualization/visualize_db.py +0 -0
  162. {megadetector-5.0.3 → megadetector-5.0.4}/md_visualization/visualize_detector_output.py +0 -0
  163. {megadetector-5.0.3 → megadetector-5.0.4}/md_visualization/visualize_incoming_annotations.py +0 -0
  164. {megadetector-5.0.3 → megadetector-5.0.4}/md_visualization/visualize_megadb.py +0 -0
  165. {megadetector-5.0.3 → megadetector-5.0.4}/megadetector.egg-info/dependency_links.txt +0 -0
  166. {megadetector-5.0.3 → megadetector-5.0.4}/megadetector.egg-info/top_level.txt +0 -0
  167. {megadetector-5.0.3 → megadetector-5.0.4}/setup.cfg +0 -0
  168. {megadetector-5.0.3 → megadetector-5.0.4}/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +0 -0
  169. {megadetector-5.0.3 → megadetector-5.0.4}/taxonomy_mapping/map_new_lila_datasets.py +0 -0
  170. {megadetector-5.0.3 → megadetector-5.0.4}/taxonomy_mapping/prepare_lila_taxonomy_release.py +0 -0
  171. {megadetector-5.0.3 → megadetector-5.0.4}/taxonomy_mapping/preview_lila_taxonomy.py +0 -0
  172. {megadetector-5.0.3 → megadetector-5.0.4}/taxonomy_mapping/retrieve_sample_image.py +0 -0
  173. {megadetector-5.0.3 → megadetector-5.0.4}/taxonomy_mapping/simple_image_download.py +0 -0
  174. {megadetector-5.0.3 → megadetector-5.0.4}/taxonomy_mapping/species_lookup.py +0 -0
  175. {megadetector-5.0.3 → megadetector-5.0.4}/taxonomy_mapping/taxonomy_csv_checker.py +0 -0
  176. {megadetector-5.0.3 → megadetector-5.0.4}/taxonomy_mapping/taxonomy_graph.py +0 -0
  177. {megadetector-5.0.3 → megadetector-5.0.4}/taxonomy_mapping/validate_lila_category_mappings.py +0 -0
@@ -0,0 +1,141 @@
1
+ Metadata-Version: 2.1
2
+ Name: megadetector
3
+ Version: 5.0.4
4
+ Summary: MegaDetector is an AI model that helps conservation folks spend less time doing boring things with camera trap images.
5
+ Author-email: Your friendly neighborhood MegaDetector team <cameratraps@lila.science>
6
+ Maintainer-email: Your friendly neighborhood MegaDetector team <cameratraps@lila.science>
7
+ License: MIT License
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
26
+
27
+ Project-URL: Homepage, https://github.com/agentmorris/MegaDetector
28
+ Project-URL: Bug Reports, https://github.com/agentmorris/MegaDetector/issues
29
+ Project-URL: Source, https://github.com/agentmorris/MegaDetector
30
+ Keywords: camera traps,conservation,wildlife,ai
31
+ Classifier: Development Status :: 3 - Alpha
32
+ Classifier: License :: OSI Approved :: MIT License
33
+ Classifier: Programming Language :: Python :: 3
34
+ Requires-Python: >=3.9
35
+ Description-Content-Type: text/markdown
36
+ License-File: LICENSE
37
+ Requires-Dist: Pillow>=9.5
38
+ Requires-Dist: tqdm>=4.64.0
39
+ Requires-Dist: jsonpickle>=3.0.2
40
+ Requires-Dist: humanfriendly>=10.0
41
+ Requires-Dist: numpy>=1.26.0
42
+ Requires-Dist: matplotlib>=3.8.0
43
+ Requires-Dist: opencv-python>=4.8.0
44
+ Requires-Dist: requests>=2.31.0
45
+ Requires-Dist: pyqtree>=1.0.0
46
+ Requires-Dist: seaborn>=0.12.2
47
+ Requires-Dist: scikit-learn>=1.3.1
48
+ Requires-Dist: pandas>=2.1.1
49
+ Requires-Dist: PyYAML>=6.0.1
50
+ Requires-Dist: torch>=2.0.1
51
+ Requires-Dist: torchvision>=0.15.2
52
+ Requires-Dist: yolov5>=7.0.12
53
+
54
+ # MegaDetector
55
+
56
+ This package is a pip-installable version of the support/inference code for [MegaDetector](https://github.com/agentmorris/MegaDetector), an object detection model that helps conservation biologists spend less time doing boring things with camera trap images.
57
+
58
+ If you want to learn more about what MegaDetector is all about, head over to the [MegaDetector repo](https://github.com/agentmorris/MegaDetector).
59
+
60
+
61
+ ## Reasons you probably aren't looking for this package
62
+
63
+ ### If you are an ecologist...
64
+
65
+ If you are an ecologist looking to use MegaDetector to help you get through your camera trap images, you probably don't want this package. We recommend starting with our "[Getting started with MegaDetector](https://github.com/agentmorris/MegaDetector/blob/main/collaborations.md)" page, then digging in to the [MegaDetector User Guide](https://github.com/agentmorris/MegaDetector/blob/main/megadetector.md), which will walk you through the process of using MegaDetector. That journey will <i>not</i> involve this package.
66
+
67
+ ### If you are a computer-vision-y type...
68
+
69
+ If you are a computer-vision-y person looking to run or fine-tune MegaDetector programmatically, you still probably don't want this package. MegaDetector is just a fine-tuned version of [YOLOv5](https://github.com/ultralytics/yolov5), and the [ultralytics](https://github.com/ultralytics/ultralytics/) package (from the developers of YOLOv5) has a zillion bells and whistles for both inference and fine-tuning that this package doesn't.
70
+
71
+ ## Reasons you might want to use this package
72
+
73
+ If you want to programatically interact with the postprocessing tools from the MegaDetector repo, or programmatically run MegaDetector in a way that produces [Timelapse](https://saul.cpsc.ucalgary.ca/timelapse)-friendly output (i.e., output in the standard [MegaDetector output format](https://github.com/agentmorris/MegaDetector/tree/main/api/batch_processing#megadetector-batch-output-format)), this package might be for you.
74
+
75
+ Although even if that describes you, you <i>still</i> might be better off cloning the MegaDetector repo. Pip-installability requires that some dependencies be newer than what was available at the time MDv5 was trained, so results are <i>very slightly</i> different than results produced in the "official" environment. These differences <i>probably</i> don't matter much, but they have not been formally characterized.
76
+
77
+ ## If I haven't talked you out of using this package...
78
+
79
+ To install:
80
+
81
+ `pip install megadetector`
82
+
83
+ MegaDetector model weights aren't downloaded at pip-install time, but they will be (optionally) automatically downloaded the first time you run the model.
84
+
85
+ ### Examples of things you can do with this package
86
+
87
+ #### Run MegaDetector on one image and count the number of detections
88
+
89
+ ```
90
+ from md_utils import url_utils
91
+ from md_visualization import visualization_utils as vis_utils
92
+ from detection import run_detector
93
+
94
+ # This is the image at the bottom of this page, it has one animal in it
95
+ image_url = 'https://github.com/agentmorris/MegaDetector/raw/main/images/orinoquia-thumb-web.jpg'
96
+ temporary_filename = url_utils.download_url(image_url)
97
+
98
+ image = vis_utils.load_image(temporary_filename)
99
+
100
+ # This will automatically download MDv5a to the system temp folder;
101
+ # you can also specify a filename explicitly, or set the $MDV5A
102
+ # environment variable to point to the model file.
103
+ model = run_detector.load_detector('MDV5A')
104
+
105
+ result = model.generate_detections_one_image(image)
106
+
107
+ detections_above_threshold = [d for d in result['detections'] if d['conf'] > 0.2]
108
+ print('Found {} detection above threshold'.format(len(detections_above_threshold)))
109
+ ```
110
+
111
+ #### Run MegaDetector on a folder of images
112
+
113
+ ```
114
+ from detection.run_detector_batch import load_and_run_detector_batch,write_results_to_file
115
+ from md_utils import path_utils
116
+ import os
117
+
118
+ # Pick a folder to run MD on recursively, and an output file
119
+ image_folder = os.path.expanduser('~/megadetector_test_images')
120
+ output_file = os.path.expanduser('~/megadetector_output_test.json')
121
+
122
+ # Recursively find images
123
+ image_file_names = path_utils.find_images(image_folder,recursive=True)
124
+
125
+ # This will automatically download MDv5a to the system temp folder;
126
+ # you can also specify a filename explicitly, or set the $MDV5A
127
+ # environment variable to point to the model file.
128
+ results = load_and_run_detector_batch('MDV5A', image_file_names)
129
+
130
+ # Write results as relative filenames, this is what Timelapse
131
+ # and other downstream tools expect.
132
+ write_results_to_file(results,output_file,relative_path_base=image_folder)
133
+ ```
134
+
135
+ ## Contact
136
+
137
+ Contact <a href="cameratraps@lila.science">cameratraps@lila.science</a> with questions.
138
+
139
+ ## Gratuitous animal picture
140
+
141
+ <img src="https://github.com/agentmorris/MegaDetector/raw/main/images/orinoquia-thumb-web_detections.jpg"><br/>Image credit University of Minnesota, from the [Orinoquía Camera Traps](http://lila.science/datasets/orinoquia-camera-traps/) data set.
@@ -0,0 +1,88 @@
1
+ # MegaDetector
2
+
3
+ This package is a pip-installable version of the support/inference code for [MegaDetector](https://github.com/agentmorris/MegaDetector), an object detection model that helps conservation biologists spend less time doing boring things with camera trap images.
4
+
5
+ If you want to learn more about what MegaDetector is all about, head over to the [MegaDetector repo](https://github.com/agentmorris/MegaDetector).
6
+
7
+
8
+ ## Reasons you probably aren't looking for this package
9
+
10
+ ### If you are an ecologist...
11
+
12
+ If you are an ecologist looking to use MegaDetector to help you get through your camera trap images, you probably don't want this package. We recommend starting with our "[Getting started with MegaDetector](https://github.com/agentmorris/MegaDetector/blob/main/collaborations.md)" page, then digging in to the [MegaDetector User Guide](https://github.com/agentmorris/MegaDetector/blob/main/megadetector.md), which will walk you through the process of using MegaDetector. That journey will <i>not</i> involve this package.
13
+
14
+ ### If you are a computer-vision-y type...
15
+
16
+ If you are a computer-vision-y person looking to run or fine-tune MegaDetector programmatically, you still probably don't want this package. MegaDetector is just a fine-tuned version of [YOLOv5](https://github.com/ultralytics/yolov5), and the [ultralytics](https://github.com/ultralytics/ultralytics/) package (from the developers of YOLOv5) has a zillion bells and whistles for both inference and fine-tuning that this package doesn't.
17
+
18
+ ## Reasons you might want to use this package
19
+
20
+ If you want to programatically interact with the postprocessing tools from the MegaDetector repo, or programmatically run MegaDetector in a way that produces [Timelapse](https://saul.cpsc.ucalgary.ca/timelapse)-friendly output (i.e., output in the standard [MegaDetector output format](https://github.com/agentmorris/MegaDetector/tree/main/api/batch_processing#megadetector-batch-output-format)), this package might be for you.
21
+
22
+ Although even if that describes you, you <i>still</i> might be better off cloning the MegaDetector repo. Pip-installability requires that some dependencies be newer than what was available at the time MDv5 was trained, so results are <i>very slightly</i> different than results produced in the "official" environment. These differences <i>probably</i> don't matter much, but they have not been formally characterized.
23
+
24
+ ## If I haven't talked you out of using this package...
25
+
26
+ To install:
27
+
28
+ `pip install megadetector`
29
+
30
+ MegaDetector model weights aren't downloaded at pip-install time, but they will be (optionally) automatically downloaded the first time you run the model.
31
+
32
+ ### Examples of things you can do with this package
33
+
34
+ #### Run MegaDetector on one image and count the number of detections
35
+
36
+ ```
37
+ from md_utils import url_utils
38
+ from md_visualization import visualization_utils as vis_utils
39
+ from detection import run_detector
40
+
41
+ # This is the image at the bottom of this page, it has one animal in it
42
+ image_url = 'https://github.com/agentmorris/MegaDetector/raw/main/images/orinoquia-thumb-web.jpg'
43
+ temporary_filename = url_utils.download_url(image_url)
44
+
45
+ image = vis_utils.load_image(temporary_filename)
46
+
47
+ # This will automatically download MDv5a to the system temp folder;
48
+ # you can also specify a filename explicitly, or set the $MDV5A
49
+ # environment variable to point to the model file.
50
+ model = run_detector.load_detector('MDV5A')
51
+
52
+ result = model.generate_detections_one_image(image)
53
+
54
+ detections_above_threshold = [d for d in result['detections'] if d['conf'] > 0.2]
55
+ print('Found {} detection above threshold'.format(len(detections_above_threshold)))
56
+ ```
57
+
58
+ #### Run MegaDetector on a folder of images
59
+
60
+ ```
61
+ from detection.run_detector_batch import load_and_run_detector_batch,write_results_to_file
62
+ from md_utils import path_utils
63
+ import os
64
+
65
+ # Pick a folder to run MD on recursively, and an output file
66
+ image_folder = os.path.expanduser('~/megadetector_test_images')
67
+ output_file = os.path.expanduser('~/megadetector_output_test.json')
68
+
69
+ # Recursively find images
70
+ image_file_names = path_utils.find_images(image_folder,recursive=True)
71
+
72
+ # This will automatically download MDv5a to the system temp folder;
73
+ # you can also specify a filename explicitly, or set the $MDV5A
74
+ # environment variable to point to the model file.
75
+ results = load_and_run_detector_batch('MDV5A', image_file_names)
76
+
77
+ # Write results as relative filenames, this is what Timelapse
78
+ # and other downstream tools expect.
79
+ write_results_to_file(results,output_file,relative_path_base=image_folder)
80
+ ```
81
+
82
+ ## Contact
83
+
84
+ Contact <a href="cameratraps@lila.science">cameratraps@lila.science</a> with questions.
85
+
86
+ ## Gratuitous animal picture
87
+
88
+ <img src="https://github.com/agentmorris/MegaDetector/raw/main/images/orinoquia-thumb-web_detections.jpg"><br/>Image credit University of Minnesota, from the [Orinoquía Camera Traps](http://lila.science/datasets/orinoquia-camera-traps/) data set.
@@ -122,7 +122,7 @@ Here are a few of the organizations that have used MegaDetector... we're only li
122
122
  * [Bavarian Forest National Park](https://www.nationalpark-bayerischer-wald.bayern.de/english/index.htm) ([story](https://customers.microsoft.com/en-au/story/1667539539271247797-nationalparkbayerischerwald-azure-en))
123
123
  * [Felidae Conservation Fund](https://felidaefund.org/) ([WildePod platform](https://wildepod.org/)) ([blog post](https://abhaykashyap.com/blog/ai-powered-camera-trap-image-annotation-system/))
124
124
  * [Alberta Biodiversity Monitoring Institute (ABMI)](https://www.abmi.ca/home.html) ([WildTrax platform](https://www.wildtrax.ca/)) (blog posts [1](https://wildcams.ca/blog/the-abmi-visits-the-zoo/),[2](http://blog.abmi.ca/2023/06/14/making-wildtrax-its-not-a-kind-of-magic-behind-the-screen/))
125
- * [Shan Shui Conservation Center](http://en.shanshui.org/) ([blog post](https://mp.weixin.qq.com/s/iOIQF3ckj0-rEG4yJgerYw?fbclid=IwAR0alwiWbe3udIcFvqqwm7y5qgr9hZpjr871FZIa-ErGUukZ7yJ3ZhgCevs)) ([translated blog post](https://mp-weixin-qq-com.translate.goog/s/iOIQF3ckj0-rEG4yJgerYw?fbclid=IwAR0alwiWbe3udIcFvqqwm7y5qgr9hZpjr871FZIa-ErGUukZ7yJ3ZhgCevs&_x_tr_sl=auto&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=wapp))
125
+ * [Shan Shui Conservation Center](http://en.shanshui.org/) ([blog post](https://mp.weixin.qq.com/s/iOIQF3ckj0-rEG4yJgerYw?fbclid=IwAR0alwiWbe3udIcFvqqwm7y5qgr9hZpjr871FZIa-ErGUukZ7yJ3ZhgCevs)) ([translated blog post](https://mp-weixin-qq-com.translate.goog/s/iOIQF3ckj0-rEG4yJgerYw?fbclid=IwAR0alwiWbe3udIcFvqqwm7y5qgr9hZpjr871FZIa-ErGUukZ7yJ3ZhgCevs&_x_tr_sl=auto&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=wapp)) ([Web demo](https://cameratrap-ai.hinature.cn/home))
126
126
  * [Irvine Ranch Conservancy](http://www.irconservancy.org/) ([story](https://www.ocregister.com/2022/03/30/ai-software-is-helping-researchers-focus-on-learning-about-ocs-wild-animals/))
127
127
  * [Wildlife Protection Solutions](https://wildlifeprotectionsolutions.org/) ([story](https://customers.microsoft.com/en-us/story/1384184517929343083-wildlife-protection-solutions-nonprofit-ai-for-earth), [story](https://www.enterpriseai.news/2023/02/20/ai-helps-wildlife-protection-solutions-safeguard-endangered-species/))
128
128
  * [Q42](https://www.q42.nl/en) ([blog post](https://engineering.q42.nl/ai-bear-repeller/))
@@ -3,8 +3,8 @@
3
3
  # md_to_labelme.py
4
4
  #
5
5
  # "Converts" a MegaDetector output .json file to labelme format (one .json per image
6
- # file). "Convert" is in quotes because this is an opinionated transformation, that requires a
7
- # confidence threshold.
6
+ # file). "Convert" is in quotes because this is an opinionated transformation that
7
+ # requires a confidence threshold.
8
8
  #
9
9
  # TODO:
10
10
  #
@@ -24,13 +24,65 @@ from md_visualization.visualization_utils import open_image
24
24
  from md_utils.ct_utils import truncate_float
25
25
 
26
26
  output_precision = 3
27
+ default_confidence_threshold = 0.15
27
28
 
28
29
 
29
30
  #%% Functions
30
31
 
31
- def md_to_labelme(results_file,image_base,confidence_threshold,overwrite=False):
32
+ def get_labelme_dict_for_image(im,image_base_name,category_id_to_name,info=None,confidence_threshold=None):
33
+ """
34
+ For the given image struct in MD results format, reformat the detections into
35
+ labelme format. Returns a dict.
36
+ """
32
37
 
33
- #%%
38
+ if confidence_threshold is None:
39
+ confidence_threshold = -1.0
40
+
41
+ output_dict = {}
42
+ if info is not None:
43
+ output_dict['md_info'] = info
44
+ output_dict['version'] = '5.3.0a0'
45
+ output_dict['flags'] = {}
46
+ output_dict['shapes'] = []
47
+ output_dict['imagePath'] = image_base_name
48
+ output_dict['imageHeight'] = im['height']
49
+ output_dict['imageWidth'] = im['width']
50
+ output_dict['imageData'] = None
51
+
52
+ for det in im['detections']:
53
+
54
+ if det['conf'] < confidence_threshold:
55
+ continue
56
+
57
+ shape = {}
58
+ shape['conf'] = det['conf']
59
+ shape['label'] = category_id_to_name[det['category']]
60
+ shape['shape_type'] = 'rectangle'
61
+ shape['description'] = ''
62
+ shape['group_id'] = None
63
+
64
+ # MD boxes are [x_min, y_min, width_of_box, height_of_box] (relative)
65
+ #
66
+ # labelme boxes are [[x0,y0],[x1,y1]] (absolute)
67
+ x0 = truncate_float(det['bbox'][0] * im['width'],output_precision)
68
+ y0 = truncate_float(det['bbox'][1] * im['height'],output_precision)
69
+ x1 = truncate_float(x0 + det['bbox'][2] * im['width'],output_precision)
70
+ y1 = truncate_float(y0 + det['bbox'][3] * im['height'],output_precision)
71
+ shape['points'] = [[x0,y0],[x1,y1]]
72
+ output_dict['shapes'].append(shape)
73
+
74
+ # ...for each detection
75
+
76
+ return output_dict
77
+
78
+ # ...def get_labelme_dict_for_image()
79
+
80
+
81
+ def md_to_labelme(results_file,image_base,confidence_threshold=None,overwrite=False):
82
+ """
83
+ For all the images in [results_file], write a .json file in labelme format alongside the
84
+ corresponding relative path within image_base.
85
+ """
34
86
 
35
87
  # Load MD results
36
88
  with open(results_file,'r') as f:
@@ -57,45 +109,20 @@ def md_to_labelme(results_file,image_base,confidence_threshold,overwrite=False):
57
109
  print('Skipping existing file {}'.format(json_path))
58
110
  continue
59
111
 
60
- output_dict = {}
61
- output_dict['md_info'] = md_results['info']
62
- output_dict['version'] = '5.3.0a0'
63
- output_dict['flags'] = {}
64
- output_dict['shapes'] = []
65
- output_dict['imagePath'] = os.path.basename(im_full_path)
66
- output_dict['imageHeight'] = im['height']
67
- output_dict['imageWidth'] = im['width']
68
- output_dict['imageData'] = None
69
-
70
- for det in im['detections']:
71
-
72
- if det['conf'] < confidence_threshold:
73
- continue
74
-
75
- shape = {}
76
- shape['conf'] = det['conf']
77
- shape['label'] = md_results['detection_categories'][det['category']]
78
- shape['shape_type'] = 'rectangle'
79
- shape['description'] = ''
80
- shape['group_id'] = None
81
-
82
- # MD boxes are [x_min, y_min, width_of_box, height_of_box] (relative)
83
- #
84
- # labelme boxes are [[x0,y0],[x1,y1]] (absolute)
85
- x0 = truncate_float(det['bbox'][0] * im['width'],output_precision)
86
- y0 = truncate_float(det['bbox'][1] * im['height'],output_precision)
87
- x1 = truncate_float(x0 + det['bbox'][2] * im['width'],output_precision)
88
- y1 = truncate_float(y0 + det['bbox'][3] * im['height'],output_precision)
89
- shape['points'] = [[x0,y0],[x1,y1]]
90
- output_dict['shapes'].append(shape)
91
-
92
- # ...for each detection
112
+ output_dict = get_labelme_dict_for_image(im,
113
+ image_base_name=os.path.basename(im_full_path),
114
+ category_id_to_name=md_results['detection_categories'],
115
+ info=md_results['info'],
116
+ confidence_threshold=confidence_threshold)
93
117
 
94
118
  with open(json_path,'w') as f:
95
119
  json.dump(output_dict,f,indent=1)
96
120
 
97
121
  # ...for each image
98
122
 
123
+ # ...def md_to_labelme()
124
+
125
+
99
126
  #%% Interactive driver
100
127
 
101
128
  if False:
@@ -131,7 +158,9 @@ def main():
131
158
  parser.add_argument(
132
159
  'confidence_threshold',
133
160
  type=float,
134
- help='Confidence threshold')
161
+ default=default_confidence_threshold,
162
+ help='Confidence threshold (default {})'.format(default_confidence_threshold)
163
+ )
135
164
 
136
165
  parser.add_argument(
137
166
  '--overwrite',
@@ -85,7 +85,7 @@ from typing import Any
85
85
  import pandas as pd
86
86
  from tqdm import tqdm
87
87
 
88
- from ct_utils import truncate_float
88
+ from md_utils.ct_utils import truncate_float
89
89
 
90
90
 
91
91
  #%% Support functions
@@ -484,7 +484,7 @@ def process_file(fn_relative,verbose=False):
484
484
  if tag['label'] in tag_mappings:
485
485
  tag['label'] = tag_mappings[tag['label']]
486
486
 
487
- # Discard tags below the minumum confidence
487
+ # Discard tags below the minimum confidence
488
488
  if tag['confidence'] >= confidence_threshold:
489
489
  valid_tags.append(tag)
490
490
  else:
@@ -103,7 +103,7 @@ def process_video(options):
103
103
  # TODO:
104
104
  #
105
105
  # This is a lazy fix to an issue... if multiple users run this script, the
106
- # "process_camera_trap_video" is owned by the first person who creates it, and others
106
+ # "process_camera_trap_video" folder is owned by the first person who creates it, and others
107
107
  # can't write to it. I could create uniquely-named folders, but I philosophically prefer
108
108
  # to put all the individual UUID-named folders within a larger folder, so as to be a
109
109
  # good tempdir citizen. So, the lazy fix is to make this world-writable.
@@ -85,7 +85,7 @@ assert utils_imported, 'YOLOv5 import error'
85
85
 
86
86
  print(f'Using PyTorch version {torch.__version__}')
87
87
 
88
-
88
+
89
89
  #%% Classes
90
90
 
91
91
  class PTDetector:
@@ -144,8 +144,8 @@ class PTDetector:
144
144
 
145
145
  return model
146
146
 
147
- def generate_detections_one_image(self, img_original, image_id,
148
- detection_threshold, image_size=None,
147
+ def generate_detections_one_image(self, img_original, image_id='unknown',
148
+ detection_threshold=0.00001, image_size=None,
149
149
  skip_image_resizing=False):
150
150
  """
151
151
  Apply the detector to an image.
@@ -127,6 +127,15 @@ DEFAULT_BOX_EXPANSION = 0
127
127
  DEFAULT_LABEL_FONT_SIZE = 16
128
128
  DETECTION_FILENAME_INSERT = '_detections'
129
129
 
130
+ # The model filenames "MDV5A", "MDV5B", and "MDV4" are special; they will trigger an
131
+ # automatic model download to the system temp folder, or they will use the paths specified in the
132
+ # $MDV4, $MDV5A, or $MDV5B environment variables if they exist.
133
+ downloadable_models = {
134
+ 'MDV4':'https://github.com/agentmorris/MegaDetector/releases/download/v4.1/md_v4.1.0.pb',
135
+ 'MDV5A':'https://github.com/agentmorris/MegaDetector/releases/download/v5.0/md_v5a.0.0.pt',
136
+ 'MDV5B':'https://github.com/agentmorris/MegaDetector/releases/download/v5.0/md_v5b.0.0.pt'
137
+ }
138
+
130
139
 
131
140
  #%% Utility functions
132
141
 
@@ -257,6 +266,9 @@ def load_detector(model_file, force_cpu=False):
257
266
  Load a TF or PT detector, depending on the extension of model_file.
258
267
  """
259
268
 
269
+ # Possibly automatically download the model
270
+ model_file = try_download_known_detector(model_file)
271
+
260
272
  start_time = time.time()
261
273
  if model_file.endswith('.pb'):
262
274
  from detection.tf_detector import TFDetector
@@ -290,6 +302,9 @@ def load_and_run_detector(model_file, image_file_names, output_dir,
290
302
  print('Warning: no files available')
291
303
  return
292
304
 
305
+ # Possibly automatically download the model
306
+ model_file = try_download_known_detector(model_file)
307
+
293
308
  print('GPU available: {}'.format(is_gpu_available(model_file)))
294
309
 
295
310
  detector = load_detector(model_file)
@@ -429,6 +444,55 @@ def load_and_run_detector(model_file, image_file_names, output_dir,
429
444
  # ...def load_and_run_detector()
430
445
 
431
446
 
447
+ def download_model(model_name,force_download=False):
448
+ """
449
+ Download one of the known models to local temp space if it hasn't already been downloaded
450
+ """
451
+
452
+ import tempfile
453
+ from md_utils.url_utils import download_url
454
+ model_tempdir = os.path.join(tempfile.gettempdir(), 'megadetector_models')
455
+ os.makedirs(model_tempdir,exist_ok=True)
456
+
457
+ # This is a lazy fix to an issue... if multiple users run this script, the
458
+ # "megadetector_models" folder is owned by the first person who creates it, and others
459
+ # can't write to it. I could create uniquely-named folders, but I philosophically prefer
460
+ # to put all the individual UUID-named folders within a larger folder, so as to be a
461
+ # good tempdir citizen. So, the lazy fix is to make this world-writable.
462
+ try:
463
+ os.chmod(model_tempdir,0o777)
464
+ except Exception:
465
+ pass
466
+ if model_name not in downloadable_models:
467
+ print('Unrecognized downloadable model {}'.format(model_name))
468
+ return None
469
+ url = downloadable_models[model_name]
470
+ destination_filename = os.path.join(model_tempdir,url.split('/')[-1])
471
+ local_file = download_url(url, destination_filename=destination_filename, progress_updater=None,
472
+ force_download=force_download, verbose=True)
473
+ return local_file
474
+
475
+
476
+ def try_download_known_detector(detector_file):
477
+ """
478
+ Check whether detector_file is really the name of a known model, in which case we will
479
+ either read the actual filename from the corresponding environment variable or download
480
+ (if necessary) to local temp space. Otherwise just returns the input string.
481
+ """
482
+
483
+ if detector_file in downloadable_models:
484
+ if detector_file in os.environ:
485
+ fn = os.environ[detector_file]
486
+ print('Reading MD location from environment variable {}: {}'.format(
487
+ detector_file,fn))
488
+ detector_file = fn
489
+ else:
490
+ print('Downloading model {}'.format(detector_file))
491
+ detector_file = download_model(detector_file)
492
+ return detector_file
493
+
494
+
495
+
432
496
  #%% Command-line driver
433
497
 
434
498
  def main():
@@ -438,7 +502,7 @@ def main():
438
502
 
439
503
  parser.add_argument(
440
504
  'detector_file',
441
- help='Path to TensorFlow (.pb) or PyTorch (.pt) detector model file')
505
+ help='Path detector model file (.pb or .pt). Can also be MDV4, MDV5A, or MDV5B to request automatic download.')
442
506
 
443
507
  # Must specify either an image file or a directory
444
508
  group = parser.add_mutually_exclusive_group(required=True)
@@ -506,6 +570,10 @@ def main():
506
570
 
507
571
  args = parser.parse_args()
508
572
 
573
+ # If the specified detector file is really the name of a known model, find
574
+ # (and possibly download) that model
575
+ args.detector_file = try_download_known_detector(args.detector_file)
576
+
509
577
  assert os.path.exists(args.detector_file), 'detector file {} does not exist'.format(
510
578
  args.detector_file)
511
579
  assert 0.0 < args.threshold <= 1.0, 'Confidence threshold needs to be between 0 and 1'
@@ -64,6 +64,7 @@ from multiprocessing.pool import Pool as workerpool
64
64
  import detection.run_detector as run_detector
65
65
  from detection.run_detector import is_gpu_available,\
66
66
  load_detector,\
67
+ try_download_known_detector,\
67
68
  get_detector_version_from_filename,\
68
69
  get_detector_metadata_from_version_string
69
70
 
@@ -413,6 +414,8 @@ def load_and_run_detector_batch(model_file, image_file_names, checkpoint_path=No
413
414
 
414
415
  already_processed = set([i['file'] for i in results])
415
416
 
417
+ model_file = try_download_known_detector(model_file)
418
+
416
419
  print('GPU available: {}'.format(is_gpu_available(model_file)))
417
420
 
418
421
  if n_cores > 1 and is_gpu_available(model_file):
@@ -743,7 +746,7 @@ def main():
743
746
  description='Module to run a TF/PT animal detection model on lots of images')
744
747
  parser.add_argument(
745
748
  'detector_file',
746
- help='Path to detector model file (.pb or .pt)')
749
+ help='Path to detector model file (.pb or .pt). Can also be MDV4, MDV5A, or MDV5B to request automatic download.')
747
750
  parser.add_argument(
748
751
  'image_file',
749
752
  help='Path to a single image file, a JSON file containing a list of paths to images, or a directory')
@@ -838,6 +841,10 @@ def main():
838
841
 
839
842
  args = parser.parse_args()
840
843
 
844
+ # If the specified detector file is really the name of a known model, find
845
+ # (and possibly download) that model
846
+ args.detector_file = try_download_known_detector(args.detector_file)
847
+
841
848
  assert os.path.exists(args.detector_file), \
842
849
  'detector file {} does not exist'.format(args.detector_file)
843
850
  assert 0.0 < args.threshold <= 1.0, 'Confidence threshold needs to be between 0 and 1'
@@ -17,9 +17,6 @@ import requests
17
17
  from tqdm import tqdm
18
18
  from urllib.parse import urlparse
19
19
 
20
- # pip install progressbar2
21
- import progressbar
22
-
23
20
  url_utils_temp_dir = None
24
21
  max_path_len = 255
25
22
 
@@ -36,6 +33,10 @@ class DownloadProgressBar():
36
33
 
37
34
  def __call__(self, block_num, block_size, total_size):
38
35
  if not self.pbar:
36
+ # This is a pretty random import I'd rather not depend on outside of the
37
+ # rare case where it's used, so importing locally
38
+ # pip install progressbar2
39
+ import progressbar
39
40
  self.pbar = progressbar.ProgressBar(max_value=total_size)
40
41
  self.pbar.start()
41
42
 
@@ -160,7 +160,7 @@ def resize_image(image, target_width, target_height=-1):
160
160
  # w = ar * h
161
161
  target_width = int(aspect_ratio * target_height)
162
162
 
163
- # This parameter changed between Pillow vesions 9 and 10, and for a bit, I'd like to
163
+ # This parameter changed between Pillow versions 9 and 10, and for a bit, I'd like to
164
164
  # support both.
165
165
  try:
166
166
  resized_image = image.resize((target_width, target_height), Image.ANTIALIAS)