megadetector 5.0.28__py3-none-any.whl → 5.0.29__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of megadetector might be problematic. Click here for more details.

Files changed (176) hide show
  1. megadetector/api/batch_processing/api_core/batch_service/score.py +4 -5
  2. megadetector/api/batch_processing/api_core_support/aggregate_results_manually.py +1 -1
  3. megadetector/api/batch_processing/api_support/summarize_daily_activity.py +1 -1
  4. megadetector/api/batch_processing/integration/digiKam/xmp_integration.py +2 -2
  5. megadetector/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +1 -1
  6. megadetector/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +1 -1
  7. megadetector/api/synchronous/api_core/tests/load_test.py +2 -3
  8. megadetector/classification/aggregate_classifier_probs.py +3 -3
  9. megadetector/classification/analyze_failed_images.py +5 -5
  10. megadetector/classification/cache_batchapi_outputs.py +5 -5
  11. megadetector/classification/create_classification_dataset.py +11 -12
  12. megadetector/classification/crop_detections.py +10 -10
  13. megadetector/classification/csv_to_json.py +8 -8
  14. megadetector/classification/detect_and_crop.py +13 -15
  15. megadetector/classification/evaluate_model.py +7 -7
  16. megadetector/classification/identify_mislabeled_candidates.py +6 -6
  17. megadetector/classification/json_to_azcopy_list.py +1 -1
  18. megadetector/classification/json_validator.py +29 -32
  19. megadetector/classification/map_classification_categories.py +9 -9
  20. megadetector/classification/merge_classification_detection_output.py +12 -9
  21. megadetector/classification/prepare_classification_script.py +19 -19
  22. megadetector/classification/prepare_classification_script_mc.py +23 -23
  23. megadetector/classification/run_classifier.py +4 -4
  24. megadetector/classification/save_mislabeled.py +6 -6
  25. megadetector/classification/train_classifier.py +1 -1
  26. megadetector/classification/train_classifier_tf.py +9 -9
  27. megadetector/classification/train_utils.py +10 -10
  28. megadetector/data_management/annotations/annotation_constants.py +1 -1
  29. megadetector/data_management/camtrap_dp_to_coco.py +45 -45
  30. megadetector/data_management/cct_json_utils.py +101 -101
  31. megadetector/data_management/cct_to_md.py +49 -49
  32. megadetector/data_management/cct_to_wi.py +33 -33
  33. megadetector/data_management/coco_to_labelme.py +75 -75
  34. megadetector/data_management/coco_to_yolo.py +189 -189
  35. megadetector/data_management/databases/add_width_and_height_to_db.py +3 -2
  36. megadetector/data_management/databases/combine_coco_camera_traps_files.py +38 -38
  37. megadetector/data_management/databases/integrity_check_json_db.py +202 -188
  38. megadetector/data_management/databases/subset_json_db.py +33 -33
  39. megadetector/data_management/generate_crops_from_cct.py +38 -38
  40. megadetector/data_management/get_image_sizes.py +54 -49
  41. megadetector/data_management/labelme_to_coco.py +130 -124
  42. megadetector/data_management/labelme_to_yolo.py +78 -72
  43. megadetector/data_management/lila/create_lila_blank_set.py +81 -83
  44. megadetector/data_management/lila/create_lila_test_set.py +32 -31
  45. megadetector/data_management/lila/create_links_to_md_results_files.py +18 -18
  46. megadetector/data_management/lila/download_lila_subset.py +21 -24
  47. megadetector/data_management/lila/generate_lila_per_image_labels.py +91 -91
  48. megadetector/data_management/lila/get_lila_annotation_counts.py +30 -30
  49. megadetector/data_management/lila/get_lila_image_counts.py +22 -22
  50. megadetector/data_management/lila/lila_common.py +70 -70
  51. megadetector/data_management/lila/test_lila_metadata_urls.py +13 -14
  52. megadetector/data_management/mewc_to_md.py +339 -340
  53. megadetector/data_management/ocr_tools.py +258 -252
  54. megadetector/data_management/read_exif.py +231 -224
  55. megadetector/data_management/remap_coco_categories.py +26 -26
  56. megadetector/data_management/remove_exif.py +31 -20
  57. megadetector/data_management/rename_images.py +187 -187
  58. megadetector/data_management/resize_coco_dataset.py +41 -41
  59. megadetector/data_management/speciesnet_to_md.py +41 -41
  60. megadetector/data_management/wi_download_csv_to_coco.py +55 -55
  61. megadetector/data_management/yolo_output_to_md_output.py +117 -120
  62. megadetector/data_management/yolo_to_coco.py +195 -188
  63. megadetector/detection/change_detection.py +831 -0
  64. megadetector/detection/process_video.py +340 -337
  65. megadetector/detection/pytorch_detector.py +304 -262
  66. megadetector/detection/run_detector.py +177 -164
  67. megadetector/detection/run_detector_batch.py +364 -363
  68. megadetector/detection/run_inference_with_yolov5_val.py +328 -325
  69. megadetector/detection/run_tiled_inference.py +256 -249
  70. megadetector/detection/tf_detector.py +24 -24
  71. megadetector/detection/video_utils.py +290 -282
  72. megadetector/postprocessing/add_max_conf.py +15 -11
  73. megadetector/postprocessing/categorize_detections_by_size.py +44 -44
  74. megadetector/postprocessing/classification_postprocessing.py +415 -415
  75. megadetector/postprocessing/combine_batch_outputs.py +20 -21
  76. megadetector/postprocessing/compare_batch_results.py +528 -517
  77. megadetector/postprocessing/convert_output_format.py +97 -97
  78. megadetector/postprocessing/create_crop_folder.py +219 -146
  79. megadetector/postprocessing/detector_calibration.py +173 -168
  80. megadetector/postprocessing/generate_csv_report.py +508 -499
  81. megadetector/postprocessing/load_api_results.py +23 -20
  82. megadetector/postprocessing/md_to_coco.py +129 -98
  83. megadetector/postprocessing/md_to_labelme.py +89 -83
  84. megadetector/postprocessing/md_to_wi.py +40 -40
  85. megadetector/postprocessing/merge_detections.py +87 -114
  86. megadetector/postprocessing/postprocess_batch_results.py +313 -298
  87. megadetector/postprocessing/remap_detection_categories.py +36 -36
  88. megadetector/postprocessing/render_detection_confusion_matrix.py +205 -199
  89. megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py +57 -57
  90. megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +27 -28
  91. megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +702 -677
  92. megadetector/postprocessing/separate_detections_into_folders.py +226 -211
  93. megadetector/postprocessing/subset_json_detector_output.py +265 -262
  94. megadetector/postprocessing/top_folders_to_bottom.py +45 -45
  95. megadetector/postprocessing/validate_batch_results.py +70 -70
  96. megadetector/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +52 -52
  97. megadetector/taxonomy_mapping/map_new_lila_datasets.py +15 -15
  98. megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +14 -14
  99. megadetector/taxonomy_mapping/preview_lila_taxonomy.py +66 -66
  100. megadetector/taxonomy_mapping/retrieve_sample_image.py +16 -16
  101. megadetector/taxonomy_mapping/simple_image_download.py +8 -8
  102. megadetector/taxonomy_mapping/species_lookup.py +33 -33
  103. megadetector/taxonomy_mapping/taxonomy_csv_checker.py +14 -14
  104. megadetector/taxonomy_mapping/taxonomy_graph.py +10 -10
  105. megadetector/taxonomy_mapping/validate_lila_category_mappings.py +13 -13
  106. megadetector/utils/azure_utils.py +22 -22
  107. megadetector/utils/ct_utils.py +1018 -200
  108. megadetector/utils/directory_listing.py +21 -77
  109. megadetector/utils/gpu_test.py +22 -22
  110. megadetector/utils/md_tests.py +541 -518
  111. megadetector/utils/path_utils.py +1457 -398
  112. megadetector/utils/process_utils.py +41 -41
  113. megadetector/utils/sas_blob_utils.py +53 -49
  114. megadetector/utils/split_locations_into_train_val.py +61 -61
  115. megadetector/utils/string_utils.py +147 -26
  116. megadetector/utils/url_utils.py +463 -173
  117. megadetector/utils/wi_utils.py +2629 -2526
  118. megadetector/utils/write_html_image_list.py +137 -137
  119. megadetector/visualization/plot_utils.py +21 -21
  120. megadetector/visualization/render_images_with_thumbnails.py +37 -73
  121. megadetector/visualization/visualization_utils.py +401 -397
  122. megadetector/visualization/visualize_db.py +197 -190
  123. megadetector/visualization/visualize_detector_output.py +79 -73
  124. {megadetector-5.0.28.dist-info → megadetector-5.0.29.dist-info}/METADATA +135 -132
  125. megadetector-5.0.29.dist-info/RECORD +163 -0
  126. {megadetector-5.0.28.dist-info → megadetector-5.0.29.dist-info}/WHEEL +1 -1
  127. {megadetector-5.0.28.dist-info → megadetector-5.0.29.dist-info}/licenses/LICENSE +0 -0
  128. {megadetector-5.0.28.dist-info → megadetector-5.0.29.dist-info}/top_level.txt +0 -0
  129. megadetector/data_management/importers/add_nacti_sizes.py +0 -52
  130. megadetector/data_management/importers/add_timestamps_to_icct.py +0 -79
  131. megadetector/data_management/importers/animl_results_to_md_results.py +0 -158
  132. megadetector/data_management/importers/auckland_doc_test_to_json.py +0 -373
  133. megadetector/data_management/importers/auckland_doc_to_json.py +0 -201
  134. megadetector/data_management/importers/awc_to_json.py +0 -191
  135. megadetector/data_management/importers/bellevue_to_json.py +0 -272
  136. megadetector/data_management/importers/cacophony-thermal-importer.py +0 -793
  137. megadetector/data_management/importers/carrizo_shrubfree_2018.py +0 -269
  138. megadetector/data_management/importers/carrizo_trail_cam_2017.py +0 -289
  139. megadetector/data_management/importers/cct_field_adjustments.py +0 -58
  140. megadetector/data_management/importers/channel_islands_to_cct.py +0 -913
  141. megadetector/data_management/importers/eMammal/copy_and_unzip_emammal.py +0 -180
  142. megadetector/data_management/importers/eMammal/eMammal_helpers.py +0 -249
  143. megadetector/data_management/importers/eMammal/make_eMammal_json.py +0 -223
  144. megadetector/data_management/importers/ena24_to_json.py +0 -276
  145. megadetector/data_management/importers/filenames_to_json.py +0 -386
  146. megadetector/data_management/importers/helena_to_cct.py +0 -283
  147. megadetector/data_management/importers/idaho-camera-traps.py +0 -1407
  148. megadetector/data_management/importers/idfg_iwildcam_lila_prep.py +0 -294
  149. megadetector/data_management/importers/import_desert_lion_conservation_camera_traps.py +0 -387
  150. megadetector/data_management/importers/jb_csv_to_json.py +0 -150
  151. megadetector/data_management/importers/mcgill_to_json.py +0 -250
  152. megadetector/data_management/importers/missouri_to_json.py +0 -490
  153. megadetector/data_management/importers/nacti_fieldname_adjustments.py +0 -79
  154. megadetector/data_management/importers/noaa_seals_2019.py +0 -181
  155. megadetector/data_management/importers/osu-small-animals-to-json.py +0 -364
  156. megadetector/data_management/importers/pc_to_json.py +0 -365
  157. megadetector/data_management/importers/plot_wni_giraffes.py +0 -123
  158. megadetector/data_management/importers/prepare_zsl_imerit.py +0 -131
  159. megadetector/data_management/importers/raic_csv_to_md_results.py +0 -416
  160. megadetector/data_management/importers/rspb_to_json.py +0 -356
  161. megadetector/data_management/importers/save_the_elephants_survey_A.py +0 -320
  162. megadetector/data_management/importers/save_the_elephants_survey_B.py +0 -329
  163. megadetector/data_management/importers/snapshot_safari_importer.py +0 -758
  164. megadetector/data_management/importers/snapshot_serengeti_lila.py +0 -1067
  165. megadetector/data_management/importers/snapshotserengeti/make_full_SS_json.py +0 -150
  166. megadetector/data_management/importers/snapshotserengeti/make_per_season_SS_json.py +0 -153
  167. megadetector/data_management/importers/sulross_get_exif.py +0 -65
  168. megadetector/data_management/importers/timelapse_csv_set_to_json.py +0 -490
  169. megadetector/data_management/importers/ubc_to_json.py +0 -399
  170. megadetector/data_management/importers/umn_to_json.py +0 -507
  171. megadetector/data_management/importers/wellington_to_json.py +0 -263
  172. megadetector/data_management/importers/wi_to_json.py +0 -442
  173. megadetector/data_management/importers/zamba_results_to_md_results.py +0 -180
  174. megadetector/data_management/lila/add_locations_to_island_camera_traps.py +0 -101
  175. megadetector/data_management/lila/add_locations_to_nacti.py +0 -151
  176. megadetector-5.0.28.dist-info/RECORD +0 -209
@@ -5,7 +5,7 @@ cct_to_wi.py
5
5
  Converts COCO Camera Traps .json files to the Wildlife Insights
6
6
  batch upload format.
7
7
 
8
- **This is very much just a demo script; all the relevant constants are hard-coded
8
+ **This is very much just a demo script; all the relevant constants are hard-coded
9
9
  at the top of main().**
10
10
 
11
11
  But given that caveat, it works. You need to set up all the paths in the "paths" cell
@@ -23,42 +23,42 @@ Also see:
23
23
  import os
24
24
  import json
25
25
  import pandas as pd
26
- from collections import defaultdict
26
+ from collections import defaultdict
27
27
 
28
28
 
29
29
  #%% Main wrapper
30
30
 
31
- def main():
31
+ def main(): # noqa
32
32
  """
33
33
  Converts COCO Camera Traps .json files to the Wildlife Insights
34
- batch upload format; to use this, you need to modify all the paths in the "Paths"
34
+ batch upload format; to use this, you need to modify all the paths in the "Paths"
35
35
  cell.
36
36
  """
37
-
37
+
38
38
  #%% Paths
39
39
 
40
40
  # A COCO camera traps file with information about this dataset
41
41
  input_file = r'c:\temp\camera_trap_images_no_people\bellevue_camera_traps.2020-12-26.json'
42
-
43
- # A .json dictionary mapping common names in this dataset to dictionaries with the
42
+
43
+ # A .json dictionary mapping common names in this dataset to dictionaries with the
44
44
  # WI taxonomy fields: common_name, wi_taxon_id, class, order, family, genus, species
45
45
  taxonomy_file = r'c:\temp\camera_trap_images_no_people\bellevue_camera_traps_to_wi.json'
46
46
 
47
47
  # The folder where the .csv template files live
48
48
  templates_dir = r'c:\temp\wi_batch_upload_templates'
49
-
49
+
50
50
  # The folder to which you want to write WI-formatted .csv files
51
51
  output_base = r'c:\temp\wi_output'
52
-
53
-
52
+
53
+
54
54
  #%% Path validation
55
-
55
+
56
56
  assert os.path.isfile(input_file)
57
57
  assert os.path.isfile(taxonomy_file)
58
58
  assert os.path.isdir(templates_dir)
59
59
  os.makedirs(output_base,exist_ok = True)
60
60
 
61
-
61
+
62
62
  #%% Constants
63
63
 
64
64
  projects_file_name = 'Template Wildlife Insights Batch Upload - Projectv1.0.csv'
@@ -99,7 +99,7 @@ def main():
99
99
  project_info['project_sensor_cluster'] = 'No'
100
100
 
101
101
  camera_info = {}
102
- camera_info['project_id'] = project_info['project_id']
102
+ camera_info['project_id'] = project_info['project_id']
103
103
  camera_info['camera_id'] = '0000'
104
104
  camera_info['make'] = ''
105
105
  camera_info['model'] = ''
@@ -108,7 +108,7 @@ def main():
108
108
 
109
109
  deployment_info = {}
110
110
 
111
- deployment_info['project_id'] = project_info['project_id']
111
+ deployment_info['project_id'] = project_info['project_id']
112
112
  deployment_info['deployment_id'] = 'test_deployment'
113
113
  deployment_info['subproject_name'] = 'test_subproject'
114
114
  deployment_info['subproject_design'] = ''
@@ -140,7 +140,7 @@ def main():
140
140
  #%% Read templates
141
141
 
142
142
  def parse_fields(templates_dir,file_name):
143
-
143
+
144
144
  with open(os.path.join(templates_dir,file_name),'r') as f:
145
145
  lines = f.readlines()
146
146
  lines = [s.strip() for s in lines if len(s.strip().replace(',','')) > 0]
@@ -158,7 +158,7 @@ def main():
158
158
  #%% Compare dictionary to template lists
159
159
 
160
160
  def compare_info_to_template(info,template_fields,name):
161
-
161
+
162
162
  for s in info.keys():
163
163
  assert s in template_fields,'Field {} not specified in {}_fields'.format(s,name)
164
164
  for s in template_fields:
@@ -166,26 +166,26 @@ def main():
166
166
 
167
167
 
168
168
  def write_table(file_name,info,template_fields):
169
-
169
+
170
170
  assert len(info) == len(template_fields)
171
-
171
+
172
172
  project_output_file = os.path.join(output_base,file_name)
173
173
  with open(project_output_file,'w') as f:
174
-
174
+
175
175
  # Write the header
176
176
  for i_field,s in enumerate(template_fields):
177
177
  f.write(s)
178
178
  if i_field != len(template_fields)-1:
179
179
  f.write(',')
180
180
  f.write('\n')
181
-
181
+
182
182
  # Write values
183
183
  for i_field,s in enumerate(template_fields):
184
184
  f.write(info[s])
185
185
  if i_field != len(template_fields)-1:
186
186
  f.write(',')
187
187
  f.write('\n')
188
-
188
+
189
189
 
190
190
  #%% Project file
191
191
 
@@ -214,7 +214,7 @@ def main():
214
214
  # Read taxonomy dictionary
215
215
  with open(taxonomy_file,'r') as f:
216
216
  taxonomy_mapping = json.load(f)
217
-
217
+
218
218
  url_base = taxonomy_mapping['url_base']
219
219
  taxonomy_mapping = taxonomy_mapping['taxonomy']
220
220
 
@@ -226,7 +226,7 @@ def main():
226
226
  image_id_to_annotations = defaultdict(list)
227
227
 
228
228
  annotations = input_data['annotations']
229
-
229
+
230
230
  # annotation = annotations[0]
231
231
  for annotation in annotations:
232
232
  image_id_to_annotations[annotation['image_id']].append(
@@ -238,31 +238,31 @@ def main():
238
238
  for im in input_data['images']:
239
239
 
240
240
  row = {}
241
-
241
+
242
242
  url = url_base + im['file_name'].replace('\\','/')
243
243
  row['project_id'] = project_info['project_id']
244
244
  row['deployment_id'] = deployment_info['deployment_id']
245
245
  row['image_id'] = im['id']
246
246
  row['location'] = url
247
247
  row['identified_by'] = image_info['identified_by']
248
-
248
+
249
249
  category_names = image_id_to_annotations[im['id']]
250
250
  assert len(category_names) == 1
251
251
  category_name = category_names[0]
252
-
252
+
253
253
  taxon_info = taxonomy_mapping[category_name]
254
-
254
+
255
255
  assert len(taxon_info.keys()) == 7
256
-
256
+
257
257
  for s in taxon_info.keys():
258
- row[s] = taxon_info[s]
259
-
258
+ row[s] = taxon_info[s]
259
+
260
260
  # We don't have counts, but we can differentiate between zero and 1
261
261
  if category_name == 'empty':
262
262
  row['number_of_objects'] = 0
263
263
  else:
264
264
  row['number_of_objects'] = 1
265
-
265
+
266
266
  row['uncertainty'] = None
267
267
  row['timestamp'] = im['datetime']; assert isinstance(im['datetime'],str)
268
268
  row['highlighted'] = 0
@@ -272,10 +272,10 @@ def main():
272
272
  row['individual_id'] = None
273
273
  row['individual_animal_notes'] = None
274
274
  row['markings'] = None
275
-
275
+
276
276
  assert len(row) == len(images_fields)
277
277
  rows.append(row)
278
-
278
+
279
279
  df = pd.DataFrame(rows)
280
280
 
281
281
  df.to_csv(os.path.join(output_base,images_file_name),index=False)
@@ -4,7 +4,7 @@ coco_to_labelme.py
4
4
 
5
5
  Converts a COCO dataset to labelme format (one .json per image file).
6
6
 
7
- If you want to convert YOLO-formatted data to labelme format, use yolo_to_coco, then
7
+ If you want to convert YOLO-formatted data to labelme format, use yolo_to_coco, then
8
8
  coco_to_labelme.
9
9
 
10
10
  """
@@ -13,34 +13,37 @@ coco_to_labelme.
13
13
 
14
14
  import os
15
15
  import json
16
+ import sys
17
+ import argparse
16
18
 
17
19
  from tqdm import tqdm
18
20
  from collections import defaultdict
19
21
 
20
22
  from megadetector.visualization.visualization_utils import open_image
21
23
  from megadetector.detection.run_detector import FAILURE_IMAGE_OPEN
24
+ from megadetector.utils import ct_utils
22
25
 
23
26
 
24
27
  #%% Functions
25
28
 
26
29
  def get_labelme_dict_for_image_from_coco_record(im,annotations,categories,info=None):
27
30
  """
28
- For the given image struct in COCO format and associated list of annotations, reformats the
29
- detections into labelme format.
30
-
31
+ For the given image struct in COCO format and associated list of annotations, reformats the
32
+ detections into labelme format.
33
+
31
34
  Args:
32
35
  im (dict): image dict, as loaded from a COCO .json file; 'height' and 'width' are required
33
- annotations (list): a list of annotations that refer to this image (this function errors if
36
+ annotations (list): a list of annotations that refer to this image (this function errors if
34
37
  that's not the case)
35
38
  categories (list): a list of category in dicts in COCO format ({'id':x,'name':'s'})
36
39
  info (dict, optional): a dict to store in a non-standard "custom_info" field in the output
37
-
40
+
38
41
  Returns:
39
42
  dict: a dict in labelme format, suitable for writing to a labelme .json file
40
43
  """
41
-
44
+
42
45
  image_base_name = os.path.basename(im['file_name'])
43
-
46
+
44
47
  output_dict = {}
45
48
  if info is not None:
46
49
  output_dict['custom_info'] = info
@@ -51,43 +54,43 @@ def get_labelme_dict_for_image_from_coco_record(im,annotations,categories,info=N
51
54
  output_dict['imageHeight'] = im['height']
52
55
  output_dict['imageWidth'] = im['width']
53
56
  output_dict['imageData'] = None
54
-
57
+
55
58
  # Store COCO categories in case we want to reconstruct the original IDs later
56
59
  output_dict['coco_categories'] = categories
57
-
60
+
58
61
  category_id_to_name = {c['id']:c['name'] for c in categories}
59
-
62
+
60
63
  if 'flags' in im:
61
64
  output_dict['flags'] = im['flags']
62
-
65
+
63
66
  # ann = annotations[0]
64
67
  for ann in annotations:
65
-
68
+
66
69
  assert ann['image_id'] == im['id'], 'Annotation {} does not refer to image {}'.format(
67
70
  ann['id'],im['id'])
68
-
71
+
69
72
  if 'bbox' not in ann:
70
73
  continue
71
-
74
+
72
75
  shape = {}
73
- shape['label'] = category_id_to_name[ann['category_id']]
76
+ shape['label'] = category_id_to_name[ann['category_id']]
74
77
  shape['shape_type'] = 'rectangle'
75
78
  shape['description'] = ''
76
79
  shape['group_id'] = None
77
-
80
+
78
81
  # COCO boxes are [x_min, y_min, width_of_box, height_of_box] (absolute)
79
- #
82
+ #
80
83
  # labelme boxes are [[x0,y0],[x1,y1]] (absolute)
81
84
  x0 = ann['bbox'][0]
82
85
  y0 = ann['bbox'][1]
83
86
  x1 = ann['bbox'][0] + ann['bbox'][2]
84
87
  y1 = ann['bbox'][1] + ann['bbox'][3]
85
-
88
+
86
89
  shape['points'] = [[x0,y0],[x1,y1]]
87
90
  output_dict['shapes'].append(shape)
88
-
91
+
89
92
  # ...for each detection
90
-
93
+
91
94
  return output_dict
92
95
 
93
96
  # ...def get_labelme_dict_for_image()
@@ -95,9 +98,9 @@ def get_labelme_dict_for_image_from_coco_record(im,annotations,categories,info=N
95
98
 
96
99
  def coco_to_labelme(coco_data,image_base,overwrite=False,bypass_image_size_check=False,verbose=False):
97
100
  """
98
- For all the images in [coco_data] (a dict or a filename), write a .json file in
101
+ For all the images in [coco_data] (a dict or a filename), write a .json file in
99
102
  labelme format alongside the corresponding relative path within image_base.
100
-
103
+
101
104
  Args:
102
105
  coco_data (dict or str): path to a COCO-formatted .json file, or an already-loaded
103
106
  COCO-formatted dict
@@ -105,40 +108,40 @@ def coco_to_labelme(coco_data,image_base,overwrite=False,bypass_image_size_check
105
108
  [image_base]); this is also where labelme files will be written
106
109
  overwrite (bool, optional): overwrite existing .json files
107
110
  bypass_image_size_check (bool, optional): if you're sure that the COCO data already has
108
- correct 'width' and 'height' fields, this bypasses the somewhat-slow loading of
111
+ correct 'width' and 'height' fields, this bypasses the somewhat-slow loading of
109
112
  each image to fetch image sizes
110
113
  verbose (bool, optional): enable additional debug output
111
114
  """
112
-
115
+
113
116
  # Load COCO data if necessary
114
117
  if isinstance(coco_data,str):
115
118
  with open(coco_data,'r') as f:
116
119
  coco_data = json.load(f)
117
120
  assert isinstance(coco_data,dict)
118
-
119
-
121
+
122
+
120
123
  ## Read image sizes if necessary
121
-
124
+
122
125
  if bypass_image_size_check:
123
-
126
+
124
127
  print('Bypassing size check')
125
-
128
+
126
129
  else:
127
-
130
+
128
131
  # TODO: parallelize this loop
129
-
132
+
130
133
  print('Reading/validating image sizes...')
131
-
134
+
132
135
  # im = coco_data['images'][0]
133
136
  for im in tqdm(coco_data['images']):
134
-
137
+
135
138
  # Make sure this file exists
136
139
  im_full_path = os.path.join(image_base,im['file_name'])
137
140
  assert os.path.isfile(im_full_path), 'Image file {} does not exist'.format(im_full_path)
138
-
141
+
139
142
  # Load w/h information if necessary
140
143
  if 'height' not in im or 'width' not in im:
141
-
144
+
142
145
  try:
143
146
  pil_im = open_image(im_full_path)
144
147
  im['width'] = pil_im.width
@@ -147,32 +150,32 @@ def coco_to_labelme(coco_data,image_base,overwrite=False,bypass_image_size_check
147
150
  print('Warning: cannot open image {}'.format(im_full_path))
148
151
  if 'failure' not in im:
149
152
  im['failure'] = FAILURE_IMAGE_OPEN
150
-
153
+
151
154
  # ...if we need to read w/h information
152
-
155
+
153
156
  # ...for each image
154
-
157
+
155
158
  # ...if we need to load image sizes
156
-
157
-
159
+
160
+
158
161
  ## Generate labelme files
159
-
162
+
160
163
  print('Generating .json files...')
161
-
164
+
162
165
  image_id_to_annotations = defaultdict(list)
163
166
  for ann in coco_data['annotations']:
164
167
  image_id_to_annotations[ann['image_id']].append(ann)
165
-
168
+
166
169
  n_json_files_written = 0
167
170
  n_json_files_error = 0
168
171
  n_json_files_exist = 0
169
-
172
+
170
173
  # Write output
171
174
  for im in tqdm(coco_data['images']):
172
-
175
+
173
176
  # Skip this image if it failed to load in whatever system generated this COCO file
174
177
  skip_image = False
175
-
178
+
176
179
  # Errors are represented differently depending on the source
177
180
  for error_string in ('failure','error'):
178
181
  if (error_string in im) and (im[error_string] is not None):
@@ -184,89 +187,86 @@ def coco_to_labelme(coco_data,image_base,overwrite=False,bypass_image_size_check
184
187
  break
185
188
  if skip_image:
186
189
  continue
187
-
190
+
188
191
  im_full_path = os.path.join(image_base,im['file_name'])
189
192
  json_path = os.path.splitext(im_full_path)[0] + '.json'
190
-
193
+
191
194
  if (not overwrite) and (os.path.isfile(json_path)):
192
195
  if verbose:
193
196
  print('Skipping existing file {}'.format(json_path))
194
197
  n_json_files_exist += 1
195
198
  continue
196
-
199
+
197
200
  annotations_this_image = image_id_to_annotations[im['id']]
198
201
  output_dict = get_labelme_dict_for_image_from_coco_record(im,
199
202
  annotations_this_image,
200
203
  coco_data['categories'],
201
204
  info=None)
202
-
205
+
203
206
  n_json_files_written += 1
204
- with open(json_path,'w') as f:
205
- json.dump(output_dict,f,indent=1)
206
-
207
+ ct_utils.write_json(json_path, output_dict)
208
+
207
209
  # ...for each image
208
-
210
+
209
211
  print('\nWrote {} .json files (skipped {} for errors, {} because they exist)'.format(
210
212
  n_json_files_written,n_json_files_error,n_json_files_exist))
211
-
213
+
212
214
  # ...def coco_to_labelme()
213
215
 
214
216
 
215
217
  #%% Interactive driver
216
218
 
217
219
  if False:
218
-
220
+
219
221
  pass
220
222
 
221
223
  #%% Configure options
222
-
224
+
223
225
  coco_file = \
224
226
  r'C:\\temp\\snapshot-exploration\\images\\training-images-good\\training-images-good_from_yolo.json'
225
- image_folder = os.path.dirname(coco_file)
226
- overwrite = True
227
-
228
-
227
+ image_folder = os.path.dirname(coco_file)
228
+ overwrite = True
229
+
230
+
229
231
  #%% Programmatic execution
230
-
232
+
231
233
  coco_to_labelme(coco_data=coco_file,image_base=image_folder,overwrite=overwrite)
232
234
 
233
-
235
+
234
236
  #%% Command-line execution
235
-
237
+
236
238
  s = 'python coco_to_labelme.py "{}" "{}"'.format(coco_file,image_folder)
237
239
  if overwrite:
238
240
  s += ' --overwrite'
239
-
241
+
240
242
  print(s)
241
243
  import clipboard; clipboard.copy(s)
242
244
 
243
245
 
244
246
  #%% Opening labelme
245
-
247
+
246
248
  s = 'python labelme {}'.format(image_folder)
247
249
  print(s)
248
250
  import clipboard; clipboard.copy(s)
249
-
250
251
 
251
- #%% Command-line driver
252
252
 
253
- import sys,argparse
253
+ #%% Command-line driver
254
254
 
255
- def main():
255
+ def main(): # noqa
256
256
 
257
257
  parser = argparse.ArgumentParser(
258
258
  description='Convert a COCO database to labelme annotation format')
259
-
259
+
260
260
  parser.add_argument(
261
261
  'coco_file',
262
262
  type=str,
263
263
  help='Path to COCO data file (.json)')
264
-
264
+
265
265
  parser.add_argument(
266
266
  'image_base',
267
267
  type=str,
268
268
  help='Path to images (also the output folder)')
269
-
269
+
270
270
  parser.add_argument(
271
271
  '--overwrite',
272
272
  action='store_true',
@@ -278,7 +278,7 @@ def main():
278
278
 
279
279
  args = parser.parse_args()
280
280
 
281
- coco_to_labelme(coco_data=args.coco_file,image_base=args.image_base,overwrite=args.overwrite)
281
+ coco_to_labelme(coco_data=args.coco_file,image_base=args.image_base,overwrite=args.overwrite)
282
282
 
283
283
  if __name__ == '__main__':
284
284
  main()