megadetector 10.0.9__tar.gz → 10.0.10__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 (153) hide show
  1. {megadetector-10.0.9/megadetector.egg-info → megadetector-10.0.10}/PKG-INFO +1 -1
  2. {megadetector-10.0.9 → megadetector-10.0.10}/README.md +2 -2
  3. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/read_exif.py +15 -2
  4. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/detection/run_detector_batch.py +58 -41
  5. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/detection/run_md_and_speciesnet.py +81 -23
  6. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/detection/tf_detector.py +3 -5
  7. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/classification_postprocessing.py +12 -13
  8. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/utils/directory_listing.py +3 -0
  9. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/utils/path_utils.py +67 -0
  10. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/utils/string_utils.py +21 -0
  11. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/utils/wi_platform_utils.py +168 -24
  12. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/utils/wi_taxonomy_utils.py +1 -0
  13. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/visualization/visualize_detector_output.py +1 -0
  14. {megadetector-10.0.9 → megadetector-10.0.10/megadetector.egg-info}/PKG-INFO +1 -1
  15. {megadetector-10.0.9 → megadetector-10.0.10}/pyproject.toml +1 -1
  16. {megadetector-10.0.9 → megadetector-10.0.10}/LICENSE +0 -0
  17. {megadetector-10.0.9 → megadetector-10.0.10}/README-package.md +0 -0
  18. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/__init__.py +0 -0
  19. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/api/__init__.py +0 -0
  20. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/api/batch_processing/integration/digiKam/setup.py +0 -0
  21. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/api/batch_processing/integration/digiKam/xmp_integration.py +0 -0
  22. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/api/batch_processing/integration/eMammal/test_scripts/config_template.py +0 -0
  23. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +0 -0
  24. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +0 -0
  25. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/__init__.py +0 -0
  26. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/aggregate_classifier_probs.py +0 -0
  27. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/analyze_failed_images.py +0 -0
  28. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/cache_batchapi_outputs.py +0 -0
  29. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/create_classification_dataset.py +0 -0
  30. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/crop_detections.py +0 -0
  31. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/csv_to_json.py +0 -0
  32. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/detect_and_crop.py +0 -0
  33. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/efficientnet/__init__.py +0 -0
  34. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/efficientnet/model.py +0 -0
  35. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/efficientnet/utils.py +0 -0
  36. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/evaluate_model.py +0 -0
  37. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/identify_mislabeled_candidates.py +0 -0
  38. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/json_to_azcopy_list.py +0 -0
  39. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/json_validator.py +0 -0
  40. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/map_classification_categories.py +0 -0
  41. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/merge_classification_detection_output.py +0 -0
  42. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/prepare_classification_script.py +0 -0
  43. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/prepare_classification_script_mc.py +0 -0
  44. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/run_classifier.py +0 -0
  45. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/save_mislabeled.py +0 -0
  46. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/train_classifier.py +0 -0
  47. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/train_classifier_tf.py +0 -0
  48. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/classification/train_utils.py +0 -0
  49. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/__init__.py +0 -0
  50. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/animl_to_md.py +0 -0
  51. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/annotations/__init__.py +0 -0
  52. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/annotations/annotation_constants.py +0 -0
  53. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/camtrap_dp_to_coco.py +0 -0
  54. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/cct_json_utils.py +0 -0
  55. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/cct_to_md.py +0 -0
  56. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/cct_to_wi.py +0 -0
  57. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/coco_to_labelme.py +0 -0
  58. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/coco_to_yolo.py +0 -0
  59. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/databases/__init__.py +0 -0
  60. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/databases/add_width_and_height_to_db.py +0 -0
  61. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/databases/combine_coco_camera_traps_files.py +0 -0
  62. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/databases/integrity_check_json_db.py +0 -0
  63. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/databases/subset_json_db.py +0 -0
  64. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/generate_crops_from_cct.py +0 -0
  65. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/get_image_sizes.py +0 -0
  66. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/labelme_to_coco.py +0 -0
  67. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/labelme_to_yolo.py +0 -0
  68. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/lila/__init__.py +0 -0
  69. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/lila/create_lila_blank_set.py +0 -0
  70. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/lila/create_lila_test_set.py +0 -0
  71. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/lila/create_links_to_md_results_files.py +0 -0
  72. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/lila/download_lila_subset.py +0 -0
  73. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/lila/generate_lila_per_image_labels.py +0 -0
  74. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/lila/get_lila_annotation_counts.py +0 -0
  75. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/lila/get_lila_image_counts.py +0 -0
  76. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/lila/lila_common.py +0 -0
  77. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/lila/test_lila_metadata_urls.py +0 -0
  78. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/mewc_to_md.py +0 -0
  79. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/ocr_tools.py +0 -0
  80. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/remap_coco_categories.py +0 -0
  81. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/remove_exif.py +0 -0
  82. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/rename_images.py +0 -0
  83. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/resize_coco_dataset.py +0 -0
  84. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/speciesnet_to_md.py +0 -0
  85. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/wi_download_csv_to_coco.py +0 -0
  86. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/yolo_output_to_md_output.py +0 -0
  87. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/yolo_to_coco.py +0 -0
  88. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/data_management/zamba_to_md.py +0 -0
  89. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/detection/__init__.py +0 -0
  90. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/detection/change_detection.py +0 -0
  91. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/detection/process_video.py +0 -0
  92. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/detection/pytorch_detector.py +0 -0
  93. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/detection/run_detector.py +0 -0
  94. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/detection/run_inference_with_yolov5_val.py +0 -0
  95. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/detection/run_tiled_inference.py +0 -0
  96. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/detection/video_utils.py +0 -0
  97. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/__init__.py +0 -0
  98. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/add_max_conf.py +0 -0
  99. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/categorize_detections_by_size.py +0 -0
  100. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/combine_batch_outputs.py +0 -0
  101. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/compare_batch_results.py +0 -0
  102. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/convert_output_format.py +0 -0
  103. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/create_crop_folder.py +0 -0
  104. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/detector_calibration.py +0 -0
  105. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/generate_csv_report.py +0 -0
  106. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/load_api_results.py +0 -0
  107. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/md_to_coco.py +0 -0
  108. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/md_to_labelme.py +0 -0
  109. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/md_to_wi.py +0 -0
  110. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/merge_detections.py +0 -0
  111. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/postprocess_batch_results.py +0 -0
  112. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/remap_detection_categories.py +0 -0
  113. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/render_detection_confusion_matrix.py +0 -0
  114. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py +0 -0
  115. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +0 -0
  116. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +0 -0
  117. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/separate_detections_into_folders.py +0 -0
  118. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/subset_json_detector_output.py +0 -0
  119. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/top_folders_to_bottom.py +0 -0
  120. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/postprocessing/validate_batch_results.py +0 -0
  121. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/taxonomy_mapping/__init__.py +0 -0
  122. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +0 -0
  123. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/taxonomy_mapping/map_new_lila_datasets.py +0 -0
  124. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +0 -0
  125. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/taxonomy_mapping/preview_lila_taxonomy.py +0 -0
  126. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/taxonomy_mapping/retrieve_sample_image.py +0 -0
  127. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/taxonomy_mapping/simple_image_download.py +0 -0
  128. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/taxonomy_mapping/species_lookup.py +0 -0
  129. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/taxonomy_mapping/taxonomy_csv_checker.py +0 -0
  130. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/taxonomy_mapping/taxonomy_graph.py +0 -0
  131. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/taxonomy_mapping/validate_lila_category_mappings.py +0 -0
  132. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/tests/__init__.py +0 -0
  133. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/tests/test_nms_synthetic.py +0 -0
  134. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/utils/__init__.py +0 -0
  135. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/utils/ct_utils.py +0 -0
  136. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/utils/extract_frames_from_video.py +0 -0
  137. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/utils/gpu_test.py +0 -0
  138. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/utils/md_tests.py +0 -0
  139. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/utils/process_utils.py +0 -0
  140. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/utils/split_locations_into_train_val.py +0 -0
  141. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/utils/url_utils.py +0 -0
  142. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/utils/write_html_image_list.py +0 -0
  143. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/visualization/__init__.py +0 -0
  144. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/visualization/plot_utils.py +0 -0
  145. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/visualization/render_images_with_thumbnails.py +0 -0
  146. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/visualization/visualization_utils.py +0 -0
  147. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/visualization/visualize_db.py +0 -0
  148. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector/visualization/visualize_video_output.py +0 -0
  149. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector.egg-info/SOURCES.txt +0 -0
  150. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector.egg-info/dependency_links.txt +0 -0
  151. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector.egg-info/requires.txt +0 -0
  152. {megadetector-10.0.9 → megadetector-10.0.10}/megadetector.egg-info/top_level.txt +0 -0
  153. {megadetector-10.0.9 → megadetector-10.0.10}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: megadetector
3
- Version: 10.0.9
3
+ Version: 10.0.10
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>
@@ -47,7 +47,6 @@ Here are a few of the organizations that have used MegaDetector... we're only li
47
47
  * [Blackbird Environmental](https://blackbirdenv.com/)
48
48
  * [Camelot](https://camelotproject.org/)
49
49
  * [Canadian Parks and Wilderness Society (CPAWS) Northern Alberta Chapter](https://cpawsnab.org/)
50
- * [Conservation X Labs](https://conservationxlabs.com/)
51
50
  * [Czech University of Life Sciences Prague](https://www.czu.cz/en)
52
51
  * [Dudek Camera Trap AI Image Toolkit (AIT)](https://ait.dudek.com/)
53
52
  * [EcoLogic Consultants Ltd.](https://www.consult-ecologic.com/)
@@ -122,7 +121,6 @@ Here are a few of the organizations that have used MegaDetector... we're only li
122
121
 
123
122
  * [School of Natural Sciences](https://www.utas.edu.au/natural-sciences), University of Tasmania ([story](https://www.utas.edu.au/about/news-and-stories/articles/2022/1204-innovative-camera-network-keeps-close-eye-on-tassie-wildlife))
124
123
  * [Kenai National Wildlife Refuge](https://www.fws.gov/refuge/kenai), U.S. Fish & Wildlife Service ([story](https://www.peninsulaclarion.com/sports/refuge-notebook-new-technology-increases-efficiency-of-refuge-cameras/))
125
-
126
124
  * [Idaho Department of Fish and Game](https://idfg.idaho.gov/) ([fancy PBS video](https://www.youtube.com/watch?v=uEsL8EZKpbA&t=261s&ab_channel=OutdoorIdaho))
127
125
  * [Australian Wildlife Conservancy](https://www.australianwildlife.org/) (blog posts [1](https://www.australianwildlife.org/cutting-edge-technology-delivering-efficiency-gains-in-conservation/), [2](https://www.australianwildlife.org/efficiency-gains-at-the-cutting-edge-of-technology/), [3](https://www.australianwildlife.org/federal-grant-to-fund-ai-supported-wildlife-recognisers))
128
126
  * [Bavarian Forest National Park](https://www.nationalpark-bayerischer-wald.bayern.de/english/index.htm) ([story](https://customers.microsoft.com/en-au/story/1667539539271247797-nationalparkbayerischerwald-azure-en))
@@ -148,6 +146,8 @@ Here are a few of the organizations that have used MegaDetector... we're only li
148
146
  * [San Diego Zoo Wildlife Alliance](https://science.sandiegozoo.org/) ([Animl R package](https://github.com/conservationtechlab/animl))
149
147
  * [TerrOïko](https://www.terroiko.fr/) ([OCAPI platform](https://www.terroiko.fr/ocapi))
150
148
  * [Wildlife Division](https://www.michigan.gov/dnr/about/contact/wildlife), Michigan Department of Natural Resources ([blog post](https://www.michigan.gov/dnr/about/newsroom/releases/2025/08/18/dnr-researchers-to-test-trail-cameras-in-elk-survey))
149
+ * [Cleveland Metroparks](https://www.clevelandmetroparks.com/) ([presentation](https://www.clevelandmetroparks.com/getmedia/d4978f4b-5641-4e6b-ac16-b29e9e3d43d1/AI_8_21_25.pdf))
150
+ * [Conservation X Labs](https://conservationxlabs.com/) ([story](https://news.mongabay.com/2025/09/turning-camera-traps-into-real-time-sentinels-interview-with-conservation-x-labs-dante-wasmuht/))
151
151
 
152
152
  Also see:
153
153
 
@@ -210,6 +210,8 @@ def read_pil_exif(im,options=None):
210
210
  if exif_info is None:
211
211
  return exif_tags
212
212
 
213
+ # Read all standard EXIF tags; if necessary, we'll filter later to a restricted
214
+ # list of tags.
213
215
  for k, v in exif_info.items():
214
216
  assert isinstance(k,str) or isinstance(k,int), \
215
217
  'Invalid EXIF key {}'.format(str(k))
@@ -221,6 +223,7 @@ def read_pil_exif(im,options=None):
221
223
 
222
224
  exif_ifd_tags = _get_exif_ifd(exif_info)
223
225
 
226
+ # Read tags that are only available via offset
224
227
  for k in exif_ifd_tags.keys():
225
228
  v = exif_ifd_tags[k]
226
229
  if k in exif_tags:
@@ -266,7 +269,7 @@ def read_pil_exif(im,options=None):
266
269
 
267
270
  # Convert to strings, e.g. 'GPSTimeStamp'
268
271
  gps_info = {}
269
- for int_tag,v in enumerate(gps_info_raw.keys()):
272
+ for int_tag,v in gps_info_raw.items():
270
273
  assert isinstance(int_tag,int)
271
274
  if int_tag in ExifTags.GPSTAGS:
272
275
  gps_info[ExifTags.GPSTAGS[int_tag]] = v
@@ -276,11 +279,15 @@ def read_pil_exif(im,options=None):
276
279
  exif_tags['GPSInfo'] = gps_info
277
280
 
278
281
  except Exception as e:
282
+
279
283
  if options.verbose:
280
284
  print('Warning: error reading GPS info: {}'.format(str(e)))
281
285
 
282
286
  # ...if we think there might be GPS tags in this image
283
287
 
288
+ # Filter tags if necessary
289
+ exif_tags = _filter_tags(exif_tags,options)
290
+
284
291
  return exif_tags
285
292
 
286
293
  # ...read_pil_exif()
@@ -337,10 +344,16 @@ def _filter_tags(tags,options):
337
344
  if options.tags_to_include is None and options.tags_to_exclude is None:
338
345
  return tags
339
346
  if options.tags_to_include is not None:
347
+ if isinstance(options.tags_to_include,str):
348
+ if options.tags_to_include == 'all':
349
+ return tags
340
350
  assert options.tags_to_exclude is None, "tags_to_include and tags_to_exclude are incompatible"
351
+ tags_to_include = options.tags_to_include.split(',')
352
+ # Case-insensitive matching
353
+ tags_to_include = [s.lower() for s in tags_to_include]
341
354
  tags_to_return = {}
342
355
  for tag_name in tags.keys():
343
- if tag_name in options.tags_to_include:
356
+ if str(tag_name).lower() in tags_to_include:
344
357
  tags_to_return[tag_name] = tags[tag_name]
345
358
  return tags_to_return
346
359
  if options.tags_to_exclude is not None:
@@ -94,10 +94,10 @@ max_queue_size = 10
94
94
  # How often should we print progress when using the image queue?
95
95
  n_queue_print = 1000
96
96
 
97
- # Only used if --include_exif_data or --include_image_timestamp are supplied
98
- exif_options = read_exif.ReadExifOptions()
99
- exif_options.processing_library = 'pil'
100
- exif_options.byte_handling = 'convert_to_string'
97
+ # Only used if --include_exif_tags or --include_image_timestamp are supplied
98
+ exif_options_base = read_exif.ReadExifOptions()
99
+ exif_options_base.processing_library = 'pil'
100
+ exif_options_base.byte_handling = 'convert_to_string'
101
101
 
102
102
  # Only relevant when we're running our test harness; because bugs in batch
103
103
  # inference are dependent on batch grouping, we randomize batch grouping
@@ -208,7 +208,7 @@ def _consumer_func(q,
208
208
  image_size=None,
209
209
  include_image_size=False,
210
210
  include_image_timestamp=False,
211
- include_exif_data=False,
211
+ include_exif_tags=None,
212
212
  augment=False,
213
213
  detector_options=None,
214
214
  preprocess_on_image_queue=default_preprocess_on_image_queue,
@@ -232,7 +232,7 @@ def _consumer_func(q,
232
232
  image_size (int, optional): image size to use for inference
233
233
  include_image_size (bool, optional): include image dimensions in output
234
234
  include_image_timestamp (bool, optional): include image timestamps in output
235
- include_exif_data (bool, optional): include EXIF data in output
235
+ include_exif_tags (str, optional): comma-separated list of EXIF tags to include in output
236
236
  augment (bool, optional): enable image augmentation
237
237
  detector_options (dict, optional): key/value pairs that are interpreted differently
238
238
  by different detectors
@@ -334,7 +334,7 @@ def _consumer_func(q,
334
334
  image_size=image_size,
335
335
  include_image_size=include_image_size,
336
336
  include_image_timestamp=include_image_timestamp,
337
- include_exif_data=include_exif_data,
337
+ include_exif_tags=include_exif_tags,
338
338
  augment=augment)
339
339
  results.extend(batch_results)
340
340
 
@@ -411,7 +411,7 @@ def _consumer_func(q,
411
411
  image_size=image_size,
412
412
  include_image_size=include_image_size,
413
413
  include_image_timestamp=include_image_timestamp,
414
- include_exif_data=include_exif_data,
414
+ include_exif_tags=include_exif_tags,
415
415
  augment=augment)
416
416
  results.extend(batch_results)
417
417
 
@@ -431,7 +431,7 @@ def _consumer_func(q,
431
431
  image_size=image_size,
432
432
  include_image_size=include_image_size,
433
433
  include_image_timestamp=include_image_timestamp,
434
- include_exif_data=include_exif_data,
434
+ include_exif_tags=include_exif_tags,
435
435
  augment=augment)
436
436
  results.append(result)
437
437
  n_images_processed += 1
@@ -464,7 +464,7 @@ def _run_detector_with_image_queue(image_files,
464
464
  image_size=None,
465
465
  include_image_size=False,
466
466
  include_image_timestamp=False,
467
- include_exif_data=False,
467
+ include_exif_tags=None,
468
468
  augment=False,
469
469
  detector_options=None,
470
470
  loader_workers=default_loaders,
@@ -487,7 +487,7 @@ def _run_detector_with_image_queue(image_files,
487
487
  doing
488
488
  include_image_size (bool, optional): should we include image size in the output for each image?
489
489
  include_image_timestamp (bool, optional): should we include image timestamps in the output for each image?
490
- include_exif_data (bool, optional): should we include EXIF data in the output for each image?
490
+ include_exif_tags (str, optional): comma-separated list of EXIF tags to include in output
491
491
  augment (bool, optional): enable image augmentation
492
492
  detector_options (dict, optional): key/value pairs that are interpreted differently
493
493
  by different detectors
@@ -562,7 +562,7 @@ def _run_detector_with_image_queue(image_files,
562
562
  image_size,
563
563
  include_image_size,
564
564
  include_image_timestamp,
565
- include_exif_data,
565
+ include_exif_tags,
566
566
  augment,
567
567
  detector_options,
568
568
  preprocess_on_image_queue,
@@ -579,7 +579,7 @@ def _run_detector_with_image_queue(image_files,
579
579
  image_size,
580
580
  include_image_size,
581
581
  include_image_timestamp,
582
- include_exif_data,
582
+ include_exif_tags,
583
583
  augment,
584
584
  detector_options,
585
585
  preprocess_on_image_queue,
@@ -598,7 +598,7 @@ def _run_detector_with_image_queue(image_files,
598
598
  image_size,
599
599
  include_image_size,
600
600
  include_image_timestamp,
601
- include_exif_data,
601
+ include_exif_tags,
602
602
  augment,
603
603
  detector_options,
604
604
  preprocess_on_image_queue,
@@ -680,7 +680,7 @@ def _process_batch(image_items_batch,
680
680
  image_size=None,
681
681
  include_image_size=False,
682
682
  include_image_timestamp=False,
683
- include_exif_data=False,
683
+ include_exif_tags=None,
684
684
  augment=False):
685
685
  """
686
686
  Process a batch of images using generate_detections_one_batch(). Does not necessarily return
@@ -695,7 +695,7 @@ def _process_batch(image_items_batch,
695
695
  image_size (int, optional): image size override
696
696
  include_image_size (bool, optional): include image dimensions in results
697
697
  include_image_timestamp (bool, optional): include image timestamps in results
698
- include_exif_data (bool, optional): include EXIF data in results
698
+ include_exif_tags (str, optional): comma-separated list of EXIF tags to include in output
699
699
  augment (bool, optional): whether to use image augmentation
700
700
 
701
701
  Returns:
@@ -762,12 +762,13 @@ def _process_batch(image_items_batch,
762
762
  image_result['detections'] = \
763
763
  [det for det in image_result['detections'] if det['conf'] >= confidence_threshold]
764
764
 
765
- if include_image_size or include_image_timestamp or include_exif_data:
765
+ if include_image_size or include_image_timestamp or (include_exif_tags is not None):
766
766
 
767
767
  image = valid_images[i_valid_image]
768
768
 
769
769
  # If this was preprocessed by the producer thread, pull out the PIL version
770
770
  if isinstance(image,dict):
771
+
771
772
  image = image['img_original_pil']
772
773
 
773
774
  if include_image_size:
@@ -779,9 +780,12 @@ def _process_batch(image_items_batch,
779
780
 
780
781
  image_result['datetime'] = get_image_datetime(image)
781
782
 
782
- if include_exif_data:
783
+ if include_exif_tags is not None:
783
784
 
784
- image_result['exif_metadata'] = read_exif.read_pil_exif(image,exif_options)
785
+ exif_options = copy.copy(exif_options_base)
786
+ exif_options.tags_to_include = include_exif_tags
787
+ image_result['exif_metadata'] = read_exif.read_pil_exif(
788
+ image,exif_options)
785
789
 
786
790
  # ...if we need to store metadata
787
791
 
@@ -834,7 +838,7 @@ def _process_images(im_files,
834
838
  checkpoint_queue=None,
835
839
  include_image_size=False,
836
840
  include_image_timestamp=False,
837
- include_exif_data=False,
841
+ include_exif_tags=None,
838
842
  augment=False,
839
843
  detector_options=None,
840
844
  loader_workers=default_loaders,
@@ -856,7 +860,7 @@ def _process_images(im_files,
856
860
  checkpoint_queue (Queue, optional): internal parameter used to pass image queues around
857
861
  include_image_size (bool, optional): should we include image size in the output for each image?
858
862
  include_image_timestamp (bool, optional): should we include image timestamps in the output for each image?
859
- include_exif_data (bool, optional): should we include EXIF data in the output for each image?
863
+ include_exif_tags (str, optional): comma-separated list of EXIF tags to include in output
860
864
  augment (bool, optional): enable image augmentation
861
865
  detector_options (dict, optional): key/value pairs that are interpreted differently
862
866
  by different detectors
@@ -890,7 +894,7 @@ def _process_images(im_files,
890
894
  image_size=image_size,
891
895
  include_image_size=include_image_size,
892
896
  include_image_timestamp=include_image_timestamp,
893
- include_exif_data=include_exif_data,
897
+ include_exif_tags=include_exif_tags,
894
898
  augment=augment,
895
899
  detector_options=detector_options,
896
900
  loader_workers=loader_workers,
@@ -907,7 +911,7 @@ def _process_images(im_files,
907
911
  image_size=image_size,
908
912
  include_image_size=include_image_size,
909
913
  include_image_timestamp=include_image_timestamp,
910
- include_exif_data=include_exif_data,
914
+ include_exif_tags=include_exif_tags,
911
915
  augment=augment)
912
916
 
913
917
  if checkpoint_queue is not None:
@@ -929,7 +933,7 @@ def _process_image(im_file,
929
933
  image_size=None,
930
934
  include_image_size=False,
931
935
  include_image_timestamp=False,
932
- include_exif_data=False,
936
+ include_exif_tags=False,
933
937
  augment=False):
934
938
  """
935
939
  Runs a detector (typically MegaDetector) on a single image file.
@@ -947,7 +951,7 @@ def _process_image(im_file,
947
951
  doing
948
952
  include_image_size (bool, optional): should we include image size in the output for each image?
949
953
  include_image_timestamp (bool, optional): should we include image timestamps in the output for each image?
950
- include_exif_data (bool, optional): should we include EXIF data in the output for each image?
954
+ include_exif_tags (str, optional): comma-separated list of EXIF tags to include in output
951
955
  augment (bool, optional): enable image augmentation
952
956
 
953
957
  Returns:
@@ -1000,7 +1004,9 @@ def _process_image(im_file,
1000
1004
  if include_image_timestamp:
1001
1005
  result['datetime'] = get_image_datetime(image)
1002
1006
 
1003
- if include_exif_data:
1007
+ if include_exif_tags is not None:
1008
+ exif_options = copy.copy(exif_options_base)
1009
+ exif_options.tags_to_include = include_exif_tags
1004
1010
  result['exif_metadata'] = read_exif.read_pil_exif(image,exif_options)
1005
1011
 
1006
1012
  return result
@@ -1055,7 +1061,7 @@ def load_and_run_detector_batch(model_file,
1055
1061
  class_mapping_filename=None,
1056
1062
  include_image_size=False,
1057
1063
  include_image_timestamp=False,
1058
- include_exif_data=False,
1064
+ include_exif_tags=None,
1059
1065
  augment=False,
1060
1066
  force_model_download=False,
1061
1067
  detector_options=None,
@@ -1088,7 +1094,7 @@ def load_and_run_detector_batch(model_file,
1088
1094
  file or YOLOv5 dataset.yaml file
1089
1095
  include_image_size (bool, optional): should we include image size in the output for each image?
1090
1096
  include_image_timestamp (bool, optional): should we include image timestamps in the output for each image?
1091
- include_exif_data (bool, optional): should we include EXIF data in the output for each image?
1097
+ include_exif_tags (str, optional): comma-separated list of EXIF tags to include in output
1092
1098
  augment (bool, optional): enable image augmentation
1093
1099
  force_model_download (bool, optional): force downloading the model file if
1094
1100
  a named model (e.g. "MDV5A") is supplied, even if the local file already
@@ -1207,7 +1213,7 @@ def load_and_run_detector_batch(model_file,
1207
1213
  image_size=image_size,
1208
1214
  include_image_size=include_image_size,
1209
1215
  include_image_timestamp=include_image_timestamp,
1210
- include_exif_data=include_exif_data,
1216
+ include_exif_tags=include_exif_tags,
1211
1217
  augment=augment,
1212
1218
  detector_options=detector_options,
1213
1219
  loader_workers=loader_workers,
@@ -1269,7 +1275,7 @@ def load_and_run_detector_batch(model_file,
1269
1275
  image_size=image_size,
1270
1276
  include_image_size=include_image_size,
1271
1277
  include_image_timestamp=include_image_timestamp,
1272
- include_exif_data=include_exif_data,
1278
+ include_exif_tags=include_exif_tags,
1273
1279
  augment=augment)
1274
1280
 
1275
1281
  results.extend(batch_results)
@@ -1295,7 +1301,7 @@ def load_and_run_detector_batch(model_file,
1295
1301
  image_size=image_size,
1296
1302
  include_image_size=include_image_size,
1297
1303
  include_image_timestamp=include_image_timestamp,
1298
- include_exif_data=include_exif_data,
1304
+ include_exif_tags=include_exif_tags,
1299
1305
  augment=augment)
1300
1306
  results.append(result)
1301
1307
 
@@ -1354,7 +1360,7 @@ def load_and_run_detector_batch(model_file,
1354
1360
  checkpoint_queue=checkpoint_queue,
1355
1361
  include_image_size=include_image_size,
1356
1362
  include_image_timestamp=include_image_timestamp,
1357
- include_exif_data=include_exif_data,
1363
+ include_exif_tags=include_exif_tags,
1358
1364
  augment=augment,
1359
1365
  detector_options=detector_options),
1360
1366
  image_chunks)
@@ -1374,7 +1380,7 @@ def load_and_run_detector_batch(model_file,
1374
1380
  image_size=image_size,
1375
1381
  include_image_size=include_image_size,
1376
1382
  include_image_timestamp=include_image_timestamp,
1377
- include_exif_data=include_exif_data,
1383
+ include_exif_tags=include_exif_tags,
1378
1384
  augment=augment,
1379
1385
  detector_options=detector_options),
1380
1386
  image_chunks)
@@ -1495,7 +1501,7 @@ def get_image_datetime(image):
1495
1501
  returns None if EXIF datetime is not available.
1496
1502
  """
1497
1503
 
1498
- exif_tags = read_exif.read_pil_exif(image,exif_options)
1504
+ exif_tags = read_exif.read_pil_exif(image,exif_options_base)
1499
1505
 
1500
1506
  try:
1501
1507
  datetime_str = exif_tags['DateTimeOriginal']
@@ -1654,7 +1660,7 @@ if False:
1654
1660
  class_mapping_filename = None
1655
1661
  include_image_size = True
1656
1662
  include_image_timestamp = True
1657
- include_exif_data = True
1663
+ include_exif_tags = None
1658
1664
  overwrite_handling = None
1659
1665
 
1660
1666
  # Generate a command line
@@ -1689,8 +1695,8 @@ if False:
1689
1695
  cmd += ' --include_image_size'
1690
1696
  if include_image_timestamp:
1691
1697
  cmd += ' --include_image_timestamp'
1692
- if include_exif_data:
1693
- cmd += ' --include_exif_data'
1698
+ if include_exif_tags is not None:
1699
+ cmd += ' --include_exif_tags "{}"'.format(include_exif_tags)
1694
1700
  if overwrite_handling is not None:
1695
1701
  cmd += ' --overwrite_handling {}'.format(overwrite_handling)
1696
1702
 
@@ -1837,9 +1843,10 @@ def main(): # noqa
1837
1843
  help='Include image datetime (if available) in output file'
1838
1844
  )
1839
1845
  parser.add_argument(
1840
- '--include_exif_data',
1841
- action='store_true',
1842
- help='Include available EXIF data in output file'
1846
+ '--include_exif_tags',
1847
+ type=str,
1848
+ default=None,
1849
+ help='Command-separated list of EXIF tags to include in output, or "all" to include all tags'
1843
1850
  )
1844
1851
  parser.add_argument(
1845
1852
  '--overwrite_handling',
@@ -1878,6 +1885,12 @@ def main(): # noqa
1878
1885
  action='store_true',
1879
1886
  help=argparse.SUPPRESS)
1880
1887
 
1888
+ # This argument is deprecated in favor use --include_exif_tags
1889
+ parser.add_argument(
1890
+ '--include_exif_data',
1891
+ action='store_true',
1892
+ help=argparse.SUPPRESS)
1893
+
1881
1894
  if len(sys.argv[1:]) == 0:
1882
1895
  parser.print_help()
1883
1896
  parser.exit()
@@ -1888,6 +1901,10 @@ def main(): # noqa
1888
1901
  if args.use_threads_for_queue:
1889
1902
  use_threads_for_queue = True
1890
1903
 
1904
+ # Support the legacy --include_exif_data flag
1905
+ if args.include_exif_data and (args.include_exif_tags is None):
1906
+ args.include_exif_tags = 'all'
1907
+
1891
1908
  detector_options = parse_kvp_list(args.detector_options)
1892
1909
 
1893
1910
  # If the specified detector file is really the name of a known model, find
@@ -2094,7 +2111,7 @@ def main(): # noqa
2094
2111
  class_mapping_filename=args.class_mapping_filename,
2095
2112
  include_image_size=args.include_image_size,
2096
2113
  include_image_timestamp=args.include_image_timestamp,
2097
- include_exif_data=args.include_exif_data,
2114
+ include_exif_tags=args.include_exif_tags,
2098
2115
  augment=args.augment,
2099
2116
  # Don't download the model *again*
2100
2117
  force_model_download=False,