megadetector 10.0.5__tar.gz → 10.0.6__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.5/megadetector.egg-info → megadetector-10.0.6}/PKG-INFO +1 -1
  2. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/detection/process_video.py +15 -6
  3. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/detection/video_utils.py +132 -21
  4. {megadetector-10.0.5 → megadetector-10.0.6/megadetector.egg-info}/PKG-INFO +1 -1
  5. {megadetector-10.0.5 → megadetector-10.0.6}/pyproject.toml +1 -1
  6. {megadetector-10.0.5 → megadetector-10.0.6}/LICENSE +0 -0
  7. {megadetector-10.0.5 → megadetector-10.0.6}/README-package.md +0 -0
  8. {megadetector-10.0.5 → megadetector-10.0.6}/README.md +0 -0
  9. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/__init__.py +0 -0
  10. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/api/__init__.py +0 -0
  11. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/api/batch_processing/integration/digiKam/setup.py +0 -0
  12. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/api/batch_processing/integration/digiKam/xmp_integration.py +0 -0
  13. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/api/batch_processing/integration/eMammal/test_scripts/config_template.py +0 -0
  14. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +0 -0
  15. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +0 -0
  16. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/__init__.py +0 -0
  17. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/aggregate_classifier_probs.py +0 -0
  18. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/analyze_failed_images.py +0 -0
  19. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/cache_batchapi_outputs.py +0 -0
  20. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/create_classification_dataset.py +0 -0
  21. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/crop_detections.py +0 -0
  22. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/csv_to_json.py +0 -0
  23. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/detect_and_crop.py +0 -0
  24. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/efficientnet/__init__.py +0 -0
  25. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/efficientnet/model.py +0 -0
  26. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/efficientnet/utils.py +0 -0
  27. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/evaluate_model.py +0 -0
  28. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/identify_mislabeled_candidates.py +0 -0
  29. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/json_to_azcopy_list.py +0 -0
  30. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/json_validator.py +0 -0
  31. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/map_classification_categories.py +0 -0
  32. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/merge_classification_detection_output.py +0 -0
  33. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/prepare_classification_script.py +0 -0
  34. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/prepare_classification_script_mc.py +0 -0
  35. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/run_classifier.py +0 -0
  36. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/save_mislabeled.py +0 -0
  37. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/train_classifier.py +0 -0
  38. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/train_classifier_tf.py +0 -0
  39. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/classification/train_utils.py +0 -0
  40. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/__init__.py +0 -0
  41. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/animl_to_md.py +0 -0
  42. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/annotations/__init__.py +0 -0
  43. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/annotations/annotation_constants.py +0 -0
  44. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/camtrap_dp_to_coco.py +0 -0
  45. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/cct_json_utils.py +0 -0
  46. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/cct_to_md.py +0 -0
  47. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/cct_to_wi.py +0 -0
  48. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/coco_to_labelme.py +0 -0
  49. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/coco_to_yolo.py +0 -0
  50. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/databases/__init__.py +0 -0
  51. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/databases/add_width_and_height_to_db.py +0 -0
  52. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/databases/combine_coco_camera_traps_files.py +0 -0
  53. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/databases/integrity_check_json_db.py +0 -0
  54. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/databases/subset_json_db.py +0 -0
  55. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/generate_crops_from_cct.py +0 -0
  56. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/get_image_sizes.py +0 -0
  57. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/labelme_to_coco.py +0 -0
  58. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/labelme_to_yolo.py +0 -0
  59. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/lila/__init__.py +0 -0
  60. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/lila/create_lila_blank_set.py +0 -0
  61. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/lila/create_lila_test_set.py +0 -0
  62. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/lila/create_links_to_md_results_files.py +0 -0
  63. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/lila/download_lila_subset.py +0 -0
  64. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/lila/generate_lila_per_image_labels.py +0 -0
  65. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/lila/get_lila_annotation_counts.py +0 -0
  66. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/lila/get_lila_image_counts.py +0 -0
  67. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/lila/lila_common.py +0 -0
  68. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/lila/test_lila_metadata_urls.py +0 -0
  69. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/mewc_to_md.py +0 -0
  70. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/ocr_tools.py +0 -0
  71. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/read_exif.py +0 -0
  72. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/remap_coco_categories.py +0 -0
  73. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/remove_exif.py +0 -0
  74. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/rename_images.py +0 -0
  75. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/resize_coco_dataset.py +0 -0
  76. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/speciesnet_to_md.py +0 -0
  77. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/wi_download_csv_to_coco.py +0 -0
  78. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/yolo_output_to_md_output.py +0 -0
  79. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/yolo_to_coco.py +0 -0
  80. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/data_management/zamba_to_md.py +0 -0
  81. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/detection/__init__.py +0 -0
  82. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/detection/change_detection.py +0 -0
  83. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/detection/pytorch_detector.py +0 -0
  84. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/detection/run_detector.py +0 -0
  85. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/detection/run_detector_batch.py +0 -0
  86. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/detection/run_inference_with_yolov5_val.py +0 -0
  87. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/detection/run_md_and_speciesnet.py +0 -0
  88. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/detection/run_tiled_inference.py +0 -0
  89. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/detection/tf_detector.py +0 -0
  90. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/__init__.py +0 -0
  91. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/add_max_conf.py +0 -0
  92. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/categorize_detections_by_size.py +0 -0
  93. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/classification_postprocessing.py +0 -0
  94. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/combine_batch_outputs.py +0 -0
  95. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/compare_batch_results.py +0 -0
  96. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/convert_output_format.py +0 -0
  97. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/create_crop_folder.py +0 -0
  98. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/detector_calibration.py +0 -0
  99. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/generate_csv_report.py +0 -0
  100. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/load_api_results.py +0 -0
  101. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/md_to_coco.py +0 -0
  102. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/md_to_labelme.py +0 -0
  103. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/md_to_wi.py +0 -0
  104. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/merge_detections.py +0 -0
  105. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/postprocess_batch_results.py +0 -0
  106. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/remap_detection_categories.py +0 -0
  107. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/render_detection_confusion_matrix.py +0 -0
  108. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py +0 -0
  109. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +0 -0
  110. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +0 -0
  111. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/separate_detections_into_folders.py +0 -0
  112. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/subset_json_detector_output.py +0 -0
  113. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/top_folders_to_bottom.py +0 -0
  114. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/postprocessing/validate_batch_results.py +0 -0
  115. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/taxonomy_mapping/__init__.py +0 -0
  116. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +0 -0
  117. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/taxonomy_mapping/map_new_lila_datasets.py +0 -0
  118. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +0 -0
  119. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/taxonomy_mapping/preview_lila_taxonomy.py +0 -0
  120. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/taxonomy_mapping/retrieve_sample_image.py +0 -0
  121. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/taxonomy_mapping/simple_image_download.py +0 -0
  122. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/taxonomy_mapping/species_lookup.py +0 -0
  123. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/taxonomy_mapping/taxonomy_csv_checker.py +0 -0
  124. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/taxonomy_mapping/taxonomy_graph.py +0 -0
  125. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/taxonomy_mapping/validate_lila_category_mappings.py +0 -0
  126. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/tests/__init__.py +0 -0
  127. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/tests/test_nms_synthetic.py +0 -0
  128. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/utils/__init__.py +0 -0
  129. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/utils/ct_utils.py +0 -0
  130. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/utils/directory_listing.py +0 -0
  131. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/utils/extract_frames_from_video.py +0 -0
  132. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/utils/gpu_test.py +0 -0
  133. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/utils/md_tests.py +0 -0
  134. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/utils/path_utils.py +0 -0
  135. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/utils/process_utils.py +0 -0
  136. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/utils/split_locations_into_train_val.py +0 -0
  137. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/utils/string_utils.py +0 -0
  138. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/utils/url_utils.py +0 -0
  139. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/utils/wi_platform_utils.py +0 -0
  140. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/utils/wi_taxonomy_utils.py +0 -0
  141. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/utils/write_html_image_list.py +0 -0
  142. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/visualization/__init__.py +0 -0
  143. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/visualization/plot_utils.py +0 -0
  144. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/visualization/render_images_with_thumbnails.py +0 -0
  145. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/visualization/visualization_utils.py +0 -0
  146. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/visualization/visualize_db.py +0 -0
  147. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/visualization/visualize_detector_output.py +0 -0
  148. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector/visualization/visualize_video_output.py +0 -0
  149. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector.egg-info/SOURCES.txt +0 -0
  150. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector.egg-info/dependency_links.txt +0 -0
  151. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector.egg-info/requires.txt +0 -0
  152. {megadetector-10.0.5 → megadetector-10.0.6}/megadetector.egg-info/top_level.txt +0 -0
  153. {megadetector-10.0.5 → megadetector-10.0.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: megadetector
3
- Version: 10.0.5
3
+ Version: 10.0.6
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>
@@ -81,8 +81,8 @@ class ProcessVideoOptions:
81
81
  self.augment = False
82
82
 
83
83
  #: By default, a video with no frames (or no frames retrievable with the current parameters)
84
- #: is treated as a failure; this causes it to be treated as a video with no detections.
85
- self.allow_empty_videos = False
84
+ #: is silently stored as a failure; this causes it to halt execution.
85
+ self.exit_on_empty_video = False
86
86
 
87
87
  #: Detector-specific options
88
88
  self.detector_options = None
@@ -134,6 +134,14 @@ def process_videos(options):
134
134
  # Check for incompatible options
135
135
  _validate_video_options(options)
136
136
 
137
+ if options.output_json_file is None:
138
+ video_file = options.input_video_file.replace('\\','/')
139
+ if video_file.endswith('/'):
140
+ video_file = video_file[:-1]
141
+ options.output_json_file = video_file + '.json'
142
+ print('Output file not specified, defaulting to {}'.format(
143
+ options.output_json_file))
144
+
137
145
  assert options.output_json_file.endswith('.json'), \
138
146
  'Illegal output file {}'.format(options.output_json_file)
139
147
 
@@ -173,7 +181,7 @@ def process_videos(options):
173
181
  every_n_frames=every_n_frames_param,
174
182
  verbose=options.verbose,
175
183
  files_to_process_relative=[video_bn],
176
- allow_empty_videos=options.allow_empty_videos)
184
+ error_on_empty_video=options.exit_on_empty_video)
177
185
 
178
186
  else:
179
187
 
@@ -187,7 +195,7 @@ def process_videos(options):
187
195
  every_n_frames=every_n_frames_param,
188
196
  verbose=options.verbose,
189
197
  recursive=options.recursive,
190
- allow_empty_videos=options.allow_empty_videos)
198
+ error_on_empty_video=options.exit_on_empty_video)
191
199
 
192
200
  # ...whether we're processing a file or a folder
193
201
 
@@ -414,9 +422,10 @@ def main(): # noqa
414
422
  action='store_true',
415
423
  help='Enable image augmentation')
416
424
 
417
- parser.add_argument('--allow_empty_videos',
425
+ parser.add_argument('--exit_on_empty_video',
418
426
  action='store_true',
419
- help='By default, videos with no retrievable frames cause an error, this makes it a warning')
427
+ help=('By default, videos with no retrievable frames are stored as failures; this' \
428
+ 'causes them to halt execution'))
420
429
 
421
430
  parser.add_argument(
422
431
  '--detector_options',
@@ -101,6 +101,99 @@ def find_videos(dirname,
101
101
  return find_video_strings(files)
102
102
 
103
103
 
104
+ #%% Shared function for opening videos
105
+
106
+ DEFAULT_BACKEND = -1
107
+
108
+ # This is the order in which we'll try to open backends.
109
+ #
110
+ # In general, the defaults are as follows, though they vary depending
111
+ # on what's installed:
112
+ #
113
+ # Windows: CAP_DSHOW or CAP_MSMF
114
+ # Linux: CAP_FFMPEG
115
+ # macOS: CAP_AVFOUNDATION
116
+ #
117
+ # Technically if the default fails, we may try the same backend again, but this
118
+ # is rare, and it's not worth the complexity of figuring out what the system
119
+ # default is.
120
+ backend_id_to_name = {
121
+ DEFAULT_BACKEND:'default',
122
+ cv2.CAP_FFMPEG: 'CAP_FFMPEG',
123
+ cv2.CAP_DSHOW: 'CAP_DSHOW',
124
+ cv2.CAP_MSMF: 'CAP_MSMF',
125
+ cv2.CAP_AVFOUNDATION: 'CAP_AVFOUNDATION',
126
+ cv2.CAP_GSTREAMER: 'CAP_GSTREAMER'
127
+ }
128
+
129
+ def open_video(video_path,verbose=False):
130
+ """
131
+ Open the video at [video_path], trying multiple OpenCV backends if necessary.
132
+
133
+ Args:
134
+ video_path (str): the file to open
135
+ verbose (bool, optional): enable additional debug output
136
+
137
+ Returns:
138
+ (cv2.VideoCapture,image): a tuple containing (a) the open video capture device
139
+ (or None if no backends succeeded) and (b) the first frame of the video (or None)
140
+ """
141
+
142
+ if not os.path.isfile(video_path):
143
+ print('Video file {} not found'.format(video_path))
144
+ return None,None
145
+
146
+ backend_ids = backend_id_to_name.keys()
147
+
148
+ for backend_id in backend_ids:
149
+
150
+ backend_name = backend_id_to_name[backend_id]
151
+ if verbose:
152
+ print('Trying backend {}'.format(backend_name))
153
+
154
+ try:
155
+ if backend_id == DEFAULT_BACKEND:
156
+ vidcap = cv2.VideoCapture(video_path)
157
+ else:
158
+ vidcap = cv2.VideoCapture(video_path, backend_id)
159
+ except Exception as e:
160
+ if verbose:
161
+ print('Warning: error opening {} with backend {}: {}'.format(
162
+ video_path,backend_name,str(e)))
163
+ continue
164
+
165
+ if not vidcap.isOpened():
166
+ if verbose:
167
+ print('Warning: isOpened() is False for {} with backend {}'.format(
168
+ video_path,backend_name))
169
+ try:
170
+ vidcap.release()
171
+ except Exception:
172
+ pass
173
+ continue
174
+
175
+ success, image = vidcap.read()
176
+ if success and (image is not None):
177
+ if verbose:
178
+ print('Successfully opened {} with backend: {}'.format(
179
+ video_path,backend_name))
180
+ return vidcap,image
181
+
182
+ print('Warning: failed to open {} with backend {}'.format(
183
+ video_path,backend_name))
184
+ try:
185
+ vidcap.release()
186
+ except Exception:
187
+ pass
188
+
189
+ # ...for each backend
190
+
191
+ print('Error: failed to open {} with any backend'.format(video_path))
192
+ return None,None
193
+
194
+ # ...def open_video(...)
195
+
196
+
104
197
  #%% Functions for rendering frames to video and vice-versa
105
198
 
106
199
  # http://tsaith.github.io/combine-images-into-a-video-with-python-3-and-opencv-3.html
@@ -146,21 +239,32 @@ def frames_to_video(images, fs, output_file_name, codec_spec=default_fourcc):
146
239
  cv2.destroyAllWindows()
147
240
 
148
241
 
149
- def get_video_fs(input_video_file):
242
+ def get_video_fs(input_video_file,verbose=False):
150
243
  """
151
244
  Retrieves the frame rate of [input_video_file].
152
245
 
153
246
  Args:
154
247
  input_video_file (str): video file for which we want the frame rate
248
+ verbose (bool, optional): enable additional debug output
155
249
 
156
250
  Returns:
157
- float: the frame rate of [input_video_file]
251
+ float: the frame rate of [input_video_file], or None if no frame
252
+ rate could be extracted
158
253
  """
159
254
 
160
- assert os.path.isfile(input_video_file), 'File {} not found'.format(input_video_file)
161
- vidcap = cv2.VideoCapture(input_video_file)
255
+ assert os.path.isfile(input_video_file), \
256
+ 'File {} not found'.format(input_video_file)
257
+ vidcap,_ = open_video(input_video_file,verbose=verbose)
258
+ if vidcap is None:
259
+ if verbose:
260
+ print('Failed to get frame rate for {}'.format(input_video_file))
261
+ return None
162
262
  fs = vidcap.get(cv2.CAP_PROP_FPS)
163
- vidcap.release()
263
+ try:
264
+ vidcap.release()
265
+ except Exception as e:
266
+ print('Warning: error closing video handle for {}: {}'.format(
267
+ input_video_file,str(e)))
164
268
  return fs
165
269
 
166
270
 
@@ -249,7 +353,7 @@ def run_callback_on_frames(input_video_file,
249
353
  of the video, no frames are extracted. Can also be a single int, specifying
250
354
  a single frame number.
251
355
  allow_empty_videos (bool, optional): Just print a warning if a video appears to have no
252
- frames (by default, this is an error).
356
+ frames (by default, this raises an Exception).
253
357
 
254
358
  Returns:
255
359
  dict: dict with keys 'frame_filenames' (list), 'frame_rate' (float), 'results' (list).
@@ -271,7 +375,7 @@ def run_callback_on_frames(input_video_file,
271
375
 
272
376
  try:
273
377
 
274
- vidcap = cv2.VideoCapture(input_video_file)
378
+ vidcap,image = open_video(input_video_file,verbose=verbose)
275
379
  n_frames = int(vidcap.get(cv2.CAP_PROP_FRAME_COUNT))
276
380
  frame_rate = vidcap.get(cv2.CAP_PROP_FPS)
277
381
 
@@ -300,7 +404,11 @@ def run_callback_on_frames(input_video_file,
300
404
  # frame_number = 0
301
405
  for frame_number in range(0,n_frames):
302
406
 
303
- success,image = vidcap.read()
407
+ # We've already read the first frame, when we opened the video
408
+ if frame_number != 0:
409
+ success,image = vidcap.read()
410
+ else:
411
+ success = True
304
412
 
305
413
  if not success:
306
414
  assert image is None
@@ -363,9 +471,9 @@ def run_callback_on_frames_for_folder(input_video_folder,
363
471
  frame_callback,
364
472
  every_n_frames=None,
365
473
  verbose=False,
366
- allow_empty_videos=False,
367
474
  recursive=True,
368
- files_to_process_relative=None):
475
+ files_to_process_relative=None,
476
+ error_on_empty_video=False):
369
477
  """
370
478
  Calls the function frame_callback(np.array,image_id) on all (or selected) frames in
371
479
  all videos in [input_video_folder].
@@ -382,10 +490,10 @@ def run_callback_on_frames_for_folder(input_video_folder,
382
490
  interpreted as a sampling rate in seconds, which is rounded to the nearest frame
383
491
  sampling rate.
384
492
  verbose (bool, optional): enable additional debug console output
385
- allow_empty_videos (bool, optional): Just print a warning if a video appears to have no
386
- frames (by default, this is an error).
387
493
  recursive (bool, optional): recurse into [input_video_folder]
388
494
  files_to_process_relative (list, optional): only process specific relative paths
495
+ error_on_empty_video (bool, optional): by default, videos with errors or no valid frames
496
+ are silently stored as failures; this turns them into exceptions
389
497
 
390
498
  Returns:
391
499
  dict: dict with keys 'video_filenames' (list of str), 'frame_rates' (list of floats),
@@ -440,18 +548,21 @@ def run_callback_on_frames_for_folder(input_video_folder,
440
548
  every_n_frames=every_n_frames,
441
549
  verbose=verbose,
442
550
  frames_to_process=None,
443
- allow_empty_videos=allow_empty_videos)
551
+ allow_empty_videos=False)
444
552
 
445
553
  except Exception as e:
446
554
 
447
- print('Warning: error processing video {}: {}'.format(
448
- video_fn_abs,str(e)
449
- ))
450
- to_return['frame_rates'].append(-1.0)
451
- failure_result = {}
452
- failure_result['failure'] = 'Failure processing video: {}'.format(str(e))
453
- to_return['results'].append(failure_result)
454
- continue
555
+ if (not error_on_empty_video):
556
+ print('Warning: error processing video {}: {}'.format(
557
+ video_fn_abs,str(e)
558
+ ))
559
+ to_return['frame_rates'].append(-1.0)
560
+ failure_result = {}
561
+ failure_result['failure'] = 'Failure processing video: {}'.format(str(e))
562
+ to_return['results'].append(failure_result)
563
+ continue
564
+ else:
565
+ raise
455
566
 
456
567
  # ...try/except
457
568
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: megadetector
3
- Version: 10.0.5
3
+ Version: 10.0.6
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>
@@ -5,7 +5,7 @@ requires = [
5
5
 
6
6
  [project]
7
7
  name = "megadetector"
8
- version = "10.0.5"
8
+ version = "10.0.6"
9
9
  description = "MegaDetector is an AI model that helps conservation folks spend less time doing boring things with camera trap images."
10
10
  readme = "README-package.md"
11
11
  requires-python = ">=3.9,<3.14"
File without changes
File without changes
File without changes