megadetector 10.0.13__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 (147) hide show
  1. megadetector/__init__.py +0 -0
  2. megadetector/api/__init__.py +0 -0
  3. megadetector/api/batch_processing/integration/digiKam/setup.py +6 -0
  4. megadetector/api/batch_processing/integration/digiKam/xmp_integration.py +465 -0
  5. megadetector/api/batch_processing/integration/eMammal/test_scripts/config_template.py +5 -0
  6. megadetector/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +125 -0
  7. megadetector/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +55 -0
  8. megadetector/classification/__init__.py +0 -0
  9. megadetector/classification/aggregate_classifier_probs.py +108 -0
  10. megadetector/classification/analyze_failed_images.py +227 -0
  11. megadetector/classification/cache_batchapi_outputs.py +198 -0
  12. megadetector/classification/create_classification_dataset.py +626 -0
  13. megadetector/classification/crop_detections.py +516 -0
  14. megadetector/classification/csv_to_json.py +226 -0
  15. megadetector/classification/detect_and_crop.py +853 -0
  16. megadetector/classification/efficientnet/__init__.py +9 -0
  17. megadetector/classification/efficientnet/model.py +415 -0
  18. megadetector/classification/efficientnet/utils.py +608 -0
  19. megadetector/classification/evaluate_model.py +520 -0
  20. megadetector/classification/identify_mislabeled_candidates.py +152 -0
  21. megadetector/classification/json_to_azcopy_list.py +63 -0
  22. megadetector/classification/json_validator.py +696 -0
  23. megadetector/classification/map_classification_categories.py +276 -0
  24. megadetector/classification/merge_classification_detection_output.py +509 -0
  25. megadetector/classification/prepare_classification_script.py +194 -0
  26. megadetector/classification/prepare_classification_script_mc.py +228 -0
  27. megadetector/classification/run_classifier.py +287 -0
  28. megadetector/classification/save_mislabeled.py +110 -0
  29. megadetector/classification/train_classifier.py +827 -0
  30. megadetector/classification/train_classifier_tf.py +725 -0
  31. megadetector/classification/train_utils.py +323 -0
  32. megadetector/data_management/__init__.py +0 -0
  33. megadetector/data_management/animl_to_md.py +161 -0
  34. megadetector/data_management/annotations/__init__.py +0 -0
  35. megadetector/data_management/annotations/annotation_constants.py +33 -0
  36. megadetector/data_management/camtrap_dp_to_coco.py +270 -0
  37. megadetector/data_management/cct_json_utils.py +566 -0
  38. megadetector/data_management/cct_to_md.py +184 -0
  39. megadetector/data_management/cct_to_wi.py +293 -0
  40. megadetector/data_management/coco_to_labelme.py +284 -0
  41. megadetector/data_management/coco_to_yolo.py +702 -0
  42. megadetector/data_management/databases/__init__.py +0 -0
  43. megadetector/data_management/databases/add_width_and_height_to_db.py +107 -0
  44. megadetector/data_management/databases/combine_coco_camera_traps_files.py +210 -0
  45. megadetector/data_management/databases/integrity_check_json_db.py +528 -0
  46. megadetector/data_management/databases/subset_json_db.py +195 -0
  47. megadetector/data_management/generate_crops_from_cct.py +200 -0
  48. megadetector/data_management/get_image_sizes.py +164 -0
  49. megadetector/data_management/labelme_to_coco.py +559 -0
  50. megadetector/data_management/labelme_to_yolo.py +349 -0
  51. megadetector/data_management/lila/__init__.py +0 -0
  52. megadetector/data_management/lila/create_lila_blank_set.py +556 -0
  53. megadetector/data_management/lila/create_lila_test_set.py +187 -0
  54. megadetector/data_management/lila/create_links_to_md_results_files.py +106 -0
  55. megadetector/data_management/lila/download_lila_subset.py +182 -0
  56. megadetector/data_management/lila/generate_lila_per_image_labels.py +777 -0
  57. megadetector/data_management/lila/get_lila_annotation_counts.py +174 -0
  58. megadetector/data_management/lila/get_lila_image_counts.py +112 -0
  59. megadetector/data_management/lila/lila_common.py +319 -0
  60. megadetector/data_management/lila/test_lila_metadata_urls.py +164 -0
  61. megadetector/data_management/mewc_to_md.py +344 -0
  62. megadetector/data_management/ocr_tools.py +873 -0
  63. megadetector/data_management/read_exif.py +964 -0
  64. megadetector/data_management/remap_coco_categories.py +195 -0
  65. megadetector/data_management/remove_exif.py +156 -0
  66. megadetector/data_management/rename_images.py +194 -0
  67. megadetector/data_management/resize_coco_dataset.py +663 -0
  68. megadetector/data_management/speciesnet_to_md.py +41 -0
  69. megadetector/data_management/wi_download_csv_to_coco.py +247 -0
  70. megadetector/data_management/yolo_output_to_md_output.py +594 -0
  71. megadetector/data_management/yolo_to_coco.py +876 -0
  72. megadetector/data_management/zamba_to_md.py +188 -0
  73. megadetector/detection/__init__.py +0 -0
  74. megadetector/detection/change_detection.py +840 -0
  75. megadetector/detection/process_video.py +479 -0
  76. megadetector/detection/pytorch_detector.py +1451 -0
  77. megadetector/detection/run_detector.py +1267 -0
  78. megadetector/detection/run_detector_batch.py +2159 -0
  79. megadetector/detection/run_inference_with_yolov5_val.py +1314 -0
  80. megadetector/detection/run_md_and_speciesnet.py +1494 -0
  81. megadetector/detection/run_tiled_inference.py +1038 -0
  82. megadetector/detection/tf_detector.py +209 -0
  83. megadetector/detection/video_utils.py +1379 -0
  84. megadetector/postprocessing/__init__.py +0 -0
  85. megadetector/postprocessing/add_max_conf.py +72 -0
  86. megadetector/postprocessing/categorize_detections_by_size.py +166 -0
  87. megadetector/postprocessing/classification_postprocessing.py +1752 -0
  88. megadetector/postprocessing/combine_batch_outputs.py +249 -0
  89. megadetector/postprocessing/compare_batch_results.py +2110 -0
  90. megadetector/postprocessing/convert_output_format.py +403 -0
  91. megadetector/postprocessing/create_crop_folder.py +629 -0
  92. megadetector/postprocessing/detector_calibration.py +570 -0
  93. megadetector/postprocessing/generate_csv_report.py +522 -0
  94. megadetector/postprocessing/load_api_results.py +223 -0
  95. megadetector/postprocessing/md_to_coco.py +428 -0
  96. megadetector/postprocessing/md_to_labelme.py +351 -0
  97. megadetector/postprocessing/md_to_wi.py +41 -0
  98. megadetector/postprocessing/merge_detections.py +392 -0
  99. megadetector/postprocessing/postprocess_batch_results.py +2077 -0
  100. megadetector/postprocessing/remap_detection_categories.py +226 -0
  101. megadetector/postprocessing/render_detection_confusion_matrix.py +677 -0
  102. megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py +206 -0
  103. megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +82 -0
  104. megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +1665 -0
  105. megadetector/postprocessing/separate_detections_into_folders.py +795 -0
  106. megadetector/postprocessing/subset_json_detector_output.py +964 -0
  107. megadetector/postprocessing/top_folders_to_bottom.py +238 -0
  108. megadetector/postprocessing/validate_batch_results.py +332 -0
  109. megadetector/taxonomy_mapping/__init__.py +0 -0
  110. megadetector/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +491 -0
  111. megadetector/taxonomy_mapping/map_new_lila_datasets.py +213 -0
  112. megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +165 -0
  113. megadetector/taxonomy_mapping/preview_lila_taxonomy.py +543 -0
  114. megadetector/taxonomy_mapping/retrieve_sample_image.py +71 -0
  115. megadetector/taxonomy_mapping/simple_image_download.py +224 -0
  116. megadetector/taxonomy_mapping/species_lookup.py +1008 -0
  117. megadetector/taxonomy_mapping/taxonomy_csv_checker.py +159 -0
  118. megadetector/taxonomy_mapping/taxonomy_graph.py +346 -0
  119. megadetector/taxonomy_mapping/validate_lila_category_mappings.py +83 -0
  120. megadetector/tests/__init__.py +0 -0
  121. megadetector/tests/test_nms_synthetic.py +335 -0
  122. megadetector/utils/__init__.py +0 -0
  123. megadetector/utils/ct_utils.py +1857 -0
  124. megadetector/utils/directory_listing.py +199 -0
  125. megadetector/utils/extract_frames_from_video.py +307 -0
  126. megadetector/utils/gpu_test.py +125 -0
  127. megadetector/utils/md_tests.py +2072 -0
  128. megadetector/utils/path_utils.py +2832 -0
  129. megadetector/utils/process_utils.py +172 -0
  130. megadetector/utils/split_locations_into_train_val.py +237 -0
  131. megadetector/utils/string_utils.py +234 -0
  132. megadetector/utils/url_utils.py +825 -0
  133. megadetector/utils/wi_platform_utils.py +968 -0
  134. megadetector/utils/wi_taxonomy_utils.py +1759 -0
  135. megadetector/utils/write_html_image_list.py +239 -0
  136. megadetector/visualization/__init__.py +0 -0
  137. megadetector/visualization/plot_utils.py +309 -0
  138. megadetector/visualization/render_images_with_thumbnails.py +243 -0
  139. megadetector/visualization/visualization_utils.py +1940 -0
  140. megadetector/visualization/visualize_db.py +630 -0
  141. megadetector/visualization/visualize_detector_output.py +479 -0
  142. megadetector/visualization/visualize_video_output.py +705 -0
  143. megadetector-10.0.13.dist-info/METADATA +134 -0
  144. megadetector-10.0.13.dist-info/RECORD +147 -0
  145. megadetector-10.0.13.dist-info/WHEEL +5 -0
  146. megadetector-10.0.13.dist-info/licenses/LICENSE +19 -0
  147. megadetector-10.0.13.dist-info/top_level.txt +1 -0
@@ -0,0 +1,403 @@
1
+ """
2
+
3
+ convert_output_format.py
4
+
5
+ Converts between file .json and .csv representations of MD output. The .csv format is
6
+ largely obsolete, don't use it unless you're super-duper sure you need it.
7
+
8
+ """
9
+
10
+ #%% Constants and imports
11
+
12
+ import argparse
13
+ import json
14
+ import sys
15
+ import os
16
+
17
+ from tqdm import tqdm
18
+ from collections import defaultdict
19
+
20
+ import pandas as pd
21
+
22
+ from megadetector.postprocessing.load_api_results import load_api_results_csv
23
+ from megadetector.utils.wi_taxonomy_utils import load_md_or_speciesnet_file
24
+ from megadetector.data_management.annotations import annotation_constants
25
+ from megadetector.utils.ct_utils import get_max_conf
26
+ from megadetector.utils.ct_utils import write_json
27
+
28
+ CONF_DIGITS = 3
29
+
30
+
31
+ #%% Conversion functions
32
+
33
+ def convert_json_to_csv(input_path,
34
+ output_path=None,
35
+ min_confidence=None,
36
+ omit_bounding_boxes=False,
37
+ output_encoding=None,
38
+ overwrite=True,
39
+ verbose=False):
40
+ """
41
+ Converts a MD results .json file to a totally non-standard .csv format.
42
+
43
+ If [output_path] is None, will convert x.json to x.csv.
44
+
45
+ Args:
46
+ input_path (str): the input .json file to convert
47
+ output_path (str, optional): the output .csv file to generate; if this is None, uses
48
+ [input_path].csv
49
+ min_confidence (float, optional): the minimum-confidence detection we should include
50
+ in the "detections" column; has no impact on the other columns
51
+ omit_bounding_boxes (bool, optional): whether to leave out the json-formatted bounding
52
+ boxes that make up the "detections" column, which are not generally useful for someone
53
+ who wants to consume this data as a .csv file
54
+ output_encoding (str, optional): encoding to use for the .csv file
55
+ overwrite (bool, optional): whether to overwrite an existing .csv file; if this is False and
56
+ the output file exists, no-ops and returns
57
+ verbose (bool, optional): enable additional debug output
58
+ """
59
+
60
+ if output_path is None:
61
+ output_path = os.path.splitext(input_path)[0]+'.csv'
62
+
63
+ if os.path.isfile(output_path) and (not overwrite):
64
+ print('File {} exists, skipping json --> csv conversion'.format(output_path))
65
+ return
66
+
67
+ print('Loading json results from {}...'.format(input_path))
68
+ json_output = load_md_or_speciesnet_file(input_path,
69
+ verbose=verbose)
70
+
71
+ def clean_category_name(s):
72
+ return s.replace(',','_').replace(' ','_').lower()
73
+
74
+ # Create column names for max detection confidences
75
+ detection_category_id_to_max_conf_column_name = {}
76
+ for category_id in json_output['detection_categories'].keys():
77
+ category_name = clean_category_name(json_output['detection_categories'][category_id])
78
+ detection_category_id_to_max_conf_column_name[category_id] = \
79
+ 'max_conf_' + category_name
80
+
81
+ classification_category_id_to_max_conf_column_name = {}
82
+
83
+ # Create column names for max classification confidences (if necessary)
84
+ if 'classification_categories' in json_output.keys():
85
+
86
+ for category_id in json_output['classification_categories'].keys():
87
+ category_name = clean_category_name(json_output['classification_categories'][category_id])
88
+ classification_category_id_to_max_conf_column_name[category_id] = \
89
+ 'max_classification_conf_' + category_name
90
+
91
+ # There are several .json fields for which we add .csv columns; other random bespoke fields
92
+ # will be ignored.
93
+ optional_fields = ['width','height','datetime','exif_metadata']
94
+ optional_fields_present = set()
95
+
96
+ # Iterate once over the data to check for optional fields
97
+ print('Looking for optional fields...')
98
+
99
+ for im in tqdm(json_output['images']):
100
+ # Which optional fields are present for this image?
101
+ for k in im.keys():
102
+ if k in optional_fields:
103
+ optional_fields_present.add(k)
104
+
105
+ optional_fields_present = sorted(list(optional_fields_present))
106
+ if len(optional_fields_present) > 0:
107
+ print('Found {} optional fields'.format(len(optional_fields_present)))
108
+
109
+ print('Formatting results...')
110
+
111
+ output_records = []
112
+
113
+ # i_image = 0; im = json_output['images'][i_image]
114
+ for im in tqdm(json_output['images']):
115
+
116
+ output_record = {}
117
+ output_records.append(output_record)
118
+
119
+ output_record['image_path'] = im['file']
120
+ output_record['max_confidence'] = ''
121
+ output_record['detections'] = ''
122
+
123
+ for field_name in optional_fields_present:
124
+ output_record[field_name] = ''
125
+ if field_name in im:
126
+ output_record[field_name] = im[field_name]
127
+
128
+ for detection_category_id in detection_category_id_to_max_conf_column_name:
129
+ column_name = detection_category_id_to_max_conf_column_name[detection_category_id]
130
+ output_record[column_name] = 0
131
+
132
+ for classification_category_id in classification_category_id_to_max_conf_column_name:
133
+ column_name = classification_category_id_to_max_conf_column_name[classification_category_id]
134
+ output_record[column_name] = 0
135
+
136
+ if 'failure' in im and im['failure'] is not None:
137
+ output_record['max_confidence'] = 'failure'
138
+ output_record['detections'] = im['failure']
139
+ # print('Skipping failed image {} ({})'.format(im['file'],im['failure']))
140
+ continue
141
+
142
+ max_conf = get_max_conf(im)
143
+ detection_category_id_to_max_conf = defaultdict(float)
144
+ classification_category_id_to_max_conf = defaultdict(float)
145
+ detections = []
146
+
147
+ # d = im['detections'][0]
148
+ for d in im['detections']:
149
+
150
+ # Skip sub-threshold detections
151
+ if (min_confidence is not None) and (d['conf'] < min_confidence):
152
+ continue
153
+
154
+ input_bbox = d['bbox']
155
+
156
+ # Our .json format is xmin/ymin/w/h
157
+ #
158
+ # Our .csv format was ymin/xmin/ymax/xmax
159
+ xmin = input_bbox[0]
160
+ ymin = input_bbox[1]
161
+ xmax = input_bbox[0] + input_bbox[2]
162
+ ymax = input_bbox[1] + input_bbox[3]
163
+ output_detection = [ymin, xmin, ymax, xmax]
164
+ output_detection.append(d['conf'])
165
+ output_detection.append(int(d['category']))
166
+ detections.append(output_detection)
167
+
168
+ detection_category_id = d['category']
169
+ detection_category_max = detection_category_id_to_max_conf[detection_category_id]
170
+ if d['conf'] > detection_category_max:
171
+ detection_category_id_to_max_conf[detection_category_id] = d['conf']
172
+
173
+ if 'classifications' in d:
174
+
175
+ for c in d['classifications']:
176
+ classification_category_id = c[0]
177
+ classification_conf = c[1]
178
+ classification_category_max = \
179
+ classification_category_id_to_max_conf[classification_category_id]
180
+ if classification_conf > classification_category_max:
181
+ classification_category_id_to_max_conf[classification_category_id] = \
182
+ classification_conf
183
+
184
+ # ...for each classification
185
+
186
+ # ...if we have classification results for this detection
187
+
188
+ # ...for each detection
189
+
190
+ detection_string = ''
191
+ if not omit_bounding_boxes:
192
+ detection_string = json.dumps(detections)
193
+
194
+ output_record['detections'] = detection_string
195
+ output_record['max_confidence'] = max_conf
196
+
197
+ for detection_category_id in detection_category_id_to_max_conf_column_name:
198
+ column_name = detection_category_id_to_max_conf_column_name[detection_category_id]
199
+ output_record[column_name] = \
200
+ detection_category_id_to_max_conf[detection_category_id]
201
+
202
+ for classification_category_id in classification_category_id_to_max_conf_column_name:
203
+ column_name = classification_category_id_to_max_conf_column_name[classification_category_id]
204
+ output_record[column_name] = \
205
+ classification_category_id_to_max_conf[classification_category_id]
206
+
207
+ # ...for each image
208
+
209
+ print('Writing to csv...')
210
+
211
+ df = pd.DataFrame(output_records)
212
+
213
+ if omit_bounding_boxes:
214
+ df = df.drop('detections',axis=1)
215
+ df.to_csv(output_path,index=False,header=True,encoding=output_encoding)
216
+
217
+ # ...def convert_json_to_csv(...)
218
+
219
+
220
+ def convert_csv_to_json(input_path,output_path=None,overwrite=True):
221
+ """
222
+ Convert .csv to .json. If output_path is None, will convert x.csv to x.json. This
223
+ supports a largely obsolete .csv format, there's almost no reason you want to do this.
224
+
225
+ Args:
226
+ input_path (str): .csv filename to convert to .json
227
+ output_path (str, optional): the output .json file to generate; if this is None, uses
228
+ [input_path].json
229
+ overwrite (bool, optional): whether to overwrite an existing .json file; if this is
230
+ False and the output file exists, no-ops and returns
231
+
232
+ """
233
+
234
+ if output_path is None:
235
+ output_path = os.path.splitext(input_path)[0]+'.json'
236
+
237
+ if os.path.isfile(output_path) and (not overwrite):
238
+ print('File {} exists, skipping csv --> json conversion'.format(output_path))
239
+ return
240
+
241
+ # Format spec:
242
+ #
243
+ # https://github.com/agentmorris/MegaDetector/tree/main/megadetector/api/batch_processing
244
+
245
+ print('Loading csv results...')
246
+ df = load_api_results_csv(input_path)
247
+
248
+ info = {
249
+ "format_version":"1.2",
250
+ "detector": "unknown",
251
+ "detection_completion_time" : "unknown",
252
+ "classifier": "unknown",
253
+ "classification_completion_time": "unknown"
254
+ }
255
+
256
+ classification_categories = {}
257
+ detection_categories = annotation_constants.detector_bbox_categories
258
+
259
+ images = []
260
+
261
+ # i_file = 0; row = df.iloc[i_file]
262
+ for i_file,row in df.iterrows():
263
+
264
+ image = {}
265
+ image['file'] = row['image_path']
266
+ image['max_detection_conf'] = round(row['max_confidence'], CONF_DIGITS)
267
+ src_detections = row['detections']
268
+ out_detections = []
269
+
270
+ for i_detection,detection in enumerate(src_detections):
271
+
272
+ # Our .csv format was ymin/xmin/ymax/xmax
273
+ #
274
+ # Our .json format is xmin/ymin/w/h
275
+ ymin = detection[0]
276
+ xmin = detection[1]
277
+ ymax = detection[2]
278
+ xmax = detection[3]
279
+ bbox = [xmin, ymin, xmax-xmin, ymax-ymin]
280
+ conf = detection[4]
281
+ i_class = detection[5]
282
+ out_detection = {}
283
+ out_detection['category'] = str(i_class)
284
+ out_detection['conf'] = conf
285
+ out_detection['bbox'] = bbox
286
+ out_detections.append(out_detection)
287
+
288
+ # ...for each detection
289
+
290
+ image['detections'] = out_detections
291
+ images.append(image)
292
+
293
+ # ...for each image
294
+ json_out = {}
295
+ json_out['info'] = info
296
+ json_out['detection_categories'] = detection_categories
297
+ json_out['classification_categories'] = classification_categories
298
+ json_out['images'] = images
299
+
300
+ write_json(output_path,json_out)
301
+
302
+ # ...def convert_csv_to_json(...)
303
+
304
+
305
+ #%% Interactive driver
306
+
307
+ if False:
308
+
309
+ #%%
310
+
311
+ input_path = r'c:\temp\test.json'
312
+ min_confidence = None
313
+ output_path = input_path + '.csv'
314
+ convert_json_to_csv(input_path,output_path,min_confidence=min_confidence,
315
+ omit_bounding_boxes=False)
316
+
317
+ #%%
318
+
319
+ base_path = r'c:\temp\json'
320
+ input_paths = os.listdir(base_path)
321
+ input_paths = [os.path.join(base_path,s) for s in input_paths]
322
+
323
+ min_confidence = None
324
+ for input_path in input_paths:
325
+ output_path = input_path + '.csv'
326
+ convert_json_to_csv(input_path,output_path,min_confidence=min_confidence,
327
+ omit_bounding_boxes=True)
328
+
329
+ #%% Concatenate .csv files from a folder
330
+
331
+ import glob
332
+ csv_files = glob.glob(os.path.join(base_path,'*.json.csv' ))
333
+ master_csv = os.path.join(base_path,'all.csv')
334
+
335
+ print('Concatenating {} files to {}'.format(len(csv_files),master_csv))
336
+
337
+ header = None
338
+ with open(master_csv, 'w') as fout:
339
+
340
+ for filename in tqdm(csv_files):
341
+
342
+ with open(filename) as fin:
343
+
344
+ lines = fin.readlines()
345
+
346
+ if header is not None:
347
+ assert lines[0] == header
348
+ else:
349
+ header = lines[0]
350
+ fout.write(header)
351
+
352
+ for line in lines[1:]:
353
+ if len(line.strip()) == 0:
354
+ continue
355
+ fout.write(line)
356
+
357
+ # ...for each .csv file
358
+
359
+ # with open(master_csv)
360
+
361
+
362
+ #%% Command-line driver
363
+
364
+ def main():
365
+ """
366
+ Command-line driver for convert_output_format(), which converts
367
+ json <--> csv.
368
+ """
369
+
370
+ parser = argparse.ArgumentParser()
371
+ parser.add_argument('input_path',type=str,
372
+ help='Input filename ending in .json or .csv')
373
+ parser.add_argument('--output_path',type=str,default=None,
374
+ help='Output filename ending in .json or .csv (defaults to ' + \
375
+ 'input file, with .json/.csv replaced by .csv/.json)')
376
+ parser.add_argument('--omit_bounding_boxes',action='store_true',
377
+ help='Omit bounding box text from .csv output (large and usually not useful)')
378
+
379
+ if len(sys.argv[1:]) == 0:
380
+ parser.print_help()
381
+ parser.exit()
382
+
383
+ args = parser.parse_args()
384
+
385
+ if args.output_path is None:
386
+ if args.input_path.endswith('.csv'):
387
+ args.output_path = args.input_path[:-4] + '.json'
388
+ elif args.input_path.endswith('.json'):
389
+ args.output_path = args.input_path[:-5] + '.csv'
390
+ else:
391
+ raise ValueError('Illegal input file extension')
392
+
393
+ if args.input_path.endswith('.csv') and args.output_path.endswith('.json'):
394
+ assert not args.omit_bounding_boxes, \
395
+ '--omit_bounding_boxes does not apply to csv --> json conversion'
396
+ convert_csv_to_json(args.input_path,args.output_path)
397
+ elif args.input_path.endswith('.json') and args.output_path.endswith('.csv'):
398
+ convert_json_to_csv(args.input_path,args.output_path,omit_bounding_boxes=args.omit_bounding_boxes)
399
+ else:
400
+ raise ValueError('Illegal format combination')
401
+
402
+ if __name__ == '__main__':
403
+ main()