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
|
@@ -1,340 +1,344 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
mewc_to_md.py
|
|
4
|
-
|
|
5
|
-
Converts the output of the MEWC inference scripts to the MD output format.
|
|
6
|
-
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
#%% Imports and constants
|
|
10
|
-
|
|
11
|
-
import os
|
|
12
|
-
import json
|
|
13
|
-
import pandas as pd
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
from
|
|
18
|
-
from
|
|
19
|
-
|
|
20
|
-
from megadetector.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
##%%
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
for
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
#
|
|
215
|
-
for
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
if
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
if
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
for
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
mewc_to_md.py
|
|
4
|
+
|
|
5
|
+
Converts the output of the MEWC inference scripts to the MD output format.
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
#%% Imports and constants
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import json
|
|
13
|
+
import pandas as pd
|
|
14
|
+
import sys
|
|
15
|
+
import argparse
|
|
16
|
+
|
|
17
|
+
from copy import deepcopy
|
|
18
|
+
from collections import defaultdict
|
|
19
|
+
from megadetector.utils.ct_utils import sort_list_of_dicts_by_key, invert_dictionary # noqa
|
|
20
|
+
from megadetector.utils.path_utils import recursive_file_list
|
|
21
|
+
|
|
22
|
+
from megadetector.postprocessing.validate_batch_results import \
|
|
23
|
+
ValidateBatchResultsOptions, validate_batch_results
|
|
24
|
+
|
|
25
|
+
default_mewc_mount_prefix = '/images/'
|
|
26
|
+
default_mewc_category_name_column = 'class_id'
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
#%% Functions
|
|
30
|
+
|
|
31
|
+
def mewc_to_md(mewc_input_folder,
|
|
32
|
+
output_file=None,
|
|
33
|
+
mount_prefix=default_mewc_mount_prefix,
|
|
34
|
+
category_name_column=default_mewc_category_name_column,
|
|
35
|
+
mewc_out_filename='mewc_out.csv',
|
|
36
|
+
md_out_filename='md_out.json'):
|
|
37
|
+
"""
|
|
38
|
+
Converts the output of the MEWC inference scripts to the MD output format.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
mewc_input_folder (str): the folder we'll search for MEWC output files
|
|
42
|
+
output_file (str, optional): .json file to write with class information
|
|
43
|
+
mount_prefix (str, optional): string to remove from all filenames in the MD
|
|
44
|
+
.json file, typically the prefix used to mount the image folder.
|
|
45
|
+
category_name_column (str, optional): column in the MEWC results .csv to use for
|
|
46
|
+
category naming.
|
|
47
|
+
mewc_out_filename (str, optional): MEWC-formatted .csv file that should be
|
|
48
|
+
in [mewc_input_folder]
|
|
49
|
+
md_out_filename (str, optional): MD-formatted .json file (without classification
|
|
50
|
+
information) that should be in [mewc_input_folder]
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
dict: an MD-formatted dict, the same as what's written to [output_file]
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
##%% Read input files
|
|
57
|
+
|
|
58
|
+
assert os.path.isdir(mewc_input_folder), \
|
|
59
|
+
'Could not find folder {}'.format(mewc_input_folder)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
##%% Find MEWC output files
|
|
63
|
+
|
|
64
|
+
relative_path_to_mewc_info = {}
|
|
65
|
+
|
|
66
|
+
print('Listing files in folder {}'.format(mewc_input_folder))
|
|
67
|
+
all_files_relative = set(recursive_file_list(mewc_input_folder,return_relative_paths=True))
|
|
68
|
+
|
|
69
|
+
for fn_relative in all_files_relative:
|
|
70
|
+
if fn_relative.endswith(mewc_out_filename):
|
|
71
|
+
folder_relative = '/'.join(fn_relative.split('/')[:-1])
|
|
72
|
+
assert folder_relative not in relative_path_to_mewc_info
|
|
73
|
+
md_output_file_relative = os.path.join(folder_relative,md_out_filename).replace('\\','/')
|
|
74
|
+
assert md_output_file_relative in all_files_relative, \
|
|
75
|
+
'Could not find MD output file {} to match to {}'.format(
|
|
76
|
+
md_output_file_relative,fn_relative)
|
|
77
|
+
relative_path_to_mewc_info[folder_relative] = \
|
|
78
|
+
{'mewc_predict_file':fn_relative,'md_file':md_output_file_relative}
|
|
79
|
+
|
|
80
|
+
del folder_relative
|
|
81
|
+
|
|
82
|
+
print('Found {} MEWC results files'.format(len(relative_path_to_mewc_info)))
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
##%% Prepare to loop over results files
|
|
86
|
+
|
|
87
|
+
md_results_all = {}
|
|
88
|
+
md_results_all['images'] = []
|
|
89
|
+
md_results_all['detection_categories'] = {}
|
|
90
|
+
md_results_all['classification_categories'] = {}
|
|
91
|
+
md_results_all['info'] = None
|
|
92
|
+
|
|
93
|
+
classification_category_name_to_id = {}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
##%% Loop over results files
|
|
97
|
+
|
|
98
|
+
# relative_folder = next(iter(relative_path_to_mewc_info.keys()))
|
|
99
|
+
for relative_folder in relative_path_to_mewc_info:
|
|
100
|
+
|
|
101
|
+
##%%
|
|
102
|
+
|
|
103
|
+
mewc_info = relative_path_to_mewc_info[relative_folder]
|
|
104
|
+
mewc_csv_fn_abs = os.path.join(mewc_input_folder,mewc_info['mewc_predict_file'])
|
|
105
|
+
mewc_md_fn_abs = os.path.join(mewc_input_folder,mewc_info['md_file'])
|
|
106
|
+
|
|
107
|
+
mewc_classification_info = pd.read_csv(mewc_csv_fn_abs)
|
|
108
|
+
mewc_classification_info = mewc_classification_info.to_dict('records')
|
|
109
|
+
|
|
110
|
+
assert os.path.isfile(mewc_md_fn_abs), \
|
|
111
|
+
'Could not find file {}'.format(mewc_md_fn_abs)
|
|
112
|
+
with open(mewc_md_fn_abs,'r') as f:
|
|
113
|
+
md_results = json.load(f)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
##%% Remove the mount prefix from MD files if necessary
|
|
117
|
+
if mount_prefix is not None and len(mount_prefix) > 0:
|
|
118
|
+
|
|
119
|
+
n_files_without_mount_prefix = 0
|
|
120
|
+
|
|
121
|
+
# im = md_results['images'][0]
|
|
122
|
+
for im in md_results['images']:
|
|
123
|
+
if not im['file'].startswith(mount_prefix):
|
|
124
|
+
n_files_without_mount_prefix += 1
|
|
125
|
+
else:
|
|
126
|
+
im['file'] = im['file'].replace(mount_prefix,'',1)
|
|
127
|
+
|
|
128
|
+
if n_files_without_mount_prefix > 0:
|
|
129
|
+
print('Warning {} of {} files in the MD results did not include the mount prefix {}'.format(
|
|
130
|
+
n_files_without_mount_prefix,len(md_results['images']),mount_prefix))
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
##%% Convert MEWC snip IDs to image files
|
|
134
|
+
|
|
135
|
+
# r = mewc_classification_info[0]
|
|
136
|
+
for r in mewc_classification_info:
|
|
137
|
+
|
|
138
|
+
# E.g. "IMG0-0.jpg"
|
|
139
|
+
snip_file = r['filename']
|
|
140
|
+
|
|
141
|
+
# E.g. "IMG0-0"
|
|
142
|
+
snip_file_no_ext = os.path.splitext(snip_file)[0]
|
|
143
|
+
ext = os.path.splitext(snip_file)[1] # noqa
|
|
144
|
+
|
|
145
|
+
tokens = snip_file_no_ext.split('-')
|
|
146
|
+
|
|
147
|
+
if len(tokens) == 1:
|
|
148
|
+
print('Warning: in folder {}, detection ID not found in snip filename {}, skipping'.format(
|
|
149
|
+
relative_folder,snip_file_no_ext))
|
|
150
|
+
r['image_filename_without_extension'] = snip_file_no_ext
|
|
151
|
+
r['snip_id'] = None
|
|
152
|
+
|
|
153
|
+
continue
|
|
154
|
+
|
|
155
|
+
filename_without_snip_id = '-'.join(tokens[0:-1])
|
|
156
|
+
snip_id = int(tokens[-1])
|
|
157
|
+
image_filename_without_extension = filename_without_snip_id
|
|
158
|
+
|
|
159
|
+
r['image_filename_without_extension'] = image_filename_without_extension
|
|
160
|
+
r['snip_id'] = snip_id
|
|
161
|
+
|
|
162
|
+
# ...for each MEWC result record
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
##%% Make sure MD results and MEWC results refer to the same files
|
|
166
|
+
|
|
167
|
+
images_in_md_results_no_extension = \
|
|
168
|
+
set([os.path.splitext(im['file'])[0] for im in md_results['images']])
|
|
169
|
+
images_in_mewc_results_no_extension = set(r['image_filename_without_extension'] \
|
|
170
|
+
for r in mewc_classification_info)
|
|
171
|
+
|
|
172
|
+
# All files with classification results should also have detection results
|
|
173
|
+
for fn in images_in_mewc_results_no_extension:
|
|
174
|
+
assert fn in images_in_md_results_no_extension, \
|
|
175
|
+
'Error: file {} is present in mewc-predict results, but not in MD results'.format(fn)
|
|
176
|
+
|
|
177
|
+
# This is just a note to self: no classification results are present for empty images
|
|
178
|
+
if False:
|
|
179
|
+
for fn in images_in_md_results_no_extension:
|
|
180
|
+
if fn not in images_in_mewc_results_no_extension:
|
|
181
|
+
print('Warning: file {}/{} is present in MD results, but not in mewc-predict results'.format(
|
|
182
|
+
relative_folder,fn))
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
##%% Validate images
|
|
186
|
+
|
|
187
|
+
for im in md_results['images']:
|
|
188
|
+
fn_relative = im['file']
|
|
189
|
+
fn_abs = os.path.join(mewc_input_folder,relative_folder,fn_relative)
|
|
190
|
+
if not os.path.isfile(fn_abs):
|
|
191
|
+
print('Warning: image file {} does not exist'.format(fn_abs))
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
##%% Map filenames to MEWC results
|
|
195
|
+
|
|
196
|
+
image_id_to_mewc_records = defaultdict(list)
|
|
197
|
+
for r in mewc_classification_info:
|
|
198
|
+
image_id_to_mewc_records[r['image_filename_without_extension']].append(r)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
##%% Add classification info to MD results
|
|
202
|
+
|
|
203
|
+
# im = md_results['images'][0]
|
|
204
|
+
for im in md_results['images']:
|
|
205
|
+
|
|
206
|
+
if ('detections' not in im) or (im['detections'] is None) or (len(im['detections']) == 0):
|
|
207
|
+
continue
|
|
208
|
+
|
|
209
|
+
detections = im['detections']
|
|
210
|
+
|
|
211
|
+
# *Don't* sort by confidence, it looks like snip IDs use the original sort order
|
|
212
|
+
# detections = sort_list_of_dicts_by_key(detections,'conf',reverse=True)
|
|
213
|
+
|
|
214
|
+
# This is just a debug assist, so I can run this cell more than once
|
|
215
|
+
for det in detections:
|
|
216
|
+
det['classifications'] = []
|
|
217
|
+
|
|
218
|
+
image_id = os.path.splitext(im['file'])[0]
|
|
219
|
+
mewc_records_this_image = image_id_to_mewc_records[image_id]
|
|
220
|
+
|
|
221
|
+
# r = mewc_records_this_image[0]
|
|
222
|
+
for r in mewc_records_this_image:
|
|
223
|
+
|
|
224
|
+
if r['snip_id'] is None:
|
|
225
|
+
continue
|
|
226
|
+
|
|
227
|
+
category_name = r[category_name_column]
|
|
228
|
+
|
|
229
|
+
# This is a *global* list of category mappings, across all mewc .csv files
|
|
230
|
+
if category_name not in classification_category_name_to_id:
|
|
231
|
+
category_id = str(len(classification_category_name_to_id))
|
|
232
|
+
classification_category_name_to_id[category_name] = category_id
|
|
233
|
+
else:
|
|
234
|
+
category_id = classification_category_name_to_id[category_name]
|
|
235
|
+
|
|
236
|
+
snip_id = r['snip_id']
|
|
237
|
+
if snip_id >= len(detections):
|
|
238
|
+
print('Warning: image {} has a classified snip ID of {}, but only {} detections are present'.format(
|
|
239
|
+
image_id,snip_id,len(detections)))
|
|
240
|
+
continue
|
|
241
|
+
|
|
242
|
+
det = detections[snip_id]
|
|
243
|
+
|
|
244
|
+
if 'classifications' not in det:
|
|
245
|
+
det['classifications'] = []
|
|
246
|
+
det['classifications'].append([category_id,r['prob']])
|
|
247
|
+
|
|
248
|
+
# ...for each classification in this image
|
|
249
|
+
|
|
250
|
+
# ...for each image
|
|
251
|
+
|
|
252
|
+
##%% Map MD results to the global level
|
|
253
|
+
|
|
254
|
+
if md_results_all['info'] is None:
|
|
255
|
+
md_results_all['info'] = md_results['info']
|
|
256
|
+
|
|
257
|
+
for category_id in md_results['detection_categories']:
|
|
258
|
+
if category_id not in md_results_all['detection_categories']:
|
|
259
|
+
md_results_all['detection_categories'][category_id] = \
|
|
260
|
+
md_results['detection_categories'][category_id]
|
|
261
|
+
else:
|
|
262
|
+
assert md_results_all['detection_categories'][category_id] == \
|
|
263
|
+
md_results['detection_categories'][category_id], \
|
|
264
|
+
'MD results present with incompatible detection categories'
|
|
265
|
+
|
|
266
|
+
# im = md_results['images'][0]
|
|
267
|
+
for im in md_results['images']:
|
|
268
|
+
im_copy = deepcopy(im)
|
|
269
|
+
im_copy['file'] = os.path.join(relative_folder,im['file']).replace('\\','/')
|
|
270
|
+
md_results_all['images'].append(im_copy)
|
|
271
|
+
|
|
272
|
+
# ...for each folder that contains MEWC results
|
|
273
|
+
|
|
274
|
+
del md_results
|
|
275
|
+
|
|
276
|
+
##%% Write output
|
|
277
|
+
|
|
278
|
+
md_results_all['classification_categories'] = invert_dictionary(classification_category_name_to_id)
|
|
279
|
+
|
|
280
|
+
if output_file is not None:
|
|
281
|
+
output_dir = os.path.dirname(output_file)
|
|
282
|
+
os.makedirs(output_dir,exist_ok=True)
|
|
283
|
+
with open(output_file,'w') as f:
|
|
284
|
+
json.dump(md_results_all,f,indent=1)
|
|
285
|
+
|
|
286
|
+
validation_options = ValidateBatchResultsOptions()
|
|
287
|
+
validation_options.check_image_existence = True
|
|
288
|
+
validation_options.relative_path_base = mewc_input_folder
|
|
289
|
+
validation_options.raise_errors = True
|
|
290
|
+
validation_results = validate_batch_results(output_file,validation_options) # noqa
|
|
291
|
+
|
|
292
|
+
# ...def mewc_to_md(...)
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
#%% Interactive driver
|
|
296
|
+
|
|
297
|
+
if False:
|
|
298
|
+
|
|
299
|
+
pass
|
|
300
|
+
|
|
301
|
+
#%%
|
|
302
|
+
|
|
303
|
+
mewc_input_folder = r'G:\temp\mewc-test'
|
|
304
|
+
mount_prefix = '/images/'
|
|
305
|
+
output_file = os.path.join(mewc_input_folder,'results_with_classes.json')
|
|
306
|
+
|
|
307
|
+
_ = mewc_to_md(mewc_input_folder=mewc_input_folder,
|
|
308
|
+
output_file=output_file,
|
|
309
|
+
mount_prefix=mount_prefix,
|
|
310
|
+
category_name_column='class_id')
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
#%% Command-line driver
|
|
314
|
+
|
|
315
|
+
def main(): # noqa
|
|
316
|
+
|
|
317
|
+
parser = argparse.ArgumentParser()
|
|
318
|
+
|
|
319
|
+
parser.add_argument(
|
|
320
|
+
'input_folder',type=str,
|
|
321
|
+
help='Folder containing images and MEWC .json/.csv files')
|
|
322
|
+
parser.add_argument(
|
|
323
|
+
'output_file',type=str,
|
|
324
|
+
help='.json file where output will be written')
|
|
325
|
+
parser.add_argument(
|
|
326
|
+
'--mount_prefix',type=str,default=default_mewc_mount_prefix,
|
|
327
|
+
help='prefix to remove from each filename in MEWC results, typically the Docker mount point')
|
|
328
|
+
parser.add_argument(
|
|
329
|
+
'--category_name_column',type=str,default=default_mewc_category_name_column,
|
|
330
|
+
help='column in the MEWC .csv file to use for category names')
|
|
331
|
+
|
|
332
|
+
if len(sys.argv[1:]) == 0:
|
|
333
|
+
parser.print_help()
|
|
334
|
+
parser.exit()
|
|
335
|
+
|
|
336
|
+
args = parser.parse_args()
|
|
337
|
+
|
|
338
|
+
_ = mewc_to_md(mewc_input_folder=args.input_folder,
|
|
339
|
+
output_file=args.output_file,
|
|
340
|
+
mount_prefix=args.mount_prefix,
|
|
341
|
+
category_name_column=args.category_name_column)
|
|
342
|
+
|
|
343
|
+
if __name__ == '__main__':
|
|
344
|
+
main()
|