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