megadetector 5.0.27__py3-none-any.whl → 5.0.29__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of megadetector might be problematic. Click here for more details.
- megadetector/api/batch_processing/api_core/batch_service/score.py +4 -5
- megadetector/api/batch_processing/api_core_support/aggregate_results_manually.py +1 -1
- megadetector/api/batch_processing/api_support/summarize_daily_activity.py +1 -1
- megadetector/api/batch_processing/integration/digiKam/xmp_integration.py +2 -2
- megadetector/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +1 -1
- megadetector/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +1 -1
- megadetector/api/synchronous/api_core/tests/load_test.py +2 -3
- megadetector/classification/aggregate_classifier_probs.py +3 -3
- megadetector/classification/analyze_failed_images.py +5 -5
- megadetector/classification/cache_batchapi_outputs.py +5 -5
- megadetector/classification/create_classification_dataset.py +11 -12
- megadetector/classification/crop_detections.py +10 -10
- megadetector/classification/csv_to_json.py +8 -8
- megadetector/classification/detect_and_crop.py +13 -15
- megadetector/classification/evaluate_model.py +7 -7
- megadetector/classification/identify_mislabeled_candidates.py +6 -6
- megadetector/classification/json_to_azcopy_list.py +1 -1
- megadetector/classification/json_validator.py +29 -32
- megadetector/classification/map_classification_categories.py +9 -9
- megadetector/classification/merge_classification_detection_output.py +12 -9
- megadetector/classification/prepare_classification_script.py +19 -19
- megadetector/classification/prepare_classification_script_mc.py +23 -23
- megadetector/classification/run_classifier.py +4 -4
- megadetector/classification/save_mislabeled.py +6 -6
- megadetector/classification/train_classifier.py +1 -1
- megadetector/classification/train_classifier_tf.py +9 -9
- megadetector/classification/train_utils.py +10 -10
- megadetector/data_management/annotations/annotation_constants.py +1 -1
- megadetector/data_management/camtrap_dp_to_coco.py +45 -45
- megadetector/data_management/cct_json_utils.py +101 -101
- megadetector/data_management/cct_to_md.py +49 -49
- megadetector/data_management/cct_to_wi.py +33 -33
- megadetector/data_management/coco_to_labelme.py +75 -75
- megadetector/data_management/coco_to_yolo.py +189 -189
- megadetector/data_management/databases/add_width_and_height_to_db.py +3 -2
- megadetector/data_management/databases/combine_coco_camera_traps_files.py +38 -38
- megadetector/data_management/databases/integrity_check_json_db.py +202 -188
- megadetector/data_management/databases/subset_json_db.py +33 -33
- megadetector/data_management/generate_crops_from_cct.py +38 -38
- megadetector/data_management/get_image_sizes.py +54 -49
- megadetector/data_management/labelme_to_coco.py +130 -124
- megadetector/data_management/labelme_to_yolo.py +78 -72
- megadetector/data_management/lila/create_lila_blank_set.py +81 -83
- megadetector/data_management/lila/create_lila_test_set.py +32 -31
- megadetector/data_management/lila/create_links_to_md_results_files.py +18 -18
- megadetector/data_management/lila/download_lila_subset.py +21 -24
- megadetector/data_management/lila/generate_lila_per_image_labels.py +91 -91
- megadetector/data_management/lila/get_lila_annotation_counts.py +30 -30
- megadetector/data_management/lila/get_lila_image_counts.py +22 -22
- megadetector/data_management/lila/lila_common.py +70 -70
- megadetector/data_management/lila/test_lila_metadata_urls.py +13 -14
- megadetector/data_management/mewc_to_md.py +339 -340
- megadetector/data_management/ocr_tools.py +258 -252
- megadetector/data_management/read_exif.py +232 -223
- megadetector/data_management/remap_coco_categories.py +26 -26
- megadetector/data_management/remove_exif.py +31 -20
- megadetector/data_management/rename_images.py +187 -187
- megadetector/data_management/resize_coco_dataset.py +41 -41
- megadetector/data_management/speciesnet_to_md.py +41 -41
- megadetector/data_management/wi_download_csv_to_coco.py +55 -55
- megadetector/data_management/yolo_output_to_md_output.py +117 -120
- megadetector/data_management/yolo_to_coco.py +195 -188
- megadetector/detection/change_detection.py +831 -0
- megadetector/detection/process_video.py +341 -338
- megadetector/detection/pytorch_detector.py +308 -266
- megadetector/detection/run_detector.py +186 -166
- megadetector/detection/run_detector_batch.py +366 -364
- megadetector/detection/run_inference_with_yolov5_val.py +328 -325
- megadetector/detection/run_tiled_inference.py +312 -253
- megadetector/detection/tf_detector.py +24 -24
- megadetector/detection/video_utils.py +291 -283
- megadetector/postprocessing/add_max_conf.py +15 -11
- megadetector/postprocessing/categorize_detections_by_size.py +44 -44
- megadetector/postprocessing/classification_postprocessing.py +808 -311
- megadetector/postprocessing/combine_batch_outputs.py +20 -21
- megadetector/postprocessing/compare_batch_results.py +528 -517
- megadetector/postprocessing/convert_output_format.py +97 -97
- megadetector/postprocessing/create_crop_folder.py +220 -147
- megadetector/postprocessing/detector_calibration.py +173 -168
- megadetector/postprocessing/generate_csv_report.py +508 -0
- megadetector/postprocessing/load_api_results.py +25 -22
- megadetector/postprocessing/md_to_coco.py +129 -98
- megadetector/postprocessing/md_to_labelme.py +89 -83
- megadetector/postprocessing/md_to_wi.py +40 -40
- megadetector/postprocessing/merge_detections.py +87 -114
- megadetector/postprocessing/postprocess_batch_results.py +319 -302
- megadetector/postprocessing/remap_detection_categories.py +36 -36
- megadetector/postprocessing/render_detection_confusion_matrix.py +205 -199
- megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py +57 -57
- megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +27 -28
- megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +702 -677
- megadetector/postprocessing/separate_detections_into_folders.py +226 -211
- megadetector/postprocessing/subset_json_detector_output.py +265 -262
- megadetector/postprocessing/top_folders_to_bottom.py +45 -45
- megadetector/postprocessing/validate_batch_results.py +70 -70
- megadetector/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +52 -52
- megadetector/taxonomy_mapping/map_new_lila_datasets.py +15 -15
- megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +14 -14
- megadetector/taxonomy_mapping/preview_lila_taxonomy.py +66 -69
- megadetector/taxonomy_mapping/retrieve_sample_image.py +16 -16
- megadetector/taxonomy_mapping/simple_image_download.py +8 -8
- megadetector/taxonomy_mapping/species_lookup.py +33 -33
- megadetector/taxonomy_mapping/taxonomy_csv_checker.py +14 -14
- megadetector/taxonomy_mapping/taxonomy_graph.py +11 -11
- megadetector/taxonomy_mapping/validate_lila_category_mappings.py +13 -13
- megadetector/utils/azure_utils.py +22 -22
- megadetector/utils/ct_utils.py +1019 -200
- megadetector/utils/directory_listing.py +21 -77
- megadetector/utils/gpu_test.py +22 -22
- megadetector/utils/md_tests.py +541 -518
- megadetector/utils/path_utils.py +1511 -406
- megadetector/utils/process_utils.py +41 -41
- megadetector/utils/sas_blob_utils.py +53 -49
- megadetector/utils/split_locations_into_train_val.py +73 -60
- megadetector/utils/string_utils.py +147 -26
- megadetector/utils/url_utils.py +463 -173
- megadetector/utils/wi_utils.py +2629 -2868
- megadetector/utils/write_html_image_list.py +137 -137
- megadetector/visualization/plot_utils.py +21 -21
- megadetector/visualization/render_images_with_thumbnails.py +37 -73
- megadetector/visualization/visualization_utils.py +424 -404
- megadetector/visualization/visualize_db.py +197 -190
- megadetector/visualization/visualize_detector_output.py +126 -98
- {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/METADATA +6 -3
- megadetector-5.0.29.dist-info/RECORD +163 -0
- {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/WHEEL +1 -1
- megadetector/data_management/importers/add_nacti_sizes.py +0 -52
- megadetector/data_management/importers/add_timestamps_to_icct.py +0 -79
- megadetector/data_management/importers/animl_results_to_md_results.py +0 -158
- megadetector/data_management/importers/auckland_doc_test_to_json.py +0 -373
- megadetector/data_management/importers/auckland_doc_to_json.py +0 -201
- megadetector/data_management/importers/awc_to_json.py +0 -191
- megadetector/data_management/importers/bellevue_to_json.py +0 -272
- megadetector/data_management/importers/cacophony-thermal-importer.py +0 -793
- megadetector/data_management/importers/carrizo_shrubfree_2018.py +0 -269
- megadetector/data_management/importers/carrizo_trail_cam_2017.py +0 -289
- megadetector/data_management/importers/cct_field_adjustments.py +0 -58
- megadetector/data_management/importers/channel_islands_to_cct.py +0 -913
- megadetector/data_management/importers/eMammal/copy_and_unzip_emammal.py +0 -180
- megadetector/data_management/importers/eMammal/eMammal_helpers.py +0 -249
- megadetector/data_management/importers/eMammal/make_eMammal_json.py +0 -223
- megadetector/data_management/importers/ena24_to_json.py +0 -276
- megadetector/data_management/importers/filenames_to_json.py +0 -386
- megadetector/data_management/importers/helena_to_cct.py +0 -283
- megadetector/data_management/importers/idaho-camera-traps.py +0 -1407
- megadetector/data_management/importers/idfg_iwildcam_lila_prep.py +0 -294
- megadetector/data_management/importers/import_desert_lion_conservation_camera_traps.py +0 -387
- megadetector/data_management/importers/jb_csv_to_json.py +0 -150
- megadetector/data_management/importers/mcgill_to_json.py +0 -250
- megadetector/data_management/importers/missouri_to_json.py +0 -490
- megadetector/data_management/importers/nacti_fieldname_adjustments.py +0 -79
- megadetector/data_management/importers/noaa_seals_2019.py +0 -181
- megadetector/data_management/importers/osu-small-animals-to-json.py +0 -364
- megadetector/data_management/importers/pc_to_json.py +0 -365
- megadetector/data_management/importers/plot_wni_giraffes.py +0 -123
- megadetector/data_management/importers/prepare_zsl_imerit.py +0 -131
- megadetector/data_management/importers/raic_csv_to_md_results.py +0 -416
- megadetector/data_management/importers/rspb_to_json.py +0 -356
- megadetector/data_management/importers/save_the_elephants_survey_A.py +0 -320
- megadetector/data_management/importers/save_the_elephants_survey_B.py +0 -329
- megadetector/data_management/importers/snapshot_safari_importer.py +0 -758
- megadetector/data_management/importers/snapshot_serengeti_lila.py +0 -1067
- megadetector/data_management/importers/snapshotserengeti/make_full_SS_json.py +0 -150
- megadetector/data_management/importers/snapshotserengeti/make_per_season_SS_json.py +0 -153
- megadetector/data_management/importers/sulross_get_exif.py +0 -65
- megadetector/data_management/importers/timelapse_csv_set_to_json.py +0 -490
- megadetector/data_management/importers/ubc_to_json.py +0 -399
- megadetector/data_management/importers/umn_to_json.py +0 -507
- megadetector/data_management/importers/wellington_to_json.py +0 -263
- megadetector/data_management/importers/wi_to_json.py +0 -442
- megadetector/data_management/importers/zamba_results_to_md_results.py +0 -180
- megadetector/data_management/lila/add_locations_to_island_camera_traps.py +0 -101
- megadetector/data_management/lila/add_locations_to_nacti.py +0 -151
- megadetector-5.0.27.dist-info/RECORD +0 -208
- {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/licenses/LICENSE +0 -0
- {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/top_level.txt +0 -0
|
@@ -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,76 @@ 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
|
|
|
85
88
|
"""
|
|
86
|
-
|
|
89
|
+
|
|
87
90
|
if isinstance(source_files,str):
|
|
88
|
-
source_files = [source_files]
|
|
89
|
-
|
|
91
|
+
source_files = [source_files]
|
|
92
|
+
|
|
90
93
|
if options is None:
|
|
91
|
-
options = MergeDetectionsOptions()
|
|
92
|
-
|
|
94
|
+
options = MergeDetectionsOptions()
|
|
95
|
+
|
|
93
96
|
if (not options.overwrite) and (os.path.isfile(output_file)):
|
|
94
97
|
print('File {} exists, bypassing merge'.format(output_file))
|
|
95
98
|
return
|
|
96
|
-
|
|
99
|
+
|
|
97
100
|
assert not ((options.categories_to_exclude is not None) and \
|
|
98
101
|
(options.categories_to_include is not None)), \
|
|
99
102
|
'categories_to_include and categories_to_exclude are mutually exclusive'
|
|
100
|
-
|
|
103
|
+
|
|
101
104
|
if options.categories_to_exclude is not None:
|
|
102
105
|
options.categories_to_exclude = [int(c) for c in options.categories_to_exclude]
|
|
103
|
-
|
|
106
|
+
|
|
104
107
|
if options.categories_to_include is not None:
|
|
105
108
|
options.categories_to_include = [int(c) for c in options.categories_to_include]
|
|
106
|
-
|
|
109
|
+
|
|
107
110
|
assert len(source_files) == len(options.source_confidence_thresholds), \
|
|
108
111
|
'{} source files provided, but {} source confidence thresholds provided'.format(
|
|
109
112
|
len(source_files),len(options.source_confidence_thresholds))
|
|
110
|
-
|
|
113
|
+
|
|
111
114
|
for fn in source_files:
|
|
112
115
|
assert os.path.isfile(fn), 'Could not find source file {}'.format(fn)
|
|
113
|
-
|
|
116
|
+
|
|
114
117
|
assert os.path.isfile(target_file)
|
|
115
|
-
|
|
118
|
+
|
|
116
119
|
os.makedirs(os.path.dirname(output_file),exist_ok=True)
|
|
117
|
-
|
|
120
|
+
|
|
118
121
|
with open(target_file,'r') as f:
|
|
119
122
|
output_data = json.load(f)
|
|
120
123
|
|
|
121
124
|
print('Loaded results for {} images'.format(len(output_data['images'])))
|
|
122
|
-
|
|
125
|
+
|
|
123
126
|
fn_to_image = {}
|
|
124
|
-
|
|
127
|
+
|
|
125
128
|
# im = output_data['images'][0]
|
|
126
129
|
for im in output_data['images']:
|
|
127
130
|
fn_to_image[im['file']] = im
|
|
128
|
-
|
|
131
|
+
|
|
129
132
|
if 'detections_transferred_from' not in output_data['info']:
|
|
130
133
|
output_data['info']['detections_transferred_from'] = []
|
|
131
134
|
|
|
132
135
|
if 'detector' not in output_data['info']:
|
|
133
136
|
output_data['info']['detector'] = 'MDv4 (assumed)'
|
|
134
|
-
|
|
137
|
+
|
|
135
138
|
detection_categories_raw = output_data['detection_categories'].keys()
|
|
136
|
-
|
|
139
|
+
|
|
137
140
|
# Determine whether we should be processing all categories, or just a subset
|
|
138
141
|
# of categories.
|
|
139
142
|
detection_categories = []
|
|
140
143
|
|
|
141
|
-
if options.categories_to_exclude is not None:
|
|
144
|
+
if options.categories_to_exclude is not None:
|
|
142
145
|
for c in detection_categories_raw:
|
|
143
146
|
if int(c) not in options.categories_to_exclude:
|
|
144
147
|
detection_categories.append(c)
|
|
@@ -151,148 +154,148 @@ def merge_detections(source_files,target_file,output_file,options=None):
|
|
|
151
154
|
detection_categories.append(c)
|
|
152
155
|
else:
|
|
153
156
|
detection_categories = detection_categories_raw
|
|
154
|
-
|
|
157
|
+
|
|
155
158
|
# i_source_file = 0; source_file = source_files[i_source_file]
|
|
156
159
|
for i_source_file,source_file in enumerate(source_files):
|
|
157
|
-
|
|
160
|
+
|
|
158
161
|
print('Processing detections from file {}'.format(source_file))
|
|
159
|
-
|
|
162
|
+
|
|
160
163
|
with open(source_file,'r') as f:
|
|
161
164
|
source_data = json.load(f)
|
|
162
|
-
|
|
165
|
+
|
|
163
166
|
if 'detector' in source_data['info']:
|
|
164
167
|
source_detector_name = source_data['info']['detector']
|
|
165
168
|
else:
|
|
166
169
|
source_detector_name = os.path.basename(source_file)
|
|
167
|
-
|
|
170
|
+
|
|
168
171
|
output_data['info']['detections_transferred_from'].append(os.path.basename(source_file))
|
|
169
172
|
output_data['info']['detector'] = output_data['info']['detector'] + ' + ' + source_detector_name
|
|
170
|
-
|
|
173
|
+
|
|
171
174
|
assert source_data['detection_categories'] == output_data['detection_categories'], \
|
|
172
175
|
'Cannot merge files with different detection category maps'
|
|
173
|
-
|
|
176
|
+
|
|
174
177
|
source_confidence_threshold = options.source_confidence_thresholds[i_source_file]
|
|
175
|
-
|
|
178
|
+
|
|
176
179
|
# source_im = source_data['images'][0]
|
|
177
180
|
for source_im in tqdm(source_data['images']):
|
|
178
|
-
|
|
179
|
-
image_filename = source_im['file']
|
|
180
|
-
|
|
181
|
+
|
|
182
|
+
image_filename = source_im['file']
|
|
183
|
+
|
|
181
184
|
assert image_filename in fn_to_image, 'Image {} not in target image set'.format(image_filename)
|
|
182
185
|
target_im = fn_to_image[image_filename]
|
|
183
|
-
|
|
186
|
+
|
|
184
187
|
if 'detections' not in source_im or source_im['detections'] is None:
|
|
185
188
|
continue
|
|
186
|
-
|
|
189
|
+
|
|
187
190
|
if 'detections' not in target_im or target_im['detections'] is None:
|
|
188
191
|
continue
|
|
189
|
-
|
|
192
|
+
|
|
190
193
|
source_detections_this_image = source_im['detections']
|
|
191
194
|
target_detections_this_image = target_im['detections']
|
|
192
|
-
|
|
195
|
+
|
|
193
196
|
detections_to_transfer = []
|
|
194
|
-
|
|
197
|
+
|
|
195
198
|
# detection_category = list(detection_categories)[0]
|
|
196
199
|
for detection_category in detection_categories:
|
|
197
|
-
|
|
200
|
+
|
|
198
201
|
target_detections_this_category = \
|
|
199
202
|
[det for det in target_detections_this_image if det['category'] == \
|
|
200
203
|
detection_category]
|
|
201
|
-
|
|
204
|
+
|
|
202
205
|
max_target_confidence_this_category = 0.0
|
|
203
|
-
|
|
206
|
+
|
|
204
207
|
if len(target_detections_this_category) > 0:
|
|
205
208
|
max_target_confidence_this_category = max([det['conf'] for \
|
|
206
209
|
det in target_detections_this_category])
|
|
207
|
-
|
|
210
|
+
|
|
208
211
|
# If we have a valid detection in the target file, and we're only merging
|
|
209
212
|
# into images that have no detections at all, we don't need to review the individual
|
|
210
213
|
# detections in the source file.
|
|
211
214
|
if options.merge_empty_only and \
|
|
212
215
|
(max_target_confidence_this_category >= options.target_confidence_threshold):
|
|
213
216
|
continue
|
|
214
|
-
|
|
217
|
+
|
|
215
218
|
source_detections_this_category_raw = [det for det in \
|
|
216
219
|
source_detections_this_image if det['category'] == detection_category]
|
|
217
|
-
|
|
220
|
+
|
|
218
221
|
# Boxes are x/y/w/h
|
|
219
222
|
# source_sizes = [det['bbox'][2]*det['bbox'][3] for det in source_detections_this_category_raw]
|
|
220
|
-
|
|
223
|
+
|
|
221
224
|
# Only look at source boxes within the size range
|
|
222
225
|
source_detections_this_category_filtered = [
|
|
223
226
|
det for det in source_detections_this_category_raw if \
|
|
224
227
|
(det['bbox'][2]*det['bbox'][3] <= options.max_detection_size) and \
|
|
225
228
|
(det['bbox'][2]*det['bbox'][3] >= options.min_detection_size) \
|
|
226
229
|
]
|
|
227
|
-
|
|
230
|
+
|
|
228
231
|
# det = source_detections_this_category_filtered[0]
|
|
229
232
|
for det in source_detections_this_category_filtered:
|
|
230
|
-
|
|
233
|
+
|
|
231
234
|
if det['conf'] >= source_confidence_threshold:
|
|
232
235
|
|
|
233
236
|
# Check only whole images
|
|
234
237
|
if options.merge_empty_only:
|
|
235
|
-
|
|
238
|
+
|
|
236
239
|
# We verified this above, asserting here for clarity
|
|
237
240
|
assert max_target_confidence_this_category < options.target_confidence_threshold
|
|
238
241
|
det['transferred_from'] = source_detector_name
|
|
239
242
|
detections_to_transfer.append(det)
|
|
240
243
|
|
|
241
|
-
# Check individual detections
|
|
244
|
+
# Check individual detections
|
|
242
245
|
else:
|
|
243
|
-
|
|
246
|
+
|
|
244
247
|
# Does this source detection match any existing above-threshold
|
|
245
248
|
# target category detections?
|
|
246
249
|
matches_existing_box = False
|
|
247
|
-
|
|
250
|
+
|
|
248
251
|
# target_detection = target_detections_this_category[0]
|
|
249
252
|
for target_detection in target_detections_this_category:
|
|
250
|
-
|
|
253
|
+
|
|
251
254
|
if (target_detection['conf'] >= options.target_confidence_threshold) \
|
|
252
255
|
and \
|
|
253
256
|
(get_iou(det['bbox'],target_detection['bbox']) >= options.iou_threshold):
|
|
254
257
|
matches_existing_box = True
|
|
255
258
|
break
|
|
256
|
-
|
|
259
|
+
|
|
257
260
|
if (not matches_existing_box):
|
|
258
261
|
det['transferred_from'] = source_detector_name
|
|
259
262
|
detections_to_transfer.append(det)
|
|
260
|
-
|
|
263
|
+
|
|
261
264
|
# ...if this source detection is above the confidence threshold
|
|
262
|
-
|
|
263
|
-
# ...for each source detection within category
|
|
264
|
-
|
|
265
|
+
|
|
266
|
+
# ...for each source detection within category
|
|
267
|
+
|
|
265
268
|
# ...for each detection category
|
|
266
|
-
|
|
269
|
+
|
|
267
270
|
if len(detections_to_transfer) > 0:
|
|
268
|
-
|
|
271
|
+
|
|
269
272
|
# print('Adding {} detections to image {}'.format(len(detections_to_transfer),image_filename))
|
|
270
|
-
detections = fn_to_image[image_filename]['detections']
|
|
273
|
+
detections = fn_to_image[image_filename]['detections']
|
|
271
274
|
detections.extend(detections_to_transfer)
|
|
272
275
|
|
|
273
276
|
# Update the max_detection_conf field (if present)
|
|
274
277
|
if 'max_detection_conf' in fn_to_image[image_filename]:
|
|
275
278
|
fn_to_image[image_filename]['max_detection_conf'] = \
|
|
276
279
|
max([d['conf'] for d in detections])
|
|
277
|
-
|
|
280
|
+
|
|
278
281
|
# ...if we have any detections to transfer
|
|
279
|
-
|
|
282
|
+
|
|
280
283
|
# ...for each image
|
|
281
|
-
|
|
282
|
-
# ...for each source file
|
|
283
|
-
|
|
284
|
+
|
|
285
|
+
# ...for each source file
|
|
286
|
+
|
|
284
287
|
with open(output_file,'w') as f:
|
|
285
288
|
json.dump(output_data,f,indent=1)
|
|
286
|
-
|
|
289
|
+
|
|
287
290
|
print('Saved merged results to {}'.format(output_file))
|
|
288
291
|
|
|
289
292
|
|
|
290
293
|
#%% Command-line driver
|
|
291
294
|
|
|
292
|
-
def main():
|
|
293
|
-
|
|
295
|
+
def main(): # noqa
|
|
296
|
+
|
|
294
297
|
default_options = MergeDetectionsOptions()
|
|
295
|
-
|
|
298
|
+
|
|
296
299
|
parser = argparse.ArgumentParser(
|
|
297
300
|
description='Merge detections from one or more MegaDetector results files into an existing reuslts file')
|
|
298
301
|
parser.add_argument(
|
|
@@ -351,7 +354,7 @@ def main():
|
|
|
351
354
|
'--merge_empty_only',
|
|
352
355
|
action='store_true',
|
|
353
356
|
help='Ignore individual detections and only merge images for which the target ' + \
|
|
354
|
-
'file contains no detections')
|
|
357
|
+
'file contains no detections')
|
|
355
358
|
parser.add_argument(
|
|
356
359
|
'--iou_threshold',
|
|
357
360
|
type=float,
|
|
@@ -374,39 +377,9 @@ def main():
|
|
|
374
377
|
options.categories_to_exclude = args.categories_to_exclude
|
|
375
378
|
options.merge_empty_only = args.merge_empty_only
|
|
376
379
|
options.iou_threshold = args.iou_threshold
|
|
377
|
-
|
|
378
|
-
merge_detections(args.source_files, args.target_file, args.output_file, options)
|
|
379
380
|
|
|
381
|
+
merge_detections(args.source_files, args.target_file, args.output_file, options)
|
|
380
382
|
|
|
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
383
|
if __name__ == '__main__':
|
|
411
384
|
main()
|
|
412
385
|
|