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
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
merge_detections.py
|
|
4
4
|
|
|
5
|
-
Merge high-confidence detections from one or more results files into another
|
|
5
|
+
Merge high-confidence detections from one or more results files into another
|
|
6
6
|
file. Typically used to combine results from MDv5b and/or MDv4 into a "primary"
|
|
7
7
|
results file from MDv5a.
|
|
8
8
|
|
|
@@ -28,39 +28,42 @@ from megadetector.utils.ct_utils import get_iou
|
|
|
28
28
|
#%% Structs
|
|
29
29
|
|
|
30
30
|
class MergeDetectionsOptions:
|
|
31
|
-
|
|
31
|
+
"""
|
|
32
|
+
Class defining options for merge_detections().
|
|
33
|
+
"""
|
|
34
|
+
|
|
32
35
|
def __init__(self):
|
|
33
|
-
|
|
36
|
+
|
|
34
37
|
#: Maximum detection size to include in the merged output
|
|
35
38
|
self.max_detection_size = 1.01
|
|
36
|
-
|
|
39
|
+
|
|
37
40
|
#: Minimum detection size to include in the merged output
|
|
38
41
|
self.min_detection_size = 0
|
|
39
|
-
|
|
42
|
+
|
|
40
43
|
#: Exclude detections whose confidence in the source file(s) is less
|
|
41
44
|
#: than this. Should have the same length as the number of source files.
|
|
42
45
|
self.source_confidence_thresholds = [0.05]
|
|
43
|
-
|
|
46
|
+
|
|
44
47
|
#: Don't bother merging into target images if there is a similar detection
|
|
45
48
|
#: above this threshold (or if there is *any* detection above this threshold,
|
|
46
49
|
#: and merge_empty_only is True)
|
|
47
50
|
self.target_confidence_threshold = 0.2
|
|
48
|
-
|
|
51
|
+
|
|
49
52
|
#: If you want to merge only certain categories, specify one
|
|
50
53
|
#: (but not both) of these. These are category IDs, not names.
|
|
51
54
|
self.categories_to_include = None
|
|
52
|
-
|
|
55
|
+
|
|
53
56
|
#: If you want to merge only certain categories, specify one
|
|
54
57
|
#: (but not both) of these. These are category IDs, not names.
|
|
55
58
|
self.categories_to_exclude = None
|
|
56
59
|
|
|
57
|
-
#: Only merge detections into images that have *no* detections in the
|
|
60
|
+
#: Only merge detections into images that have *no* detections in the
|
|
58
61
|
#: target results file.
|
|
59
62
|
self.merge_empty_only = False
|
|
60
|
-
|
|
63
|
+
|
|
61
64
|
#: IoU threshold above which two detections are considered the same
|
|
62
65
|
self.iou_threshold = 0.65
|
|
63
|
-
|
|
66
|
+
|
|
64
67
|
#: Error if this is False and the output file exists
|
|
65
68
|
self.overwrite = False
|
|
66
69
|
|
|
@@ -69,76 +72,81 @@ class MergeDetectionsOptions:
|
|
|
69
72
|
|
|
70
73
|
def merge_detections(source_files,target_file,output_file,options=None):
|
|
71
74
|
"""
|
|
72
|
-
Merge high-confidence detections from one or more results files into another
|
|
75
|
+
Merge high-confidence detections from one or more results files into another
|
|
73
76
|
file. Typically used to combine results from MDv5b and/or MDv4 into a "primary"
|
|
74
77
|
results file from MDv5a.
|
|
75
|
-
|
|
76
|
-
[source_files] (a list of files or a single filename) specifies the set of
|
|
77
|
-
results files that will be merged into [target_file]. The difference between a
|
|
78
|
+
|
|
79
|
+
[source_files] (a list of files or a single filename) specifies the set of
|
|
80
|
+
results files that will be merged into [target_file]. The difference between a
|
|
78
81
|
"source file" and the "target file" is that if no merging is necessary, either because
|
|
79
82
|
two boxes are nearly identical or because merge_only_empty is True and the target
|
|
80
83
|
file already has above-threshold detection for an image+category, the output file gets
|
|
81
84
|
the results of the "target" file. I.e., the "target" file wins all ties.
|
|
82
|
-
|
|
85
|
+
|
|
83
86
|
The results are written to [output_file].
|
|
84
87
|
|
|
88
|
+
Args:
|
|
89
|
+
source_files (list of str): list of files to merge into the results in [target_file]
|
|
90
|
+
target_file (str): filename that is treated as the primary source of results
|
|
91
|
+
output_file (str): file to which we should write merged results
|
|
92
|
+
options (MergeDetectionsOptions, optional): see MergeDetectionsOptions
|
|
85
93
|
"""
|
|
86
|
-
|
|
94
|
+
|
|
87
95
|
if isinstance(source_files,str):
|
|
88
|
-
source_files = [source_files]
|
|
89
|
-
|
|
96
|
+
source_files = [source_files]
|
|
97
|
+
|
|
90
98
|
if options is None:
|
|
91
|
-
options = MergeDetectionsOptions()
|
|
92
|
-
|
|
99
|
+
options = MergeDetectionsOptions()
|
|
100
|
+
|
|
93
101
|
if (not options.overwrite) and (os.path.isfile(output_file)):
|
|
94
102
|
print('File {} exists, bypassing merge'.format(output_file))
|
|
95
103
|
return
|
|
96
|
-
|
|
104
|
+
|
|
97
105
|
assert not ((options.categories_to_exclude is not None) and \
|
|
98
106
|
(options.categories_to_include is not None)), \
|
|
99
107
|
'categories_to_include and categories_to_exclude are mutually exclusive'
|
|
100
|
-
|
|
108
|
+
|
|
101
109
|
if options.categories_to_exclude is not None:
|
|
102
110
|
options.categories_to_exclude = [int(c) for c in options.categories_to_exclude]
|
|
103
|
-
|
|
111
|
+
|
|
104
112
|
if options.categories_to_include is not None:
|
|
105
113
|
options.categories_to_include = [int(c) for c in options.categories_to_include]
|
|
106
|
-
|
|
114
|
+
|
|
107
115
|
assert len(source_files) == len(options.source_confidence_thresholds), \
|
|
108
116
|
'{} source files provided, but {} source confidence thresholds provided'.format(
|
|
109
117
|
len(source_files),len(options.source_confidence_thresholds))
|
|
110
|
-
|
|
118
|
+
|
|
111
119
|
for fn in source_files:
|
|
112
120
|
assert os.path.isfile(fn), 'Could not find source file {}'.format(fn)
|
|
113
|
-
|
|
121
|
+
|
|
114
122
|
assert os.path.isfile(target_file)
|
|
115
|
-
|
|
123
|
+
|
|
116
124
|
os.makedirs(os.path.dirname(output_file),exist_ok=True)
|
|
117
|
-
|
|
125
|
+
|
|
118
126
|
with open(target_file,'r') as f:
|
|
119
127
|
output_data = json.load(f)
|
|
120
128
|
|
|
121
129
|
print('Loaded results for {} images'.format(len(output_data['images'])))
|
|
122
|
-
|
|
130
|
+
|
|
123
131
|
fn_to_image = {}
|
|
124
|
-
|
|
132
|
+
|
|
125
133
|
# im = output_data['images'][0]
|
|
126
134
|
for im in output_data['images']:
|
|
127
135
|
fn_to_image[im['file']] = im
|
|
128
|
-
|
|
136
|
+
|
|
129
137
|
if 'detections_transferred_from' not in output_data['info']:
|
|
130
138
|
output_data['info']['detections_transferred_from'] = []
|
|
131
139
|
|
|
132
140
|
if 'detector' not in output_data['info']:
|
|
133
141
|
output_data['info']['detector'] = 'MDv4 (assumed)'
|
|
134
|
-
|
|
142
|
+
|
|
135
143
|
detection_categories_raw = output_data['detection_categories'].keys()
|
|
136
|
-
|
|
144
|
+
|
|
137
145
|
# Determine whether we should be processing all categories, or just a subset
|
|
138
146
|
# of categories.
|
|
139
147
|
detection_categories = []
|
|
140
148
|
|
|
141
|
-
if options.categories_to_exclude is not None:
|
|
149
|
+
if options.categories_to_exclude is not None:
|
|
142
150
|
for c in detection_categories_raw:
|
|
143
151
|
if int(c) not in options.categories_to_exclude:
|
|
144
152
|
detection_categories.append(c)
|
|
@@ -151,148 +159,148 @@ def merge_detections(source_files,target_file,output_file,options=None):
|
|
|
151
159
|
detection_categories.append(c)
|
|
152
160
|
else:
|
|
153
161
|
detection_categories = detection_categories_raw
|
|
154
|
-
|
|
162
|
+
|
|
155
163
|
# i_source_file = 0; source_file = source_files[i_source_file]
|
|
156
164
|
for i_source_file,source_file in enumerate(source_files):
|
|
157
|
-
|
|
165
|
+
|
|
158
166
|
print('Processing detections from file {}'.format(source_file))
|
|
159
|
-
|
|
167
|
+
|
|
160
168
|
with open(source_file,'r') as f:
|
|
161
169
|
source_data = json.load(f)
|
|
162
|
-
|
|
170
|
+
|
|
163
171
|
if 'detector' in source_data['info']:
|
|
164
172
|
source_detector_name = source_data['info']['detector']
|
|
165
173
|
else:
|
|
166
174
|
source_detector_name = os.path.basename(source_file)
|
|
167
|
-
|
|
175
|
+
|
|
168
176
|
output_data['info']['detections_transferred_from'].append(os.path.basename(source_file))
|
|
169
177
|
output_data['info']['detector'] = output_data['info']['detector'] + ' + ' + source_detector_name
|
|
170
|
-
|
|
178
|
+
|
|
171
179
|
assert source_data['detection_categories'] == output_data['detection_categories'], \
|
|
172
180
|
'Cannot merge files with different detection category maps'
|
|
173
|
-
|
|
181
|
+
|
|
174
182
|
source_confidence_threshold = options.source_confidence_thresholds[i_source_file]
|
|
175
|
-
|
|
183
|
+
|
|
176
184
|
# source_im = source_data['images'][0]
|
|
177
185
|
for source_im in tqdm(source_data['images']):
|
|
178
|
-
|
|
179
|
-
image_filename = source_im['file']
|
|
180
|
-
|
|
186
|
+
|
|
187
|
+
image_filename = source_im['file']
|
|
188
|
+
|
|
181
189
|
assert image_filename in fn_to_image, 'Image {} not in target image set'.format(image_filename)
|
|
182
190
|
target_im = fn_to_image[image_filename]
|
|
183
|
-
|
|
191
|
+
|
|
184
192
|
if 'detections' not in source_im or source_im['detections'] is None:
|
|
185
193
|
continue
|
|
186
|
-
|
|
194
|
+
|
|
187
195
|
if 'detections' not in target_im or target_im['detections'] is None:
|
|
188
196
|
continue
|
|
189
|
-
|
|
197
|
+
|
|
190
198
|
source_detections_this_image = source_im['detections']
|
|
191
199
|
target_detections_this_image = target_im['detections']
|
|
192
|
-
|
|
200
|
+
|
|
193
201
|
detections_to_transfer = []
|
|
194
|
-
|
|
202
|
+
|
|
195
203
|
# detection_category = list(detection_categories)[0]
|
|
196
204
|
for detection_category in detection_categories:
|
|
197
|
-
|
|
205
|
+
|
|
198
206
|
target_detections_this_category = \
|
|
199
207
|
[det for det in target_detections_this_image if det['category'] == \
|
|
200
208
|
detection_category]
|
|
201
|
-
|
|
209
|
+
|
|
202
210
|
max_target_confidence_this_category = 0.0
|
|
203
|
-
|
|
211
|
+
|
|
204
212
|
if len(target_detections_this_category) > 0:
|
|
205
213
|
max_target_confidence_this_category = max([det['conf'] for \
|
|
206
214
|
det in target_detections_this_category])
|
|
207
|
-
|
|
215
|
+
|
|
208
216
|
# If we have a valid detection in the target file, and we're only merging
|
|
209
217
|
# into images that have no detections at all, we don't need to review the individual
|
|
210
218
|
# detections in the source file.
|
|
211
219
|
if options.merge_empty_only and \
|
|
212
220
|
(max_target_confidence_this_category >= options.target_confidence_threshold):
|
|
213
221
|
continue
|
|
214
|
-
|
|
222
|
+
|
|
215
223
|
source_detections_this_category_raw = [det for det in \
|
|
216
224
|
source_detections_this_image if det['category'] == detection_category]
|
|
217
|
-
|
|
225
|
+
|
|
218
226
|
# Boxes are x/y/w/h
|
|
219
227
|
# source_sizes = [det['bbox'][2]*det['bbox'][3] for det in source_detections_this_category_raw]
|
|
220
|
-
|
|
228
|
+
|
|
221
229
|
# Only look at source boxes within the size range
|
|
222
230
|
source_detections_this_category_filtered = [
|
|
223
231
|
det for det in source_detections_this_category_raw if \
|
|
224
232
|
(det['bbox'][2]*det['bbox'][3] <= options.max_detection_size) and \
|
|
225
233
|
(det['bbox'][2]*det['bbox'][3] >= options.min_detection_size) \
|
|
226
234
|
]
|
|
227
|
-
|
|
235
|
+
|
|
228
236
|
# det = source_detections_this_category_filtered[0]
|
|
229
237
|
for det in source_detections_this_category_filtered:
|
|
230
|
-
|
|
238
|
+
|
|
231
239
|
if det['conf'] >= source_confidence_threshold:
|
|
232
240
|
|
|
233
241
|
# Check only whole images
|
|
234
242
|
if options.merge_empty_only:
|
|
235
|
-
|
|
243
|
+
|
|
236
244
|
# We verified this above, asserting here for clarity
|
|
237
245
|
assert max_target_confidence_this_category < options.target_confidence_threshold
|
|
238
246
|
det['transferred_from'] = source_detector_name
|
|
239
247
|
detections_to_transfer.append(det)
|
|
240
248
|
|
|
241
|
-
# Check individual detections
|
|
249
|
+
# Check individual detections
|
|
242
250
|
else:
|
|
243
|
-
|
|
251
|
+
|
|
244
252
|
# Does this source detection match any existing above-threshold
|
|
245
253
|
# target category detections?
|
|
246
254
|
matches_existing_box = False
|
|
247
|
-
|
|
255
|
+
|
|
248
256
|
# target_detection = target_detections_this_category[0]
|
|
249
257
|
for target_detection in target_detections_this_category:
|
|
250
|
-
|
|
258
|
+
|
|
251
259
|
if (target_detection['conf'] >= options.target_confidence_threshold) \
|
|
252
260
|
and \
|
|
253
261
|
(get_iou(det['bbox'],target_detection['bbox']) >= options.iou_threshold):
|
|
254
262
|
matches_existing_box = True
|
|
255
263
|
break
|
|
256
|
-
|
|
264
|
+
|
|
257
265
|
if (not matches_existing_box):
|
|
258
266
|
det['transferred_from'] = source_detector_name
|
|
259
267
|
detections_to_transfer.append(det)
|
|
260
|
-
|
|
268
|
+
|
|
261
269
|
# ...if this source detection is above the confidence threshold
|
|
262
|
-
|
|
263
|
-
# ...for each source detection within category
|
|
264
|
-
|
|
270
|
+
|
|
271
|
+
# ...for each source detection within category
|
|
272
|
+
|
|
265
273
|
# ...for each detection category
|
|
266
|
-
|
|
274
|
+
|
|
267
275
|
if len(detections_to_transfer) > 0:
|
|
268
|
-
|
|
276
|
+
|
|
269
277
|
# print('Adding {} detections to image {}'.format(len(detections_to_transfer),image_filename))
|
|
270
|
-
detections = fn_to_image[image_filename]['detections']
|
|
278
|
+
detections = fn_to_image[image_filename]['detections']
|
|
271
279
|
detections.extend(detections_to_transfer)
|
|
272
280
|
|
|
273
281
|
# Update the max_detection_conf field (if present)
|
|
274
282
|
if 'max_detection_conf' in fn_to_image[image_filename]:
|
|
275
283
|
fn_to_image[image_filename]['max_detection_conf'] = \
|
|
276
284
|
max([d['conf'] for d in detections])
|
|
277
|
-
|
|
285
|
+
|
|
278
286
|
# ...if we have any detections to transfer
|
|
279
|
-
|
|
287
|
+
|
|
280
288
|
# ...for each image
|
|
281
|
-
|
|
282
|
-
# ...for each source file
|
|
283
|
-
|
|
289
|
+
|
|
290
|
+
# ...for each source file
|
|
291
|
+
|
|
284
292
|
with open(output_file,'w') as f:
|
|
285
293
|
json.dump(output_data,f,indent=1)
|
|
286
|
-
|
|
294
|
+
|
|
287
295
|
print('Saved merged results to {}'.format(output_file))
|
|
288
296
|
|
|
289
297
|
|
|
290
298
|
#%% Command-line driver
|
|
291
299
|
|
|
292
|
-
def main():
|
|
293
|
-
|
|
300
|
+
def main(): # noqa
|
|
301
|
+
|
|
294
302
|
default_options = MergeDetectionsOptions()
|
|
295
|
-
|
|
303
|
+
|
|
296
304
|
parser = argparse.ArgumentParser(
|
|
297
305
|
description='Merge detections from one or more MegaDetector results files into an existing reuslts file')
|
|
298
306
|
parser.add_argument(
|
|
@@ -351,7 +359,7 @@ def main():
|
|
|
351
359
|
'--merge_empty_only',
|
|
352
360
|
action='store_true',
|
|
353
361
|
help='Ignore individual detections and only merge images for which the target ' + \
|
|
354
|
-
'file contains no detections')
|
|
362
|
+
'file contains no detections')
|
|
355
363
|
parser.add_argument(
|
|
356
364
|
'--iou_threshold',
|
|
357
365
|
type=float,
|
|
@@ -374,39 +382,9 @@ def main():
|
|
|
374
382
|
options.categories_to_exclude = args.categories_to_exclude
|
|
375
383
|
options.merge_empty_only = args.merge_empty_only
|
|
376
384
|
options.iou_threshold = args.iou_threshold
|
|
377
|
-
|
|
378
|
-
merge_detections(args.source_files, args.target_file, args.output_file, options)
|
|
379
385
|
|
|
386
|
+
merge_detections(args.source_files, args.target_file, args.output_file, options)
|
|
380
387
|
|
|
381
|
-
#%% Test driver
|
|
382
|
-
|
|
383
|
-
if False:
|
|
384
|
-
|
|
385
|
-
#%%
|
|
386
|
-
|
|
387
|
-
options = MergeDetectionsOptions()
|
|
388
|
-
options.max_detection_size = 0.1
|
|
389
|
-
options.target_confidence_threshold = 0.3
|
|
390
|
-
options.categories_to_include = [1]
|
|
391
|
-
source_files = ['/home/user/postprocessing/iwildcam/iwildcam-mdv4-2022-05-01/combined_api_outputs/iwildcam-mdv4-2022-05-01_detections.json']
|
|
392
|
-
options.source_confidence_thresholds = [0.8]
|
|
393
|
-
target_file = '/home/user/postprocessing/iwildcam/iwildcam-mdv5-camcocoinat-2022-05-02/combined_api_outputs/iwildcam-mdv5-camcocoinat-2022-05-02_detections.json'
|
|
394
|
-
output_file = '/home/user/postprocessing/iwildcam/merged-detections/mdv4_mdv5-camcocoinat-2022-05-02.json'
|
|
395
|
-
merge_detections(source_files, target_file, output_file, options)
|
|
396
|
-
|
|
397
|
-
options = MergeDetectionsOptions()
|
|
398
|
-
options.max_detection_size = 0.1
|
|
399
|
-
options.target_confidence_threshold = 0.3
|
|
400
|
-
options.categories_to_include = [1]
|
|
401
|
-
source_files = [
|
|
402
|
-
'/home/user/postprocessing/iwildcam/iwildcam-mdv4-2022-05-01/combined_api_outputs/iwildcam-mdv4-2022-05-01_detections.json',
|
|
403
|
-
'/home/user/postprocessing/iwildcam/iwildcam-mdv5-camonly-2022-05-02/combined_api_outputs/iwildcam-mdv5-camonly-2022-05-02_detections.json',
|
|
404
|
-
]
|
|
405
|
-
options.source_confidence_thresholds = [0.8,0.5]
|
|
406
|
-
target_file = '/home/user/postprocessing/iwildcam/iwildcam-mdv5-camcocoinat-2022-05-02/combined_api_outputs/iwildcam-mdv5-camcocoinat-2022-05-02_detections.json'
|
|
407
|
-
output_file = '/home/user/postprocessing/iwildcam/merged-detections/mdv4_mdv5-camonly_mdv5-camcocoinat-2022-05-02.json'
|
|
408
|
-
merge_detections(source_files, target_file, output_file, options)
|
|
409
|
-
|
|
410
388
|
if __name__ == '__main__':
|
|
411
389
|
main()
|
|
412
390
|
|