megadetector 5.0.9__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.9.dist-info → megadetector-5.0.11.dist-info}/LICENSE +0 -0
  2. {megadetector-5.0.9.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.9.dist-info/RECORD +0 -224
  214. megadetector-5.0.9.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.9.dist-info → megadetector-5.0.11.dist-info}/WHEEL +0 -0
@@ -1,548 +0,0 @@
1
- """
2
-
3
- labelme_to_coco.py
4
-
5
- Converts a folder of labelme-formatted .json files to COCO.
6
-
7
- """
8
-
9
- #%% Constants and imports
10
-
11
- import json
12
- import os
13
- import uuid
14
-
15
- from md_utils import path_utils
16
- from md_visualization.visualization_utils import open_image
17
-
18
- from multiprocessing.pool import Pool, ThreadPool
19
- from functools import partial
20
-
21
- from tqdm import tqdm
22
-
23
-
24
- #%% Support functions
25
-
26
- def _add_category(category_name,category_name_to_id,candidate_category_id=0):
27
- """
28
- Adds the category [category_name] to the dict [category_name_to_id], by default
29
- using the next available integer index.
30
- """
31
-
32
- if category_name in category_name_to_id:
33
- return category_name_to_id[category_name]
34
- while candidate_category_id in category_name_to_id.values():
35
- candidate_category_id += 1
36
- category_name_to_id[category_name] = candidate_category_id
37
- return candidate_category_id
38
-
39
-
40
- def _process_labelme_file(image_fn_relative,input_folder,use_folders_as_labels,
41
- no_json_handling,validate_image_sizes,
42
- category_name_to_id,allow_new_categories=True):
43
- """
44
- Internal function for processing each image; this support function facilitates parallelization.
45
- """
46
-
47
- result = {}
48
- result['im'] = None
49
- result['annotations_this_image'] = None
50
- result['status'] = None
51
-
52
- image_fn_abs = os.path.join(input_folder,image_fn_relative)
53
- json_fn_abs = os.path.splitext(image_fn_abs)[0] + '.json'
54
-
55
- im = {}
56
- im['id'] = image_fn_relative
57
- im['file_name'] = image_fn_relative
58
-
59
- # If there's no .json file for this image...
60
- if not os.path.isfile(json_fn_abs):
61
-
62
- # Either skip it...
63
- if no_json_handling == 'skip':
64
- print('Skipping image {} (no .json file)'.format(image_fn_relative))
65
- result['status'] = 'skipped (no .json file)'
66
- return result
67
-
68
- # ...or error
69
- elif no_json_handling == 'error':
70
- raise ValueError('Image file {} has no corresponding .json file'.format(
71
- image_fn_relative))
72
-
73
- # ...or treat it as empty.
74
- elif no_json_handling == 'empty':
75
- try:
76
- pil_im = open_image(image_fn_abs)
77
- except Exception:
78
- print('Warning: error opening image {}, skipping'.format(image_fn_abs))
79
- result['status'] = 'image load error'
80
- return result
81
- im['width'] = pil_im.width
82
- im['height'] = pil_im.height
83
-
84
- # Just in case we need to differentiate between "no .json file" and "a .json file with no annotations"
85
- im['no_labelme_json'] = True
86
- shapes = []
87
- else:
88
- raise ValueError('Unrecognized specifier {} for handling images with no .json files'.format(
89
- no_json_handling))
90
-
91
- # If we found a .json file for this image...
92
- else:
93
-
94
- # Read the .json file
95
- with open(json_fn_abs,'r') as f:
96
- labelme_data = json.load(f)
97
- im['width'] = labelme_data['imageWidth']
98
- im['height'] = labelme_data['imageHeight']
99
-
100
- if validate_image_sizes:
101
- try:
102
- pil_im = open_image(image_fn_abs)
103
- except Exception:
104
- print('Warning: error opening image {} for size validation, skipping'.format(image_fn_abs))
105
- result['status'] = 'skipped (size validation error)'
106
- return result
107
- if not (im['width'] == pil_im.width and im['height'] == pil_im.height):
108
- print('Warning: image size validation error for file {}'.format(image_fn_relative))
109
- im['width'] = pil_im.width
110
- im['height'] = pil_im.height
111
- im['labelme_width'] = labelme_data['imageWidth']
112
- im['labelme_height'] = labelme_data['imageHeight']
113
-
114
- shapes = labelme_data['shapes']
115
-
116
- if ('flags' in labelme_data) and (len(labelme_data['flags']) > 0):
117
- im['flags'] = labelme_data['flags']
118
-
119
- annotations_this_image = []
120
-
121
- if len(shapes) == 0:
122
-
123
- if allow_new_categories:
124
- category_id = _add_category('empty',category_name_to_id)
125
- else:
126
- assert 'empty' in category_name_to_id
127
- category_id = category_name_to_id['empty']
128
-
129
- ann = {}
130
- ann['id'] = str(uuid.uuid1())
131
- ann['image_id'] = im['id']
132
- ann['category_id'] = category_id
133
- ann['sequence_level_annotation'] = False
134
- annotations_this_image.append(ann)
135
-
136
- else:
137
-
138
- for shape in shapes:
139
-
140
- if shape['shape_type'] != 'rectangle':
141
- print('Only rectangles are supported, skipping an annotation of type {} in {}'.format(
142
- shape['shape_type'],image_fn_relative))
143
- continue
144
-
145
- if use_folders_as_labels:
146
- category_name = os.path.basename(os.path.dirname(image_fn_abs))
147
- else:
148
- category_name = shape['label']
149
-
150
- if allow_new_categories:
151
- category_id = _add_category(category_name,category_name_to_id)
152
- else:
153
- assert category_name in category_name_to_id
154
- category_id = category_name_to_id[category_name]
155
-
156
- points = shape['points']
157
- if len(points) != 2:
158
- print('Warning: illegal rectangle with {} points for {}'.format(
159
- len(points),image_fn_relative))
160
- continue
161
-
162
- p0 = points[0]
163
- p1 = points[1]
164
- x0 = min(p0[0],p1[0])
165
- x1 = max(p0[0],p1[0])
166
- y0 = min(p0[1],p1[1])
167
- y1 = max(p0[1],p1[1])
168
-
169
- bbox = [x0,y0,abs(x1-x0),abs(y1-y0)]
170
- ann = {}
171
- ann['id'] = str(uuid.uuid1())
172
- ann['image_id'] = im['id']
173
- ann['category_id'] = category_id
174
- ann['sequence_level_annotation'] = False
175
- ann['bbox'] = bbox
176
- annotations_this_image.append(ann)
177
-
178
- # ...for each shape
179
-
180
- result['im'] = im
181
- result['annotations_this_image'] = annotations_this_image
182
-
183
- return result
184
-
185
- # ...def _process_labelme_file(...)
186
-
187
-
188
- #%% Main function
189
-
190
- def labelme_to_coco(input_folder,
191
- output_file=None,
192
- category_id_to_category_name=None,
193
- empty_category_name='empty',
194
- empty_category_id=None,
195
- info_struct=None,
196
- relative_paths_to_include=None,
197
- relative_paths_to_exclude=None,
198
- use_folders_as_labels=False,
199
- recursive=True,
200
- no_json_handling='skip',
201
- validate_image_sizes=True,
202
- max_workers=1,
203
- use_threads=True):
204
- """
205
- Finds all images in [input_folder] that have corresponding .json files, and converts
206
- to a COCO .json file.
207
-
208
- Currently only supports bounding box annotations and image-level flags (i.e., does not
209
- support point or general polygon annotations).
210
-
211
- Labelme's image-level flags don't quite fit the COCO annotations format, so they are attached
212
- to image objects, rather than annotation objects.
213
-
214
- If output_file is None, just returns the resulting dict, does not write to file.
215
-
216
- if use_folders_as_labels is False (default), the output labels come from the labelme
217
- .json files. If use_folders_as_labels is True, the lowest-level folder name containing
218
- each .json file will determine the output label. E.g., if use_folders_as_labels is True,
219
- and the folder contains:
220
-
221
- images/train/lion/image0001.json
222
-
223
- ...all boxes in image0001.json will be given the label "lion", regardless of the labels in the
224
- file. Empty images in the "lion" folder will still be given the label "empty" (or
225
- [empty_category_name]).
226
-
227
- Args:
228
- input_folder (str): input folder to search for images and Labelme .json files
229
- output_file (str, optional): output file to which we should write COCO-formatted data; if None
230
- this function just returns the COCO-formatted dict
231
- category_id_to_category_name (dict, optional): dict mapping category IDs to category names;
232
- really used to map Labelme category names to COCO category IDs. IDs will be auto-generated
233
- if this is None.
234
- empty_category_id (int, optional): category ID to use for the not-very-COCO-like "empty" category;
235
- also see the no_json_handling parameter.
236
- info_struct (dict, optional): dict to stash in the "info" field of the resulting COCO dict
237
- relative_paths_to_include (list, optional): allowlist of relative paths to include in the COCO
238
- dict; there's no reason to specify this along with relative_paths_to_exclude.
239
- relative_paths_to_exclude (list, optional): blocklist of relative paths to exclude from the COCO
240
- dict; there's no reason to specify this along with relative_paths_to_include.
241
- use_folders_as_labels (bool, optional): if this is True, class names will be pulled from folder names,
242
- useful if you have images like a/b/cat/image001.jpg, a/b/dog/image002.jpg, etc.
243
- recursive (bool, optional): whether to recurse into [input_folder]
244
- no_json_handling (str, optional): how to deal with image files that have no corresponding .json files,
245
- can be:
246
-
247
- - 'skip': ignore image files with no corresponding .json files
248
- - 'empty': treat image files with no corresponding .json files as empty
249
- - 'error': throw an error when an image file has no corresponding .json file
250
- validate_image_sizes (bool, optional): whether to load images to verify that the sizes specified
251
- in the labelme files are correct
252
- max_workers (int, optional): number of workers to use for parallelization, set to <=1 to disable
253
- parallelization
254
- use_threads (bool, optional): whether to use threads (True) or processes (False) for parallelization,
255
- not relevant if max_workers <= 1
256
-
257
- Returns:
258
- dict: a COCO-formatted dictionary, identical to what's written to [output_file] if [output_file] is not None.
259
- """
260
-
261
- if max_workers > 1:
262
- assert category_id_to_category_name is not None, \
263
- 'When parallelizing labelme --> COCO conversion, you must supply a category mapping'
264
-
265
- if category_id_to_category_name is None:
266
- category_name_to_id = {}
267
- else:
268
- category_name_to_id = {v: k for k, v in category_id_to_category_name.items()}
269
- for category_name in category_name_to_id:
270
- try:
271
- category_name_to_id[category_name] = int(category_name_to_id[category_name])
272
- except ValueError:
273
- raise ValueError('Category IDs must be ints or string-formatted ints')
274
-
275
- # If the user supplied an explicit empty category ID, and the empty category
276
- # name is already in category_name_to_id, make sure they match.
277
- if empty_category_id is not None:
278
- if empty_category_name in category_name_to_id:
279
- assert category_name_to_id[empty_category_name] == empty_category_id, \
280
- 'Ambiguous empty category specification'
281
- if empty_category_id in category_id_to_category_name:
282
- assert category_id_to_category_name[empty_category_id] == empty_category_name, \
283
- 'Ambiguous empty category specification'
284
- else:
285
- if empty_category_name in category_name_to_id:
286
- empty_category_id = category_name_to_id[empty_category_name]
287
-
288
- del category_id_to_category_name
289
-
290
- # Enumerate images
291
- print('Enumerating images in {}'.format(input_folder))
292
- image_filenames_relative = path_utils.find_images(input_folder,recursive=recursive,
293
- return_relative_paths=True,
294
- convert_slashes=True)
295
-
296
- # Remove any images we're supposed to skip
297
- if (relative_paths_to_include is not None) or (relative_paths_to_exclude is not None):
298
- image_filenames_relative_to_process = []
299
- for image_fn_relative in image_filenames_relative:
300
- if relative_paths_to_include is not None and image_fn_relative not in relative_paths_to_include:
301
- continue
302
- if relative_paths_to_exclude is not None and image_fn_relative in relative_paths_to_exclude:
303
- continue
304
- image_filenames_relative_to_process.append(image_fn_relative)
305
- print('Processing {} of {} images'.format(
306
- len(image_filenames_relative_to_process),
307
- len(image_filenames_relative)))
308
- image_filenames_relative = image_filenames_relative_to_process
309
-
310
- # If the user supplied a category ID to use for empty images...
311
- if empty_category_id is not None:
312
- try:
313
- empty_category_id = int(empty_category_id)
314
- except ValueError:
315
- raise ValueError('Category IDs must be ints or string-formatted ints')
316
-
317
- if empty_category_id is None:
318
- empty_category_id = _add_category(empty_category_name,category_name_to_id)
319
-
320
- if max_workers <= 1:
321
-
322
- image_results = []
323
- for image_fn_relative in tqdm(image_filenames_relative):
324
-
325
- result = _process_labelme_file(image_fn_relative,input_folder,use_folders_as_labels,
326
- no_json_handling,validate_image_sizes,
327
- category_name_to_id,allow_new_categories=True)
328
- image_results.append(result)
329
-
330
- else:
331
-
332
- n_workers = min(max_workers,len(image_filenames_relative))
333
- assert category_name_to_id is not None
334
-
335
- if use_threads:
336
- pool = ThreadPool(n_workers)
337
- else:
338
- pool = Pool(n_workers)
339
-
340
- image_results = list(tqdm(pool.imap(
341
- partial(_process_labelme_file,
342
- input_folder=input_folder,
343
- use_folders_as_labels=use_folders_as_labels,
344
- no_json_handling=no_json_handling,
345
- validate_image_sizes=validate_image_sizes,
346
- category_name_to_id=category_name_to_id,
347
- allow_new_categories=False
348
- ),image_filenames_relative), total=len(image_filenames_relative)))
349
-
350
- images = []
351
- annotations = []
352
-
353
- # Flatten the lists of images and annotations
354
- for result in image_results:
355
- im = result['im']
356
- annotations_this_image = result['annotations_this_image']
357
-
358
- if im is None:
359
- assert annotations_this_image is None
360
- else:
361
- images.append(im)
362
- annotations.extend(annotations_this_image)
363
-
364
- output_dict = {}
365
- output_dict['images'] = images
366
- output_dict['annotations'] = annotations
367
-
368
- if info_struct is None:
369
- info_struct = {}
370
- if 'description' not in info_struct:
371
- info_struct['description'] = \
372
- 'Converted to COCO from labelme annotations in folder {}'.format(input_folder)
373
- if 'version' not in info_struct:
374
- info_struct['version'] = 1.0
375
-
376
- output_dict['info'] = info_struct
377
- categories = []
378
- for category_name in category_name_to_id:
379
- categories.append({'name':category_name,'id':category_name_to_id[category_name]})
380
- output_dict['categories'] = categories
381
-
382
- if output_file is not None:
383
- with open(output_file,'w') as f:
384
- json.dump(output_dict,f,indent=1)
385
-
386
- return output_dict
387
-
388
- # ...def labelme_to_coco()
389
-
390
-
391
- def find_empty_labelme_files(input_folder,recursive=True):
392
- """
393
- Returns a list of all image files in in [input_folder] associated with .json files that have
394
- no boxes in them. Also returns a list of images with no associated .json files. Specifically,
395
- returns a dict:
396
-
397
- .. code-block: none
398
-
399
- {
400
- 'images_with_empty_json_files':[list],
401
- 'images_with_no_json_files':[list],
402
- 'images_with_non_empty_json_files':[list]
403
- }
404
-
405
- Args:
406
- input_folder (str): the folder to search for empty (i.e., box-less) Labelme .json files
407
- recursive (bool, optional): whether to recurse into [input_folder]
408
-
409
- Returns:
410
- dict: a dict with fields:
411
- - images_with_empty_json_files: a list of all image files in [input_folder] associated with
412
- .json files that have no boxes in them
413
- - images_with_no_json_files: a list of images in [input_folder] with no associated .json files
414
- - images_with_non_empty_json_files: a list of images in [input_folder] associated with .json
415
- files that have at least one box
416
- """
417
- image_filenames_relative = path_utils.find_images(input_folder,recursive=True,
418
- return_relative_paths=True)
419
-
420
- images_with_empty_json_files = []
421
- images_with_no_json_files = []
422
- images_with_non_empty_json_files = []
423
-
424
- # fn_relative = image_filenames_relative[0]
425
- for fn_relative in image_filenames_relative:
426
-
427
- image_fn_abs = os.path.join(input_folder,fn_relative)
428
- json_fn_abs = os.path.splitext(image_fn_abs)[0] + '.json'
429
-
430
- if not os.path.isfile(json_fn_abs):
431
- images_with_no_json_files.append(fn_relative)
432
- continue
433
-
434
- else:
435
- # Read the .json file
436
- with open(json_fn_abs,'r') as f:
437
- labelme_data = json.load(f)
438
- shapes = labelme_data['shapes']
439
- if len(shapes) == 0:
440
- images_with_empty_json_files.append(fn_relative)
441
- else:
442
- images_with_non_empty_json_files.append(fn_relative)
443
-
444
- # ...for every image
445
-
446
- return {'images_with_empty_json_files':images_with_empty_json_files,
447
- 'images_with_no_json_files':images_with_no_json_files,
448
- 'images_with_non_empty_json_files':images_with_non_empty_json_files}
449
-
450
- # ...def find_empty_labelme_files(...)
451
-
452
-
453
- #%% Interactive driver
454
-
455
- if False:
456
-
457
- pass
458
-
459
- #%% Options
460
-
461
- empty_category_name = 'empty'
462
- empty_category_id = None
463
- category_id_to_category_name = None
464
- info_struct = None
465
-
466
- input_folder = os.path.expanduser('~/data/md-test')
467
- output_file = os.path.expanduser('~/data/md-test-labelme-to-coco.json')
468
-
469
-
470
- #%% Programmatic execution
471
-
472
- output_dict = labelme_to_coco(input_folder,output_file,
473
- category_id_to_category_name=category_id_to_category_name,
474
- empty_category_name=empty_category_name,
475
- empty_category_id=empty_category_id,
476
- info_struct=None,
477
- use_folders_as_labels=False,
478
- validate_image_sizes=False,
479
- no_json_handling='empty')
480
-
481
-
482
- #%% Validate
483
-
484
- from data_management.databases import integrity_check_json_db
485
-
486
- options = integrity_check_json_db.IntegrityCheckOptions()
487
-
488
- options.baseDir = input_folder
489
- options.bCheckImageSizes = True
490
- options.bCheckImageExistence = True
491
- options.bFindUnusedImages = True
492
- options.bRequireLocation = False
493
-
494
- sortedCategories, _, errorInfo = integrity_check_json_db.integrity_check_json_db(output_file,options)
495
-
496
-
497
- #%% Preview
498
-
499
- from md_visualization import visualize_db
500
- options = visualize_db.DbVizOptions()
501
- options.parallelize_rendering = True
502
- options.viz_size = (900, -1)
503
- options.num_to_visualize = 5000
504
-
505
- html_file,_ = visualize_db.visualize_db(output_file,os.path.expanduser('~/tmp/labelme_to_coco_preview'),
506
- input_folder,options)
507
-
508
-
509
- from md_utils import path_utils # noqa
510
- path_utils.open_file(html_file)
511
-
512
-
513
- #%% Prepare command line
514
-
515
- s = 'python labelme_to_coco.py {} {}'.format(input_folder,output_file)
516
- print(s)
517
- import clipboard; clipboard.copy(s)
518
-
519
-
520
- #%% Command-line driver
521
-
522
- import sys,argparse
523
-
524
- def main():
525
-
526
- parser = argparse.ArgumentParser(
527
- description='Convert labelme-formatted data to COCO')
528
-
529
- parser.add_argument(
530
- 'input_folder',
531
- type=str,
532
- help='Path to images and .json annotation files')
533
-
534
- parser.add_argument(
535
- 'output_file',
536
- type=str,
537
- help='Output filename (.json)')
538
-
539
- if len(sys.argv[1:]) == 0:
540
- parser.print_help()
541
- parser.exit()
542
-
543
- args = parser.parse_args()
544
-
545
- labelme_to_coco(args.input_folder,args.output_file)
546
-
547
- if __name__ == '__main__':
548
- main()