megadetector 5.0.28__py3-none-any.whl → 10.0.0__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/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/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/efficientnet/model.py +8 -8
- megadetector/classification/efficientnet/utils.py +6 -5
- 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 +26 -26
- 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 -2
- megadetector/data_management/camtrap_dp_to_coco.py +79 -46
- megadetector/data_management/cct_json_utils.py +103 -103
- 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 +210 -193
- megadetector/data_management/databases/add_width_and_height_to_db.py +86 -12
- megadetector/data_management/databases/combine_coco_camera_traps_files.py +40 -40
- megadetector/data_management/databases/integrity_check_json_db.py +228 -200
- megadetector/data_management/databases/subset_json_db.py +33 -33
- megadetector/data_management/generate_crops_from_cct.py +88 -39
- megadetector/data_management/get_image_sizes.py +54 -49
- megadetector/data_management/labelme_to_coco.py +133 -125
- megadetector/data_management/labelme_to_yolo.py +159 -73
- 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 +365 -107
- megadetector/data_management/lila/get_lila_annotation_counts.py +35 -33
- megadetector/data_management/lila/get_lila_image_counts.py +22 -22
- megadetector/data_management/lila/lila_common.py +73 -70
- megadetector/data_management/lila/test_lila_metadata_urls.py +28 -19
- megadetector/data_management/mewc_to_md.py +344 -340
- megadetector/data_management/ocr_tools.py +262 -255
- megadetector/data_management/read_exif.py +249 -227
- megadetector/data_management/remap_coco_categories.py +90 -28
- megadetector/data_management/remove_exif.py +81 -21
- megadetector/data_management/rename_images.py +187 -187
- megadetector/data_management/resize_coco_dataset.py +588 -120
- 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 +248 -122
- megadetector/data_management/yolo_to_coco.py +333 -191
- megadetector/detection/change_detection.py +832 -0
- megadetector/detection/process_video.py +340 -337
- megadetector/detection/pytorch_detector.py +358 -278
- megadetector/detection/run_detector.py +399 -186
- megadetector/detection/run_detector_batch.py +404 -377
- megadetector/detection/run_inference_with_yolov5_val.py +340 -327
- megadetector/detection/run_tiled_inference.py +257 -249
- megadetector/detection/tf_detector.py +24 -24
- megadetector/detection/video_utils.py +332 -295
- megadetector/postprocessing/add_max_conf.py +19 -11
- megadetector/postprocessing/categorize_detections_by_size.py +45 -45
- megadetector/postprocessing/classification_postprocessing.py +468 -433
- megadetector/postprocessing/combine_batch_outputs.py +23 -23
- megadetector/postprocessing/compare_batch_results.py +590 -525
- megadetector/postprocessing/convert_output_format.py +106 -102
- megadetector/postprocessing/create_crop_folder.py +347 -147
- megadetector/postprocessing/detector_calibration.py +173 -168
- megadetector/postprocessing/generate_csv_report.py +508 -499
- megadetector/postprocessing/load_api_results.py +48 -27
- megadetector/postprocessing/md_to_coco.py +133 -102
- megadetector/postprocessing/md_to_labelme.py +107 -90
- megadetector/postprocessing/md_to_wi.py +40 -40
- megadetector/postprocessing/merge_detections.py +92 -114
- megadetector/postprocessing/postprocess_batch_results.py +319 -301
- megadetector/postprocessing/remap_detection_categories.py +91 -38
- megadetector/postprocessing/render_detection_confusion_matrix.py +214 -205
- 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 +704 -679
- 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 +18 -19
- megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +54 -33
- megadetector/taxonomy_mapping/preview_lila_taxonomy.py +67 -67
- megadetector/taxonomy_mapping/retrieve_sample_image.py +16 -16
- megadetector/taxonomy_mapping/simple_image_download.py +8 -8
- megadetector/taxonomy_mapping/species_lookup.py +156 -74
- megadetector/taxonomy_mapping/taxonomy_csv_checker.py +14 -14
- megadetector/taxonomy_mapping/taxonomy_graph.py +10 -10
- megadetector/taxonomy_mapping/validate_lila_category_mappings.py +13 -13
- megadetector/utils/ct_utils.py +1049 -211
- megadetector/utils/directory_listing.py +21 -77
- megadetector/utils/gpu_test.py +22 -22
- megadetector/utils/md_tests.py +632 -529
- megadetector/utils/path_utils.py +1520 -431
- megadetector/utils/process_utils.py +41 -41
- megadetector/utils/split_locations_into_train_val.py +62 -62
- megadetector/utils/string_utils.py +148 -27
- megadetector/utils/url_utils.py +489 -176
- megadetector/utils/wi_utils.py +2658 -2526
- megadetector/utils/write_html_image_list.py +137 -137
- megadetector/visualization/plot_utils.py +34 -30
- megadetector/visualization/render_images_with_thumbnails.py +39 -74
- megadetector/visualization/visualization_utils.py +487 -435
- megadetector/visualization/visualize_db.py +232 -198
- megadetector/visualization/visualize_detector_output.py +82 -76
- {megadetector-5.0.28.dist-info → megadetector-10.0.0.dist-info}/METADATA +5 -2
- megadetector-10.0.0.dist-info/RECORD +139 -0
- {megadetector-5.0.28.dist-info → megadetector-10.0.0.dist-info}/WHEEL +1 -1
- megadetector/api/batch_processing/api_core/__init__.py +0 -0
- megadetector/api/batch_processing/api_core/batch_service/__init__.py +0 -0
- megadetector/api/batch_processing/api_core/batch_service/score.py +0 -439
- megadetector/api/batch_processing/api_core/server.py +0 -294
- megadetector/api/batch_processing/api_core/server_api_config.py +0 -97
- megadetector/api/batch_processing/api_core/server_app_config.py +0 -55
- megadetector/api/batch_processing/api_core/server_batch_job_manager.py +0 -220
- megadetector/api/batch_processing/api_core/server_job_status_table.py +0 -149
- megadetector/api/batch_processing/api_core/server_orchestration.py +0 -360
- megadetector/api/batch_processing/api_core/server_utils.py +0 -88
- megadetector/api/batch_processing/api_core_support/__init__.py +0 -0
- megadetector/api/batch_processing/api_core_support/aggregate_results_manually.py +0 -46
- megadetector/api/batch_processing/api_support/__init__.py +0 -0
- megadetector/api/batch_processing/api_support/summarize_daily_activity.py +0 -152
- megadetector/api/batch_processing/data_preparation/__init__.py +0 -0
- megadetector/api/synchronous/__init__.py +0 -0
- megadetector/api/synchronous/api_core/animal_detection_api/__init__.py +0 -0
- megadetector/api/synchronous/api_core/animal_detection_api/api_backend.py +0 -151
- megadetector/api/synchronous/api_core/animal_detection_api/api_frontend.py +0 -263
- megadetector/api/synchronous/api_core/animal_detection_api/config.py +0 -35
- megadetector/api/synchronous/api_core/tests/__init__.py +0 -0
- megadetector/api/synchronous/api_core/tests/load_test.py +0 -110
- 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/utils/azure_utils.py +0 -178
- megadetector/utils/sas_blob_utils.py +0 -509
- megadetector-5.0.28.dist-info/RECORD +0 -209
- /megadetector/{api/batch_processing/__init__.py → __init__.py} +0 -0
- {megadetector-5.0.28.dist-info → megadetector-10.0.0.dist-info}/licenses/LICENSE +0 -0
- {megadetector-5.0.28.dist-info → megadetector-10.0.0.dist-info}/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ convert_output_format.py
|
|
|
4
4
|
|
|
5
5
|
Converts between file formats output by our batch processing API. Currently
|
|
6
6
|
supports json <--> csv conversion, but this should be the landing place for any
|
|
7
|
-
conversion - including between hypothetical alternative .json versions - that we support
|
|
7
|
+
conversion - including between hypothetical alternative .json versions - that we support
|
|
8
8
|
in the future.
|
|
9
9
|
|
|
10
10
|
The .csv format is largely obsolete, don't use it unless you're super-duper sure you need it.
|
|
@@ -38,43 +38,43 @@ def convert_json_to_csv(input_path,
|
|
|
38
38
|
overwrite=True):
|
|
39
39
|
"""
|
|
40
40
|
Converts a MD results .json file to a totally non-standard .csv format.
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
If [output_path] is None, will convert x.json to x.csv.
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
TODO: this function should obviously be using Pandas or some other sensible structured
|
|
45
45
|
representation of tabular data. Even a list of dicts. This implementation is quite
|
|
46
46
|
brittle and depends on adding fields to every row in exactly the right order.
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
Args:
|
|
49
49
|
input_path (str): the input .json file to convert
|
|
50
|
-
output_path (str, optional): the output .csv file to generate; if this is None, uses
|
|
50
|
+
output_path (str, optional): the output .csv file to generate; if this is None, uses
|
|
51
51
|
[input_path].csv
|
|
52
|
-
min_confidence (float, optional): the minimum-confidence detection we should include
|
|
52
|
+
min_confidence (float, optional): the minimum-confidence detection we should include
|
|
53
53
|
in the "detections" column; has no impact on the other columns
|
|
54
|
-
omit_bounding_boxes (bool): whether to leave out the json-formatted bounding
|
|
55
|
-
that make up the "detections" column, which are not generally useful for someone
|
|
56
|
-
wants to consume this data as a .csv file
|
|
54
|
+
omit_bounding_boxes (bool, optional): whether to leave out the json-formatted bounding
|
|
55
|
+
boxes that make up the "detections" column, which are not generally useful for someone
|
|
56
|
+
who wants to consume this data as a .csv file
|
|
57
57
|
output_encoding (str, optional): encoding to use for the .csv file
|
|
58
|
-
overwrite (bool): whether to overwrite an existing .csv file; if this is False and
|
|
59
|
-
output file exists, no-ops and returns
|
|
60
|
-
|
|
58
|
+
overwrite (bool, optional): whether to overwrite an existing .csv file; if this is False and
|
|
59
|
+
the output file exists, no-ops and returns
|
|
60
|
+
|
|
61
61
|
"""
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
if output_path is None:
|
|
64
64
|
output_path = os.path.splitext(input_path)[0]+'.csv'
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
if os.path.isfile(output_path) and (not overwrite):
|
|
67
67
|
print('File {} exists, skipping json --> csv conversion'.format(output_path))
|
|
68
68
|
return
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
print('Loading json results from {}...'.format(input_path))
|
|
71
71
|
json_output = json.load(open(input_path))
|
|
72
72
|
|
|
73
73
|
rows = []
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
fixed_columns = ['image_path', 'max_confidence', 'detections']
|
|
76
|
-
|
|
77
|
-
# We add an output column for each class other than 'empty',
|
|
76
|
+
|
|
77
|
+
# We add an output column for each class other than 'empty',
|
|
78
78
|
# containing the maximum probability of that class for each image
|
|
79
79
|
# n_non_empty_detection_categories = len(annotation_constants.annotation_bbox_categories) - 1
|
|
80
80
|
n_non_empty_detection_categories = annotation_constants.NUM_DETECTOR_CATEGORIES
|
|
@@ -83,9 +83,9 @@ def convert_json_to_csv(input_path,
|
|
|
83
83
|
for cat_id in range(1,n_non_empty_detection_categories+1):
|
|
84
84
|
cat_name = annotation_constants.detector_bbox_category_id_to_name[cat_id]
|
|
85
85
|
detection_category_column_names.append('max_conf_' + cat_name)
|
|
86
|
-
|
|
86
|
+
|
|
87
87
|
n_classification_categories = 0
|
|
88
|
-
|
|
88
|
+
|
|
89
89
|
if 'classification_categories' in json_output.keys():
|
|
90
90
|
classification_category_id_to_name = json_output['classification_categories']
|
|
91
91
|
classification_category_ids = list(classification_category_id_to_name.keys())
|
|
@@ -98,35 +98,35 @@ def convert_json_to_csv(input_path,
|
|
|
98
98
|
classification_category_id_to_column_number[category_id] = i_category
|
|
99
99
|
|
|
100
100
|
n_classification_categories = len(classification_category_ids)
|
|
101
|
-
|
|
101
|
+
|
|
102
102
|
# There are several .json fields for which we add .csv columns; other random bespoke fields
|
|
103
103
|
# will be ignored.
|
|
104
104
|
optional_fields = ['width','height','datetime','exif_metadata']
|
|
105
105
|
optional_fields_present = set()
|
|
106
|
-
|
|
106
|
+
|
|
107
107
|
# Iterate once over the data to check for optional fields
|
|
108
108
|
print('Looking for optional fields...')
|
|
109
|
-
|
|
109
|
+
|
|
110
110
|
for im in tqdm(json_output['images']):
|
|
111
111
|
# Which optional fields are present for this image?
|
|
112
112
|
for k in im.keys():
|
|
113
113
|
if k in optional_fields:
|
|
114
114
|
optional_fields_present.add(k)
|
|
115
|
-
|
|
115
|
+
|
|
116
116
|
optional_fields_present = sorted(list(optional_fields_present))
|
|
117
117
|
if len(optional_fields_present) > 0:
|
|
118
118
|
print('Found {} optional fields'.format(len(optional_fields_present)))
|
|
119
|
-
|
|
119
|
+
|
|
120
120
|
expected_row_length = len(fixed_columns) + len(detection_category_column_names) + \
|
|
121
121
|
n_classification_categories + len(optional_fields_present)
|
|
122
|
-
|
|
122
|
+
|
|
123
123
|
print('Formatting results...')
|
|
124
|
-
|
|
124
|
+
|
|
125
125
|
# i_image = 0; im = json_output['images'][i_image]
|
|
126
126
|
for im in tqdm(json_output['images']):
|
|
127
|
-
|
|
127
|
+
|
|
128
128
|
image_id = im['file']
|
|
129
|
-
|
|
129
|
+
|
|
130
130
|
if 'failure' in im and im['failure'] is not None:
|
|
131
131
|
row = [image_id, 'failure', im['failure']]
|
|
132
132
|
rows.append(row)
|
|
@@ -137,16 +137,16 @@ def convert_json_to_csv(input_path,
|
|
|
137
137
|
detections = []
|
|
138
138
|
max_detection_category_probabilities = [None] * n_non_empty_detection_categories
|
|
139
139
|
max_classification_category_probabilities = [0] * n_classification_categories
|
|
140
|
-
|
|
140
|
+
|
|
141
141
|
# d = im['detections'][0]
|
|
142
142
|
for d in im['detections']:
|
|
143
|
-
|
|
143
|
+
|
|
144
144
|
# Skip sub-threshold detections
|
|
145
145
|
if (min_confidence is not None) and (d['conf'] < min_confidence):
|
|
146
146
|
continue
|
|
147
|
-
|
|
147
|
+
|
|
148
148
|
input_bbox = d['bbox']
|
|
149
|
-
|
|
149
|
+
|
|
150
150
|
# Our .json format is xmin/ymin/w/h
|
|
151
151
|
#
|
|
152
152
|
# Our .csv format was ymin/xmin/ymax/xmax
|
|
@@ -155,9 +155,9 @@ def convert_json_to_csv(input_path,
|
|
|
155
155
|
xmax = input_bbox[0] + input_bbox[2]
|
|
156
156
|
ymax = input_bbox[1] + input_bbox[3]
|
|
157
157
|
output_detection = [ymin, xmin, ymax, xmax]
|
|
158
|
-
|
|
158
|
+
|
|
159
159
|
output_detection.append(d['conf'])
|
|
160
|
-
|
|
160
|
+
|
|
161
161
|
# Category 0 is empty, for which we don't have a column, so the max
|
|
162
162
|
# confidence for category N goes in column N-1
|
|
163
163
|
detection_category_id = int(d['category'])
|
|
@@ -167,10 +167,10 @@ def convert_json_to_csv(input_path,
|
|
|
167
167
|
detection_category_max = max_detection_category_probabilities[detection_category_column]
|
|
168
168
|
if detection_category_max is None or d['conf'] > detection_category_max:
|
|
169
169
|
max_detection_category_probabilities[detection_category_column] = d['conf']
|
|
170
|
-
|
|
170
|
+
|
|
171
171
|
output_detection.append(detection_category_id)
|
|
172
172
|
detections.append(output_detection)
|
|
173
|
-
|
|
173
|
+
|
|
174
174
|
if 'classifications' in d:
|
|
175
175
|
assert n_classification_categories > 0,\
|
|
176
176
|
'Oops, I have classification results, but no classification metadata'
|
|
@@ -180,34 +180,34 @@ def convert_json_to_csv(input_path,
|
|
|
180
180
|
category_index = classification_category_id_to_column_number[category_id]
|
|
181
181
|
if (max_classification_category_probabilities[category_index] < p):
|
|
182
182
|
max_classification_category_probabilities[category_index] = p
|
|
183
|
-
|
|
183
|
+
|
|
184
184
|
# ...for each classification
|
|
185
|
-
|
|
185
|
+
|
|
186
186
|
# ...if we have classification results for this detection
|
|
187
|
-
|
|
187
|
+
|
|
188
188
|
# ...for each detection
|
|
189
|
-
|
|
189
|
+
|
|
190
190
|
detection_string = ''
|
|
191
191
|
if not omit_bounding_boxes:
|
|
192
192
|
detection_string = json.dumps(detections)
|
|
193
|
-
|
|
193
|
+
|
|
194
194
|
row = [image_id, max_conf, detection_string]
|
|
195
195
|
row.extend(max_detection_category_probabilities)
|
|
196
196
|
row.extend(max_classification_category_probabilities)
|
|
197
|
-
|
|
197
|
+
|
|
198
198
|
for field_name in optional_fields_present:
|
|
199
199
|
if field_name not in im:
|
|
200
200
|
row.append('')
|
|
201
201
|
else:
|
|
202
202
|
row.append(str(im[field_name]))
|
|
203
|
-
|
|
203
|
+
|
|
204
204
|
assert len(row) == expected_row_length
|
|
205
205
|
rows.append(row)
|
|
206
|
-
|
|
206
|
+
|
|
207
207
|
# ...for each image
|
|
208
208
|
|
|
209
209
|
print('Writing to csv...')
|
|
210
|
-
|
|
210
|
+
|
|
211
211
|
with open(output_path, 'w', newline='', encoding=output_encoding) as f:
|
|
212
212
|
writer = csv.writer(f, delimiter=',')
|
|
213
213
|
header = fixed_columns
|
|
@@ -221,31 +221,31 @@ def convert_json_to_csv(input_path,
|
|
|
221
221
|
|
|
222
222
|
# ...def convert_json_to_csv(...)
|
|
223
223
|
|
|
224
|
-
|
|
224
|
+
|
|
225
225
|
def convert_csv_to_json(input_path,output_path=None,overwrite=True):
|
|
226
226
|
"""
|
|
227
227
|
Convert .csv to .json. If output_path is None, will convert x.csv to x.json.
|
|
228
|
-
|
|
228
|
+
|
|
229
229
|
Args:
|
|
230
230
|
input_path (str): .csv filename to convert to .json
|
|
231
|
-
output_path (str, optional): the output .json file to generate; if this is None, uses
|
|
231
|
+
output_path (str, optional): the output .json file to generate; if this is None, uses
|
|
232
232
|
[input_path].json
|
|
233
|
-
overwrite (bool): whether to overwrite an existing .json file; if this is
|
|
234
|
-
output file exists, no-ops and returns
|
|
235
|
-
|
|
233
|
+
overwrite (bool, optional): whether to overwrite an existing .json file; if this is
|
|
234
|
+
False and the output file exists, no-ops and returns
|
|
235
|
+
|
|
236
236
|
"""
|
|
237
|
-
|
|
237
|
+
|
|
238
238
|
if output_path is None:
|
|
239
239
|
output_path = os.path.splitext(input_path)[0]+'.json'
|
|
240
|
-
|
|
240
|
+
|
|
241
241
|
if os.path.isfile(output_path) and (not overwrite):
|
|
242
242
|
print('File {} exists, skipping csv --> json conversion'.format(output_path))
|
|
243
243
|
return
|
|
244
|
-
|
|
244
|
+
|
|
245
245
|
# Format spec:
|
|
246
246
|
#
|
|
247
247
|
# https://github.com/agentmorris/MegaDetector/tree/main/megadetector/api/batch_processing
|
|
248
|
-
|
|
248
|
+
|
|
249
249
|
print('Loading csv results...')
|
|
250
250
|
df = load_api_results_csv(input_path)
|
|
251
251
|
|
|
@@ -256,23 +256,23 @@ def convert_csv_to_json(input_path,output_path=None,overwrite=True):
|
|
|
256
256
|
"classifier": "unknown",
|
|
257
257
|
"classification_completion_time": "unknown"
|
|
258
258
|
}
|
|
259
|
-
|
|
259
|
+
|
|
260
260
|
classification_categories = {}
|
|
261
261
|
detection_categories = annotation_constants.detector_bbox_categories
|
|
262
262
|
|
|
263
263
|
images = []
|
|
264
|
-
|
|
265
|
-
#
|
|
266
|
-
for
|
|
267
|
-
|
|
264
|
+
|
|
265
|
+
# i_file = 0; row = df.iloc[i_file]
|
|
266
|
+
for i_file,row in df.iterrows():
|
|
267
|
+
|
|
268
268
|
image = {}
|
|
269
269
|
image['file'] = row['image_path']
|
|
270
270
|
image['max_detection_conf'] = round(row['max_confidence'], CONF_DIGITS)
|
|
271
|
-
src_detections = row['detections']
|
|
271
|
+
src_detections = row['detections']
|
|
272
272
|
out_detections = []
|
|
273
|
-
|
|
274
|
-
for
|
|
275
|
-
|
|
273
|
+
|
|
274
|
+
for i_detection,detection in enumerate(src_detections):
|
|
275
|
+
|
|
276
276
|
# Our .csv format was ymin/xmin/ymax/xmax
|
|
277
277
|
#
|
|
278
278
|
# Our .json format is xmin/ymin/w/h
|
|
@@ -282,91 +282,95 @@ def convert_csv_to_json(input_path,output_path=None,overwrite=True):
|
|
|
282
282
|
xmax = detection[3]
|
|
283
283
|
bbox = [xmin, ymin, xmax-xmin, ymax-ymin]
|
|
284
284
|
conf = detection[4]
|
|
285
|
-
|
|
285
|
+
i_class = detection[5]
|
|
286
286
|
out_detection = {}
|
|
287
|
-
out_detection['category'] = str(
|
|
287
|
+
out_detection['category'] = str(i_class)
|
|
288
288
|
out_detection['conf'] = conf
|
|
289
|
-
out_detection['bbox'] = bbox
|
|
289
|
+
out_detection['bbox'] = bbox
|
|
290
290
|
out_detections.append(out_detection)
|
|
291
|
-
|
|
291
|
+
|
|
292
292
|
# ...for each detection
|
|
293
|
-
|
|
293
|
+
|
|
294
294
|
image['detections'] = out_detections
|
|
295
295
|
images.append(image)
|
|
296
|
-
|
|
297
|
-
# ...for each image
|
|
296
|
+
|
|
297
|
+
# ...for each image
|
|
298
298
|
json_out = {}
|
|
299
299
|
json_out['info'] = info
|
|
300
300
|
json_out['detection_categories'] = detection_categories
|
|
301
301
|
json_out['classification_categories'] = classification_categories
|
|
302
302
|
json_out['images'] = images
|
|
303
|
-
|
|
303
|
+
|
|
304
304
|
json.dump(json_out,open(output_path,'w'),indent=1)
|
|
305
|
-
|
|
305
|
+
|
|
306
306
|
# ...def convert_csv_to_json(...)
|
|
307
307
|
|
|
308
308
|
|
|
309
309
|
#%% Interactive driver
|
|
310
310
|
|
|
311
|
-
if False:
|
|
311
|
+
if False:
|
|
312
312
|
|
|
313
313
|
#%%
|
|
314
|
-
|
|
314
|
+
|
|
315
315
|
input_path = r'c:\temp\test.json'
|
|
316
316
|
min_confidence = None
|
|
317
317
|
output_path = input_path + '.csv'
|
|
318
318
|
convert_json_to_csv(input_path,output_path,min_confidence=min_confidence,
|
|
319
319
|
omit_bounding_boxes=False)
|
|
320
|
-
|
|
320
|
+
|
|
321
321
|
#%%
|
|
322
|
-
|
|
322
|
+
|
|
323
323
|
base_path = r'c:\temp\json'
|
|
324
324
|
input_paths = os.listdir(base_path)
|
|
325
325
|
input_paths = [os.path.join(base_path,s) for s in input_paths]
|
|
326
|
-
|
|
327
|
-
min_confidence = None
|
|
326
|
+
|
|
327
|
+
min_confidence = None
|
|
328
328
|
for input_path in input_paths:
|
|
329
329
|
output_path = input_path + '.csv'
|
|
330
330
|
convert_json_to_csv(input_path,output_path,min_confidence=min_confidence,
|
|
331
|
-
omit_bounding_boxes=True)
|
|
332
|
-
|
|
331
|
+
omit_bounding_boxes=True)
|
|
332
|
+
|
|
333
333
|
#%% Concatenate .csv files from a folder
|
|
334
334
|
|
|
335
335
|
import glob
|
|
336
336
|
csv_files = glob.glob(os.path.join(base_path,'*.json.csv' ))
|
|
337
337
|
master_csv = os.path.join(base_path,'all.csv')
|
|
338
|
-
|
|
338
|
+
|
|
339
339
|
print('Concatenating {} files to {}'.format(len(csv_files),master_csv))
|
|
340
|
-
|
|
340
|
+
|
|
341
341
|
header = None
|
|
342
342
|
with open(master_csv, 'w') as fout:
|
|
343
|
-
|
|
343
|
+
|
|
344
344
|
for filename in tqdm(csv_files):
|
|
345
|
-
|
|
345
|
+
|
|
346
346
|
with open(filename) as fin:
|
|
347
|
-
|
|
347
|
+
|
|
348
348
|
lines = fin.readlines()
|
|
349
|
-
|
|
349
|
+
|
|
350
350
|
if header is not None:
|
|
351
351
|
assert lines[0] == header
|
|
352
352
|
else:
|
|
353
353
|
header = lines[0]
|
|
354
354
|
fout.write(header)
|
|
355
|
-
|
|
355
|
+
|
|
356
356
|
for line in lines[1:]:
|
|
357
357
|
if len(line.strip()) == 0:
|
|
358
|
-
continue
|
|
358
|
+
continue
|
|
359
359
|
fout.write(line)
|
|
360
|
-
|
|
360
|
+
|
|
361
361
|
# ...for each .csv file
|
|
362
|
-
|
|
362
|
+
|
|
363
363
|
# with open(master_csv)
|
|
364
|
-
|
|
365
|
-
|
|
364
|
+
|
|
365
|
+
|
|
366
366
|
#%% Command-line driver
|
|
367
|
-
|
|
367
|
+
|
|
368
368
|
def main():
|
|
369
|
-
|
|
369
|
+
"""
|
|
370
|
+
Command-line driver for convert_output_format(), which converts
|
|
371
|
+
json <--> csv.
|
|
372
|
+
"""
|
|
373
|
+
|
|
370
374
|
parser = argparse.ArgumentParser()
|
|
371
375
|
parser.add_argument('input_path',type=str,
|
|
372
376
|
help='Input filename ending in .json or .csv')
|
|
@@ -374,22 +378,22 @@ def main():
|
|
|
374
378
|
help='Output filename ending in .json or .csv (defaults to ' + \
|
|
375
379
|
'input file, with .json/.csv replaced by .csv/.json)')
|
|
376
380
|
parser.add_argument('--omit_bounding_boxes',action='store_true',
|
|
377
|
-
help='Output bounding box text from .csv output (large and usually not useful)')
|
|
378
|
-
|
|
381
|
+
help='Output bounding box text from .csv output (large and usually not useful)')
|
|
382
|
+
|
|
379
383
|
if len(sys.argv[1:]) == 0:
|
|
380
384
|
parser.print_help()
|
|
381
385
|
parser.exit()
|
|
382
386
|
|
|
383
387
|
args = parser.parse_args()
|
|
384
|
-
|
|
388
|
+
|
|
385
389
|
if args.output_path is None:
|
|
386
390
|
if args.input_path.endswith('.csv'):
|
|
387
391
|
args.output_path = args.input_path[:-4] + '.json'
|
|
388
392
|
elif args.input_path.endswith('.json'):
|
|
389
393
|
args.output_path = args.input_path[:-5] + '.csv'
|
|
390
394
|
else:
|
|
391
|
-
raise ValueError('Illegal input file extension')
|
|
392
|
-
|
|
395
|
+
raise ValueError('Illegal input file extension')
|
|
396
|
+
|
|
393
397
|
if args.input_path.endswith('.csv') and args.output_path.endswith('.json'):
|
|
394
398
|
assert not args.omit_bounding_boxes, \
|
|
395
399
|
'--omit_bounding_boxes does not apply to csv --> json conversion'
|
|
@@ -397,7 +401,7 @@ def main():
|
|
|
397
401
|
elif args.input_path.endswith('.json') and args.output_path.endswith('.csv'):
|
|
398
402
|
convert_json_to_csv(args.input_path,args.output_path,omit_bounding_boxes=args.omit_bounding_boxes)
|
|
399
403
|
else:
|
|
400
|
-
raise ValueError('Illegal format combination')
|
|
404
|
+
raise ValueError('Illegal format combination')
|
|
401
405
|
|
|
402
406
|
if __name__ == '__main__':
|
|
403
407
|
main()
|