megadetector 5.0.8__py3-none-any.whl → 5.0.10__py3-none-any.whl

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 (190) hide show
  1. api/__init__.py +0 -0
  2. api/batch_processing/__init__.py +0 -0
  3. api/batch_processing/api_core/__init__.py +0 -0
  4. api/batch_processing/api_core/batch_service/__init__.py +0 -0
  5. api/batch_processing/api_core/batch_service/score.py +0 -1
  6. api/batch_processing/api_core/server_job_status_table.py +0 -1
  7. api/batch_processing/api_core_support/__init__.py +0 -0
  8. api/batch_processing/api_core_support/aggregate_results_manually.py +0 -1
  9. api/batch_processing/api_support/__init__.py +0 -0
  10. api/batch_processing/api_support/summarize_daily_activity.py +0 -1
  11. api/batch_processing/data_preparation/__init__.py +0 -0
  12. api/batch_processing/data_preparation/manage_local_batch.py +65 -65
  13. api/batch_processing/data_preparation/manage_video_batch.py +8 -8
  14. api/batch_processing/integration/digiKam/xmp_integration.py +0 -1
  15. api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +0 -1
  16. api/batch_processing/postprocessing/__init__.py +0 -0
  17. api/batch_processing/postprocessing/add_max_conf.py +12 -12
  18. api/batch_processing/postprocessing/categorize_detections_by_size.py +32 -14
  19. api/batch_processing/postprocessing/combine_api_outputs.py +68 -54
  20. api/batch_processing/postprocessing/compare_batch_results.py +113 -43
  21. api/batch_processing/postprocessing/convert_output_format.py +41 -16
  22. api/batch_processing/postprocessing/load_api_results.py +16 -17
  23. api/batch_processing/postprocessing/md_to_coco.py +31 -21
  24. api/batch_processing/postprocessing/md_to_labelme.py +52 -22
  25. api/batch_processing/postprocessing/merge_detections.py +14 -14
  26. api/batch_processing/postprocessing/postprocess_batch_results.py +246 -174
  27. api/batch_processing/postprocessing/remap_detection_categories.py +32 -25
  28. api/batch_processing/postprocessing/render_detection_confusion_matrix.py +60 -27
  29. api/batch_processing/postprocessing/repeat_detection_elimination/find_repeat_detections.py +53 -44
  30. api/batch_processing/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +25 -14
  31. api/batch_processing/postprocessing/repeat_detection_elimination/repeat_detections_core.py +242 -158
  32. api/batch_processing/postprocessing/separate_detections_into_folders.py +159 -114
  33. api/batch_processing/postprocessing/subset_json_detector_output.py +146 -169
  34. api/batch_processing/postprocessing/top_folders_to_bottom.py +77 -43
  35. api/synchronous/__init__.py +0 -0
  36. api/synchronous/api_core/animal_detection_api/__init__.py +0 -0
  37. api/synchronous/api_core/animal_detection_api/api_backend.py +0 -2
  38. api/synchronous/api_core/animal_detection_api/api_frontend.py +266 -268
  39. api/synchronous/api_core/animal_detection_api/config.py +35 -35
  40. api/synchronous/api_core/tests/__init__.py +0 -0
  41. api/synchronous/api_core/tests/load_test.py +109 -109
  42. classification/__init__.py +0 -0
  43. classification/aggregate_classifier_probs.py +21 -24
  44. classification/analyze_failed_images.py +11 -13
  45. classification/cache_batchapi_outputs.py +51 -51
  46. classification/create_classification_dataset.py +69 -68
  47. classification/crop_detections.py +54 -53
  48. classification/csv_to_json.py +97 -100
  49. classification/detect_and_crop.py +105 -105
  50. classification/evaluate_model.py +43 -42
  51. classification/identify_mislabeled_candidates.py +47 -46
  52. classification/json_to_azcopy_list.py +10 -10
  53. classification/json_validator.py +72 -71
  54. classification/map_classification_categories.py +44 -43
  55. classification/merge_classification_detection_output.py +68 -68
  56. classification/prepare_classification_script.py +157 -154
  57. classification/prepare_classification_script_mc.py +228 -228
  58. classification/run_classifier.py +27 -26
  59. classification/save_mislabeled.py +30 -30
  60. classification/train_classifier.py +20 -20
  61. classification/train_classifier_tf.py +21 -22
  62. classification/train_utils.py +10 -10
  63. data_management/__init__.py +0 -0
  64. data_management/annotations/__init__.py +0 -0
  65. data_management/annotations/annotation_constants.py +18 -31
  66. data_management/camtrap_dp_to_coco.py +238 -0
  67. data_management/cct_json_utils.py +102 -59
  68. data_management/cct_to_md.py +176 -158
  69. data_management/cct_to_wi.py +247 -219
  70. data_management/coco_to_labelme.py +272 -263
  71. data_management/coco_to_yolo.py +79 -58
  72. data_management/databases/__init__.py +0 -0
  73. data_management/databases/add_width_and_height_to_db.py +20 -16
  74. data_management/databases/combine_coco_camera_traps_files.py +35 -31
  75. data_management/databases/integrity_check_json_db.py +62 -24
  76. data_management/databases/subset_json_db.py +24 -15
  77. data_management/generate_crops_from_cct.py +27 -45
  78. data_management/get_image_sizes.py +188 -162
  79. data_management/importers/add_nacti_sizes.py +8 -8
  80. data_management/importers/add_timestamps_to_icct.py +78 -78
  81. data_management/importers/animl_results_to_md_results.py +158 -158
  82. data_management/importers/auckland_doc_test_to_json.py +9 -9
  83. data_management/importers/auckland_doc_to_json.py +8 -8
  84. data_management/importers/awc_to_json.py +7 -7
  85. data_management/importers/bellevue_to_json.py +15 -15
  86. data_management/importers/cacophony-thermal-importer.py +13 -13
  87. data_management/importers/carrizo_shrubfree_2018.py +8 -8
  88. data_management/importers/carrizo_trail_cam_2017.py +8 -8
  89. data_management/importers/cct_field_adjustments.py +9 -9
  90. data_management/importers/channel_islands_to_cct.py +10 -10
  91. data_management/importers/eMammal/copy_and_unzip_emammal.py +1 -0
  92. data_management/importers/ena24_to_json.py +7 -7
  93. data_management/importers/filenames_to_json.py +8 -8
  94. data_management/importers/helena_to_cct.py +7 -7
  95. data_management/importers/idaho-camera-traps.py +7 -7
  96. data_management/importers/idfg_iwildcam_lila_prep.py +10 -10
  97. data_management/importers/jb_csv_to_json.py +9 -9
  98. data_management/importers/mcgill_to_json.py +8 -8
  99. data_management/importers/missouri_to_json.py +18 -18
  100. data_management/importers/nacti_fieldname_adjustments.py +10 -10
  101. data_management/importers/noaa_seals_2019.py +7 -7
  102. data_management/importers/pc_to_json.py +7 -7
  103. data_management/importers/plot_wni_giraffes.py +7 -7
  104. data_management/importers/prepare-noaa-fish-data-for-lila.py +359 -359
  105. data_management/importers/prepare_zsl_imerit.py +7 -7
  106. data_management/importers/rspb_to_json.py +8 -8
  107. data_management/importers/save_the_elephants_survey_A.py +8 -8
  108. data_management/importers/save_the_elephants_survey_B.py +9 -9
  109. data_management/importers/snapshot_safari_importer.py +26 -26
  110. data_management/importers/snapshot_safari_importer_reprise.py +665 -665
  111. data_management/importers/snapshot_serengeti_lila.py +14 -14
  112. data_management/importers/sulross_get_exif.py +8 -9
  113. data_management/importers/timelapse_csv_set_to_json.py +11 -11
  114. data_management/importers/ubc_to_json.py +13 -13
  115. data_management/importers/umn_to_json.py +7 -7
  116. data_management/importers/wellington_to_json.py +8 -8
  117. data_management/importers/wi_to_json.py +9 -9
  118. data_management/importers/zamba_results_to_md_results.py +181 -181
  119. data_management/labelme_to_coco.py +65 -24
  120. data_management/labelme_to_yolo.py +8 -8
  121. data_management/lila/__init__.py +0 -0
  122. data_management/lila/add_locations_to_island_camera_traps.py +9 -9
  123. data_management/lila/add_locations_to_nacti.py +147 -147
  124. data_management/lila/create_lila_blank_set.py +13 -13
  125. data_management/lila/create_lila_test_set.py +8 -8
  126. data_management/lila/create_links_to_md_results_files.py +106 -106
  127. data_management/lila/download_lila_subset.py +44 -110
  128. data_management/lila/generate_lila_per_image_labels.py +55 -42
  129. data_management/lila/get_lila_annotation_counts.py +18 -15
  130. data_management/lila/get_lila_image_counts.py +11 -11
  131. data_management/lila/lila_common.py +96 -33
  132. data_management/lila/test_lila_metadata_urls.py +132 -116
  133. data_management/ocr_tools.py +173 -128
  134. data_management/read_exif.py +110 -97
  135. data_management/remap_coco_categories.py +83 -83
  136. data_management/remove_exif.py +58 -62
  137. data_management/resize_coco_dataset.py +30 -23
  138. data_management/wi_download_csv_to_coco.py +246 -239
  139. data_management/yolo_output_to_md_output.py +86 -73
  140. data_management/yolo_to_coco.py +300 -60
  141. detection/__init__.py +0 -0
  142. detection/detector_training/__init__.py +0 -0
  143. detection/process_video.py +85 -33
  144. detection/pytorch_detector.py +43 -25
  145. detection/run_detector.py +157 -72
  146. detection/run_detector_batch.py +179 -113
  147. detection/run_inference_with_yolov5_val.py +108 -48
  148. detection/run_tiled_inference.py +111 -40
  149. detection/tf_detector.py +51 -29
  150. detection/video_utils.py +606 -521
  151. docs/source/conf.py +43 -0
  152. md_utils/__init__.py +0 -0
  153. md_utils/azure_utils.py +9 -9
  154. md_utils/ct_utils.py +228 -68
  155. md_utils/directory_listing.py +59 -64
  156. md_utils/md_tests.py +968 -871
  157. md_utils/path_utils.py +460 -134
  158. md_utils/process_utils.py +157 -133
  159. md_utils/sas_blob_utils.py +20 -20
  160. md_utils/split_locations_into_train_val.py +45 -32
  161. md_utils/string_utils.py +33 -10
  162. md_utils/url_utils.py +176 -60
  163. md_utils/write_html_image_list.py +40 -33
  164. md_visualization/__init__.py +0 -0
  165. md_visualization/plot_utils.py +102 -109
  166. md_visualization/render_images_with_thumbnails.py +34 -34
  167. md_visualization/visualization_utils.py +597 -291
  168. md_visualization/visualize_db.py +76 -48
  169. md_visualization/visualize_detector_output.py +61 -42
  170. {megadetector-5.0.8.dist-info → megadetector-5.0.10.dist-info}/METADATA +13 -7
  171. megadetector-5.0.10.dist-info/RECORD +224 -0
  172. {megadetector-5.0.8.dist-info → megadetector-5.0.10.dist-info}/top_level.txt +1 -0
  173. taxonomy_mapping/__init__.py +0 -0
  174. taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +342 -335
  175. taxonomy_mapping/map_new_lila_datasets.py +154 -154
  176. taxonomy_mapping/prepare_lila_taxonomy_release.py +142 -134
  177. taxonomy_mapping/preview_lila_taxonomy.py +591 -591
  178. taxonomy_mapping/retrieve_sample_image.py +12 -12
  179. taxonomy_mapping/simple_image_download.py +11 -11
  180. taxonomy_mapping/species_lookup.py +10 -10
  181. taxonomy_mapping/taxonomy_csv_checker.py +18 -18
  182. taxonomy_mapping/taxonomy_graph.py +47 -47
  183. taxonomy_mapping/validate_lila_category_mappings.py +83 -76
  184. data_management/cct_json_to_filename_json.py +0 -89
  185. data_management/cct_to_csv.py +0 -140
  186. data_management/databases/remove_corrupted_images_from_db.py +0 -191
  187. detection/detector_training/copy_checkpoints.py +0 -43
  188. megadetector-5.0.8.dist-info/RECORD +0 -205
  189. {megadetector-5.0.8.dist-info → megadetector-5.0.10.dist-info}/LICENSE +0 -0
  190. {megadetector-5.0.8.dist-info → megadetector-5.0.10.dist-info}/WHEEL +0 -0
@@ -1,76 +1,76 @@
1
- ########
2
- #
3
- # separate_detections_into_folders.py
4
- #
5
- ### Overview
6
- #
7
- # Given a .json file with batch processing results, separate the files in that
8
- # set of results into folders that contain animals/people/vehicles/nothing,
9
- # according to per-class thresholds.
10
- #
11
- # Image files are copied, not moved.
12
- #
13
- ### Output structure
14
- #
15
- # Preserves relative paths within each of those folders; cannot be used with .json
16
- # files that have absolute paths in them.
17
- #
18
- # For example, if your .json file has these images:
19
- #
20
- # a/b/c/1.jpg
21
- # a/b/d/2.jpg
22
- # a/b/e/3.jpg
23
- # a/b/f/4.jpg
24
- # a/x/y/5.jpg
25
- #
26
- # And let's say:
27
- #
28
- # * The results say that the first three images are empty/person/vehicle, respectively
29
- # * The fourth image is above threshold for "animal" and "person"
30
- # * The fifth image contains an animal
31
- #
32
- # * You specify an output base folder of c:\out
33
- #
34
- # You will get the following files:
35
- #
36
- # c:\out\empty\a\b\c\1.jpg
37
- # c:\out\people\a\b\d\2.jpg
38
- # c:\out\vehicles\a\b\e\3.jpg
39
- # c:\out\animal_person\a\b\f\4.jpg
40
- # c:\out\animals\a\x\y\5.jpg
41
- #
42
- ### Rendering bounding boxes
43
- #
44
- # By default, images are just copied to the target output folder. If you specify --render_boxes,
45
- # bounding boxes will be rendered on the output images. Because this is no longer strictly
46
- # a copy operation, this may result in the loss of metadata. More accurately, this *may*
47
- # result in the loss of some EXIF metadata; this *will* result in the loss of IPTC/XMP metadata.
48
- #
49
- # Rendering boxes also makes this script a lot slower.
50
- #
51
- ### Classification-based separation
52
- #
53
- # If you have a results file with classification data, you can also specify classes to put
54
- # in their own folders, within the "animals" folder, like this:
55
- #
56
- # --classification_thresholds "deer=0.75,cow=0.75"
57
- #
58
- # So, e.g., you might get:
59
- #
60
- # c:\out\animals\deer\a\x\y\5.jpg
61
- #
62
- # In this scenario, the folders within "animals" will be:
63
- #
64
- # deer, cow, multiple, unclassified
65
- #
66
- # "multiple" in this case only means "deer and cow"; if an image is classified as containing a
67
- # bird and a bear, that would end up in "unclassified", since the folder separation is based only
68
- # on the categories you provide at the command line.
69
- #
70
- # No classification-based separation is done within the animal_person, animal_vehicle, or
71
- # animal_person_vehicle folders.
72
- #
73
- ########
1
+ r"""
2
+
3
+ separate_detections_into_folders.py
4
+
5
+ **Overview**
6
+
7
+ Given a .json file with batch processing results, separate the files in that
8
+ set of results into folders that contain animals/people/vehicles/nothing,
9
+ according to per-class thresholds.
10
+
11
+ Image files are copied, not moved.
12
+
13
+ **Output structure**
14
+
15
+ Preserves relative paths within each of those folders; cannot be used with .json
16
+ files that have absolute paths in them.
17
+
18
+ For example, if your .json file has these images:
19
+
20
+ * a/b/c/1.jpg
21
+ * a/b/d/2.jpg
22
+ * a/b/e/3.jpg
23
+ * a/b/f/4.jpg
24
+ * a/x/y/5.jpg
25
+
26
+ And let's say:
27
+
28
+ * The results say that the first three images are empty/person/vehicle, respectively
29
+ * The fourth image is above threshold for "animal" and "person"
30
+ * The fifth image contains an animal
31
+
32
+ * You specify an output base folder of c:/out
33
+
34
+ You will get the following files:
35
+
36
+ * c:/out/empty/a/b/c/1.jpg
37
+ * c:/out/people/a/b/d/2.jpg
38
+ * c:/out/vehicles/a/b/e/3.jpg
39
+ * c:/out/animal_person/a/b/f/4.jpg
40
+ * c:/out/animals/a/x/y/5.jpg
41
+
42
+ **Rendering bounding boxes**
43
+
44
+ By default, images are just copied to the target output folder. If you specify --render_boxes,
45
+ bounding boxes will be rendered on the output images. Because this is no longer strictly
46
+ a copy operation, this may result in the loss of metadata. More accurately, this *may*
47
+ result in the loss of some EXIF metadata; this *will* result in the loss of IPTC/XMP metadata.
48
+
49
+ Rendering boxes also makes this script a lot slower.
50
+
51
+ **Classification-based separation**
52
+
53
+ If you have a results file with classification data, you can also specify classes to put
54
+ in their own folders, within the "animals" folder, like this:
55
+
56
+ ``--classification_thresholds "deer=0.75,cow=0.75"``
57
+
58
+ So, e.g., you might get:
59
+
60
+ c:/out/animals/deer/a/x/y/5.jpg
61
+
62
+ In this scenario, the folders within "animals" will be:
63
+
64
+ deer, cow, multiple, unclassified
65
+
66
+ "multiple" in this case only means "deer and cow"; if an image is classified as containing a
67
+ bird and a bear, that would end up in "unclassified", since the folder separation is based only
68
+ on the categories you provide at the command line.
69
+
70
+ No classification-based separation is done within the animal_person, animal_vehicle, or
71
+ animal_person_vehicle folders.
72
+
73
+ """
74
74
 
75
75
  #%% Constants and imports
76
76
 
@@ -85,7 +85,7 @@ from multiprocessing.pool import ThreadPool
85
85
  from functools import partial
86
86
  from tqdm import tqdm
87
87
 
88
- from md_utils.ct_utils import args_to_object
88
+ from md_utils.ct_utils import args_to_object, is_float
89
89
  from detection.run_detector import get_typical_confidence_threshold_from_results
90
90
 
91
91
  import md_visualization.visualization_utils as vis_utils
@@ -104,47 +104,91 @@ default_box_expansion = 3
104
104
  #%% Options class
105
105
 
106
106
  class SeparateDetectionsIntoFoldersOptions:
107
-
107
+ """
108
+ Options used to parameterize separate_detections_into_folders()
109
+ """
110
+
108
111
  def __init__(self,threshold=None):
109
112
 
113
+ #: Default threshold for categories not specified in category_name_to_threshold
110
114
  self.threshold = None
111
115
 
116
+ #: Dict mapping category names to thresholds; for example, an image with only a detection of class
117
+ #: "animal" whose confidence is greater than or equal to category_name_to_threshold['animal']
118
+ #: will be put in the "animal" folder.
112
119
  self.category_name_to_threshold = {
113
120
  'animal': self.threshold,
114
121
  'person': self.threshold,
115
122
  'vehicle': self.threshold
116
123
  }
117
124
 
125
+ #: Number of workers to use, set to <= 1 to disable parallelization
118
126
  self.n_threads = 1
119
127
 
128
+ #: By default, this function errors if you try to output to an existing folder
120
129
  self.allow_existing_directory = False
130
+
131
+ #: By default, this function errors if any of the images specified in the results file don't
132
+ #: exist in the source folder.
121
133
  self.allow_missing_files = False
134
+
135
+ #: Whether to overwrite images that already exist in the target folder; only relevant if
136
+ #: [allow_existing_directory] is True
122
137
  self.overwrite = True
138
+
139
+ #: Whether to skip empty images; if this is False, empty images (i.e., images with no detections
140
+ #: above the corresponding threshold) will be copied to an "empty" folder.
123
141
  self.skip_empty_images = False
124
142
 
143
+ #: The MD results .json file to process
125
144
  self.results_file = None
145
+
146
+ #: The folder containing source images; filenames in [results_file] should be relative to this
147
+ #: folder.
126
148
  self.base_input_folder = None
149
+
150
+ #: The folder to which we should write output images; see the module header comment for information
151
+ #: about how that folder will be structured.
127
152
  self.base_output_folder = None
128
153
 
129
- # Dictionary mapping categories (plus combinations of categories, and 'empty') to output folders
130
- self.category_name_to_folder = None
131
- self.category_id_to_category_name = None
132
- self.debug_max_images = None
154
+ #: Should we move rather than copy?
155
+ self.move_images = False
133
156
 
134
- # Populated only when using classification results
135
- self.classification_category_id_to_name = None
136
- self.classification_categories = None
137
-
157
+ #: Should we render boxes on the output images? Makes everything a lot slower.
138
158
  self.render_boxes = False
159
+
160
+ #: Line thickness in pixels; only relevant if [render_boxes] is True
139
161
  self.line_thickness = default_line_thickness
140
- self.box_expansion = default_box_expansion
141
162
 
142
- # Should we move rather than copy?
143
- self.move_images = False
163
+ #: Box expansion in pixels; only relevant if [render_boxes] is True
164
+ self.box_expansion = default_box_expansion
144
165
 
145
- # Originally specified as a string, converted to a dict mapping name:threshold
166
+ #: Originally specified as a string that looks like this:
167
+ #:
168
+ #: deer=0.75,cow=0.75
169
+ #:
170
+ #: Converted internally to a dict mapping name:threshold
146
171
  self.classification_thresholds = None
147
172
 
173
+ ## Debug or internal attributes
174
+
175
+ #: Do not set explicitly; populated from data when using classification results
176
+ self.classification_category_id_to_name = None
177
+
178
+ #: Do not set explicitly; populated from data when using classification results
179
+ self.classification_categories = None
180
+
181
+ #: Used to test this script; sets a limit on the number of images to process.
182
+ self.debug_max_images = None
183
+
184
+ #: Do not set explicitly; this gets created based on [results_file]
185
+ #:
186
+ #:Dictionary mapping categories (plus combinations of categories, and 'empty') to output folders
187
+ self.category_name_to_folder = None
188
+
189
+ #: Do not set explicitly; this gets loaded from [results_file]
190
+ self.category_id_to_category_name = None
191
+
148
192
  # ...__init__()
149
193
 
150
194
  # ...class SeparateDetectionsIntoFoldersOptions
@@ -152,21 +196,11 @@ class SeparateDetectionsIntoFoldersOptions:
152
196
 
153
197
  #%% Support functions
154
198
 
155
- def path_is_abs(p): return (len(p) > 1) and (p[0] == '/' or p[1] == ':')
156
-
157
- def is_float(v):
158
- """
159
- Determines whether v is either a float or a string representation of a float.
160
- """
161
- try:
162
- _ = float(v)
163
- return True
164
- except ValueError:
165
- return False
199
+ def _path_is_abs(p): return (len(p) > 1) and (p[0] == '/' or p[1] == ':')
166
200
 
167
201
  printed_missing_file_warning = False
168
202
 
169
- def process_detections(im,options):
203
+ def _process_detections(im,options):
170
204
  """
171
205
  Process all detections for a single image
172
206
 
@@ -393,13 +427,24 @@ def process_detections(im,options):
393
427
 
394
428
  # ...if we don't/do need to render boxes
395
429
 
396
- # ...def process_detections()
430
+ # ...def _process_detections()
397
431
 
398
432
 
399
433
  #%% Main function
400
434
 
401
435
  def separate_detections_into_folders(options):
402
-
436
+ """
437
+ Given a .json file with batch processing results, separate the files in that
438
+ set of results into folders that contain animals/people/vehicles/nothing,
439
+ according to per-class thresholds. See the header comment of this module for
440
+ more details about the output folder structure.
441
+
442
+ Args:
443
+ options (SeparateDetectionsIntoFoldersOptions): parameters guiding image
444
+ separation, see the SeparateDetectionsIntoFoldersOptions documentation for specific
445
+ options.
446
+ """
447
+
403
448
  # Input validation
404
449
 
405
450
  # Currently we don't support moving (instead of copying) when we're also rendering
@@ -424,7 +469,7 @@ def separate_detections_into_folders(options):
424
469
 
425
470
  for im in images:
426
471
  fn = im['file']
427
- assert not path_is_abs(fn), 'Cannot process results with absolute image paths'
472
+ assert not _path_is_abs(fn), 'Cannot process results with absolute image paths'
428
473
 
429
474
  print('Processing detections for {} images'.format(len(images)))
430
475
 
@@ -532,15 +577,15 @@ def separate_detections_into_folders(options):
532
577
  for i_image,im in enumerate(tqdm(images)):
533
578
  if options.debug_max_images is not None and i_image > options.debug_max_images:
534
579
  break
535
- process_detections(im,options)
580
+ _process_detections(im,options)
536
581
  # ...for each image
537
582
 
538
583
  else:
539
584
 
540
585
  print('Starting a pool with {} threads'.format(options.n_threads))
541
586
  pool = ThreadPool(options.n_threads)
542
- process_detections_with_options = partial(process_detections, options=options)
543
- results = list(tqdm(pool.imap(process_detections_with_options, images), total=len(images)))
587
+ process_detections_with_options = partial(_process_detections, options=options)
588
+ _ = list(tqdm(pool.imap(process_detections_with_options, images), total=len(images)))
544
589
 
545
590
  # ...def separate_detections_into_folders
546
591
 
@@ -595,7 +640,7 @@ if False:
595
640
  python separate_detections_into_folders.py ~/data/ena24-2022-06-15-v5a.0.0_megaclassifier.json ~/data/ENA24/images ~/data/ENA24-separated --threshold 0.17 --animal_threshold 0.2 --n_threads 10 --allow_existing_directory --classification_thresholds "deer=0.75,cow=0.75,bird=0.75"
596
641
  """
597
642
 
598
- #%% Command-line driver
643
+ #%% Command-line driver
599
644
 
600
645
  def main():
601
646
 
@@ -620,27 +665,29 @@ def main():
620
665
 
621
666
  parser.add_argument('--n_threads', type=int, default=1,
622
667
  help='Number of threads to use for parallel operation (default=1)')
668
+
623
669
  parser.add_argument('--allow_existing_directory', action='store_true',
624
670
  help='Proceed even if the target directory exists and is not empty')
625
671
  parser.add_argument('--no_overwrite', action='store_true',
626
672
  help='Skip images that already exist in the target folder, must also ' + \
627
673
  'specify --allow_existing_directory')
628
674
  parser.add_argument('--skip_empty_images', action='store_true',
629
- help='Don\'t copy empty images to the output folder')
675
+ help='Do not copy empty images to the output folder')
630
676
  parser.add_argument('--move_images', action='store_true',
631
- help='Move images (rather than coping) (we don\'t recommend this if you haven\'t ' + \
677
+ help='Move images (rather than copying) (not recommended this if you have not ' + \
632
678
  'backed up your data!)')
679
+
633
680
  parser.add_argument('--render_boxes', action='store_true',
634
681
  help='Render bounding boxes on output images; may result in some ' + \
635
682
  'metadata not being transferred')
636
683
  parser.add_argument('--line_thickness', type=int, default=default_line_thickness,
637
684
  help='Line thickness (in pixels) for rendering, only meaningful if ' + \
638
685
  'using render_boxes (defaults to {})'.format(
639
- default_line_thickness))
686
+ default_line_thickness))
640
687
  parser.add_argument('--box_expansion', type=int, default=default_line_thickness,
641
688
  help='Box expansion (in pixels) for rendering, only meaningful if ' + \
642
- 'using render_boxes (defaults to {})'.format(
643
- default_box_expansion))
689
+ 'using render_boxes (defaults to {})'.format(
690
+ default_box_expansion))
644
691
 
645
692
  if len(sys.argv[1:])==0:
646
693
  parser.print_help()
@@ -680,7 +727,5 @@ def main():
680
727
 
681
728
  separate_detections_into_folders(options)
682
729
 
683
- if __name__ == '__main__':
684
-
730
+ if __name__ == '__main__':
685
731
  main()
686
-