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
@@ -1,441 +0,0 @@
1
- """
2
-
3
- yolo_output_to_md_output.py
4
-
5
- Converts the output of YOLOv5's detect.py or val.py to the MD API output format.
6
-
7
- **Converting .txt files**
8
-
9
- detect.py writes a .txt file per image, in YOLO training format. Converting from this
10
- format does not currently support recursive results, since detect.py doesn't save filenames
11
- in a way that allows easy inference of folder names. Requires access to the input
12
- images, because the YOLO format uses the *absence* of a results file to indicate that
13
- no detections are present.
14
-
15
- YOLOv5 output has one text file per image, like so:
16
-
17
- 0 0.0141693 0.469758 0.0283385 0.131552 0.761428
18
-
19
- That's [class, x_center, y_center, width_of_box, height_of_box, confidence]
20
-
21
- val.py can write in this format as well, using the --save-txt argument.
22
-
23
- In both cases, a confidence value is only written to each line if you include the --save-conf
24
- argument. Confidence values are required by this conversion script.
25
-
26
-
27
- **Converting .json files**
28
-
29
- val.py can also write a .json file in COCO-ish format. It's "COCO-ish" because it's
30
- just the "images" portion of a COCO .json file.
31
-
32
- Converting from this format also requires access to the original images, since the format
33
- written by YOLOv5 uses absolute coordinates, but MD results are in relative coordinates.
34
-
35
- """
36
-
37
- #%% Imports and constants
38
-
39
- import json
40
- import csv
41
- import os
42
- import re
43
-
44
- from collections import defaultdict
45
- from tqdm import tqdm
46
-
47
- from md_utils import path_utils
48
- from md_utils import ct_utils
49
- from md_visualization import visualization_utils as vis_utils
50
- from detection.run_detector import CONF_DIGITS, COORD_DIGITS
51
-
52
-
53
- #%% Support functions
54
-
55
- def read_classes_from_yolo_dataset_file(fn):
56
- """
57
- Reads a dictionary mapping integer class IDs to class names from a YOLOv5/YOLOv8
58
- dataset.yaml file or a .json file. A .json file should contain a dictionary mapping
59
- integer category IDs to string category names.
60
-
61
- Args:
62
- fn (str): YOLOv5/YOLOv8 dataset file with a .yml or .yaml extension, or a .json file
63
- mapping integer category IDs to category names.
64
-
65
- Returns:
66
- dict: a mapping from integer category IDs to category names
67
- """
68
-
69
- if fn.endswith('.yml') or fn.endswith('.yaml'):
70
-
71
- with open(fn,'r') as f:
72
- lines = f.readlines()
73
-
74
- category_id_to_name = {}
75
- pat = '\d+:.+'
76
- for s in lines:
77
- if re.search(pat,s) is not None:
78
- tokens = s.split(':')
79
- assert len(tokens) == 2, 'Invalid token in category file {}'.format(fn)
80
- category_id_to_name[int(tokens[0].strip())] = tokens[1].strip()
81
-
82
- elif fn.endswith('.json'):
83
-
84
- with open(fn,'r') as f:
85
- d_in = json.load(f)
86
- category_id_to_name = {}
87
- for k in d_in.keys():
88
- category_id_to_name[int(k)] = d_in[k]
89
-
90
- else:
91
-
92
- raise ValueError('Unrecognized category file type: {}'.format(fn))
93
-
94
- assert len(category_id_to_name) > 0, 'Failed to read class mappings from {}'.format(fn)
95
-
96
- return category_id_to_name
97
-
98
-
99
- def yolo_json_output_to_md_output(yolo_json_file,
100
- image_folder,
101
- output_file,
102
- yolo_category_id_to_name,
103
- detector_name='unknown',
104
- image_id_to_relative_path=None,
105
- offset_yolo_class_ids=True,
106
- truncate_to_standard_md_precision=True,
107
- image_id_to_error=None):
108
- """
109
- Converts a YOLOv5/YOLOv8 .json file to MD .json format.
110
-
111
- Args:
112
-
113
- yolo_json_file (str): the .json file to convert from YOLOv5 format to MD output format
114
- image_folder (str): the .json file contains relative path names, this is the path base
115
- yolo_category_id_to_name (str or dict): the .json results file contains only numeric
116
- identifiers for categories, but we want names and numbers for the output format;
117
- yolo_category_id_to_name provides that mapping either as a dict or as a YOLOv5
118
- dataset.yaml file.
119
- detector_name (str, optional): a string that gets put in the output file, not otherwise
120
- used within this function
121
- image_id_to_relative_path (dict, optional): YOLOv5 .json uses only basenames (e.g.
122
- abc1234.JPG); by default these will be appended to the input path to create pathnames.
123
- If you have a flat folder, this is fine. If you want to map base names to relative paths in
124
- a more complicated way, use this parameter.
125
- offset_yolo_class_ids (bool, optional): YOLOv5 class IDs always start at zero; if you want to
126
- make the output classes start at 1, set offset_yolo_class_ids to True.
127
- truncate_to_standard_md_precision (bool, optional): YOLOv5 .json includes lots of
128
- (not-super-meaningful) precision, set this to truncate to COORD_DIGITS and CONF_DIGITS.
129
- image_id_to_error (dict, optional): if you want to include image IDs in the output file for which
130
- you couldn't prepare the input file in the first place due to errors, include them here.
131
- """
132
-
133
- assert os.path.isfile(yolo_json_file), \
134
- 'Could not find YOLO .json file {}'.format(yolo_json_file)
135
- assert os.path.isdir(image_folder), \
136
- 'Could not find image folder {}'.format(image_folder)
137
-
138
- if image_id_to_error is None:
139
- image_id_to_error = {}
140
-
141
- print('Converting {} to MD format and writing results to {}'.format(
142
- yolo_json_file,output_file))
143
-
144
- if isinstance(yolo_category_id_to_name,str):
145
- assert os.path.isfile(yolo_category_id_to_name), \
146
- 'YOLO category mapping specified as a string, but file does not exist: {}'.format(
147
- yolo_category_id_to_name)
148
- yolo_category_id_to_name = read_classes_from_yolo_dataset_file(yolo_category_id_to_name)
149
-
150
- if image_id_to_relative_path is None:
151
-
152
- image_files = path_utils.find_images(image_folder,recursive=True)
153
- image_files = [os.path.relpath(fn,image_folder) for fn in image_files]
154
-
155
- # YOLOv5 identifies images in .json output by ID, which is the filename without
156
- # extension. If a mapping is not provided, these need to be unique.
157
- image_id_to_relative_path = {}
158
-
159
- for fn in image_files:
160
- image_id = os.path.splitext(os.path.basename(fn))[0]
161
- if image_id in image_id_to_relative_path:
162
- print('Error: image ID {} refers to:\n{}\n{}'.format(
163
- image_id,image_id_to_relative_path[image_id],fn))
164
- raise ValueError('Duplicate image ID {}'.format(image_id))
165
- image_id_to_relative_path[image_id] = fn
166
-
167
- image_files_relative = sorted(list(image_id_to_relative_path.values()))
168
-
169
- image_file_relative_to_image_id = {}
170
- for image_id in image_id_to_relative_path:
171
- relative_path = image_id_to_relative_path[image_id]
172
- assert relative_path not in image_file_relative_to_image_id, \
173
- 'Duplication image IDs in YOLO output conversion for image {}'.format(relative_path)
174
- image_file_relative_to_image_id[relative_path] = image_id
175
-
176
- with open(yolo_json_file,'r') as f:
177
- detections = json.load(f)
178
- assert isinstance(detections,list)
179
-
180
- image_id_to_detections = defaultdict(list)
181
-
182
- int_formatted_image_ids = False
183
-
184
- # det = detections[0]
185
- for det in detections:
186
-
187
- # This could be a string, but if the YOLOv5 inference script sees that the strings
188
- # are really ints, it converts to ints.
189
- image_id = det['image_id']
190
- image_id_to_detections[image_id].append(det)
191
- if isinstance(image_id,int):
192
- int_formatted_image_ids = True
193
-
194
- # If there are any ints present, everything should be ints
195
- if int_formatted_image_ids:
196
- for det in detections:
197
- assert isinstance(det['image_id'],int), \
198
- 'Found mixed int and string image IDs'
199
-
200
- # Convert the keys in image_id_to_error to ints
201
- #
202
- # This should error if we're given non-int-friendly IDs
203
- int_formatted_image_id_to_error = {}
204
- for image_id in image_id_to_error:
205
- int_formatted_image_id_to_error[int(image_id)] = \
206
- image_id_to_error[image_id]
207
- image_id_to_error = int_formatted_image_id_to_error
208
-
209
- # ...if image IDs are formatted as integers in YOLO output
210
-
211
- # In a modified version of val.py, we use negative category IDs to indicate an error
212
- # that happened during inference (typically truncated images with valid headers,
213
- # so corruption was not detected during val.py's initial corruption check pass.
214
- for det in detections:
215
- if det['category_id'] < 0:
216
- assert 'error' in det, 'Negative category ID present with no error string'
217
- error_string = det['error']
218
- print('Caught inference-time failure {} for image {}'.format(error_string,det['image_id']))
219
- image_id_to_error[det['image_id']] = error_string
220
-
221
- output_images = []
222
-
223
- # image_file_relative = image_files_relative[10]
224
- for image_file_relative in tqdm(image_files_relative):
225
-
226
- im = {}
227
- im['file'] = image_file_relative
228
- image_id = image_file_relative_to_image_id[image_file_relative]
229
- if int_formatted_image_ids:
230
- image_id = int(image_id)
231
- if image_id in image_id_to_error:
232
- im['failure'] = str(image_id_to_error[image_id])
233
- output_images.append(im)
234
- continue
235
- elif image_id not in image_id_to_detections:
236
- detections = []
237
- else:
238
- detections = image_id_to_detections[image_id]
239
-
240
- image_full_path = os.path.join(image_folder,image_file_relative)
241
- try:
242
- pil_im = vis_utils.open_image(image_full_path)
243
- except Exception as e:
244
- s = str(e).replace('\n',' ')
245
- print('Warning: error opening image {}: {}, outputting as a failure'.format(image_full_path,s))
246
- im['failure'] = 'Conversion error: {}'.format(s)
247
- output_images.append(im)
248
- continue
249
-
250
- im['detections'] = []
251
-
252
- image_w = pil_im.size[0]
253
- image_h = pil_im.size[1]
254
-
255
- # det = detections[0]
256
- for det in detections:
257
-
258
- output_det = {}
259
-
260
- yolo_cat_id = int(det['category_id'])
261
- if offset_yolo_class_ids:
262
- yolo_cat_id += 1
263
- output_det['category'] = str(int(yolo_cat_id))
264
- conf = det['score']
265
- if truncate_to_standard_md_precision:
266
- conf = ct_utils.truncate_float(conf,CONF_DIGITS)
267
- output_det['conf'] = conf
268
- input_bbox = det['bbox']
269
-
270
- # YOLO's COCO .json is not *that* COCO-like, but it is COCO-like in
271
- # that the boxes are already [xmin/ymin/w/h]
272
- box_xmin_absolute = input_bbox[0]
273
- box_ymin_absolute = input_bbox[1]
274
- box_width_absolute = input_bbox[2]
275
- box_height_absolute = input_bbox[3]
276
-
277
- box_xmin_relative = box_xmin_absolute / image_w
278
- box_ymin_relative = box_ymin_absolute / image_h
279
- box_width_relative = box_width_absolute / image_w
280
- box_height_relative = box_height_absolute / image_h
281
-
282
- output_bbox = [box_xmin_relative,box_ymin_relative,
283
- box_width_relative,box_height_relative]
284
-
285
- if truncate_to_standard_md_precision:
286
- output_bbox = ct_utils.truncate_float_array(output_bbox,COORD_DIGITS)
287
-
288
- output_det['bbox'] = output_bbox
289
- im['detections'].append(output_det)
290
-
291
- # ...for each detection
292
-
293
- output_images.append(im)
294
-
295
- # ...for each image file
296
-
297
- d = {}
298
- d['images'] = output_images
299
- d['info'] = {'format_version':1.3,'detector':detector_name}
300
- d['detection_categories'] = {}
301
-
302
- for cat_id in yolo_category_id_to_name:
303
- yolo_cat_id = int(cat_id)
304
- if offset_yolo_class_ids:
305
- yolo_cat_id += 1
306
- d['detection_categories'][str(yolo_cat_id)] = yolo_category_id_to_name[cat_id]
307
-
308
- with open(output_file,'w') as f:
309
- json.dump(d,f,indent=1)
310
-
311
- # ...def yolo_json_output_to_md_output(...)
312
-
313
-
314
- def yolo_txt_output_to_md_output(input_results_folder,
315
- image_folder,
316
- output_file,
317
- detector_tag=None):
318
- """
319
- Converts a folder of YOLO-output .txt files to MD .json format.
320
-
321
- Less finished than the .json conversion function; this .txt conversion assumes
322
- a hard-coded mapping representing the standard MD categories (in MD indexing,
323
- 1/2/3=animal/person/vehicle; in YOLO indexing, 0/1/2=animal/person/vehicle).
324
-
325
- Args:
326
- input_results_folder (str): the folder containing YOLO-output .txt files
327
- image_folder (str): the folder where images live, may be the same as
328
- [input_results_folder]
329
- output_file (str): the MD-formatted .json file to which we should write
330
- results
331
- detector_tag (str, optional): string to put in the 'detector' field in the
332
- output file
333
- """
334
-
335
- assert os.path.isdir(input_results_folder)
336
- assert os.path.isdir(image_folder)
337
-
338
- ## Enumerate results files and image files
339
-
340
- yolo_results_files = os.listdir(input_results_folder)
341
- yolo_results_files = [f for f in yolo_results_files if f.lower().endswith('.txt')]
342
- # print('Found {} results files'.format(len(yolo_results_files)))
343
-
344
- image_files = path_utils.find_images(image_folder,recursive=False)
345
- image_files_relative = [os.path.basename(f) for f in image_files]
346
- # print('Found {} images'.format(len(image_files)))
347
-
348
- image_files_relative_no_extension = [os.path.splitext(f)[0] for f in image_files_relative]
349
-
350
- ## Make sure that every results file corresponds to an image
351
-
352
- for f in yolo_results_files:
353
- result_no_extension = os.path.splitext(f)[0]
354
- assert result_no_extension in image_files_relative_no_extension
355
-
356
- ## Build MD output data
357
-
358
- # Map 0-indexed YOLO categories to 1-indexed MD categories
359
- yolo_cat_map = { 0: 1, 1: 2, 2: 3 }
360
-
361
- images_entries = []
362
-
363
- # image_fn = image_files_relative[0]
364
- for image_fn in image_files_relative:
365
-
366
- image_name, ext = os.path.splitext(image_fn)
367
- label_fn = image_name + '.txt'
368
- label_path = os.path.join(input_results_folder, label_fn)
369
-
370
- detections = []
371
-
372
- if not os.path.exists(label_path):
373
- # This is assumed to be an image with no detections
374
- pass
375
- else:
376
- with open(label_path, newline='') as f:
377
- reader = csv.reader(f, delimiter=' ')
378
- for row in reader:
379
- category = yolo_cat_map[int(row[0])]
380
- api_box = ct_utils.convert_yolo_to_xywh([float(row[1]), float(row[2]),
381
- float(row[3]), float(row[4])])
382
-
383
- conf = ct_utils.truncate_float(float(row[5]), precision=4)
384
-
385
- detections.append({
386
- 'category': str(category),
387
- 'conf': conf,
388
- 'bbox': ct_utils.truncate_float_array(api_box, precision=4)
389
- })
390
-
391
- images_entries.append({
392
- 'file': image_fn,
393
- 'detections': detections
394
- })
395
-
396
- # ...for each image
397
-
398
- ## Save output file
399
-
400
- detector_string = 'converted_from_yolo_format'
401
-
402
- if detector_tag is not None:
403
- detector_string = detector_tag
404
-
405
- output_content = {
406
- 'info': {
407
- 'detector': detector_string,
408
- 'detector_metadata': {},
409
- 'format_version': '1.3'
410
- },
411
- 'detection_categories': {
412
- '1': 'animal',
413
- '2': 'person',
414
- '3': 'vehicle'
415
- },
416
- 'images': images_entries
417
- }
418
-
419
- with open(output_file,'w') as f:
420
- json.dump(output_content,f,indent=1)
421
-
422
- # ...def yolo_txt_output_to_md_output(...)
423
-
424
-
425
- #%% Interactive driver
426
-
427
- if False:
428
-
429
- pass
430
-
431
- #%%
432
-
433
- input_results_folder = os.path.expanduser('~/tmp/model-version-experiments/pt-test-kru/exp/labels')
434
- image_folder = os.path.expanduser('~/data/KRU-test')
435
- output_file = os.path.expanduser('~/data/mdv5a-yolo-pt-kru.json')
436
- yolo_txt_output_to_md_output(input_results_folder,image_folder,output_file)
437
-
438
-
439
- #%% Command-line driver
440
-
441
- # TODO