megadetector 5.0.21__tar.gz → 5.0.23__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 (213) hide show
  1. {megadetector-5.0.21/megadetector.egg-info → megadetector-5.0.23}/PKG-INFO +5 -4
  2. {megadetector-5.0.21 → megadetector-5.0.23}/README.md +1 -1
  3. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/cct_json_utils.py +143 -7
  4. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/cct_to_md.py +12 -5
  5. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/databases/integrity_check_json_db.py +83 -77
  6. megadetector-5.0.23/megadetector/data_management/importers/raic_csv_to_md_results.py +416 -0
  7. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/zamba_results_to_md_results.py +1 -2
  8. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/lila/create_lila_test_set.py +25 -11
  9. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/lila/download_lila_subset.py +9 -2
  10. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/lila/generate_lila_per_image_labels.py +3 -2
  11. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/lila/test_lila_metadata_urls.py +5 -1
  12. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/read_exif.py +10 -14
  13. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/rename_images.py +1 -1
  14. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/detection/process_video.py +14 -3
  15. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/detection/pytorch_detector.py +15 -3
  16. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/detection/run_detector.py +4 -3
  17. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/detection/run_detector_batch.py +2 -2
  18. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/detection/run_inference_with_yolov5_val.py +121 -13
  19. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/detection/video_utils.py +21 -10
  20. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/classification_postprocessing.py +1 -1
  21. megadetector-5.0.23/megadetector/postprocessing/compare_batch_results.py +1755 -0
  22. megadetector-5.0.23/megadetector/postprocessing/detector_calibration.py +565 -0
  23. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/md_to_coco.py +85 -20
  24. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/postprocess_batch_results.py +0 -1
  25. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/validate_batch_results.py +65 -15
  26. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/taxonomy_mapping/map_new_lila_datasets.py +15 -12
  27. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +1 -1
  28. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/taxonomy_mapping/preview_lila_taxonomy.py +3 -1
  29. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/utils/ct_utils.py +71 -14
  30. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/utils/md_tests.py +9 -1
  31. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/utils/path_utils.py +14 -7
  32. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/utils/process_utils.py +9 -3
  33. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/utils/write_html_image_list.py +5 -1
  34. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/visualization/visualization_utils.py +211 -87
  35. {megadetector-5.0.21 → megadetector-5.0.23/megadetector.egg-info}/PKG-INFO +5 -4
  36. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector.egg-info/SOURCES.txt +1 -0
  37. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector.egg-info/requires.txt +2 -1
  38. {megadetector-5.0.21 → megadetector-5.0.23}/pyproject.toml +12 -5
  39. megadetector-5.0.21/megadetector/postprocessing/compare_batch_results.py +0 -966
  40. megadetector-5.0.21/megadetector/postprocessing/detector_calibration.py +0 -367
  41. {megadetector-5.0.21 → megadetector-5.0.23}/LICENSE +0 -0
  42. {megadetector-5.0.21 → megadetector-5.0.23}/README-package.md +0 -0
  43. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/__init__.py +0 -0
  44. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/__init__.py +0 -0
  45. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/api_core/__init__.py +0 -0
  46. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/api_core/batch_service/__init__.py +0 -0
  47. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/api_core/batch_service/score.py +0 -0
  48. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/api_core/server.py +0 -0
  49. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/api_core/server_api_config.py +0 -0
  50. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/api_core/server_app_config.py +0 -0
  51. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/api_core/server_batch_job_manager.py +0 -0
  52. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/api_core/server_job_status_table.py +0 -0
  53. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/api_core/server_orchestration.py +0 -0
  54. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/api_core/server_utils.py +0 -0
  55. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/api_core_support/__init__.py +0 -0
  56. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/api_core_support/aggregate_results_manually.py +0 -0
  57. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/api_support/__init__.py +0 -0
  58. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/api_support/summarize_daily_activity.py +0 -0
  59. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/data_preparation/__init__.py +0 -0
  60. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/integration/digiKam/setup.py +0 -0
  61. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/integration/digiKam/xmp_integration.py +0 -0
  62. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/integration/eMammal/test_scripts/config_template.py +0 -0
  63. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +0 -0
  64. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +0 -0
  65. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/synchronous/__init__.py +0 -0
  66. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/synchronous/api_core/animal_detection_api/__init__.py +0 -0
  67. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/synchronous/api_core/animal_detection_api/api_backend.py +0 -0
  68. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/synchronous/api_core/animal_detection_api/api_frontend.py +0 -0
  69. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/synchronous/api_core/animal_detection_api/config.py +0 -0
  70. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/synchronous/api_core/tests/__init__.py +0 -0
  71. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/api/synchronous/api_core/tests/load_test.py +0 -0
  72. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/__init__.py +0 -0
  73. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/aggregate_classifier_probs.py +0 -0
  74. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/analyze_failed_images.py +0 -0
  75. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/cache_batchapi_outputs.py +0 -0
  76. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/create_classification_dataset.py +0 -0
  77. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/crop_detections.py +0 -0
  78. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/csv_to_json.py +0 -0
  79. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/detect_and_crop.py +0 -0
  80. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/efficientnet/__init__.py +0 -0
  81. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/efficientnet/model.py +0 -0
  82. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/efficientnet/utils.py +0 -0
  83. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/evaluate_model.py +0 -0
  84. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/identify_mislabeled_candidates.py +0 -0
  85. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/json_to_azcopy_list.py +0 -0
  86. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/json_validator.py +0 -0
  87. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/map_classification_categories.py +0 -0
  88. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/merge_classification_detection_output.py +0 -0
  89. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/prepare_classification_script.py +0 -0
  90. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/prepare_classification_script_mc.py +0 -0
  91. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/run_classifier.py +0 -0
  92. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/save_mislabeled.py +0 -0
  93. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/train_classifier.py +0 -0
  94. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/train_classifier_tf.py +0 -0
  95. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/classification/train_utils.py +0 -0
  96. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/__init__.py +0 -0
  97. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/annotations/__init__.py +0 -0
  98. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/annotations/annotation_constants.py +0 -0
  99. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/camtrap_dp_to_coco.py +0 -0
  100. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/cct_to_wi.py +0 -0
  101. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/coco_to_labelme.py +0 -0
  102. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/coco_to_yolo.py +0 -0
  103. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/databases/__init__.py +0 -0
  104. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/databases/add_width_and_height_to_db.py +0 -0
  105. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/databases/combine_coco_camera_traps_files.py +0 -0
  106. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/databases/subset_json_db.py +0 -0
  107. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/generate_crops_from_cct.py +0 -0
  108. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/get_image_sizes.py +0 -0
  109. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/add_nacti_sizes.py +0 -0
  110. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/add_timestamps_to_icct.py +0 -0
  111. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/animl_results_to_md_results.py +0 -0
  112. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/auckland_doc_test_to_json.py +0 -0
  113. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/auckland_doc_to_json.py +0 -0
  114. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/awc_to_json.py +0 -0
  115. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/bellevue_to_json.py +0 -0
  116. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/cacophony-thermal-importer.py +0 -0
  117. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/carrizo_shrubfree_2018.py +0 -0
  118. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/carrizo_trail_cam_2017.py +0 -0
  119. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/cct_field_adjustments.py +0 -0
  120. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/channel_islands_to_cct.py +0 -0
  121. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/eMammal/copy_and_unzip_emammal.py +0 -0
  122. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/eMammal/eMammal_helpers.py +0 -0
  123. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/eMammal/make_eMammal_json.py +0 -0
  124. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/ena24_to_json.py +0 -0
  125. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/filenames_to_json.py +0 -0
  126. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/helena_to_cct.py +0 -0
  127. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/idaho-camera-traps.py +0 -0
  128. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/idfg_iwildcam_lila_prep.py +0 -0
  129. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/import_desert_lion_conservation_camera_traps.py +0 -0
  130. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/jb_csv_to_json.py +0 -0
  131. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/mcgill_to_json.py +0 -0
  132. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/missouri_to_json.py +0 -0
  133. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/nacti_fieldname_adjustments.py +0 -0
  134. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/noaa_seals_2019.py +0 -0
  135. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/osu-small-animals-to-json.py +0 -0
  136. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/pc_to_json.py +0 -0
  137. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/plot_wni_giraffes.py +0 -0
  138. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/prepare_zsl_imerit.py +0 -0
  139. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/rspb_to_json.py +0 -0
  140. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/save_the_elephants_survey_A.py +0 -0
  141. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/save_the_elephants_survey_B.py +0 -0
  142. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/snapshot_safari_importer.py +0 -0
  143. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/snapshot_serengeti_lila.py +0 -0
  144. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/snapshotserengeti/make_full_SS_json.py +0 -0
  145. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/snapshotserengeti/make_per_season_SS_json.py +0 -0
  146. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/sulross_get_exif.py +0 -0
  147. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/timelapse_csv_set_to_json.py +0 -0
  148. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/ubc_to_json.py +0 -0
  149. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/umn_to_json.py +0 -0
  150. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/wellington_to_json.py +0 -0
  151. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/importers/wi_to_json.py +0 -0
  152. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/labelme_to_coco.py +0 -0
  153. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/labelme_to_yolo.py +0 -0
  154. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/lila/__init__.py +0 -0
  155. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/lila/add_locations_to_island_camera_traps.py +0 -0
  156. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/lila/add_locations_to_nacti.py +0 -0
  157. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/lila/create_lila_blank_set.py +0 -0
  158. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/lila/create_links_to_md_results_files.py +0 -0
  159. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/lila/get_lila_annotation_counts.py +0 -0
  160. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/lila/get_lila_image_counts.py +0 -0
  161. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/lila/lila_common.py +0 -0
  162. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/ocr_tools.py +0 -0
  163. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/remap_coco_categories.py +0 -0
  164. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/remove_exif.py +0 -0
  165. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/resize_coco_dataset.py +0 -0
  166. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/wi_download_csv_to_coco.py +0 -0
  167. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/yolo_output_to_md_output.py +0 -0
  168. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/data_management/yolo_to_coco.py +0 -0
  169. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/detection/__init__.py +0 -0
  170. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/detection/detector_training/__init__.py +0 -0
  171. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/detection/detector_training/model_main_tf2.py +0 -0
  172. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/detection/run_tiled_inference.py +0 -0
  173. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/detection/tf_detector.py +0 -0
  174. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/__init__.py +0 -0
  175. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/add_max_conf.py +0 -0
  176. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/categorize_detections_by_size.py +0 -0
  177. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/combine_api_outputs.py +0 -0
  178. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/convert_output_format.py +0 -0
  179. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/load_api_results.py +0 -0
  180. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/md_to_labelme.py +0 -0
  181. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/merge_detections.py +0 -0
  182. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/remap_detection_categories.py +0 -0
  183. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/render_detection_confusion_matrix.py +0 -0
  184. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py +0 -0
  185. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +0 -0
  186. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +0 -0
  187. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/separate_detections_into_folders.py +0 -0
  188. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/subset_json_detector_output.py +0 -0
  189. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/postprocessing/top_folders_to_bottom.py +0 -0
  190. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/taxonomy_mapping/__init__.py +0 -0
  191. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +0 -0
  192. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/taxonomy_mapping/retrieve_sample_image.py +0 -0
  193. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/taxonomy_mapping/simple_image_download.py +0 -0
  194. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/taxonomy_mapping/species_lookup.py +0 -0
  195. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/taxonomy_mapping/taxonomy_csv_checker.py +0 -0
  196. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/taxonomy_mapping/taxonomy_graph.py +0 -0
  197. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/taxonomy_mapping/validate_lila_category_mappings.py +0 -0
  198. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/utils/__init__.py +0 -0
  199. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/utils/azure_utils.py +0 -0
  200. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/utils/directory_listing.py +0 -0
  201. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/utils/sas_blob_utils.py +0 -0
  202. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/utils/split_locations_into_train_val.py +0 -0
  203. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/utils/string_utils.py +0 -0
  204. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/utils/torch_test.py +0 -0
  205. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/utils/url_utils.py +0 -0
  206. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/visualization/__init__.py +0 -0
  207. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/visualization/plot_utils.py +0 -0
  208. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/visualization/render_images_with_thumbnails.py +0 -0
  209. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/visualization/visualize_db.py +0 -0
  210. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector/visualization/visualize_detector_output.py +0 -0
  211. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector.egg-info/dependency_links.txt +0 -0
  212. {megadetector-5.0.21 → megadetector-5.0.23}/megadetector.egg-info/top_level.txt +0 -0
  213. {megadetector-5.0.21 → megadetector-5.0.23}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: megadetector
3
- Version: 5.0.21
3
+ Version: 5.0.23
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>
@@ -32,14 +32,14 @@ Keywords: camera traps,conservation,wildlife,ai,megadetector
32
32
  Classifier: Development Status :: 3 - Alpha
33
33
  Classifier: License :: OSI Approved :: MIT License
34
34
  Classifier: Programming Language :: Python :: 3
35
- Requires-Python: <3.12,>=3.9
35
+ Requires-Python: <=3.13,>=3.9
36
36
  Description-Content-Type: text/markdown
37
37
  License-File: LICENSE
38
38
  Requires-Dist: Pillow>=9.5
39
39
  Requires-Dist: tqdm>=4.64.0
40
40
  Requires-Dist: jsonpickle>=3.0.2
41
41
  Requires-Dist: humanfriendly>=10.0
42
- Requires-Dist: numpy<1.24,>=1.22
42
+ Requires-Dist: numpy<2.0,>=1.26.4
43
43
  Requires-Dist: matplotlib>=3.8.0
44
44
  Requires-Dist: opencv-python>=4.8.0
45
45
  Requires-Dist: requests>=2.31.0
@@ -49,6 +49,7 @@ Requires-Dist: scikit-learn>=1.3.1
49
49
  Requires-Dist: pandas>=2.1.1
50
50
  Requires-Dist: PyYAML>=6.0.1
51
51
  Requires-Dist: ultralytics-yolov5==0.1.1
52
+ Requires-Dist: python-dateutil
52
53
 
53
54
  # MegaDetector
54
55
 
@@ -107,7 +107,7 @@ Here are a few of the organizations that have used MegaDetector... we're only li
107
107
  * [Wildlife Coexistence Lab](https://wildlife.forestry.ubc.ca/), University of British Columbia
108
108
  * [Wildlife Research](https://www.dfw.state.or.us/wildlife/research/index.asp), Oregon Department of Fish and Wildlife
109
109
  * [Wildlife Division](https://www.michigan.gov/dnr/about/contact/wildlife), Michigan Department of Natural Resources
110
-
110
+ * [Kohl Wildlife Lab](https://kohlwildlifelab.com/), University of Georgia
111
111
  * Department of Ecology, TU Berlin
112
112
  * Ghost Cat Analytics
113
113
  * Protected Areas Unit, Canadian Wildlife Service
@@ -12,6 +12,8 @@ https://github.com/agentmorris/MegaDetector/blob/main/megadetector/data_manageme
12
12
 
13
13
  import json
14
14
  import os
15
+ import datetime
16
+ import dateutil
15
17
 
16
18
  from tqdm import tqdm
17
19
  from collections import defaultdict, OrderedDict
@@ -302,6 +304,106 @@ class SequenceOptions:
302
304
 
303
305
  #%% Functions
304
306
 
307
+ def write_object_with_serialized_datetimes(d,json_fn):
308
+ """
309
+ Writes the object [d] to the .json file [json_fn] with a standard approach
310
+ to serializing Python datetime objects.
311
+
312
+ Args:
313
+ d (obj): the object to write, typically a dict
314
+ json_fn (str): the output filename
315
+ """
316
+
317
+ # This writes datetimes as:
318
+ #
319
+ # 2022-12-31T09:52:50
320
+ def json_serialize_datetime(obj):
321
+ if isinstance(obj, (datetime.datetime, datetime.date)):
322
+ return obj.isoformat()
323
+ raise TypeError('Object {} (type {}) not serializable'.format(
324
+ str(obj),type(obj)))
325
+
326
+ with open(json_fn,'w') as f:
327
+ json.dump(d,f,indent=1,default=json_serialize_datetime)
328
+
329
+
330
+ def parse_datetimes_from_cct_image_list(images,conversion_failure_behavior='error'):
331
+ """
332
+ Given the "images" field from a COCO camera traps dictionary, converts all
333
+ string-formatted datetime fields to Python datetimes, making reasonable assumptions
334
+ about datetime representations. Modifies [images] in place.
335
+
336
+ Args:
337
+ images (list): a list of dicts in CCT images format
338
+ conversion_failure_behavior (str, optional): determines what happens on a failed
339
+ conversion; can be "error" (raise an error), "str" (leave as a string), or
340
+ "none" (convert to None)
341
+
342
+ Returns:
343
+ images: the input list, with datetimes converted (after modifying in place)
344
+ """
345
+
346
+ assert isinstance(images,list)
347
+
348
+ for im in images:
349
+
350
+ if 'datetime' not in im:
351
+ continue
352
+ if isinstance(im['datetime'],datetime.datetime):
353
+ continue
354
+ try:
355
+ dt = dateutil.parser.parse(im['datetime'])
356
+ im['datetime'] = dt
357
+ except Exception as e:
358
+ s = 'could not parse datetime {}: {}'.format(str(im['datetime']),str(e))
359
+ if conversion_failure_behavior == 'error':
360
+ raise ValueError(s)
361
+ elif conversion_failure_behavior == 'str':
362
+ print('Warning: {}'.format(s))
363
+ pass
364
+ elif conversion_failure_behavior == 'none':
365
+ print('Warning: {}'.format(s))
366
+ im['datetime'] = None
367
+
368
+ # ...for each image
369
+
370
+ return images
371
+
372
+ # ...def parse_datetimes_from_cct_image_list(...)
373
+
374
+
375
+ def parse_datetimes_from_cct_dict(d,conversion_failure_behavior='error'):
376
+ """
377
+ Given a COCO camera traps dictionary that may just have been loaded from file,
378
+ converts all string-formatted datetime fields to Python datetimes, making
379
+ reasonable assumptions about datetime representations. Modifies [d] in place
380
+ if [d] is supplied as a dict
381
+
382
+ Args:
383
+ d (dict or str): a dict in CCT format or a filename pointing to a CCT .json file
384
+ conversion_failure_behavior (str, optional): determines what happens on a failed
385
+ conversion; can be "error" (raise an error), "str" (leave as a string), or
386
+ "none" (convert to None)
387
+
388
+ Returns:
389
+ dict: the CCT dict with converted datetimes.
390
+ """
391
+
392
+ if isinstance(d,str):
393
+ assert os.path.isfile(d), 'Could not find .json file {}'.format(d)
394
+ with open(d,'r') as f:
395
+ d = json.load(f)
396
+
397
+ images = d['images']
398
+
399
+ # Modifies in place
400
+ _ = parse_datetimes_from_cct_image_list(images)
401
+
402
+ return d
403
+
404
+ # ...def parse_datetimes_from_cct_dict(...)
405
+
406
+
305
407
  def create_sequences(image_info,options=None):
306
408
  """
307
409
  Synthesizes episodes/sequences/bursts for the images in [image_info].
@@ -310,21 +412,41 @@ def create_sequences(image_info,options=None):
310
412
  fields for each image.
311
413
 
312
414
  Args:
313
- image_info (str, dict, or list): a dict in CCT format, a CCT .json file, or just the 'images' component
314
- of a CCT dataset (a list of dicts with fields 'file_name' (str), 'datetime' (datetime), and
315
- 'location' (str)).
415
+ image_info (str, dict, or list): a dict in CCT format, a CCT .json file, or just the
416
+ 'images' component of a CCT dataset (a list of dicts with fields 'file_name' (str),
417
+ 'datetime' (datetime), and 'location' (str)).
418
+ options (SequenceOptions): options parameterizing the assembly of images into sequences;
419
+ see the SequenceOptions class for details.
420
+
421
+ Returns:
422
+ image_info: if [image_info] is passed as a list, returns the list, otherwise returns
423
+ a CCT-formatted dict.
316
424
  """
317
425
 
318
426
  if options is None:
319
427
  options = SequenceOptions()
320
428
 
321
- if isinstance(image_info,str):
429
+ to_return = None
430
+
431
+ if isinstance(image_info,list):
432
+ to_return = image_info
433
+
434
+ elif isinstance(image_info,str):
322
435
  with open(image_info,'r') as f:
323
- image_info = json.load(f)
436
+ d = json.load(f)
437
+ to_return = d
438
+ image_info = d['images']
324
439
 
325
- if isinstance(image_info,dict):
440
+ elif isinstance(image_info,dict):
441
+ to_return = image_info
326
442
  image_info = image_info['images']
443
+
444
+ else:
445
+ raise ValueError('Unrecognized type for [image_info]')
327
446
 
447
+ # Modifies the images in place
448
+ _ = parse_datetimes_from_cct_image_list(image_info)
449
+
328
450
  # Find all unique locations
329
451
  locations = set()
330
452
  for im in image_info:
@@ -401,4 +523,18 @@ def create_sequences(image_info,options=None):
401
523
 
402
524
  print('Created {} sequences from {} images'.format(len(all_sequences),len(image_info)))
403
525
 
404
- # ...create_sequences()
526
+ return to_return
527
+
528
+ # ...def create_sequences(...)
529
+
530
+
531
+ #%% Test drivers
532
+
533
+ if False:
534
+
535
+ pass
536
+
537
+ #%%
538
+
539
+ fn = r'g:\temp\test.json'
540
+ d = parse_datetimes_from_cct_dict(fn,conversion_failure_behavior='error')
@@ -27,10 +27,13 @@ from tqdm import tqdm
27
27
  def cct_to_md(input_filename,output_filename=None):
28
28
  """
29
29
  "Converts" a COCO Camera Traps file to a MD results file. Currently ignores
30
- non-bounding-box annotations, and gives all annotations a confidence of 1.0.
30
+ non-bounding-box annotations. If the semi-standard "score" field is present in
31
+ an annotation, or the totally non-standard "conf" field is present, it will be
32
+ transferred to the output, otherwise a confidence value of 1.0 is assumed for
33
+ all annotations.
31
34
 
32
- The only reason to do this is if you are going to add information to an existing
33
- CCT-formatted dataset, and you want to do that in Timelapse.
35
+ The main reason to run this script the scenario where you are going to add information
36
+ to an existing CCT-formatted dataset, and you want to do that in Timelapse.
34
37
 
35
38
  Currently assumes that width and height are present in the input data, does not
36
39
  read them from images.
@@ -113,8 +116,12 @@ def cct_to_md(input_filename,output_filename=None):
113
116
 
114
117
  det = {}
115
118
  det['category'] = str(ann['category_id'])
116
- det['conf'] = 1.0
117
- # max_detection_conf = 1.0
119
+ if 'score' in ann:
120
+ det['conf'] = ann['score']
121
+ elif 'conf' in ann:
122
+ det['conf'] = ann['conf']
123
+ else:
124
+ det['conf'] = 1.0
118
125
 
119
126
  # MegaDetector: [x,y,width,height] (normalized, origin upper-left)
120
127
  # CCT: [x,y,width,height] (absolute, origin upper-left)
@@ -28,6 +28,7 @@ from tqdm import tqdm
28
28
 
29
29
  from megadetector.visualization.visualization_utils import open_image
30
30
  from megadetector.utils import ct_utils
31
+ from megadetector.utils.path_utils import find_images
31
32
 
32
33
 
33
34
  #%% Classes and environment
@@ -67,7 +68,7 @@ class IntegrityCheckOptions:
67
68
  self.allowIntIDs = False
68
69
 
69
70
  # This is used in a medium-hacky way to share modified options across threads
70
- defaultOptions = IntegrityCheckOptions()
71
+ default_options = IntegrityCheckOptions()
71
72
 
72
73
 
73
74
  #%% Functions
@@ -89,7 +90,7 @@ def _check_image_existence_and_size(image,options=None):
89
90
  """
90
91
 
91
92
  if options is None:
92
- options = defaultOptions
93
+ options = default_options
93
94
 
94
95
  assert options.bCheckImageExistence
95
96
 
@@ -124,9 +125,9 @@ def integrity_check_json_db(jsonFile, options=None):
124
125
 
125
126
  Returns:
126
127
  tuple: tuple containing:
127
- - sortedCategories (dict): list of categories used in [jsonFile], sorted by frequency
128
+ - sorted_categories (dict): list of categories used in [jsonFile], sorted by frequency
128
129
  - data (dict): the data loaded from [jsonFile]
129
- - errorInfo (dict): specific validation errors
130
+ - error_info (dict): specific validation errors
130
131
  """
131
132
 
132
133
  if options is None:
@@ -141,7 +142,7 @@ def integrity_check_json_db(jsonFile, options=None):
141
142
  if options.baseDir is None:
142
143
  options.baseDir = ''
143
144
 
144
- baseDir = options.baseDir
145
+ base_dir = options.baseDir
145
146
 
146
147
 
147
148
  ##%% Read .json file if necessary, integrity-check fields
@@ -156,7 +157,7 @@ def integrity_check_json_db(jsonFile, options=None):
156
157
 
157
158
  if options.verbose:
158
159
  print('Reading .json {} with base dir [{}]...'.format(
159
- jsonFile,baseDir))
160
+ jsonFile,base_dir))
160
161
 
161
162
  with open(jsonFile,'r') as f:
162
163
  data = json.load(f)
@@ -171,17 +172,17 @@ def integrity_check_json_db(jsonFile, options=None):
171
172
  # info = data['info']
172
173
  assert 'info' in data, 'No info struct in database'
173
174
 
174
- if len(baseDir) > 0:
175
- assert os.path.isdir(baseDir), 'Base directory {} does not exist'.format(baseDir)
175
+ if len(base_dir) > 0:
176
+ assert os.path.isdir(base_dir), 'Base directory {} does not exist'.format(base_dir)
176
177
 
177
178
 
178
179
  ##%% Build dictionaries, checking ID uniqueness and internal validity as we go
179
180
 
180
- imageIdToImage = {}
181
- annIdToAnn = {}
182
- catIdToCat = {}
183
- catNameToCat = {}
184
- imageLocationSet = set()
181
+ image_id_to_image = {}
182
+ ann_id_to_ann = {}
183
+ category_id_to_category = {}
184
+ category_name_to_category = {}
185
+ image_location_set = set()
185
186
 
186
187
  if options.verbose:
187
188
  print('Checking categories...')
@@ -195,16 +196,16 @@ def integrity_check_json_db(jsonFile, options=None):
195
196
  assert isinstance(cat['id'],int), 'Illegal category ID type: [{}]'.format(str(cat['id']))
196
197
  assert isinstance(cat['name'],str), 'Illegal category name type [{}]'.format(str(cat['name']))
197
198
 
198
- catId = cat['id']
199
- catName = cat['name']
199
+ category_id = cat['id']
200
+ category_name = cat['name']
200
201
 
201
202
  # Confirm ID uniqueness
202
- assert catId not in catIdToCat, 'Category ID {} is used more than once'.format(catId)
203
- catIdToCat[catId] = cat
203
+ assert category_id not in category_id_to_category, 'Category ID {} is used more than once'.format(category_id)
204
+ category_id_to_category[category_id] = cat
204
205
  cat['_count'] = 0
205
206
 
206
- assert catName not in catNameToCat, 'Category name {} is used more than once'.format(catName)
207
- catNameToCat[catName] = cat
207
+ assert category_name not in category_name_to_category, 'Category name {} is used more than once'.format(category_name)
208
+ category_name_to_category[category_name] = cat
208
209
 
209
210
  # ...for each category
210
211
 
@@ -217,7 +218,7 @@ def integrity_check_json_db(jsonFile, options=None):
217
218
  print('Trimming image list to {}'.format(options.iMaxNumImages))
218
219
  images = images[0:options.iMaxNumImages]
219
220
 
220
- imagePathsInJson = set()
221
+ image_paths_in_json = set()
221
222
 
222
223
  sequences = set()
223
224
 
@@ -230,9 +231,9 @@ def integrity_check_json_db(jsonFile, options=None):
230
231
  assert 'file_name' in image
231
232
  assert 'id' in image
232
233
 
233
- image['file_name'] = os.path.normpath(image['file_name'])
234
+ image['file_name'] = image['file_name'].replace('\\','/')
234
235
 
235
- imagePathsInJson.add(image['file_name'])
236
+ image_paths_in_json.add(image['file_name'])
236
237
 
237
238
  assert isinstance(image['file_name'],str), 'Illegal image filename type'
238
239
 
@@ -242,12 +243,12 @@ def integrity_check_json_db(jsonFile, options=None):
242
243
  else:
243
244
  assert isinstance(image['id'],str), 'Illegal image ID type'
244
245
 
245
- imageId = image['id']
246
+ image_id = image['id']
246
247
 
247
248
  # Confirm ID uniqueness
248
- assert imageId not in imageIdToImage, 'Duplicate image ID {}'.format(imageId)
249
+ assert image_id not in image_id_to_image, 'Duplicate image ID {}'.format(image_id)
249
250
 
250
- imageIdToImage[imageId] = image
251
+ image_id_to_image[image_id] = image
251
252
 
252
253
  if 'height' in image:
253
254
  assert 'width' in image, 'Image with height but no width: {}'.format(image['id'])
@@ -263,70 +264,74 @@ def integrity_check_json_db(jsonFile, options=None):
263
264
  # assert isinstance(image['location'], str) or isinstance(image['location'], int), \
264
265
  # 'Illegal image location type'
265
266
  assert isinstance(image['location'], str)
266
- imageLocationSet.add(image['location'])
267
+ image_location_set.add(image['location'])
267
268
 
268
269
  if 'seq_id' in image:
269
270
  sequences.add(image['seq_id'])
270
271
 
271
272
  assert not ('sequence_id' in image or 'sequence' in image), 'Illegal sequence identifier'
272
273
 
273
- unusedFiles = []
274
+ unused_files = []
274
275
 
276
+ image_paths_relative = None
277
+
275
278
  # Are we checking for unused images?
276
- if (len(baseDir) > 0) and options.bFindUnusedImages:
279
+ if (len(base_dir) > 0) and options.bFindUnusedImages:
277
280
 
278
281
  if options.verbose:
279
282
  print('\nEnumerating images...')
280
283
 
281
- # Recursively enumerate images
282
- imagePaths = []
283
- for root, dirs, files in os.walk(baseDir):
284
- for file in files:
285
- if file.lower().endswith(('.jpeg', '.jpg', '.png')):
286
- relDir = os.path.relpath(root, baseDir)
287
- relFile = os.path.join(relDir,file)
288
- relFile = os.path.normpath(relFile)
289
- if len(relFile) > 2 and \
290
- (relFile[0:2] == './' or relFile[0:2] == '.\\'):
291
- relFile = relFile[2:]
292
- imagePaths.append(relFile)
293
-
294
- for p in imagePaths:
295
- if p not in imagePathsInJson:
296
- # print('Image {} is unused'.format(p))
297
- unusedFiles.append(p)
284
+ image_paths_relative = find_images(base_dir,return_relative_paths=True,recursive=True)
285
+
286
+ for fn_relative in image_paths_relative:
287
+ if fn_relative not in image_paths_in_json:
288
+ unused_files.append(fn_relative)
298
289
 
299
- validationErrors = []
290
+ validation_errors = []
300
291
 
301
- # Are we checking file existence and/or image size?
302
- if options.bCheckImageSizes or options.bCheckImageExistence:
292
+ # If we're checking image existence but not image size, we don't need to read the images
293
+ if options.bCheckImageExistence and not options.bCheckImageSizes:
294
+
295
+ if image_paths_relative is None:
296
+ image_paths_relative = find_images(base_dir,return_relative_paths=True,recursive=True)
297
+
298
+ image_paths_relative_set = set(image_paths_relative)
299
+
300
+ for im in images:
301
+ if im['file_name'] not in image_paths_relative_set:
302
+ validation_errors.append(im['file_name'])
303
+
304
+ # If we're checking image size, we need to read the images
305
+ if options.bCheckImageSizes:
303
306
 
304
- if len(baseDir) == 0:
307
+ if len(base_dir) == 0:
305
308
  print('Warning: checking image sizes without a base directory, assuming "."')
306
309
 
307
310
  if options.verbose:
308
311
  print('Checking image existence and/or image sizes...')
309
312
 
310
313
  if options.nThreads is not None and options.nThreads > 1:
314
+ if options.verbose:
315
+ print('Starting a pool of {} workers'.format(options.nThreads))
311
316
  pool = ThreadPool(options.nThreads)
312
317
  # results = pool.imap_unordered(lambda x: fetch_url(x,nImages), indexedUrlList)
313
- defaultOptions.baseDir = options.baseDir
314
- defaultOptions.bCheckImageSizes = options.bCheckImageSizes
315
- defaultOptions.bCheckImageExistence = options.bCheckImageExistence
318
+ default_options.baseDir = options.baseDir
319
+ default_options.bCheckImageSizes = options.bCheckImageSizes
320
+ default_options.bCheckImageExistence = options.bCheckImageExistence
316
321
  results = tqdm(pool.imap(_check_image_existence_and_size, images), total=len(images))
317
322
  else:
318
323
  results = []
319
324
  for im in tqdm(images):
320
325
  results.append(_check_image_existence_and_size(im,options))
321
326
 
322
- for iImage,r in enumerate(results):
323
- if not r:
324
- validationErrors.append(os.path.join(options.baseDir,images[iImage]['file_name']))
327
+ for i_image,result in enumerate(results):
328
+ if result is not None:
329
+ validation_errors.append(images[i_image]['file_name'])
325
330
 
326
331
  # ...for each image
327
332
 
328
333
  if options.verbose:
329
- print('{} validation errors (of {})'.format(len(validationErrors),len(images)))
334
+ print('{} validation errors (of {})'.format(len(validation_errors),len(images)))
330
335
  print('Checking annotations...')
331
336
 
332
337
  nBoxes = 0
@@ -355,22 +360,22 @@ def integrity_check_json_db(jsonFile, options=None):
355
360
  annId = ann['id']
356
361
 
357
362
  # Confirm ID uniqueness
358
- assert annId not in annIdToAnn
359
- annIdToAnn[annId] = ann
363
+ assert annId not in ann_id_to_ann
364
+ ann_id_to_ann[annId] = ann
360
365
 
361
366
  # Confirm validity
362
- assert ann['category_id'] in catIdToCat, \
367
+ assert ann['category_id'] in category_id_to_category, \
363
368
  'Category {} not found in category list'.format(ann['category_id'])
364
- assert ann['image_id'] in imageIdToImage, \
369
+ assert ann['image_id'] in image_id_to_image, \
365
370
  'Image ID {} referred to by annotation {}, not available'.format(
366
371
  ann['image_id'],ann['id'])
367
372
 
368
- imageIdToImage[ann['image_id']]['_count'] += 1
369
- catIdToCat[ann['category_id']]['_count'] +=1
373
+ image_id_to_image[ann['image_id']]['_count'] += 1
374
+ category_id_to_category[ann['category_id']]['_count'] +=1
370
375
 
371
376
  # ...for each annotation
372
377
 
373
- sortedCategories = sorted(categories, key=itemgetter('_count'), reverse=True)
378
+ sorted_categories = sorted(categories, key=itemgetter('_count'), reverse=True)
374
379
 
375
380
 
376
381
  ##%% Print statistics
@@ -390,18 +395,18 @@ def integrity_check_json_db(jsonFile, options=None):
390
395
  print('Found {} unannotated images, {} images with multiple annotations'.format(
391
396
  nUnannotated,nMultiAnnotated))
392
397
 
393
- if (len(baseDir) > 0) and options.bFindUnusedImages:
394
- print('Found {} unused image files'.format(len(unusedFiles)))
398
+ if (len(base_dir) > 0) and options.bFindUnusedImages:
399
+ print('Found {} unused image files'.format(len(unused_files)))
395
400
 
396
- nUnusedCategories = 0
401
+ n_unused_categories = 0
397
402
 
398
403
  # Find unused categories
399
404
  for cat in categories:
400
405
  if cat['_count'] == 0:
401
406
  print('Unused category: {}'.format(cat['name']))
402
- nUnusedCategories += 1
407
+ n_unused_categories += 1
403
408
 
404
- print('Found {} unused categories'.format(nUnusedCategories))
409
+ print('Found {} unused categories'.format(n_unused_categories))
405
410
 
406
411
  sequenceString = 'no sequence info'
407
412
  if len(sequences) > 0:
@@ -410,21 +415,21 @@ def integrity_check_json_db(jsonFile, options=None):
410
415
  print('\nDB contains {} images, {} annotations, {} bboxes, {} categories, {}\n'.format(
411
416
  len(images),len(annotations),nBoxes,len(categories),sequenceString))
412
417
 
413
- if len(imageLocationSet) > 0:
414
- print('DB contains images from {} locations\n'.format(len(imageLocationSet)))
418
+ if len(image_location_set) > 0:
419
+ print('DB contains images from {} locations\n'.format(len(image_location_set)))
415
420
 
416
421
  print('Categories and annotation (not image) counts:\n')
417
422
 
418
- for cat in sortedCategories:
423
+ for cat in sorted_categories:
419
424
  print('{:6} {}'.format(cat['_count'],cat['name']))
420
425
 
421
426
  print('')
422
427
 
423
- errorInfo = {}
424
- errorInfo['unusedFiles'] = unusedFiles
425
- errorInfo['validationErrors'] = validationErrors
428
+ error_info = {}
429
+ error_info['unused_files'] = unused_files
430
+ error_info['validation_errors'] = validation_errors
426
431
 
427
- return sortedCategories, data, errorInfo
432
+ return sorted_categories, data, error_info
428
433
 
429
434
  # ...def integrity_check_json_db()
430
435
 
@@ -434,7 +439,8 @@ def integrity_check_json_db(jsonFile, options=None):
434
439
  def main():
435
440
 
436
441
  parser = argparse.ArgumentParser()
437
- parser.add_argument('jsonFile')
442
+ parser.add_argument('jsonFile',type=str,
443
+ help='COCO-formatted .json file to validate')
438
444
  parser.add_argument('--bCheckImageSizes', action='store_true',
439
445
  help='Validate image size, requires baseDir to be specified. ' + \
440
446
  'Implies existence checking.')
@@ -490,4 +496,4 @@ if False:
490
496
 
491
497
  for json_file in json_files:
492
498
 
493
- sortedCategories,data,_ = integrity_check_json_db(json_file, options)
499
+ sorted_categories,data,_ = integrity_check_json_db(json_file, options)