megadetector 5.0.16__tar.gz → 5.0.18__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 (209) hide show
  1. {megadetector-5.0.16/megadetector.egg-info → megadetector-5.0.18}/PKG-INFO +4 -6
  2. {megadetector-5.0.16 → megadetector-5.0.18}/README-package.md +3 -5
  3. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/snapshot_safari_importer_reprise.py +28 -16
  4. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/detection/process_video.py +20 -10
  5. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/detection/run_detector_batch.py +1 -1
  6. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/detection/video_utils.py +15 -4
  7. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/postprocess_batch_results.py +4 -4
  8. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +5 -2
  9. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/utils/ct_utils.py +48 -0
  10. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/utils/md_tests.py +43 -15
  11. megadetector-5.0.18/megadetector/utils/torch_test.py +32 -0
  12. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/utils/url_utils.py +94 -3
  13. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/visualization/visualization_utils.py +21 -6
  14. {megadetector-5.0.16 → megadetector-5.0.18/megadetector.egg-info}/PKG-INFO +4 -6
  15. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector.egg-info/SOURCES.txt +1 -0
  16. {megadetector-5.0.16 → megadetector-5.0.18}/pyproject.toml +1 -1
  17. {megadetector-5.0.16 → megadetector-5.0.18}/LICENSE +0 -0
  18. {megadetector-5.0.16 → megadetector-5.0.18}/README.md +0 -0
  19. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/__init__.py +0 -0
  20. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/__init__.py +0 -0
  21. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/api_core/__init__.py +0 -0
  22. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/api_core/batch_service/__init__.py +0 -0
  23. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/api_core/batch_service/score.py +0 -0
  24. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/api_core/server.py +0 -0
  25. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/api_core/server_api_config.py +0 -0
  26. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/api_core/server_app_config.py +0 -0
  27. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/api_core/server_batch_job_manager.py +0 -0
  28. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/api_core/server_job_status_table.py +0 -0
  29. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/api_core/server_orchestration.py +0 -0
  30. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/api_core/server_utils.py +0 -0
  31. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/api_core_support/__init__.py +0 -0
  32. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/api_core_support/aggregate_results_manually.py +0 -0
  33. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/api_support/__init__.py +0 -0
  34. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/api_support/summarize_daily_activity.py +0 -0
  35. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/data_preparation/__init__.py +0 -0
  36. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/integration/digiKam/setup.py +0 -0
  37. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/integration/digiKam/xmp_integration.py +0 -0
  38. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/integration/eMammal/test_scripts/config_template.py +0 -0
  39. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +0 -0
  40. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +0 -0
  41. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/synchronous/__init__.py +0 -0
  42. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/synchronous/api_core/animal_detection_api/__init__.py +0 -0
  43. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/synchronous/api_core/animal_detection_api/api_backend.py +0 -0
  44. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/synchronous/api_core/animal_detection_api/api_frontend.py +0 -0
  45. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/synchronous/api_core/animal_detection_api/config.py +0 -0
  46. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/synchronous/api_core/tests/__init__.py +0 -0
  47. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/api/synchronous/api_core/tests/load_test.py +0 -0
  48. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/__init__.py +0 -0
  49. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/aggregate_classifier_probs.py +0 -0
  50. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/analyze_failed_images.py +0 -0
  51. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/cache_batchapi_outputs.py +0 -0
  52. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/create_classification_dataset.py +0 -0
  53. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/crop_detections.py +0 -0
  54. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/csv_to_json.py +0 -0
  55. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/detect_and_crop.py +0 -0
  56. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/efficientnet/__init__.py +0 -0
  57. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/efficientnet/model.py +0 -0
  58. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/efficientnet/utils.py +0 -0
  59. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/evaluate_model.py +0 -0
  60. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/identify_mislabeled_candidates.py +0 -0
  61. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/json_to_azcopy_list.py +0 -0
  62. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/json_validator.py +0 -0
  63. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/map_classification_categories.py +0 -0
  64. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/merge_classification_detection_output.py +0 -0
  65. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/prepare_classification_script.py +0 -0
  66. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/prepare_classification_script_mc.py +0 -0
  67. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/run_classifier.py +0 -0
  68. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/save_mislabeled.py +0 -0
  69. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/train_classifier.py +0 -0
  70. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/train_classifier_tf.py +0 -0
  71. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/classification/train_utils.py +0 -0
  72. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/__init__.py +0 -0
  73. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/annotations/__init__.py +0 -0
  74. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/annotations/annotation_constants.py +0 -0
  75. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/camtrap_dp_to_coco.py +0 -0
  76. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/cct_json_utils.py +0 -0
  77. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/cct_to_md.py +0 -0
  78. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/cct_to_wi.py +0 -0
  79. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/coco_to_labelme.py +0 -0
  80. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/coco_to_yolo.py +0 -0
  81. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/databases/__init__.py +0 -0
  82. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/databases/add_width_and_height_to_db.py +0 -0
  83. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/databases/combine_coco_camera_traps_files.py +0 -0
  84. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/databases/integrity_check_json_db.py +0 -0
  85. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/databases/subset_json_db.py +0 -0
  86. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/generate_crops_from_cct.py +0 -0
  87. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/get_image_sizes.py +0 -0
  88. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/add_nacti_sizes.py +0 -0
  89. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/add_timestamps_to_icct.py +0 -0
  90. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/animl_results_to_md_results.py +0 -0
  91. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/auckland_doc_test_to_json.py +0 -0
  92. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/auckland_doc_to_json.py +0 -0
  93. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/awc_to_json.py +0 -0
  94. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/bellevue_to_json.py +0 -0
  95. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/cacophony-thermal-importer.py +0 -0
  96. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/carrizo_shrubfree_2018.py +0 -0
  97. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/carrizo_trail_cam_2017.py +0 -0
  98. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/cct_field_adjustments.py +0 -0
  99. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/channel_islands_to_cct.py +0 -0
  100. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/eMammal/copy_and_unzip_emammal.py +0 -0
  101. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/eMammal/eMammal_helpers.py +0 -0
  102. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/eMammal/make_eMammal_json.py +0 -0
  103. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/ena24_to_json.py +0 -0
  104. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/filenames_to_json.py +0 -0
  105. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/helena_to_cct.py +0 -0
  106. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/idaho-camera-traps.py +0 -0
  107. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/idfg_iwildcam_lila_prep.py +0 -0
  108. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/import_desert_lion_conservation_camera_traps.py +0 -0
  109. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/jb_csv_to_json.py +0 -0
  110. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/mcgill_to_json.py +0 -0
  111. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/missouri_to_json.py +0 -0
  112. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/nacti_fieldname_adjustments.py +0 -0
  113. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/noaa_seals_2019.py +0 -0
  114. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/pc_to_json.py +0 -0
  115. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/plot_wni_giraffes.py +0 -0
  116. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/prepare-noaa-fish-data-for-lila.py +0 -0
  117. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/prepare_zsl_imerit.py +0 -0
  118. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/rspb_to_json.py +0 -0
  119. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/save_the_elephants_survey_A.py +0 -0
  120. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/save_the_elephants_survey_B.py +0 -0
  121. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/snapshot_safari_importer.py +0 -0
  122. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/snapshot_serengeti_lila.py +0 -0
  123. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/snapshotserengeti/make_full_SS_json.py +0 -0
  124. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/snapshotserengeti/make_per_season_SS_json.py +0 -0
  125. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/sulross_get_exif.py +0 -0
  126. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/timelapse_csv_set_to_json.py +0 -0
  127. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/ubc_to_json.py +0 -0
  128. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/umn_to_json.py +0 -0
  129. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/wellington_to_json.py +0 -0
  130. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/wi_to_json.py +0 -0
  131. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/importers/zamba_results_to_md_results.py +0 -0
  132. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/labelme_to_coco.py +0 -0
  133. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/labelme_to_yolo.py +0 -0
  134. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/lila/__init__.py +0 -0
  135. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/lila/add_locations_to_island_camera_traps.py +0 -0
  136. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/lila/add_locations_to_nacti.py +0 -0
  137. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/lila/create_lila_blank_set.py +0 -0
  138. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/lila/create_lila_test_set.py +0 -0
  139. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/lila/create_links_to_md_results_files.py +0 -0
  140. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/lila/download_lila_subset.py +0 -0
  141. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/lila/generate_lila_per_image_labels.py +0 -0
  142. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/lila/get_lila_annotation_counts.py +0 -0
  143. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/lila/get_lila_image_counts.py +0 -0
  144. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/lila/lila_common.py +0 -0
  145. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/lila/test_lila_metadata_urls.py +0 -0
  146. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/ocr_tools.py +0 -0
  147. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/read_exif.py +0 -0
  148. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/remap_coco_categories.py +0 -0
  149. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/remove_exif.py +0 -0
  150. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/rename_images.py +0 -0
  151. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/resize_coco_dataset.py +0 -0
  152. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/wi_download_csv_to_coco.py +0 -0
  153. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/yolo_output_to_md_output.py +0 -0
  154. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/data_management/yolo_to_coco.py +0 -0
  155. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/detection/__init__.py +0 -0
  156. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/detection/detector_training/__init__.py +0 -0
  157. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/detection/detector_training/model_main_tf2.py +0 -0
  158. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/detection/pytorch_detector.py +0 -0
  159. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/detection/run_detector.py +0 -0
  160. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/detection/run_inference_with_yolov5_val.py +0 -0
  161. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/detection/run_tiled_inference.py +0 -0
  162. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/detection/tf_detector.py +0 -0
  163. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/__init__.py +0 -0
  164. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/add_max_conf.py +0 -0
  165. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/categorize_detections_by_size.py +0 -0
  166. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/classification_postprocessing.py +0 -0
  167. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/combine_api_outputs.py +0 -0
  168. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/compare_batch_results.py +0 -0
  169. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/convert_output_format.py +0 -0
  170. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/load_api_results.py +0 -0
  171. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/md_to_coco.py +0 -0
  172. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/md_to_labelme.py +0 -0
  173. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/merge_detections.py +0 -0
  174. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/remap_detection_categories.py +0 -0
  175. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/render_detection_confusion_matrix.py +0 -0
  176. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py +0 -0
  177. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +0 -0
  178. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/separate_detections_into_folders.py +0 -0
  179. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/subset_json_detector_output.py +0 -0
  180. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/postprocessing/top_folders_to_bottom.py +0 -0
  181. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/taxonomy_mapping/__init__.py +0 -0
  182. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +0 -0
  183. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/taxonomy_mapping/map_new_lila_datasets.py +0 -0
  184. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +0 -0
  185. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/taxonomy_mapping/preview_lila_taxonomy.py +0 -0
  186. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/taxonomy_mapping/retrieve_sample_image.py +0 -0
  187. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/taxonomy_mapping/simple_image_download.py +0 -0
  188. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/taxonomy_mapping/species_lookup.py +0 -0
  189. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/taxonomy_mapping/taxonomy_csv_checker.py +0 -0
  190. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/taxonomy_mapping/taxonomy_graph.py +0 -0
  191. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/taxonomy_mapping/validate_lila_category_mappings.py +0 -0
  192. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/utils/__init__.py +0 -0
  193. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/utils/azure_utils.py +0 -0
  194. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/utils/directory_listing.py +0 -0
  195. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/utils/path_utils.py +0 -0
  196. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/utils/process_utils.py +0 -0
  197. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/utils/sas_blob_utils.py +0 -0
  198. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/utils/split_locations_into_train_val.py +0 -0
  199. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/utils/string_utils.py +0 -0
  200. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/utils/write_html_image_list.py +0 -0
  201. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/visualization/__init__.py +0 -0
  202. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/visualization/plot_utils.py +0 -0
  203. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/visualization/render_images_with_thumbnails.py +0 -0
  204. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/visualization/visualize_db.py +0 -0
  205. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector/visualization/visualize_detector_output.py +0 -0
  206. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector.egg-info/dependency_links.txt +0 -0
  207. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector.egg-info/requires.txt +0 -0
  208. {megadetector-5.0.16 → megadetector-5.0.18}/megadetector.egg-info/top_level.txt +0 -0
  209. {megadetector-5.0.16 → megadetector-5.0.18}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: megadetector
3
- Version: 5.0.16
3
+ Version: 5.0.18
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>
@@ -57,22 +57,20 @@ This package is a pip-installable version of the support/inference code for [Meg
57
57
  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).
58
58
 
59
59
 
60
- ## Reasons you probably aren't looking for this package
60
+ ## Reasons you might not be looking for this package
61
61
 
62
62
  ### If you are an ecologist...
63
63
 
64
- 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/getting-started.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 Python package.
64
+ 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, or at least you probably don't want to start at this page. We recommend starting with our "[Getting started with MegaDetector](https://github.com/agentmorris/MegaDetector/blob/main/getting-started.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.
65
65
 
66
66
  ### If you are a computer-vision-y type...
67
67
 
68
- 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.
68
+ If you are a computer-vision-y person looking to run or fine-tune MegaDetector programmatically, you 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.
69
69
 
70
70
  ## Reasons you might want to use this package
71
71
 
72
72
  If you want to programmatically 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/megadetector/api/batch_processing#megadetector-batch-output-format)), this package might be for you.
73
73
 
74
- 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.
75
-
76
74
  ## If I haven't talked you out of using this package...
77
75
 
78
76
  To install:
@@ -5,22 +5,20 @@ This package is a pip-installable version of the support/inference code for [Meg
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
7
 
8
- ## Reasons you probably aren't looking for this package
8
+ ## Reasons you might not be looking for this package
9
9
 
10
10
  ### If you are an ecologist...
11
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/getting-started.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 Python package.
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, or at least you probably don't want to start at this page. We recommend starting with our "[Getting started with MegaDetector](https://github.com/agentmorris/MegaDetector/blob/main/getting-started.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.
13
13
 
14
14
  ### If you are a computer-vision-y type...
15
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.
16
+ If you are a computer-vision-y person looking to run or fine-tune MegaDetector programmatically, you 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
17
 
18
18
  ## Reasons you might want to use this package
19
19
 
20
20
  If you want to programmatically 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/megadetector/api/batch_processing#megadetector-batch-output-format)), this package might be for you.
21
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
22
  ## If I haven't talked you out of using this package...
25
23
 
26
24
  To install:
@@ -24,7 +24,7 @@ from collections import defaultdict
24
24
 
25
25
  from megadetector.utils import path_utils
26
26
 
27
- input_base = '/media/user/Elements'
27
+ input_base = 'e:/'
28
28
  output_base = os.path.expanduser('~/data/snapshot-safari-metadata')
29
29
  file_list_cache_file = os.path.join(output_base,'file_list.json')
30
30
 
@@ -76,23 +76,16 @@ print('Found a total of {} files, {} of which are images'.format(
76
76
  len(all_files_relative),len(all_image_files)))
77
77
 
78
78
 
79
- #%% Copy all csv files to the annotation cache folder
79
+ #%% Copy all .csv files to the annotation cache folder
80
80
 
81
81
  # fn = csv_files[0]
82
- for fn in csv_files:
82
+ for fn in tqdm(csv_files):
83
+
83
84
  target_file = os.path.join(annotation_cache_dir,os.path.basename(fn))
84
85
  source_file = os.path.join(input_base,fn)
85
86
  shutil.copyfile(source_file,target_file)
86
87
 
87
- def read_cached_csv_file(fn):
88
- """
89
- Later cells will ask to read a .csv file from the original hard drive;
90
- read from the annotation cache instead.
91
- """
92
-
93
- cached_csv_file = os.path.join(annotation_cache_dir,os.path.basename(fn))
94
- df = pd.read_csv(cached_csv_file)
95
- return df
88
+ print('Copied {} .csv files to cache folder'.format(len(csv_files)))
96
89
 
97
90
 
98
91
  #%% List project folders
@@ -123,6 +116,21 @@ project_folder_to_project_code = {v: k for k, v in project_code_to_project_folde
123
116
  project_codes = sorted(list(project_code_to_project_folder.keys()))
124
117
  project_folders = sorted(list(project_code_to_project_folder.values()))
125
118
 
119
+ print('Eumerated {} project folders'.format(len(project_folders)))
120
+
121
+
122
+ #%% Support functions
123
+
124
+ def read_cached_csv_file(fn):
125
+ """
126
+ Later cells will ask to read a .csv file from the original hard drive;
127
+ read from the annotation cache instead.
128
+ """
129
+
130
+ cached_csv_file = os.path.join(annotation_cache_dir,os.path.basename(fn))
131
+ df = pd.read_csv(cached_csv_file)
132
+ return df
133
+
126
134
  def file_to_project_folder(fn):
127
135
  """
128
136
  For a given filename relative to the drive root, return the corresponding
@@ -138,7 +146,6 @@ def file_to_project_folder(fn):
138
146
  assert project_folder in project_folders
139
147
  return project_folder
140
148
 
141
-
142
149
  def file_to_project_code(fn):
143
150
  """
144
151
  For a given filename relative to the drive root, return the corresponding
@@ -147,6 +154,9 @@ def file_to_project_code(fn):
147
154
 
148
155
  return project_folder_to_project_code[file_to_project_folder(fn)]
149
156
 
157
+
158
+ #%% Consistency checking
159
+
150
160
  assert file_to_project_folder(
151
161
  'APN/APN_S2/DW/DW_R5/APN_S2_DW_R5_IMAG0003.JPG') == 'APN'
152
162
  assert file_to_project_folder(
@@ -163,9 +173,11 @@ assert file_to_project_code(
163
173
  #
164
174
  # E.g.:
165
175
  #
166
- # 'DHP': ['Snapshot South Africa/DHP/LILA_Reports/DHP_S1_report_lila.csv',
167
- # 'Snapshot South Africa/DHP/LILA_Reports/DHP_S2_report_lila.csv',
168
- # 'Snapshot South Africa/DHP/LILA_Reports/DHP_S3_report_lila.csv']
176
+ # 'DHP': [
177
+ # 'Snapshot South Africa/DHP/LILA_Reports/DHP_S1_report_lila.csv',
178
+ # 'Snapshot South Africa/DHP/LILA_Reports/DHP_S2_report_lila.csv',
179
+ # 'Snapshot South Africa/DHP/LILA_Reports/DHP_S3_report_lila.csv'
180
+ # ]
169
181
  #
170
182
  project_code_to_report_files = defaultdict(list)
171
183
 
@@ -345,7 +345,8 @@ def process_video(options):
345
345
  caller_provided_rendering_output_folder = (options.frame_rendering_folder is not None)
346
346
 
347
347
  frame_output_folder = None
348
-
348
+ frame_filenames = None
349
+
349
350
  # If we should re-use existing results, and the output file exists, don't bother running MD
350
351
  if (options.reuse_results_if_available and os.path.isfile(options.output_json_file)):
351
352
 
@@ -383,7 +384,7 @@ def process_video(options):
383
384
  verbose=options.verbose,
384
385
  frames_to_process=options.frames_to_extract)
385
386
 
386
- _add_frame_numbers_to_results(frame_results['results'])
387
+ frame_results['results'] = _add_frame_numbers_to_results(frame_results['results'])
387
388
 
388
389
  run_detector_batch.write_results_to_file(
389
390
  frame_results['results'],
@@ -444,7 +445,7 @@ def process_video(options):
444
445
  augment=options.augment,
445
446
  image_size=options.image_size)
446
447
 
447
- _add_frame_numbers_to_results(results)
448
+ results = _add_frame_numbers_to_results(results)
448
449
 
449
450
  run_detector_batch.write_results_to_file(
450
451
  results,
@@ -545,6 +546,7 @@ def process_video_folder(options):
545
546
 
546
547
  frame_output_folder = None
547
548
  image_file_names = None
549
+ video_filename_to_fs = {}
548
550
 
549
551
  # Run MD in memory if we don't need to generate frames
550
552
  #
@@ -575,6 +577,10 @@ def process_video_folder(options):
575
577
 
576
578
  video_results = md_results['results']
577
579
 
580
+ for i_video,video_filename in enumerate(md_results['video_filenames']):
581
+ assert video_filename not in video_filename_to_fs
582
+ video_filename_to_fs[video_filename] = md_results['frame_rates'][i_video]
583
+
578
584
  all_frame_results = []
579
585
 
580
586
  # r = video_results[0]
@@ -586,13 +592,15 @@ def process_video_folder(options):
586
592
  all_frame_results,
587
593
  frames_json,
588
594
  relative_path_base=None,
589
- detector_file=options.model_file,
590
- custom_metadata={'video_frame_rate':md_results['frame_rates']})
595
+ detector_file=options.model_file)
591
596
 
592
597
  else:
593
598
 
594
599
  ## Split every video into frames
595
600
 
601
+ if options.verbose:
602
+ print('Extracting frames for folder {}'.format(options.input_video_file))
603
+
596
604
  if caller_provided_frame_output_folder:
597
605
  frame_output_folder = options.frame_folder
598
606
  else:
@@ -600,8 +608,6 @@ def process_video_folder(options):
600
608
 
601
609
  os.makedirs(frame_output_folder, exist_ok=True)
602
610
 
603
- print('Extracting frames')
604
-
605
611
  frame_filenames, Fs, video_filenames = \
606
612
  video_folder_to_frames(input_folder=options.input_video_file,
607
613
  output_folder_base=frame_output_folder,
@@ -615,6 +621,10 @@ def process_video_folder(options):
615
621
  frames_to_extract=options.frames_to_extract,
616
622
  allow_empty_videos=options.allow_empty_videos)
617
623
 
624
+ for i_video,video_filename in enumerate(video_filenames):
625
+ assert video_filename not in video_filename_to_fs
626
+ video_filename_to_fs[video_filename] = Fs[i_video]
627
+
618
628
  print('Extracted frames for {} videos'.format(len(set(video_filenames))))
619
629
  image_file_names = list(itertools.chain.from_iterable(frame_filenames))
620
630
 
@@ -660,15 +670,15 @@ def process_video_folder(options):
660
670
  results,
661
671
  frames_json,
662
672
  relative_path_base=frame_output_folder,
663
- detector_file=options.model_file,
664
- custom_metadata={'video_frame_rate':Fs})
673
+ detector_file=options.model_file)
665
674
 
666
675
  # ...if we're running MD on in-memory frames vs. extracting frames to disk
667
676
 
668
677
  ## Convert frame-level results to video-level results
669
678
 
670
679
  print('Converting frame-level results to video-level results')
671
- frame_results_to_video_results(frames_json,video_json)
680
+ frame_results_to_video_results(frames_json,video_json,
681
+ video_filename_to_frame_rate=video_filename_to_fs)
672
682
 
673
683
 
674
684
  ## (Optionally) render output videos
@@ -846,7 +846,7 @@ def write_results_to_file(results,
846
846
  https://github.com/agentmorris/MegaDetector/tree/main/megadetector/api/batch_processing#batch-processing-api-output-format
847
847
 
848
848
  Args:
849
- results (list): list of dict, each dict represents detections on one image
849
+ results (list): list of dict, each dict represents detections on one image
850
850
  output_file (str): path to JSON output file, should end in '.json'
851
851
  relative_path_base (str, optional): path to a directory as the base for relative paths, can
852
852
  be None if the paths in [results] are absolute
@@ -22,6 +22,7 @@ from functools import partial
22
22
  from inspect import signature
23
23
 
24
24
  from megadetector.utils import path_utils
25
+ from megadetector.utils.ct_utils import sort_list_of_dicts_by_key
25
26
  from megadetector.visualization import visualization_utils as vis_utils
26
27
 
27
28
  default_fourcc = 'h264'
@@ -197,7 +198,7 @@ def _filename_to_frame_number(filename):
197
198
  def _add_frame_numbers_to_results(results):
198
199
  """
199
200
  Given the 'images' list from a set of MD results that was generated on video frames,
200
- add a 'frame_number' field to each image.
201
+ add a 'frame_number' field to each image, and return the list, sorted by frame number.
201
202
 
202
203
  Args:
203
204
  results (list): list of image dicts
@@ -208,6 +209,9 @@ def _add_frame_numbers_to_results(results):
208
209
  fn = im['file']
209
210
  frame_number = _filename_to_frame_number(fn)
210
211
  im['frame_number'] = frame_number
212
+
213
+ results = sort_list_of_dicts_by_key(results,'frame_number')
214
+ return results
211
215
 
212
216
 
213
217
  def run_callback_on_frames(input_video_file,
@@ -332,8 +336,8 @@ def run_callback_on_frames_for_folder(input_video_folder,
332
336
  recursive (bool, optional): recurse into [input_video_folder]
333
337
 
334
338
  Returns:
335
- dict: dict with keys 'video_filenames' (list), 'frame_rates' (list of floats), 'results' (list).
336
- video_filenames will be *relative* filenames.
339
+ dict: dict with keys 'video_filenames' (list of str), 'frame_rates' (list of floats),
340
+ 'results' (list of list of dicts). 'video_filenames' will contain *relative* filenames.
337
341
  """
338
342
 
339
343
  to_return = {'video_filenames':[],'frame_rates':[],'results':[]}
@@ -777,7 +781,8 @@ class FrameToVideoOptions:
777
781
  self.non_video_behavior = 'error'
778
782
 
779
783
 
780
- def frame_results_to_video_results(input_file,output_file,options=None):
784
+ def frame_results_to_video_results(input_file,output_file,options=None,
785
+ video_filename_to_frame_rate=None):
781
786
  """
782
787
  Given an MD results file produced at the *frame* level, corresponding to a directory
783
788
  created with video_folder_to_frames, maps those frame-level results back to the
@@ -790,6 +795,8 @@ def frame_results_to_video_results(input_file,output_file,options=None):
790
795
  output_file (str): the .json file to which we should write video-level results
791
796
  options (FrameToVideoOptions, optional): parameters for converting frame-level results
792
797
  to video-level results, see FrameToVideoOptions for details
798
+ video_filename_to_frame_rate (dict): maps (relative) video path names to frame rates,
799
+ used only to populate the output file
793
800
  """
794
801
 
795
802
  if options is None:
@@ -878,6 +885,10 @@ def frame_results_to_video_results(input_file,output_file,options=None):
878
885
  im_out['file'] = video_name
879
886
  im_out['detections'] = canonical_detections
880
887
 
888
+ if (video_filename_to_frame_rate is not None) and \
889
+ (video_name in video_filename_to_frame_rate):
890
+ im_out['frame_rate'] = video_filename_to_frame_rate[video_name]
891
+
881
892
  # 'max_detection_conf' is no longer included in output files by default
882
893
  if False:
883
894
  im_out['max_detection_conf'] = 0
@@ -770,7 +770,7 @@ def _render_image_no_gt(file_info,detection_categories_to_results_name,
770
770
  if det['conf'] > max_conf:
771
771
  max_conf = det['conf']
772
772
 
773
- if ('classifications' in det):
773
+ if ('classifications' in det) and (len(det['classifications']) > 0):
774
774
 
775
775
  # This is a list of [class,confidence] pairs, sorted by confidence
776
776
  classifications = det['classifications']
@@ -1203,13 +1203,13 @@ def process_batch_results(options):
1203
1203
  # Rows / first index is ground truth, columns / second index is predicted category
1204
1204
  classifier_cm = collections.defaultdict(lambda: collections.defaultdict(lambda: 0))
1205
1205
 
1206
- # iDetection = 0; fn = detector_files[iDetection]; print(fn)
1206
+ # i_detection = 0; fn = detector_files[i_detection]; print(fn)
1207
1207
  assert len(detector_files) == len(detections_df)
1208
- for iDetection, fn in enumerate(detector_files):
1208
+ for i_detection, fn in enumerate(detector_files):
1209
1209
 
1210
1210
  image_id = ground_truth_indexed_db.filename_to_id[fn]
1211
1211
  image = ground_truth_indexed_db.image_id_to_image[image_id]
1212
- detections = detections_df['detections'].iloc[iDetection]
1212
+ detections = detections_df['detections'].iloc[i_detection]
1213
1213
  pred_class_ids = [det['classifications'][0][0] \
1214
1214
  for det in detections if 'classifications' in det.keys()]
1215
1215
  pred_classnames = [classification_categories[pd] for pd in pred_class_ids]
@@ -210,9 +210,12 @@ class RepeatDetectionOptions:
210
210
  #: a/b/c/RECONYX100 and a/b/c/RECONYX101 may really be the same camera).
211
211
  #:
212
212
  #: See ct_utils for a common replacement function that handles most common
213
- #: manufacturer folder names.
213
+ #: manufacturer folder names:
214
+ #:
215
+ #: from megadetector.utils import ct_utils
216
+ #: self.customDirNameFunction = ct_utils.image_file_to_camera_folder
214
217
  self.customDirNameFunction = None
215
-
218
+
216
219
  #: Include only specific folders, mutually exclusive with [excludeFolders]
217
220
  self.includeFolders = None
218
221
 
@@ -16,6 +16,8 @@ import os
16
16
  import jsonpickle
17
17
  import numpy as np
18
18
 
19
+ from operator import itemgetter
20
+
19
21
  # List of file extensions we'll consider images; comparisons will be case-insensitive
20
22
  # (i.e., no need to include both .jpg and .JPG on this list).
21
23
  image_extensions = ['.jpg', '.jpeg', '.gif', '.png']
@@ -294,6 +296,29 @@ def get_max_conf(im):
294
296
  return max_conf
295
297
 
296
298
 
299
+ def sort_results_for_image(im):
300
+ """
301
+ Sort classification and detection results in descending order by confidence (in place).
302
+
303
+ Args:
304
+ im (dict): image dictionary in the MD output format (with a 'detections' field)
305
+ """
306
+ if 'detections' not in im or im['detections'] is None:
307
+ return
308
+
309
+ # Sort detections in descending order by confidence
310
+ im['detections'] = sort_list_of_dicts_by_key(im['detections'],k='conf',reverse=True)
311
+
312
+ for det in im['detections']:
313
+
314
+ # Sort classifications (which are (class,conf) tuples) in descending order by confidence
315
+ if 'classifications' in det and \
316
+ (det['classifications'] is not None) and \
317
+ (len(det['classifications']) > 0):
318
+ L = det['classifications']
319
+ det['classifications'] = sorted(L,key=itemgetter(1),reverse=True)
320
+
321
+
297
322
  def point_dist(p1,p2):
298
323
  """
299
324
  Computes the distance between two points, represented as length-two tuples.
@@ -406,6 +431,21 @@ def split_list_into_n_chunks(L, n, chunk_strategy='greedy'):
406
431
  raise ValueError('Invalid chunk strategy: {}'.format(chunk_strategy))
407
432
 
408
433
 
434
+ def sort_list_of_dicts_by_key(L,k,reverse=False):
435
+ """
436
+ Sorts the list of dictionaries [L] by the key [k].
437
+
438
+ Args:
439
+ L (list): list of dictionaries to sort
440
+ k (object, typically str): the sort key
441
+ reverse (bool, optional): whether to sort in reverse (descending) order
442
+
443
+ Returns:
444
+ dict: sorted copy of [d]
445
+ """
446
+ return sorted(L, key=lambda d: d[k], reverse=reverse)
447
+
448
+
409
449
  def sort_dictionary_by_key(d,reverse=False):
410
450
  """
411
451
  Sorts the dictionary [d] by key.
@@ -611,3 +651,11 @@ if False:
611
651
  r1 = [0.4,0.8,10,22]; r2 = [100, 101, 200, 210.4]; assert abs(rect_distance(r1,r2)-119.753) < 0.001
612
652
  r1 = [0.4,0.8,10,22]; r2 = [101, 101, 200, 210.4]; assert abs(rect_distance(r1,r2)-120.507) < 0.001
613
653
  r1 = [0.4,0.8,10,22]; r2 = [120, 120, 200, 210.4]; assert abs(rect_distance(r1,r2)-147.323) < 0.001
654
+
655
+
656
+ #%% Test dictionary sorting
657
+
658
+ L = [{'a':5},{'a':0},{'a':10}]
659
+ k = 'a'
660
+ sort_list_of_dicts_by_key(L, k, reverse=True)
661
+