megadetector 5.0.27__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.
- megadetector/api/batch_processing/api_core/batch_service/score.py +4 -5
- megadetector/api/batch_processing/api_core_support/aggregate_results_manually.py +1 -1
- megadetector/api/batch_processing/api_support/summarize_daily_activity.py +1 -1
- megadetector/api/batch_processing/integration/digiKam/xmp_integration.py +2 -2
- megadetector/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +1 -1
- megadetector/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +1 -1
- megadetector/api/synchronous/api_core/tests/load_test.py +2 -3
- megadetector/classification/aggregate_classifier_probs.py +3 -3
- megadetector/classification/analyze_failed_images.py +5 -5
- megadetector/classification/cache_batchapi_outputs.py +5 -5
- megadetector/classification/create_classification_dataset.py +11 -12
- megadetector/classification/crop_detections.py +10 -10
- megadetector/classification/csv_to_json.py +8 -8
- megadetector/classification/detect_and_crop.py +13 -15
- megadetector/classification/evaluate_model.py +7 -7
- megadetector/classification/identify_mislabeled_candidates.py +6 -6
- megadetector/classification/json_to_azcopy_list.py +1 -1
- megadetector/classification/json_validator.py +29 -32
- megadetector/classification/map_classification_categories.py +9 -9
- megadetector/classification/merge_classification_detection_output.py +12 -9
- megadetector/classification/prepare_classification_script.py +19 -19
- megadetector/classification/prepare_classification_script_mc.py +23 -23
- megadetector/classification/run_classifier.py +4 -4
- megadetector/classification/save_mislabeled.py +6 -6
- megadetector/classification/train_classifier.py +1 -1
- megadetector/classification/train_classifier_tf.py +9 -9
- megadetector/classification/train_utils.py +10 -10
- megadetector/data_management/annotations/annotation_constants.py +1 -1
- megadetector/data_management/camtrap_dp_to_coco.py +45 -45
- megadetector/data_management/cct_json_utils.py +101 -101
- megadetector/data_management/cct_to_md.py +49 -49
- megadetector/data_management/cct_to_wi.py +33 -33
- megadetector/data_management/coco_to_labelme.py +75 -75
- megadetector/data_management/coco_to_yolo.py +189 -189
- megadetector/data_management/databases/add_width_and_height_to_db.py +3 -2
- megadetector/data_management/databases/combine_coco_camera_traps_files.py +38 -38
- megadetector/data_management/databases/integrity_check_json_db.py +202 -188
- megadetector/data_management/databases/subset_json_db.py +33 -33
- megadetector/data_management/generate_crops_from_cct.py +38 -38
- megadetector/data_management/get_image_sizes.py +54 -49
- megadetector/data_management/labelme_to_coco.py +130 -124
- megadetector/data_management/labelme_to_yolo.py +78 -72
- megadetector/data_management/lila/create_lila_blank_set.py +81 -83
- megadetector/data_management/lila/create_lila_test_set.py +32 -31
- megadetector/data_management/lila/create_links_to_md_results_files.py +18 -18
- megadetector/data_management/lila/download_lila_subset.py +21 -24
- megadetector/data_management/lila/generate_lila_per_image_labels.py +91 -91
- megadetector/data_management/lila/get_lila_annotation_counts.py +30 -30
- megadetector/data_management/lila/get_lila_image_counts.py +22 -22
- megadetector/data_management/lila/lila_common.py +70 -70
- megadetector/data_management/lila/test_lila_metadata_urls.py +13 -14
- megadetector/data_management/mewc_to_md.py +339 -340
- megadetector/data_management/ocr_tools.py +258 -252
- megadetector/data_management/read_exif.py +232 -223
- megadetector/data_management/remap_coco_categories.py +26 -26
- megadetector/data_management/remove_exif.py +31 -20
- megadetector/data_management/rename_images.py +187 -187
- megadetector/data_management/resize_coco_dataset.py +41 -41
- megadetector/data_management/speciesnet_to_md.py +41 -41
- megadetector/data_management/wi_download_csv_to_coco.py +55 -55
- megadetector/data_management/yolo_output_to_md_output.py +117 -120
- megadetector/data_management/yolo_to_coco.py +195 -188
- megadetector/detection/change_detection.py +831 -0
- megadetector/detection/process_video.py +341 -338
- megadetector/detection/pytorch_detector.py +308 -266
- megadetector/detection/run_detector.py +186 -166
- megadetector/detection/run_detector_batch.py +366 -364
- megadetector/detection/run_inference_with_yolov5_val.py +328 -325
- megadetector/detection/run_tiled_inference.py +312 -253
- megadetector/detection/tf_detector.py +24 -24
- megadetector/detection/video_utils.py +291 -283
- megadetector/postprocessing/add_max_conf.py +15 -11
- megadetector/postprocessing/categorize_detections_by_size.py +44 -44
- megadetector/postprocessing/classification_postprocessing.py +808 -311
- megadetector/postprocessing/combine_batch_outputs.py +20 -21
- megadetector/postprocessing/compare_batch_results.py +528 -517
- megadetector/postprocessing/convert_output_format.py +97 -97
- megadetector/postprocessing/create_crop_folder.py +220 -147
- megadetector/postprocessing/detector_calibration.py +173 -168
- megadetector/postprocessing/generate_csv_report.py +508 -0
- megadetector/postprocessing/load_api_results.py +25 -22
- megadetector/postprocessing/md_to_coco.py +129 -98
- megadetector/postprocessing/md_to_labelme.py +89 -83
- megadetector/postprocessing/md_to_wi.py +40 -40
- megadetector/postprocessing/merge_detections.py +87 -114
- megadetector/postprocessing/postprocess_batch_results.py +319 -302
- megadetector/postprocessing/remap_detection_categories.py +36 -36
- megadetector/postprocessing/render_detection_confusion_matrix.py +205 -199
- megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py +57 -57
- megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +27 -28
- megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +702 -677
- megadetector/postprocessing/separate_detections_into_folders.py +226 -211
- megadetector/postprocessing/subset_json_detector_output.py +265 -262
- megadetector/postprocessing/top_folders_to_bottom.py +45 -45
- megadetector/postprocessing/validate_batch_results.py +70 -70
- megadetector/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +52 -52
- megadetector/taxonomy_mapping/map_new_lila_datasets.py +15 -15
- megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +14 -14
- megadetector/taxonomy_mapping/preview_lila_taxonomy.py +66 -69
- megadetector/taxonomy_mapping/retrieve_sample_image.py +16 -16
- megadetector/taxonomy_mapping/simple_image_download.py +8 -8
- megadetector/taxonomy_mapping/species_lookup.py +33 -33
- megadetector/taxonomy_mapping/taxonomy_csv_checker.py +14 -14
- megadetector/taxonomy_mapping/taxonomy_graph.py +11 -11
- megadetector/taxonomy_mapping/validate_lila_category_mappings.py +13 -13
- megadetector/utils/azure_utils.py +22 -22
- megadetector/utils/ct_utils.py +1019 -200
- megadetector/utils/directory_listing.py +21 -77
- megadetector/utils/gpu_test.py +22 -22
- megadetector/utils/md_tests.py +541 -518
- megadetector/utils/path_utils.py +1511 -406
- megadetector/utils/process_utils.py +41 -41
- megadetector/utils/sas_blob_utils.py +53 -49
- megadetector/utils/split_locations_into_train_val.py +73 -60
- megadetector/utils/string_utils.py +147 -26
- megadetector/utils/url_utils.py +463 -173
- megadetector/utils/wi_utils.py +2629 -2868
- megadetector/utils/write_html_image_list.py +137 -137
- megadetector/visualization/plot_utils.py +21 -21
- megadetector/visualization/render_images_with_thumbnails.py +37 -73
- megadetector/visualization/visualization_utils.py +424 -404
- megadetector/visualization/visualize_db.py +197 -190
- megadetector/visualization/visualize_detector_output.py +126 -98
- {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/METADATA +6 -3
- megadetector-5.0.29.dist-info/RECORD +163 -0
- {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/WHEEL +1 -1
- megadetector/data_management/importers/add_nacti_sizes.py +0 -52
- megadetector/data_management/importers/add_timestamps_to_icct.py +0 -79
- megadetector/data_management/importers/animl_results_to_md_results.py +0 -158
- megadetector/data_management/importers/auckland_doc_test_to_json.py +0 -373
- megadetector/data_management/importers/auckland_doc_to_json.py +0 -201
- megadetector/data_management/importers/awc_to_json.py +0 -191
- megadetector/data_management/importers/bellevue_to_json.py +0 -272
- megadetector/data_management/importers/cacophony-thermal-importer.py +0 -793
- megadetector/data_management/importers/carrizo_shrubfree_2018.py +0 -269
- megadetector/data_management/importers/carrizo_trail_cam_2017.py +0 -289
- megadetector/data_management/importers/cct_field_adjustments.py +0 -58
- megadetector/data_management/importers/channel_islands_to_cct.py +0 -913
- megadetector/data_management/importers/eMammal/copy_and_unzip_emammal.py +0 -180
- megadetector/data_management/importers/eMammal/eMammal_helpers.py +0 -249
- megadetector/data_management/importers/eMammal/make_eMammal_json.py +0 -223
- megadetector/data_management/importers/ena24_to_json.py +0 -276
- megadetector/data_management/importers/filenames_to_json.py +0 -386
- megadetector/data_management/importers/helena_to_cct.py +0 -283
- megadetector/data_management/importers/idaho-camera-traps.py +0 -1407
- megadetector/data_management/importers/idfg_iwildcam_lila_prep.py +0 -294
- megadetector/data_management/importers/import_desert_lion_conservation_camera_traps.py +0 -387
- megadetector/data_management/importers/jb_csv_to_json.py +0 -150
- megadetector/data_management/importers/mcgill_to_json.py +0 -250
- megadetector/data_management/importers/missouri_to_json.py +0 -490
- megadetector/data_management/importers/nacti_fieldname_adjustments.py +0 -79
- megadetector/data_management/importers/noaa_seals_2019.py +0 -181
- megadetector/data_management/importers/osu-small-animals-to-json.py +0 -364
- megadetector/data_management/importers/pc_to_json.py +0 -365
- megadetector/data_management/importers/plot_wni_giraffes.py +0 -123
- megadetector/data_management/importers/prepare_zsl_imerit.py +0 -131
- megadetector/data_management/importers/raic_csv_to_md_results.py +0 -416
- megadetector/data_management/importers/rspb_to_json.py +0 -356
- megadetector/data_management/importers/save_the_elephants_survey_A.py +0 -320
- megadetector/data_management/importers/save_the_elephants_survey_B.py +0 -329
- megadetector/data_management/importers/snapshot_safari_importer.py +0 -758
- megadetector/data_management/importers/snapshot_serengeti_lila.py +0 -1067
- megadetector/data_management/importers/snapshotserengeti/make_full_SS_json.py +0 -150
- megadetector/data_management/importers/snapshotserengeti/make_per_season_SS_json.py +0 -153
- megadetector/data_management/importers/sulross_get_exif.py +0 -65
- megadetector/data_management/importers/timelapse_csv_set_to_json.py +0 -490
- megadetector/data_management/importers/ubc_to_json.py +0 -399
- megadetector/data_management/importers/umn_to_json.py +0 -507
- megadetector/data_management/importers/wellington_to_json.py +0 -263
- megadetector/data_management/importers/wi_to_json.py +0 -442
- megadetector/data_management/importers/zamba_results_to_md_results.py +0 -180
- megadetector/data_management/lila/add_locations_to_island_camera_traps.py +0 -101
- megadetector/data_management/lila/add_locations_to_nacti.py +0 -151
- megadetector-5.0.27.dist-info/RECORD +0 -208
- {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/licenses/LICENSE +0 -0
- {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/top_level.txt +0 -0
|
@@ -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
|
-
|
|
205
|
-
|
|
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
|
-
|
|
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()
|