megadetector 5.0.27__py3-none-any.whl → 5.0.29__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 (176) hide show
  1. megadetector/api/batch_processing/api_core/batch_service/score.py +4 -5
  2. megadetector/api/batch_processing/api_core_support/aggregate_results_manually.py +1 -1
  3. megadetector/api/batch_processing/api_support/summarize_daily_activity.py +1 -1
  4. megadetector/api/batch_processing/integration/digiKam/xmp_integration.py +2 -2
  5. megadetector/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +1 -1
  6. megadetector/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +1 -1
  7. megadetector/api/synchronous/api_core/tests/load_test.py +2 -3
  8. megadetector/classification/aggregate_classifier_probs.py +3 -3
  9. megadetector/classification/analyze_failed_images.py +5 -5
  10. megadetector/classification/cache_batchapi_outputs.py +5 -5
  11. megadetector/classification/create_classification_dataset.py +11 -12
  12. megadetector/classification/crop_detections.py +10 -10
  13. megadetector/classification/csv_to_json.py +8 -8
  14. megadetector/classification/detect_and_crop.py +13 -15
  15. megadetector/classification/evaluate_model.py +7 -7
  16. megadetector/classification/identify_mislabeled_candidates.py +6 -6
  17. megadetector/classification/json_to_azcopy_list.py +1 -1
  18. megadetector/classification/json_validator.py +29 -32
  19. megadetector/classification/map_classification_categories.py +9 -9
  20. megadetector/classification/merge_classification_detection_output.py +12 -9
  21. megadetector/classification/prepare_classification_script.py +19 -19
  22. megadetector/classification/prepare_classification_script_mc.py +23 -23
  23. megadetector/classification/run_classifier.py +4 -4
  24. megadetector/classification/save_mislabeled.py +6 -6
  25. megadetector/classification/train_classifier.py +1 -1
  26. megadetector/classification/train_classifier_tf.py +9 -9
  27. megadetector/classification/train_utils.py +10 -10
  28. megadetector/data_management/annotations/annotation_constants.py +1 -1
  29. megadetector/data_management/camtrap_dp_to_coco.py +45 -45
  30. megadetector/data_management/cct_json_utils.py +101 -101
  31. megadetector/data_management/cct_to_md.py +49 -49
  32. megadetector/data_management/cct_to_wi.py +33 -33
  33. megadetector/data_management/coco_to_labelme.py +75 -75
  34. megadetector/data_management/coco_to_yolo.py +189 -189
  35. megadetector/data_management/databases/add_width_and_height_to_db.py +3 -2
  36. megadetector/data_management/databases/combine_coco_camera_traps_files.py +38 -38
  37. megadetector/data_management/databases/integrity_check_json_db.py +202 -188
  38. megadetector/data_management/databases/subset_json_db.py +33 -33
  39. megadetector/data_management/generate_crops_from_cct.py +38 -38
  40. megadetector/data_management/get_image_sizes.py +54 -49
  41. megadetector/data_management/labelme_to_coco.py +130 -124
  42. megadetector/data_management/labelme_to_yolo.py +78 -72
  43. megadetector/data_management/lila/create_lila_blank_set.py +81 -83
  44. megadetector/data_management/lila/create_lila_test_set.py +32 -31
  45. megadetector/data_management/lila/create_links_to_md_results_files.py +18 -18
  46. megadetector/data_management/lila/download_lila_subset.py +21 -24
  47. megadetector/data_management/lila/generate_lila_per_image_labels.py +91 -91
  48. megadetector/data_management/lila/get_lila_annotation_counts.py +30 -30
  49. megadetector/data_management/lila/get_lila_image_counts.py +22 -22
  50. megadetector/data_management/lila/lila_common.py +70 -70
  51. megadetector/data_management/lila/test_lila_metadata_urls.py +13 -14
  52. megadetector/data_management/mewc_to_md.py +339 -340
  53. megadetector/data_management/ocr_tools.py +258 -252
  54. megadetector/data_management/read_exif.py +232 -223
  55. megadetector/data_management/remap_coco_categories.py +26 -26
  56. megadetector/data_management/remove_exif.py +31 -20
  57. megadetector/data_management/rename_images.py +187 -187
  58. megadetector/data_management/resize_coco_dataset.py +41 -41
  59. megadetector/data_management/speciesnet_to_md.py +41 -41
  60. megadetector/data_management/wi_download_csv_to_coco.py +55 -55
  61. megadetector/data_management/yolo_output_to_md_output.py +117 -120
  62. megadetector/data_management/yolo_to_coco.py +195 -188
  63. megadetector/detection/change_detection.py +831 -0
  64. megadetector/detection/process_video.py +341 -338
  65. megadetector/detection/pytorch_detector.py +308 -266
  66. megadetector/detection/run_detector.py +186 -166
  67. megadetector/detection/run_detector_batch.py +366 -364
  68. megadetector/detection/run_inference_with_yolov5_val.py +328 -325
  69. megadetector/detection/run_tiled_inference.py +312 -253
  70. megadetector/detection/tf_detector.py +24 -24
  71. megadetector/detection/video_utils.py +291 -283
  72. megadetector/postprocessing/add_max_conf.py +15 -11
  73. megadetector/postprocessing/categorize_detections_by_size.py +44 -44
  74. megadetector/postprocessing/classification_postprocessing.py +808 -311
  75. megadetector/postprocessing/combine_batch_outputs.py +20 -21
  76. megadetector/postprocessing/compare_batch_results.py +528 -517
  77. megadetector/postprocessing/convert_output_format.py +97 -97
  78. megadetector/postprocessing/create_crop_folder.py +220 -147
  79. megadetector/postprocessing/detector_calibration.py +173 -168
  80. megadetector/postprocessing/generate_csv_report.py +508 -0
  81. megadetector/postprocessing/load_api_results.py +25 -22
  82. megadetector/postprocessing/md_to_coco.py +129 -98
  83. megadetector/postprocessing/md_to_labelme.py +89 -83
  84. megadetector/postprocessing/md_to_wi.py +40 -40
  85. megadetector/postprocessing/merge_detections.py +87 -114
  86. megadetector/postprocessing/postprocess_batch_results.py +319 -302
  87. megadetector/postprocessing/remap_detection_categories.py +36 -36
  88. megadetector/postprocessing/render_detection_confusion_matrix.py +205 -199
  89. megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py +57 -57
  90. megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +27 -28
  91. megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +702 -677
  92. megadetector/postprocessing/separate_detections_into_folders.py +226 -211
  93. megadetector/postprocessing/subset_json_detector_output.py +265 -262
  94. megadetector/postprocessing/top_folders_to_bottom.py +45 -45
  95. megadetector/postprocessing/validate_batch_results.py +70 -70
  96. megadetector/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +52 -52
  97. megadetector/taxonomy_mapping/map_new_lila_datasets.py +15 -15
  98. megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +14 -14
  99. megadetector/taxonomy_mapping/preview_lila_taxonomy.py +66 -69
  100. megadetector/taxonomy_mapping/retrieve_sample_image.py +16 -16
  101. megadetector/taxonomy_mapping/simple_image_download.py +8 -8
  102. megadetector/taxonomy_mapping/species_lookup.py +33 -33
  103. megadetector/taxonomy_mapping/taxonomy_csv_checker.py +14 -14
  104. megadetector/taxonomy_mapping/taxonomy_graph.py +11 -11
  105. megadetector/taxonomy_mapping/validate_lila_category_mappings.py +13 -13
  106. megadetector/utils/azure_utils.py +22 -22
  107. megadetector/utils/ct_utils.py +1019 -200
  108. megadetector/utils/directory_listing.py +21 -77
  109. megadetector/utils/gpu_test.py +22 -22
  110. megadetector/utils/md_tests.py +541 -518
  111. megadetector/utils/path_utils.py +1511 -406
  112. megadetector/utils/process_utils.py +41 -41
  113. megadetector/utils/sas_blob_utils.py +53 -49
  114. megadetector/utils/split_locations_into_train_val.py +73 -60
  115. megadetector/utils/string_utils.py +147 -26
  116. megadetector/utils/url_utils.py +463 -173
  117. megadetector/utils/wi_utils.py +2629 -2868
  118. megadetector/utils/write_html_image_list.py +137 -137
  119. megadetector/visualization/plot_utils.py +21 -21
  120. megadetector/visualization/render_images_with_thumbnails.py +37 -73
  121. megadetector/visualization/visualization_utils.py +424 -404
  122. megadetector/visualization/visualize_db.py +197 -190
  123. megadetector/visualization/visualize_detector_output.py +126 -98
  124. {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/METADATA +6 -3
  125. megadetector-5.0.29.dist-info/RECORD +163 -0
  126. {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/WHEEL +1 -1
  127. megadetector/data_management/importers/add_nacti_sizes.py +0 -52
  128. megadetector/data_management/importers/add_timestamps_to_icct.py +0 -79
  129. megadetector/data_management/importers/animl_results_to_md_results.py +0 -158
  130. megadetector/data_management/importers/auckland_doc_test_to_json.py +0 -373
  131. megadetector/data_management/importers/auckland_doc_to_json.py +0 -201
  132. megadetector/data_management/importers/awc_to_json.py +0 -191
  133. megadetector/data_management/importers/bellevue_to_json.py +0 -272
  134. megadetector/data_management/importers/cacophony-thermal-importer.py +0 -793
  135. megadetector/data_management/importers/carrizo_shrubfree_2018.py +0 -269
  136. megadetector/data_management/importers/carrizo_trail_cam_2017.py +0 -289
  137. megadetector/data_management/importers/cct_field_adjustments.py +0 -58
  138. megadetector/data_management/importers/channel_islands_to_cct.py +0 -913
  139. megadetector/data_management/importers/eMammal/copy_and_unzip_emammal.py +0 -180
  140. megadetector/data_management/importers/eMammal/eMammal_helpers.py +0 -249
  141. megadetector/data_management/importers/eMammal/make_eMammal_json.py +0 -223
  142. megadetector/data_management/importers/ena24_to_json.py +0 -276
  143. megadetector/data_management/importers/filenames_to_json.py +0 -386
  144. megadetector/data_management/importers/helena_to_cct.py +0 -283
  145. megadetector/data_management/importers/idaho-camera-traps.py +0 -1407
  146. megadetector/data_management/importers/idfg_iwildcam_lila_prep.py +0 -294
  147. megadetector/data_management/importers/import_desert_lion_conservation_camera_traps.py +0 -387
  148. megadetector/data_management/importers/jb_csv_to_json.py +0 -150
  149. megadetector/data_management/importers/mcgill_to_json.py +0 -250
  150. megadetector/data_management/importers/missouri_to_json.py +0 -490
  151. megadetector/data_management/importers/nacti_fieldname_adjustments.py +0 -79
  152. megadetector/data_management/importers/noaa_seals_2019.py +0 -181
  153. megadetector/data_management/importers/osu-small-animals-to-json.py +0 -364
  154. megadetector/data_management/importers/pc_to_json.py +0 -365
  155. megadetector/data_management/importers/plot_wni_giraffes.py +0 -123
  156. megadetector/data_management/importers/prepare_zsl_imerit.py +0 -131
  157. megadetector/data_management/importers/raic_csv_to_md_results.py +0 -416
  158. megadetector/data_management/importers/rspb_to_json.py +0 -356
  159. megadetector/data_management/importers/save_the_elephants_survey_A.py +0 -320
  160. megadetector/data_management/importers/save_the_elephants_survey_B.py +0 -329
  161. megadetector/data_management/importers/snapshot_safari_importer.py +0 -758
  162. megadetector/data_management/importers/snapshot_serengeti_lila.py +0 -1067
  163. megadetector/data_management/importers/snapshotserengeti/make_full_SS_json.py +0 -150
  164. megadetector/data_management/importers/snapshotserengeti/make_per_season_SS_json.py +0 -153
  165. megadetector/data_management/importers/sulross_get_exif.py +0 -65
  166. megadetector/data_management/importers/timelapse_csv_set_to_json.py +0 -490
  167. megadetector/data_management/importers/ubc_to_json.py +0 -399
  168. megadetector/data_management/importers/umn_to_json.py +0 -507
  169. megadetector/data_management/importers/wellington_to_json.py +0 -263
  170. megadetector/data_management/importers/wi_to_json.py +0 -442
  171. megadetector/data_management/importers/zamba_results_to_md_results.py +0 -180
  172. megadetector/data_management/lila/add_locations_to_island_camera_traps.py +0 -101
  173. megadetector/data_management/lila/add_locations_to_nacti.py +0 -151
  174. megadetector-5.0.27.dist-info/RECORD +0 -208
  175. {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/licenses/LICENSE +0 -0
  176. {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/top_level.txt +0 -0
@@ -2,7 +2,7 @@
2
2
 
3
3
  merge_detections.py
4
4
 
5
- Merge high-confidence detections from one or more results files into another
5
+ Merge high-confidence detections from one or more results files into another
6
6
  file. Typically used to combine results from MDv5b and/or MDv4 into a "primary"
7
7
  results file from MDv5a.
8
8
 
@@ -28,39 +28,42 @@ from megadetector.utils.ct_utils import get_iou
28
28
  #%% Structs
29
29
 
30
30
  class MergeDetectionsOptions:
31
-
31
+ """
32
+ Class defining options for merge_detections().
33
+ """
34
+
32
35
  def __init__(self):
33
-
36
+
34
37
  #: Maximum detection size to include in the merged output
35
38
  self.max_detection_size = 1.01
36
-
39
+
37
40
  #: Minimum detection size to include in the merged output
38
41
  self.min_detection_size = 0
39
-
42
+
40
43
  #: Exclude detections whose confidence in the source file(s) is less
41
44
  #: than this. Should have the same length as the number of source files.
42
45
  self.source_confidence_thresholds = [0.05]
43
-
46
+
44
47
  #: Don't bother merging into target images if there is a similar detection
45
48
  #: above this threshold (or if there is *any* detection above this threshold,
46
49
  #: and merge_empty_only is True)
47
50
  self.target_confidence_threshold = 0.2
48
-
51
+
49
52
  #: If you want to merge only certain categories, specify one
50
53
  #: (but not both) of these. These are category IDs, not names.
51
54
  self.categories_to_include = None
52
-
55
+
53
56
  #: If you want to merge only certain categories, specify one
54
57
  #: (but not both) of these. These are category IDs, not names.
55
58
  self.categories_to_exclude = None
56
59
 
57
- #: Only merge detections into images that have *no* detections in the
60
+ #: Only merge detections into images that have *no* detections in the
58
61
  #: target results file.
59
62
  self.merge_empty_only = False
60
-
63
+
61
64
  #: IoU threshold above which two detections are considered the same
62
65
  self.iou_threshold = 0.65
63
-
66
+
64
67
  #: Error if this is False and the output file exists
65
68
  self.overwrite = False
66
69
 
@@ -69,76 +72,76 @@ class MergeDetectionsOptions:
69
72
 
70
73
  def merge_detections(source_files,target_file,output_file,options=None):
71
74
  """
72
- Merge high-confidence detections from one or more results files into another
75
+ Merge high-confidence detections from one or more results files into another
73
76
  file. Typically used to combine results from MDv5b and/or MDv4 into a "primary"
74
77
  results file from MDv5a.
75
-
76
- [source_files] (a list of files or a single filename) specifies the set of
77
- results files that will be merged into [target_file]. The difference between a
78
+
79
+ [source_files] (a list of files or a single filename) specifies the set of
80
+ results files that will be merged into [target_file]. The difference between a
78
81
  "source file" and the "target file" is that if no merging is necessary, either because
79
82
  two boxes are nearly identical or because merge_only_empty is True and the target
80
83
  file already has above-threshold detection for an image+category, the output file gets
81
84
  the results of the "target" file. I.e., the "target" file wins all ties.
82
-
85
+
83
86
  The results are written to [output_file].
84
87
 
85
88
  """
86
-
89
+
87
90
  if isinstance(source_files,str):
88
- source_files = [source_files]
89
-
91
+ source_files = [source_files]
92
+
90
93
  if options is None:
91
- options = MergeDetectionsOptions()
92
-
94
+ options = MergeDetectionsOptions()
95
+
93
96
  if (not options.overwrite) and (os.path.isfile(output_file)):
94
97
  print('File {} exists, bypassing merge'.format(output_file))
95
98
  return
96
-
99
+
97
100
  assert not ((options.categories_to_exclude is not None) and \
98
101
  (options.categories_to_include is not None)), \
99
102
  'categories_to_include and categories_to_exclude are mutually exclusive'
100
-
103
+
101
104
  if options.categories_to_exclude is not None:
102
105
  options.categories_to_exclude = [int(c) for c in options.categories_to_exclude]
103
-
106
+
104
107
  if options.categories_to_include is not None:
105
108
  options.categories_to_include = [int(c) for c in options.categories_to_include]
106
-
109
+
107
110
  assert len(source_files) == len(options.source_confidence_thresholds), \
108
111
  '{} source files provided, but {} source confidence thresholds provided'.format(
109
112
  len(source_files),len(options.source_confidence_thresholds))
110
-
113
+
111
114
  for fn in source_files:
112
115
  assert os.path.isfile(fn), 'Could not find source file {}'.format(fn)
113
-
116
+
114
117
  assert os.path.isfile(target_file)
115
-
118
+
116
119
  os.makedirs(os.path.dirname(output_file),exist_ok=True)
117
-
120
+
118
121
  with open(target_file,'r') as f:
119
122
  output_data = json.load(f)
120
123
 
121
124
  print('Loaded results for {} images'.format(len(output_data['images'])))
122
-
125
+
123
126
  fn_to_image = {}
124
-
127
+
125
128
  # im = output_data['images'][0]
126
129
  for im in output_data['images']:
127
130
  fn_to_image[im['file']] = im
128
-
131
+
129
132
  if 'detections_transferred_from' not in output_data['info']:
130
133
  output_data['info']['detections_transferred_from'] = []
131
134
 
132
135
  if 'detector' not in output_data['info']:
133
136
  output_data['info']['detector'] = 'MDv4 (assumed)'
134
-
137
+
135
138
  detection_categories_raw = output_data['detection_categories'].keys()
136
-
139
+
137
140
  # Determine whether we should be processing all categories, or just a subset
138
141
  # of categories.
139
142
  detection_categories = []
140
143
 
141
- if options.categories_to_exclude is not None:
144
+ if options.categories_to_exclude is not None:
142
145
  for c in detection_categories_raw:
143
146
  if int(c) not in options.categories_to_exclude:
144
147
  detection_categories.append(c)
@@ -151,148 +154,148 @@ def merge_detections(source_files,target_file,output_file,options=None):
151
154
  detection_categories.append(c)
152
155
  else:
153
156
  detection_categories = detection_categories_raw
154
-
157
+
155
158
  # i_source_file = 0; source_file = source_files[i_source_file]
156
159
  for i_source_file,source_file in enumerate(source_files):
157
-
160
+
158
161
  print('Processing detections from file {}'.format(source_file))
159
-
162
+
160
163
  with open(source_file,'r') as f:
161
164
  source_data = json.load(f)
162
-
165
+
163
166
  if 'detector' in source_data['info']:
164
167
  source_detector_name = source_data['info']['detector']
165
168
  else:
166
169
  source_detector_name = os.path.basename(source_file)
167
-
170
+
168
171
  output_data['info']['detections_transferred_from'].append(os.path.basename(source_file))
169
172
  output_data['info']['detector'] = output_data['info']['detector'] + ' + ' + source_detector_name
170
-
173
+
171
174
  assert source_data['detection_categories'] == output_data['detection_categories'], \
172
175
  'Cannot merge files with different detection category maps'
173
-
176
+
174
177
  source_confidence_threshold = options.source_confidence_thresholds[i_source_file]
175
-
178
+
176
179
  # source_im = source_data['images'][0]
177
180
  for source_im in tqdm(source_data['images']):
178
-
179
- image_filename = source_im['file']
180
-
181
+
182
+ image_filename = source_im['file']
183
+
181
184
  assert image_filename in fn_to_image, 'Image {} not in target image set'.format(image_filename)
182
185
  target_im = fn_to_image[image_filename]
183
-
186
+
184
187
  if 'detections' not in source_im or source_im['detections'] is None:
185
188
  continue
186
-
189
+
187
190
  if 'detections' not in target_im or target_im['detections'] is None:
188
191
  continue
189
-
192
+
190
193
  source_detections_this_image = source_im['detections']
191
194
  target_detections_this_image = target_im['detections']
192
-
195
+
193
196
  detections_to_transfer = []
194
-
197
+
195
198
  # detection_category = list(detection_categories)[0]
196
199
  for detection_category in detection_categories:
197
-
200
+
198
201
  target_detections_this_category = \
199
202
  [det for det in target_detections_this_image if det['category'] == \
200
203
  detection_category]
201
-
204
+
202
205
  max_target_confidence_this_category = 0.0
203
-
206
+
204
207
  if len(target_detections_this_category) > 0:
205
208
  max_target_confidence_this_category = max([det['conf'] for \
206
209
  det in target_detections_this_category])
207
-
210
+
208
211
  # If we have a valid detection in the target file, and we're only merging
209
212
  # into images that have no detections at all, we don't need to review the individual
210
213
  # detections in the source file.
211
214
  if options.merge_empty_only and \
212
215
  (max_target_confidence_this_category >= options.target_confidence_threshold):
213
216
  continue
214
-
217
+
215
218
  source_detections_this_category_raw = [det for det in \
216
219
  source_detections_this_image if det['category'] == detection_category]
217
-
220
+
218
221
  # Boxes are x/y/w/h
219
222
  # source_sizes = [det['bbox'][2]*det['bbox'][3] for det in source_detections_this_category_raw]
220
-
223
+
221
224
  # Only look at source boxes within the size range
222
225
  source_detections_this_category_filtered = [
223
226
  det for det in source_detections_this_category_raw if \
224
227
  (det['bbox'][2]*det['bbox'][3] <= options.max_detection_size) and \
225
228
  (det['bbox'][2]*det['bbox'][3] >= options.min_detection_size) \
226
229
  ]
227
-
230
+
228
231
  # det = source_detections_this_category_filtered[0]
229
232
  for det in source_detections_this_category_filtered:
230
-
233
+
231
234
  if det['conf'] >= source_confidence_threshold:
232
235
 
233
236
  # Check only whole images
234
237
  if options.merge_empty_only:
235
-
238
+
236
239
  # We verified this above, asserting here for clarity
237
240
  assert max_target_confidence_this_category < options.target_confidence_threshold
238
241
  det['transferred_from'] = source_detector_name
239
242
  detections_to_transfer.append(det)
240
243
 
241
- # Check individual detections
244
+ # Check individual detections
242
245
  else:
243
-
246
+
244
247
  # Does this source detection match any existing above-threshold
245
248
  # target category detections?
246
249
  matches_existing_box = False
247
-
250
+
248
251
  # target_detection = target_detections_this_category[0]
249
252
  for target_detection in target_detections_this_category:
250
-
253
+
251
254
  if (target_detection['conf'] >= options.target_confidence_threshold) \
252
255
  and \
253
256
  (get_iou(det['bbox'],target_detection['bbox']) >= options.iou_threshold):
254
257
  matches_existing_box = True
255
258
  break
256
-
259
+
257
260
  if (not matches_existing_box):
258
261
  det['transferred_from'] = source_detector_name
259
262
  detections_to_transfer.append(det)
260
-
263
+
261
264
  # ...if this source detection is above the confidence threshold
262
-
263
- # ...for each source detection within category
264
-
265
+
266
+ # ...for each source detection within category
267
+
265
268
  # ...for each detection category
266
-
269
+
267
270
  if len(detections_to_transfer) > 0:
268
-
271
+
269
272
  # print('Adding {} detections to image {}'.format(len(detections_to_transfer),image_filename))
270
- detections = fn_to_image[image_filename]['detections']
273
+ detections = fn_to_image[image_filename]['detections']
271
274
  detections.extend(detections_to_transfer)
272
275
 
273
276
  # Update the max_detection_conf field (if present)
274
277
  if 'max_detection_conf' in fn_to_image[image_filename]:
275
278
  fn_to_image[image_filename]['max_detection_conf'] = \
276
279
  max([d['conf'] for d in detections])
277
-
280
+
278
281
  # ...if we have any detections to transfer
279
-
282
+
280
283
  # ...for each image
281
-
282
- # ...for each source file
283
-
284
+
285
+ # ...for each source file
286
+
284
287
  with open(output_file,'w') as f:
285
288
  json.dump(output_data,f,indent=1)
286
-
289
+
287
290
  print('Saved merged results to {}'.format(output_file))
288
291
 
289
292
 
290
293
  #%% Command-line driver
291
294
 
292
- def main():
293
-
295
+ def main(): # noqa
296
+
294
297
  default_options = MergeDetectionsOptions()
295
-
298
+
296
299
  parser = argparse.ArgumentParser(
297
300
  description='Merge detections from one or more MegaDetector results files into an existing reuslts file')
298
301
  parser.add_argument(
@@ -351,7 +354,7 @@ def main():
351
354
  '--merge_empty_only',
352
355
  action='store_true',
353
356
  help='Ignore individual detections and only merge images for which the target ' + \
354
- 'file contains no detections')
357
+ 'file contains no detections')
355
358
  parser.add_argument(
356
359
  '--iou_threshold',
357
360
  type=float,
@@ -374,39 +377,9 @@ def main():
374
377
  options.categories_to_exclude = args.categories_to_exclude
375
378
  options.merge_empty_only = args.merge_empty_only
376
379
  options.iou_threshold = args.iou_threshold
377
-
378
- merge_detections(args.source_files, args.target_file, args.output_file, options)
379
380
 
381
+ merge_detections(args.source_files, args.target_file, args.output_file, options)
380
382
 
381
- #%% Test driver
382
-
383
- if False:
384
-
385
- #%%
386
-
387
- options = MergeDetectionsOptions()
388
- options.max_detection_size = 0.1
389
- options.target_confidence_threshold = 0.3
390
- options.categories_to_include = [1]
391
- source_files = ['/home/user/postprocessing/iwildcam/iwildcam-mdv4-2022-05-01/combined_api_outputs/iwildcam-mdv4-2022-05-01_detections.json']
392
- options.source_confidence_thresholds = [0.8]
393
- target_file = '/home/user/postprocessing/iwildcam/iwildcam-mdv5-camcocoinat-2022-05-02/combined_api_outputs/iwildcam-mdv5-camcocoinat-2022-05-02_detections.json'
394
- output_file = '/home/user/postprocessing/iwildcam/merged-detections/mdv4_mdv5-camcocoinat-2022-05-02.json'
395
- merge_detections(source_files, target_file, output_file, options)
396
-
397
- options = MergeDetectionsOptions()
398
- options.max_detection_size = 0.1
399
- options.target_confidence_threshold = 0.3
400
- options.categories_to_include = [1]
401
- source_files = [
402
- '/home/user/postprocessing/iwildcam/iwildcam-mdv4-2022-05-01/combined_api_outputs/iwildcam-mdv4-2022-05-01_detections.json',
403
- '/home/user/postprocessing/iwildcam/iwildcam-mdv5-camonly-2022-05-02/combined_api_outputs/iwildcam-mdv5-camonly-2022-05-02_detections.json',
404
- ]
405
- options.source_confidence_thresholds = [0.8,0.5]
406
- target_file = '/home/user/postprocessing/iwildcam/iwildcam-mdv5-camcocoinat-2022-05-02/combined_api_outputs/iwildcam-mdv5-camcocoinat-2022-05-02_detections.json'
407
- output_file = '/home/user/postprocessing/iwildcam/merged-detections/mdv4_mdv5-camonly_mdv5-camcocoinat-2022-05-02.json'
408
- merge_detections(source_files, target_file, output_file, options)
409
-
410
383
  if __name__ == '__main__':
411
384
  main()
412
385