megadetector 5.0.10__py3-none-any.whl → 5.0.11__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 (226) hide show
  1. {megadetector-5.0.10.dist-info → megadetector-5.0.11.dist-info}/LICENSE +0 -0
  2. {megadetector-5.0.10.dist-info → megadetector-5.0.11.dist-info}/METADATA +12 -11
  3. megadetector-5.0.11.dist-info/RECORD +5 -0
  4. megadetector-5.0.11.dist-info/top_level.txt +1 -0
  5. api/__init__.py +0 -0
  6. api/batch_processing/__init__.py +0 -0
  7. api/batch_processing/api_core/__init__.py +0 -0
  8. api/batch_processing/api_core/batch_service/__init__.py +0 -0
  9. api/batch_processing/api_core/batch_service/score.py +0 -439
  10. api/batch_processing/api_core/server.py +0 -294
  11. api/batch_processing/api_core/server_api_config.py +0 -98
  12. api/batch_processing/api_core/server_app_config.py +0 -55
  13. api/batch_processing/api_core/server_batch_job_manager.py +0 -220
  14. api/batch_processing/api_core/server_job_status_table.py +0 -152
  15. api/batch_processing/api_core/server_orchestration.py +0 -360
  16. api/batch_processing/api_core/server_utils.py +0 -92
  17. api/batch_processing/api_core_support/__init__.py +0 -0
  18. api/batch_processing/api_core_support/aggregate_results_manually.py +0 -46
  19. api/batch_processing/api_support/__init__.py +0 -0
  20. api/batch_processing/api_support/summarize_daily_activity.py +0 -152
  21. api/batch_processing/data_preparation/__init__.py +0 -0
  22. api/batch_processing/data_preparation/manage_local_batch.py +0 -2391
  23. api/batch_processing/data_preparation/manage_video_batch.py +0 -327
  24. api/batch_processing/integration/digiKam/setup.py +0 -6
  25. api/batch_processing/integration/digiKam/xmp_integration.py +0 -465
  26. api/batch_processing/integration/eMammal/test_scripts/config_template.py +0 -5
  27. api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +0 -126
  28. api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +0 -55
  29. api/batch_processing/postprocessing/__init__.py +0 -0
  30. api/batch_processing/postprocessing/add_max_conf.py +0 -64
  31. api/batch_processing/postprocessing/categorize_detections_by_size.py +0 -163
  32. api/batch_processing/postprocessing/combine_api_outputs.py +0 -249
  33. api/batch_processing/postprocessing/compare_batch_results.py +0 -958
  34. api/batch_processing/postprocessing/convert_output_format.py +0 -397
  35. api/batch_processing/postprocessing/load_api_results.py +0 -195
  36. api/batch_processing/postprocessing/md_to_coco.py +0 -310
  37. api/batch_processing/postprocessing/md_to_labelme.py +0 -330
  38. api/batch_processing/postprocessing/merge_detections.py +0 -401
  39. api/batch_processing/postprocessing/postprocess_batch_results.py +0 -1904
  40. api/batch_processing/postprocessing/remap_detection_categories.py +0 -170
  41. api/batch_processing/postprocessing/render_detection_confusion_matrix.py +0 -661
  42. api/batch_processing/postprocessing/repeat_detection_elimination/find_repeat_detections.py +0 -211
  43. api/batch_processing/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +0 -82
  44. api/batch_processing/postprocessing/repeat_detection_elimination/repeat_detections_core.py +0 -1631
  45. api/batch_processing/postprocessing/separate_detections_into_folders.py +0 -731
  46. api/batch_processing/postprocessing/subset_json_detector_output.py +0 -696
  47. api/batch_processing/postprocessing/top_folders_to_bottom.py +0 -223
  48. api/synchronous/__init__.py +0 -0
  49. api/synchronous/api_core/animal_detection_api/__init__.py +0 -0
  50. api/synchronous/api_core/animal_detection_api/api_backend.py +0 -152
  51. api/synchronous/api_core/animal_detection_api/api_frontend.py +0 -266
  52. api/synchronous/api_core/animal_detection_api/config.py +0 -35
  53. api/synchronous/api_core/animal_detection_api/data_management/annotations/annotation_constants.py +0 -47
  54. api/synchronous/api_core/animal_detection_api/detection/detector_training/copy_checkpoints.py +0 -43
  55. api/synchronous/api_core/animal_detection_api/detection/detector_training/model_main_tf2.py +0 -114
  56. api/synchronous/api_core/animal_detection_api/detection/process_video.py +0 -543
  57. api/synchronous/api_core/animal_detection_api/detection/pytorch_detector.py +0 -304
  58. api/synchronous/api_core/animal_detection_api/detection/run_detector.py +0 -627
  59. api/synchronous/api_core/animal_detection_api/detection/run_detector_batch.py +0 -1029
  60. api/synchronous/api_core/animal_detection_api/detection/run_inference_with_yolov5_val.py +0 -581
  61. api/synchronous/api_core/animal_detection_api/detection/run_tiled_inference.py +0 -754
  62. api/synchronous/api_core/animal_detection_api/detection/tf_detector.py +0 -165
  63. api/synchronous/api_core/animal_detection_api/detection/video_utils.py +0 -495
  64. api/synchronous/api_core/animal_detection_api/md_utils/azure_utils.py +0 -174
  65. api/synchronous/api_core/animal_detection_api/md_utils/ct_utils.py +0 -262
  66. api/synchronous/api_core/animal_detection_api/md_utils/directory_listing.py +0 -251
  67. api/synchronous/api_core/animal_detection_api/md_utils/matlab_porting_tools.py +0 -97
  68. api/synchronous/api_core/animal_detection_api/md_utils/path_utils.py +0 -416
  69. api/synchronous/api_core/animal_detection_api/md_utils/process_utils.py +0 -110
  70. api/synchronous/api_core/animal_detection_api/md_utils/sas_blob_utils.py +0 -509
  71. api/synchronous/api_core/animal_detection_api/md_utils/string_utils.py +0 -59
  72. api/synchronous/api_core/animal_detection_api/md_utils/url_utils.py +0 -144
  73. api/synchronous/api_core/animal_detection_api/md_utils/write_html_image_list.py +0 -226
  74. api/synchronous/api_core/animal_detection_api/md_visualization/visualization_utils.py +0 -841
  75. api/synchronous/api_core/tests/__init__.py +0 -0
  76. api/synchronous/api_core/tests/load_test.py +0 -110
  77. classification/__init__.py +0 -0
  78. classification/aggregate_classifier_probs.py +0 -108
  79. classification/analyze_failed_images.py +0 -227
  80. classification/cache_batchapi_outputs.py +0 -198
  81. classification/create_classification_dataset.py +0 -627
  82. classification/crop_detections.py +0 -516
  83. classification/csv_to_json.py +0 -226
  84. classification/detect_and_crop.py +0 -855
  85. classification/efficientnet/__init__.py +0 -9
  86. classification/efficientnet/model.py +0 -415
  87. classification/efficientnet/utils.py +0 -610
  88. classification/evaluate_model.py +0 -520
  89. classification/identify_mislabeled_candidates.py +0 -152
  90. classification/json_to_azcopy_list.py +0 -63
  91. classification/json_validator.py +0 -695
  92. classification/map_classification_categories.py +0 -276
  93. classification/merge_classification_detection_output.py +0 -506
  94. classification/prepare_classification_script.py +0 -194
  95. classification/prepare_classification_script_mc.py +0 -228
  96. classification/run_classifier.py +0 -286
  97. classification/save_mislabeled.py +0 -110
  98. classification/train_classifier.py +0 -825
  99. classification/train_classifier_tf.py +0 -724
  100. classification/train_utils.py +0 -322
  101. data_management/__init__.py +0 -0
  102. data_management/annotations/__init__.py +0 -0
  103. data_management/annotations/annotation_constants.py +0 -34
  104. data_management/camtrap_dp_to_coco.py +0 -238
  105. data_management/cct_json_utils.py +0 -395
  106. data_management/cct_to_md.py +0 -176
  107. data_management/cct_to_wi.py +0 -289
  108. data_management/coco_to_labelme.py +0 -272
  109. data_management/coco_to_yolo.py +0 -662
  110. data_management/databases/__init__.py +0 -0
  111. data_management/databases/add_width_and_height_to_db.py +0 -33
  112. data_management/databases/combine_coco_camera_traps_files.py +0 -206
  113. data_management/databases/integrity_check_json_db.py +0 -477
  114. data_management/databases/subset_json_db.py +0 -115
  115. data_management/generate_crops_from_cct.py +0 -149
  116. data_management/get_image_sizes.py +0 -188
  117. data_management/importers/add_nacti_sizes.py +0 -52
  118. data_management/importers/add_timestamps_to_icct.py +0 -79
  119. data_management/importers/animl_results_to_md_results.py +0 -158
  120. data_management/importers/auckland_doc_test_to_json.py +0 -372
  121. data_management/importers/auckland_doc_to_json.py +0 -200
  122. data_management/importers/awc_to_json.py +0 -189
  123. data_management/importers/bellevue_to_json.py +0 -273
  124. data_management/importers/cacophony-thermal-importer.py +0 -796
  125. data_management/importers/carrizo_shrubfree_2018.py +0 -268
  126. data_management/importers/carrizo_trail_cam_2017.py +0 -287
  127. data_management/importers/cct_field_adjustments.py +0 -57
  128. data_management/importers/channel_islands_to_cct.py +0 -913
  129. data_management/importers/eMammal/copy_and_unzip_emammal.py +0 -180
  130. data_management/importers/eMammal/eMammal_helpers.py +0 -249
  131. data_management/importers/eMammal/make_eMammal_json.py +0 -223
  132. data_management/importers/ena24_to_json.py +0 -275
  133. data_management/importers/filenames_to_json.py +0 -385
  134. data_management/importers/helena_to_cct.py +0 -282
  135. data_management/importers/idaho-camera-traps.py +0 -1407
  136. data_management/importers/idfg_iwildcam_lila_prep.py +0 -294
  137. data_management/importers/jb_csv_to_json.py +0 -150
  138. data_management/importers/mcgill_to_json.py +0 -250
  139. data_management/importers/missouri_to_json.py +0 -489
  140. data_management/importers/nacti_fieldname_adjustments.py +0 -79
  141. data_management/importers/noaa_seals_2019.py +0 -181
  142. data_management/importers/pc_to_json.py +0 -365
  143. data_management/importers/plot_wni_giraffes.py +0 -123
  144. data_management/importers/prepare-noaa-fish-data-for-lila.py +0 -359
  145. data_management/importers/prepare_zsl_imerit.py +0 -131
  146. data_management/importers/rspb_to_json.py +0 -356
  147. data_management/importers/save_the_elephants_survey_A.py +0 -320
  148. data_management/importers/save_the_elephants_survey_B.py +0 -332
  149. data_management/importers/snapshot_safari_importer.py +0 -758
  150. data_management/importers/snapshot_safari_importer_reprise.py +0 -665
  151. data_management/importers/snapshot_serengeti_lila.py +0 -1067
  152. data_management/importers/snapshotserengeti/make_full_SS_json.py +0 -150
  153. data_management/importers/snapshotserengeti/make_per_season_SS_json.py +0 -153
  154. data_management/importers/sulross_get_exif.py +0 -65
  155. data_management/importers/timelapse_csv_set_to_json.py +0 -490
  156. data_management/importers/ubc_to_json.py +0 -399
  157. data_management/importers/umn_to_json.py +0 -507
  158. data_management/importers/wellington_to_json.py +0 -263
  159. data_management/importers/wi_to_json.py +0 -441
  160. data_management/importers/zamba_results_to_md_results.py +0 -181
  161. data_management/labelme_to_coco.py +0 -548
  162. data_management/labelme_to_yolo.py +0 -272
  163. data_management/lila/__init__.py +0 -0
  164. data_management/lila/add_locations_to_island_camera_traps.py +0 -97
  165. data_management/lila/add_locations_to_nacti.py +0 -147
  166. data_management/lila/create_lila_blank_set.py +0 -557
  167. data_management/lila/create_lila_test_set.py +0 -151
  168. data_management/lila/create_links_to_md_results_files.py +0 -106
  169. data_management/lila/download_lila_subset.py +0 -177
  170. data_management/lila/generate_lila_per_image_labels.py +0 -515
  171. data_management/lila/get_lila_annotation_counts.py +0 -170
  172. data_management/lila/get_lila_image_counts.py +0 -111
  173. data_management/lila/lila_common.py +0 -300
  174. data_management/lila/test_lila_metadata_urls.py +0 -132
  175. data_management/ocr_tools.py +0 -874
  176. data_management/read_exif.py +0 -681
  177. data_management/remap_coco_categories.py +0 -84
  178. data_management/remove_exif.py +0 -66
  179. data_management/resize_coco_dataset.py +0 -189
  180. data_management/wi_download_csv_to_coco.py +0 -246
  181. data_management/yolo_output_to_md_output.py +0 -441
  182. data_management/yolo_to_coco.py +0 -676
  183. detection/__init__.py +0 -0
  184. detection/detector_training/__init__.py +0 -0
  185. detection/detector_training/model_main_tf2.py +0 -114
  186. detection/process_video.py +0 -703
  187. detection/pytorch_detector.py +0 -337
  188. detection/run_detector.py +0 -779
  189. detection/run_detector_batch.py +0 -1219
  190. detection/run_inference_with_yolov5_val.py +0 -917
  191. detection/run_tiled_inference.py +0 -935
  192. detection/tf_detector.py +0 -188
  193. detection/video_utils.py +0 -606
  194. docs/source/conf.py +0 -43
  195. md_utils/__init__.py +0 -0
  196. md_utils/azure_utils.py +0 -174
  197. md_utils/ct_utils.py +0 -612
  198. md_utils/directory_listing.py +0 -246
  199. md_utils/md_tests.py +0 -968
  200. md_utils/path_utils.py +0 -1044
  201. md_utils/process_utils.py +0 -157
  202. md_utils/sas_blob_utils.py +0 -509
  203. md_utils/split_locations_into_train_val.py +0 -228
  204. md_utils/string_utils.py +0 -92
  205. md_utils/url_utils.py +0 -323
  206. md_utils/write_html_image_list.py +0 -225
  207. md_visualization/__init__.py +0 -0
  208. md_visualization/plot_utils.py +0 -293
  209. md_visualization/render_images_with_thumbnails.py +0 -275
  210. md_visualization/visualization_utils.py +0 -1537
  211. md_visualization/visualize_db.py +0 -551
  212. md_visualization/visualize_detector_output.py +0 -406
  213. megadetector-5.0.10.dist-info/RECORD +0 -224
  214. megadetector-5.0.10.dist-info/top_level.txt +0 -8
  215. taxonomy_mapping/__init__.py +0 -0
  216. taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +0 -491
  217. taxonomy_mapping/map_new_lila_datasets.py +0 -154
  218. taxonomy_mapping/prepare_lila_taxonomy_release.py +0 -142
  219. taxonomy_mapping/preview_lila_taxonomy.py +0 -591
  220. taxonomy_mapping/retrieve_sample_image.py +0 -71
  221. taxonomy_mapping/simple_image_download.py +0 -218
  222. taxonomy_mapping/species_lookup.py +0 -834
  223. taxonomy_mapping/taxonomy_csv_checker.py +0 -159
  224. taxonomy_mapping/taxonomy_graph.py +0 -346
  225. taxonomy_mapping/validate_lila_category_mappings.py +0 -83
  226. {megadetector-5.0.10.dist-info → megadetector-5.0.11.dist-info}/WHEEL +0 -0
md_utils/ct_utils.py DELETED
@@ -1,612 +0,0 @@
1
- """
2
-
3
- ct_utils.py
4
-
5
- Numeric/geometry/array utility functions.
6
-
7
- """
8
-
9
- #%% Imports and constants
10
-
11
- import inspect
12
- import json
13
- import math
14
- import os
15
-
16
- import jsonpickle
17
- import numpy as np
18
-
19
- # List of file extensions we'll consider images; comparisons will be case-insensitive
20
- # (i.e., no need to include both .jpg and .JPG on this list).
21
- image_extensions = ['.jpg', '.jpeg', '.gif', '.png']
22
-
23
-
24
- #%% Functions
25
-
26
- def truncate_float_array(xs, precision=3):
27
- """
28
- Vectorized version of truncate_float(...), truncates the fractional portion of each
29
- floating-point value to a specific number of floating-point digits.
30
-
31
- Args:
32
- xs (list): list of floats to truncate
33
- precision (int, optional): the number of significant digits to preserve, should be >= 1
34
-
35
- Returns:
36
- list: list of truncated floats
37
- """
38
-
39
- return [truncate_float(x, precision=precision) for x in xs]
40
-
41
-
42
- def truncate_float(x, precision=3):
43
- """
44
- Truncates the fractional portion of a floating-point value to a specific number of
45
- floating-point digits.
46
-
47
- For example:
48
-
49
- truncate_float(0.0003214884) --> 0.000321
50
- truncate_float(1.0003214884) --> 1.000321
51
-
52
- This function is primarily used to achieve a certain float representation
53
- before exporting to JSON.
54
-
55
- Args:
56
- x (float): scalar to truncate
57
- precision (int, optional): the number of significant digits to preserve, should be >= 1
58
-
59
- Returns:
60
- float: truncated version of [x]
61
- """
62
-
63
- assert precision > 0
64
-
65
- if np.isclose(x, 0):
66
-
67
- return 0
68
-
69
- elif (x > 1):
70
-
71
- fractional_component = x - 1.0
72
- return 1 + truncate_float(fractional_component)
73
-
74
- else:
75
-
76
- # Determine the factor, which shifts the decimal point of x
77
- # just behind the last significant digit.
78
- factor = math.pow(10, precision - 1 - math.floor(math.log10(abs(x))))
79
-
80
- # Shift decimal point by multiplication with factor, flooring, and
81
- # division by factor.
82
- return math.floor(x * factor)/factor
83
-
84
-
85
- def args_to_object(args, obj):
86
- """
87
- Copies all fields from a Namespace (typically the output from parse_args) to an
88
- object. Skips fields starting with _. Does not check existence in the target
89
- object.
90
-
91
- Args:
92
- args (argparse.Namespace): the namespace to convert to an object
93
- obj (object): object whose whose attributes will be updated
94
-
95
- Returns:
96
- object: the modified object (modified in place, but also returned)
97
- """
98
-
99
- for n, v in inspect.getmembers(args):
100
- if not n.startswith('_'):
101
- setattr(obj, n, v)
102
-
103
- return obj
104
-
105
-
106
- def pretty_print_object(obj, b_print=True):
107
- """
108
- Converts an arbitrary object to .json, optionally printing the .json representation.
109
-
110
- Args:
111
- obj (object): object to print
112
- b_print (bool, optional): whether to print the object
113
-
114
- Returns:
115
- str: .json reprepresentation of [obj]
116
- """
117
-
118
- # _ = pretty_print_object(obj)
119
-
120
- # TODO: it's sloppy that I'm making a module-wide change here.
121
- jsonpickle.set_encoder_options('json', sort_keys=True, indent=2)
122
- a = jsonpickle.encode(obj)
123
- s = '{}'.format(a)
124
- if b_print:
125
- print(s)
126
- return s
127
-
128
-
129
- def is_list_sorted(L, reverse=False):
130
- """
131
- Returns True if the list L appears to be sorted, otherwise False.
132
-
133
- Calling is_list_sorted(L,reverse=True) is the same as calling
134
- is_list_sorted(L.reverse(),reverse=False).
135
-
136
- Args:
137
- L (list): list to evaluate
138
- reverse (bool, optional): whether to reverse the list before evaluating sort status
139
-
140
- Returns:
141
- bool: True if the list L appears to be sorted, otherwise False
142
- """
143
-
144
- if reverse:
145
- return all(L[i] >= L[i + 1] for i in range(len(L)-1))
146
- else:
147
- return all(L[i] <= L[i + 1] for i in range(len(L)-1))
148
-
149
-
150
- def write_json(path, content, indent=1):
151
- """
152
- Standardized wrapper for json.dump().
153
-
154
- Args:
155
- path (str): filename to write to
156
- content (object): object to dump
157
- indent (int, optional): indentation depth passed to json.dump
158
- """
159
-
160
- with open(path, 'w') as f:
161
- json.dump(content, f, indent=indent)
162
-
163
-
164
- def convert_yolo_to_xywh(yolo_box):
165
- """
166
- Converts a YOLO format bounding box to [x_min, y_min, width_of_box, height_of_box].
167
-
168
- Args:
169
- yolo_box (list): bounding box of format [x_center, y_center, width_of_box, height_of_box]
170
-
171
- Returns:
172
- list: bbox with coordinates represented as [x_min, y_min, width_of_box, height_of_box]
173
- """
174
-
175
- x_center, y_center, width_of_box, height_of_box = yolo_box
176
- x_min = x_center - width_of_box / 2.0
177
- y_min = y_center - height_of_box / 2.0
178
- return [x_min, y_min, width_of_box, height_of_box]
179
-
180
-
181
- def convert_xywh_to_tf(api_box):
182
- """
183
- Converts an xywh bounding box (the format used in MD output) to the [y_min, x_min, y_max, x_max]
184
- format that the TensorFlow Object Detection API uses.
185
-
186
- Args:
187
- api_box: bbox output by the batch processing API [x_min, y_min, width_of_box, height_of_box]
188
-
189
- Returns:
190
- list: bbox with coordinates represented as [y_min, x_min, y_max, x_max]
191
- """
192
-
193
- x_min, y_min, width_of_box, height_of_box = api_box
194
- x_max = x_min + width_of_box
195
- y_max = y_min + height_of_box
196
- return [y_min, x_min, y_max, x_max]
197
-
198
-
199
- def convert_xywh_to_xyxy(api_bbox):
200
- """
201
- Converts an xywh bounding box (the MD output format) to an xyxy bounding box.
202
-
203
- Args:
204
- api_bbox (list): bbox formatted as [x_min, y_min, width_of_box, height_of_box]
205
-
206
- Returns:
207
- list: bbox formatted as [x_min, y_min, x_max, y_max]
208
- """
209
-
210
- x_min, y_min, width_of_box, height_of_box = api_bbox
211
- x_max, y_max = x_min + width_of_box, y_min + height_of_box
212
- return [x_min, y_min, x_max, y_max]
213
-
214
-
215
- def get_iou(bb1, bb2):
216
- """
217
- Calculates the intersection over union (IoU) of two bounding boxes.
218
-
219
- Adapted from:
220
-
221
- https://stackoverflow.com/questions/25349178/calculating-percentage-of-bounding-box-overlap-for-image-detector-evaluation
222
-
223
- Args:
224
- bb1 (list): [x_min, y_min, width_of_box, height_of_box]
225
- bb2 (list): [x_min, y_min, width_of_box, height_of_box]
226
-
227
- Returns:
228
- float: intersection_over_union, a float in [0, 1]
229
- """
230
-
231
- bb1 = convert_xywh_to_xyxy(bb1)
232
- bb2 = convert_xywh_to_xyxy(bb2)
233
-
234
- assert bb1[0] < bb1[2], 'Malformed bounding box (x2 >= x1)'
235
- assert bb1[1] < bb1[3], 'Malformed bounding box (y2 >= y1)'
236
-
237
- assert bb2[0] < bb2[2], 'Malformed bounding box (x2 >= x1)'
238
- assert bb2[1] < bb2[3], 'Malformed bounding box (y2 >= y1)'
239
-
240
- # Determine the coordinates of the intersection rectangle
241
- x_left = max(bb1[0], bb2[0])
242
- y_top = max(bb1[1], bb2[1])
243
- x_right = min(bb1[2], bb2[2])
244
- y_bottom = min(bb1[3], bb2[3])
245
-
246
- if x_right < x_left or y_bottom < y_top:
247
- return 0.0
248
-
249
- # The intersection of two axis-aligned bounding boxes is always an
250
- # axis-aligned bounding box
251
- intersection_area = (x_right - x_left) * (y_bottom - y_top)
252
-
253
- # Compute the area of both AABBs
254
- bb1_area = (bb1[2] - bb1[0]) * (bb1[3] - bb1[1])
255
- bb2_area = (bb2[2] - bb2[0]) * (bb2[3] - bb2[1])
256
-
257
- # Compute the intersection over union by taking the intersection
258
- # area and dividing it by the sum of prediction + ground-truth
259
- # areas - the intersection area.
260
- iou = intersection_area / float(bb1_area + bb2_area - intersection_area)
261
- assert iou >= 0.0, 'Illegal IOU < 0'
262
- assert iou <= 1.0, 'Illegal IOU > 1'
263
- return iou
264
-
265
-
266
- def _get_max_conf_from_detections(detections):
267
- """
268
- Internal function used by get_max_conf(); don't call this directly.
269
- """
270
-
271
- max_conf = 0.0
272
- if detections is not None and len(detections) > 0:
273
- confidences = [det['conf'] for det in detections]
274
- max_conf = max(confidences)
275
- return max_conf
276
-
277
-
278
- def get_max_conf(im):
279
- """
280
- Given an image dict in the MD output format, computes the maximum detection confidence for any
281
- class. Returns 0.0 (rather than None) if there was a failure or 'detections' isn't present.
282
-
283
- Args:
284
- im (dict): image dictionary in the MD output format (with a 'detections' field)
285
-
286
- Returns:
287
- float: the maximum detection confidence across all classes
288
- """
289
-
290
- max_conf = 0.0
291
- if 'detections' in im and im['detections'] is not None and len(im['detections']) > 0:
292
- max_conf = _get_max_conf_from_detections(im['detections'])
293
- return max_conf
294
-
295
-
296
- def point_dist(p1,p2):
297
- """
298
- Computes the distance between two points, represented as length-two tuples.
299
-
300
- Args:
301
- p1: point, formatted as (x,y)
302
- p2: point, formatted as (x,y)
303
-
304
- Returns:
305
- float: the Euclidean distance between p1 and p2
306
- """
307
-
308
- return math.sqrt( ((p1[0]-p2[0])**2) + ((p1[1]-p2[1])**2) )
309
-
310
-
311
- def rect_distance(r1, r2, format='x0y0x1y1'):
312
- """
313
- Computes the minimum distance between two axis-aligned rectangles, each represented as
314
- (x0,y0,x1,y1) by default.
315
-
316
- Can also specify "format" as x0y0wh for MD-style bbox formatting (x0,y0,w,h).
317
-
318
- Args:
319
- r1: rectangle, formatted as (x0,y0,x1,y1) or (x0,y0,xy,y1)
320
- r2: rectangle, formatted as (x0,y0,x1,y1) or (x0,y0,xy,y1)
321
- format (str, optional): whether the boxes are formatted as 'x0y0x1y1' (default) or 'x0y0wh'
322
-
323
- Returns:
324
- float: the minimum distance between r1 and r2
325
- """
326
-
327
- assert format in ('x0y0x1y1','x0y0wh'), 'Illegal rectangle format {}'.format(format)
328
-
329
- if format == 'x0y0wh':
330
- # Convert to x0y0x1y1 without modifying the original rectangles
331
- r1 = [r1[0],r1[1],r1[0]+r1[2],r1[1]+r1[3]]
332
- r2 = [r2[0],r2[1],r2[0]+r2[2],r2[1]+r2[3]]
333
-
334
- # https://stackoverflow.com/a/26178015
335
- x1, y1, x1b, y1b = r1
336
- x2, y2, x2b, y2b = r2
337
- left = x2b < x1
338
- right = x1b < x2
339
- bottom = y2b < y1
340
- top = y1b < y2
341
- if top and left:
342
- return point_dist((x1, y1b), (x2b, y2))
343
- elif left and bottom:
344
- return point_dist((x1, y1), (x2b, y2b))
345
- elif bottom and right:
346
- return point_dist((x1b, y1), (x2, y2b))
347
- elif right and top:
348
- return point_dist((x1b, y1b), (x2, y2))
349
- elif left:
350
- return x1 - x2b
351
- elif right:
352
- return x2 - x1b
353
- elif bottom:
354
- return y1 - y2b
355
- elif top:
356
- return y2 - y1b
357
- else:
358
- return 0.0
359
-
360
-
361
- def split_list_into_fixed_size_chunks(L,n):
362
- """
363
- Split the list or tuple L into chunks of size n (allowing chunks of size n-1 if necessary,
364
- i.e. len(L) does not have to be a multiple of n).
365
-
366
- Args:
367
- L (list): list to split into chunks
368
- n (int): preferred chunk size
369
-
370
- Returns:
371
- list: list of chunks, where each chunk is a list of length n or n-1
372
- """
373
-
374
- return [L[i * n:(i + 1) * n] for i in range((len(L) + n - 1) // n )]
375
-
376
-
377
- def split_list_into_n_chunks(L, n, chunk_strategy='greedy'):
378
- """
379
- Splits the list or tuple L into n equally-sized chunks (some chunks may be one
380
- element smaller than others, i.e. len(L) does not have to be a multiple of n).
381
-
382
- chunk_strategy can be "greedy" (default, if there are k samples per chunk, the first
383
- k go into the first chunk) or "balanced" (alternate between chunks when pulling
384
- items from the list).
385
-
386
- Args:
387
- L (list): list to split into chunks
388
- n (int): number of chunks
389
- chunk_strategy (str, optiopnal): "greedy" or "balanced"; see above
390
-
391
- Returns:
392
- list: list of chunks, each of which is a list
393
- """
394
-
395
- if chunk_strategy == 'greedy':
396
- k, m = divmod(len(L), n)
397
- return list(L[i*k+min(i, m):(i+1)*k+min(i+1, m)] for i in range(n))
398
- elif chunk_strategy == 'balanced':
399
- chunks = [ [] for _ in range(n) ]
400
- for i_item,item in enumerate(L):
401
- i_chunk = i_item % n
402
- chunks[i_chunk].append(item)
403
- return chunks
404
- else:
405
- raise ValueError('Invalid chunk strategy: {}'.format(chunk_strategy))
406
-
407
-
408
- def sort_dictionary_by_key(d,reverse=False):
409
- """
410
- Sorts the dictionary [d] by key.
411
-
412
- Args:
413
- d (dict): dictionary to sort
414
- reverse (bool, optional): whether to sort in reverse (descending) order
415
-
416
- Returns:
417
- dict: sorted copy of [d]
418
- """
419
-
420
- d = dict(sorted(d.items(),reverse=reverse))
421
- return d
422
-
423
-
424
- def sort_dictionary_by_value(d,sort_values=None,reverse=False):
425
- """
426
- Sorts the dictionary [d] by value. If sort_values is None, uses d.values(),
427
- otherwise uses the dictionary sort_values as the sorting criterion.
428
-
429
- Args:
430
- d (dict): dictionary to sort
431
- sort_values (dict, optional): dictionary mapping keys in [d] to sort values (defaults
432
- to None, uses [d] itself for sorting)
433
- reverse (bool, optional): whether to sort in reverse (descending) order
434
-
435
- Returns:
436
- dict: sorted copy of [d]
437
- """
438
-
439
- if sort_values is None:
440
- d = {k: v for k, v in sorted(d.items(), key=lambda item: item[1], reverse=reverse)}
441
- else:
442
- d = {k: v for k, v in sorted(d.items(), key=lambda item: sort_values[item[0]], reverse=reverse)}
443
- return d
444
-
445
-
446
- def invert_dictionary(d):
447
- """
448
- Creates a new dictionary that maps d.values() to d.keys(). Does not check
449
- uniqueness.
450
-
451
- Args:
452
- d (dict): dictionary to invert
453
-
454
- Returns:
455
- dict: inverted copy of [d]
456
- """
457
-
458
- return {v: k for k, v in d.items()}
459
-
460
-
461
- def image_file_to_camera_folder(image_fn):
462
- r"""
463
- Removes common overflow folders (e.g. RECNX101, RECNX102) from paths, i.e. turn:
464
-
465
- a\b\c\RECNX101\image001.jpg
466
-
467
- ...into:
468
-
469
- a\b\c
470
-
471
- Returns the same thing as os.dirname() (i.e., just the folder name) if no overflow folders are
472
- present.
473
-
474
- Always converts backslashes to slashes.
475
-
476
- Args:
477
- image_fn (str): the image filename from which we should remove overflow folders
478
-
479
- Returns:
480
- str: a version of [image_fn] from which camera overflow folders have been removed
481
- """
482
-
483
- import re
484
-
485
- # 100RECNX is the overflow folder style for Reconyx cameras
486
- # 100EK113 is (for some reason) the overflow folder style for Bushnell cameras
487
- # 100_BTCF is the overflow folder style for Browning cameras
488
- # 100MEDIA is the overflow folder style used on a number of consumer-grade cameras
489
- patterns = ['\/\d+RECNX\/','\/\d+EK\d+\/','\/\d+_BTCF\/','\/\d+MEDIA\/']
490
-
491
- image_fn = image_fn.replace('\\','/')
492
- for pat in patterns:
493
- image_fn = re.sub(pat,'/',image_fn)
494
- camera_folder = os.path.dirname(image_fn)
495
-
496
- return camera_folder
497
-
498
-
499
- def is_float(v):
500
- """
501
- Determines whether v is either a float or a string representation of a float.
502
-
503
- Args:
504
- v (object): object to evaluate
505
-
506
- Returns:
507
- bool: True if [v] is a float or a string representation of a float, otherwise False
508
- """
509
-
510
- try:
511
- _ = float(v)
512
- return True
513
- except ValueError:
514
- return False
515
-
516
-
517
- def is_iterable(x):
518
- """
519
- Uses duck typing to assess whether [x] is iterable (list, set, dict, etc.).
520
-
521
- Args:
522
- x (object): the object to test
523
-
524
- Returns:
525
- bool: True if [x] appears to be iterable, otherwise False
526
- """
527
-
528
- try:
529
- _ = iter(x)
530
- except:
531
- return False
532
- return True
533
-
534
-
535
- def is_empty(v):
536
- """
537
- A common definition of "empty" used throughout the repo, particularly when loading
538
- data from .csv files. "empty" includes None, '', and NaN.
539
-
540
- Args:
541
- v: the object to evaluate for emptiness
542
-
543
- Returns:
544
- bool: True if [v] is None, '', or NaN, otherwise False
545
- """
546
- if v is None:
547
- return True
548
- if isinstance(v,str) and v == '':
549
- return True
550
- if isinstance(v,float) and np.isnan(v):
551
- return True
552
- return False
553
-
554
-
555
- def isnan(v):
556
- """
557
- Returns True if v is a nan-valued float, otherwise returns False.
558
-
559
- Args:
560
- v: the object to evaluate for nan-ness
561
-
562
- Returns:
563
- bool: True if v is a nan-valued float, otherwise False
564
- """
565
-
566
- try:
567
- return np.isnan(v)
568
- except Exception:
569
- return False
570
-
571
-
572
- def sets_overlap(set1, set2):
573
- """
574
- Determines whether two sets overlap.
575
-
576
- Args:
577
- set1 (set): the first set to compare (converted to a set if it's not already)
578
- set2 (set): the second set to compare (converted to a set if it's not already)
579
-
580
- Returns:
581
- bool: True if any elements are shared between set1 and set2
582
- """
583
-
584
- return not set(set1).isdisjoint(set(set2))
585
-
586
-
587
-
588
- #%% Test drivers
589
-
590
- if False:
591
-
592
- pass
593
-
594
- #%% Test image_file_to_camera_folder()
595
-
596
- relative_path = 'a/b/c/d/100EK113/blah.jpg'
597
- print(image_file_to_camera_folder(relative_path))
598
-
599
- relative_path = 'a/b/c/d/100RECNX/blah.jpg'
600
- print(image_file_to_camera_folder(relative_path))
601
-
602
-
603
- #%% Test a few rectangle distances
604
-
605
- r1 = [0,0,1,1]; r2 = [0,0,1,1]; assert rect_distance(r1,r2)==0
606
- r1 = [0,0,1,1]; r2 = [0,0,1,100]; assert rect_distance(r1,r2)==0
607
- r1 = [0,0,1,1]; r2 = [1,1,2,2]; assert rect_distance(r1,r2)==0
608
- r1 = [0,0,1,1]; r2 = [1.1,0,0,1.1]; assert abs(rect_distance(r1,r2)-.1) < 0.00001
609
-
610
- r1 = [0.4,0.8,10,22]; r2 = [100, 101, 200, 210.4]; assert abs(rect_distance(r1,r2)-119.753) < 0.001
611
- r1 = [0.4,0.8,10,22]; r2 = [101, 101, 200, 210.4]; assert abs(rect_distance(r1,r2)-120.507) < 0.001
612
- r1 = [0.4,0.8,10,22]; r2 = [120, 120, 200, 210.4]; assert abs(rect_distance(r1,r2)-147.323) < 0.001