megadetector 5.0.8__py3-none-any.whl → 5.0.10__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.
- api/__init__.py +0 -0
- api/batch_processing/__init__.py +0 -0
- api/batch_processing/api_core/__init__.py +0 -0
- api/batch_processing/api_core/batch_service/__init__.py +0 -0
- api/batch_processing/api_core/batch_service/score.py +0 -1
- api/batch_processing/api_core/server_job_status_table.py +0 -1
- api/batch_processing/api_core_support/__init__.py +0 -0
- api/batch_processing/api_core_support/aggregate_results_manually.py +0 -1
- api/batch_processing/api_support/__init__.py +0 -0
- api/batch_processing/api_support/summarize_daily_activity.py +0 -1
- api/batch_processing/data_preparation/__init__.py +0 -0
- api/batch_processing/data_preparation/manage_local_batch.py +65 -65
- api/batch_processing/data_preparation/manage_video_batch.py +8 -8
- api/batch_processing/integration/digiKam/xmp_integration.py +0 -1
- api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +0 -1
- api/batch_processing/postprocessing/__init__.py +0 -0
- api/batch_processing/postprocessing/add_max_conf.py +12 -12
- api/batch_processing/postprocessing/categorize_detections_by_size.py +32 -14
- api/batch_processing/postprocessing/combine_api_outputs.py +68 -54
- api/batch_processing/postprocessing/compare_batch_results.py +113 -43
- api/batch_processing/postprocessing/convert_output_format.py +41 -16
- api/batch_processing/postprocessing/load_api_results.py +16 -17
- api/batch_processing/postprocessing/md_to_coco.py +31 -21
- api/batch_processing/postprocessing/md_to_labelme.py +52 -22
- api/batch_processing/postprocessing/merge_detections.py +14 -14
- api/batch_processing/postprocessing/postprocess_batch_results.py +246 -174
- api/batch_processing/postprocessing/remap_detection_categories.py +32 -25
- api/batch_processing/postprocessing/render_detection_confusion_matrix.py +60 -27
- api/batch_processing/postprocessing/repeat_detection_elimination/find_repeat_detections.py +53 -44
- api/batch_processing/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +25 -14
- api/batch_processing/postprocessing/repeat_detection_elimination/repeat_detections_core.py +242 -158
- api/batch_processing/postprocessing/separate_detections_into_folders.py +159 -114
- api/batch_processing/postprocessing/subset_json_detector_output.py +146 -169
- api/batch_processing/postprocessing/top_folders_to_bottom.py +77 -43
- api/synchronous/__init__.py +0 -0
- api/synchronous/api_core/animal_detection_api/__init__.py +0 -0
- api/synchronous/api_core/animal_detection_api/api_backend.py +0 -2
- api/synchronous/api_core/animal_detection_api/api_frontend.py +266 -268
- api/synchronous/api_core/animal_detection_api/config.py +35 -35
- api/synchronous/api_core/tests/__init__.py +0 -0
- api/synchronous/api_core/tests/load_test.py +109 -109
- classification/__init__.py +0 -0
- classification/aggregate_classifier_probs.py +21 -24
- classification/analyze_failed_images.py +11 -13
- classification/cache_batchapi_outputs.py +51 -51
- classification/create_classification_dataset.py +69 -68
- classification/crop_detections.py +54 -53
- classification/csv_to_json.py +97 -100
- classification/detect_and_crop.py +105 -105
- classification/evaluate_model.py +43 -42
- classification/identify_mislabeled_candidates.py +47 -46
- classification/json_to_azcopy_list.py +10 -10
- classification/json_validator.py +72 -71
- classification/map_classification_categories.py +44 -43
- classification/merge_classification_detection_output.py +68 -68
- classification/prepare_classification_script.py +157 -154
- classification/prepare_classification_script_mc.py +228 -228
- classification/run_classifier.py +27 -26
- classification/save_mislabeled.py +30 -30
- classification/train_classifier.py +20 -20
- classification/train_classifier_tf.py +21 -22
- classification/train_utils.py +10 -10
- data_management/__init__.py +0 -0
- data_management/annotations/__init__.py +0 -0
- data_management/annotations/annotation_constants.py +18 -31
- data_management/camtrap_dp_to_coco.py +238 -0
- data_management/cct_json_utils.py +102 -59
- data_management/cct_to_md.py +176 -158
- data_management/cct_to_wi.py +247 -219
- data_management/coco_to_labelme.py +272 -263
- data_management/coco_to_yolo.py +79 -58
- data_management/databases/__init__.py +0 -0
- data_management/databases/add_width_and_height_to_db.py +20 -16
- data_management/databases/combine_coco_camera_traps_files.py +35 -31
- data_management/databases/integrity_check_json_db.py +62 -24
- data_management/databases/subset_json_db.py +24 -15
- data_management/generate_crops_from_cct.py +27 -45
- data_management/get_image_sizes.py +188 -162
- data_management/importers/add_nacti_sizes.py +8 -8
- data_management/importers/add_timestamps_to_icct.py +78 -78
- data_management/importers/animl_results_to_md_results.py +158 -158
- data_management/importers/auckland_doc_test_to_json.py +9 -9
- data_management/importers/auckland_doc_to_json.py +8 -8
- data_management/importers/awc_to_json.py +7 -7
- data_management/importers/bellevue_to_json.py +15 -15
- data_management/importers/cacophony-thermal-importer.py +13 -13
- data_management/importers/carrizo_shrubfree_2018.py +8 -8
- data_management/importers/carrizo_trail_cam_2017.py +8 -8
- data_management/importers/cct_field_adjustments.py +9 -9
- data_management/importers/channel_islands_to_cct.py +10 -10
- data_management/importers/eMammal/copy_and_unzip_emammal.py +1 -0
- data_management/importers/ena24_to_json.py +7 -7
- data_management/importers/filenames_to_json.py +8 -8
- data_management/importers/helena_to_cct.py +7 -7
- data_management/importers/idaho-camera-traps.py +7 -7
- data_management/importers/idfg_iwildcam_lila_prep.py +10 -10
- data_management/importers/jb_csv_to_json.py +9 -9
- data_management/importers/mcgill_to_json.py +8 -8
- data_management/importers/missouri_to_json.py +18 -18
- data_management/importers/nacti_fieldname_adjustments.py +10 -10
- data_management/importers/noaa_seals_2019.py +7 -7
- data_management/importers/pc_to_json.py +7 -7
- data_management/importers/plot_wni_giraffes.py +7 -7
- data_management/importers/prepare-noaa-fish-data-for-lila.py +359 -359
- data_management/importers/prepare_zsl_imerit.py +7 -7
- data_management/importers/rspb_to_json.py +8 -8
- data_management/importers/save_the_elephants_survey_A.py +8 -8
- data_management/importers/save_the_elephants_survey_B.py +9 -9
- data_management/importers/snapshot_safari_importer.py +26 -26
- data_management/importers/snapshot_safari_importer_reprise.py +665 -665
- data_management/importers/snapshot_serengeti_lila.py +14 -14
- data_management/importers/sulross_get_exif.py +8 -9
- data_management/importers/timelapse_csv_set_to_json.py +11 -11
- data_management/importers/ubc_to_json.py +13 -13
- data_management/importers/umn_to_json.py +7 -7
- data_management/importers/wellington_to_json.py +8 -8
- data_management/importers/wi_to_json.py +9 -9
- data_management/importers/zamba_results_to_md_results.py +181 -181
- data_management/labelme_to_coco.py +65 -24
- data_management/labelme_to_yolo.py +8 -8
- data_management/lila/__init__.py +0 -0
- data_management/lila/add_locations_to_island_camera_traps.py +9 -9
- data_management/lila/add_locations_to_nacti.py +147 -147
- data_management/lila/create_lila_blank_set.py +13 -13
- data_management/lila/create_lila_test_set.py +8 -8
- data_management/lila/create_links_to_md_results_files.py +106 -106
- data_management/lila/download_lila_subset.py +44 -110
- data_management/lila/generate_lila_per_image_labels.py +55 -42
- data_management/lila/get_lila_annotation_counts.py +18 -15
- data_management/lila/get_lila_image_counts.py +11 -11
- data_management/lila/lila_common.py +96 -33
- data_management/lila/test_lila_metadata_urls.py +132 -116
- data_management/ocr_tools.py +173 -128
- data_management/read_exif.py +110 -97
- data_management/remap_coco_categories.py +83 -83
- data_management/remove_exif.py +58 -62
- data_management/resize_coco_dataset.py +30 -23
- data_management/wi_download_csv_to_coco.py +246 -239
- data_management/yolo_output_to_md_output.py +86 -73
- data_management/yolo_to_coco.py +300 -60
- detection/__init__.py +0 -0
- detection/detector_training/__init__.py +0 -0
- detection/process_video.py +85 -33
- detection/pytorch_detector.py +43 -25
- detection/run_detector.py +157 -72
- detection/run_detector_batch.py +179 -113
- detection/run_inference_with_yolov5_val.py +108 -48
- detection/run_tiled_inference.py +111 -40
- detection/tf_detector.py +51 -29
- detection/video_utils.py +606 -521
- docs/source/conf.py +43 -0
- md_utils/__init__.py +0 -0
- md_utils/azure_utils.py +9 -9
- md_utils/ct_utils.py +228 -68
- md_utils/directory_listing.py +59 -64
- md_utils/md_tests.py +968 -871
- md_utils/path_utils.py +460 -134
- md_utils/process_utils.py +157 -133
- md_utils/sas_blob_utils.py +20 -20
- md_utils/split_locations_into_train_val.py +45 -32
- md_utils/string_utils.py +33 -10
- md_utils/url_utils.py +176 -60
- md_utils/write_html_image_list.py +40 -33
- md_visualization/__init__.py +0 -0
- md_visualization/plot_utils.py +102 -109
- md_visualization/render_images_with_thumbnails.py +34 -34
- md_visualization/visualization_utils.py +597 -291
- md_visualization/visualize_db.py +76 -48
- md_visualization/visualize_detector_output.py +61 -42
- {megadetector-5.0.8.dist-info → megadetector-5.0.10.dist-info}/METADATA +13 -7
- megadetector-5.0.10.dist-info/RECORD +224 -0
- {megadetector-5.0.8.dist-info → megadetector-5.0.10.dist-info}/top_level.txt +1 -0
- taxonomy_mapping/__init__.py +0 -0
- taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +342 -335
- taxonomy_mapping/map_new_lila_datasets.py +154 -154
- taxonomy_mapping/prepare_lila_taxonomy_release.py +142 -134
- taxonomy_mapping/preview_lila_taxonomy.py +591 -591
- taxonomy_mapping/retrieve_sample_image.py +12 -12
- taxonomy_mapping/simple_image_download.py +11 -11
- taxonomy_mapping/species_lookup.py +10 -10
- taxonomy_mapping/taxonomy_csv_checker.py +18 -18
- taxonomy_mapping/taxonomy_graph.py +47 -47
- taxonomy_mapping/validate_lila_category_mappings.py +83 -76
- data_management/cct_json_to_filename_json.py +0 -89
- data_management/cct_to_csv.py +0 -140
- data_management/databases/remove_corrupted_images_from_db.py +0 -191
- detection/detector_training/copy_checkpoints.py +0 -43
- megadetector-5.0.8.dist-info/RECORD +0 -205
- {megadetector-5.0.8.dist-info → megadetector-5.0.10.dist-info}/LICENSE +0 -0
- {megadetector-5.0.8.dist-info → megadetector-5.0.10.dist-info}/WHEEL +0 -0
|
@@ -1,76 +1,76 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
1
|
+
r"""
|
|
2
|
+
|
|
3
|
+
separate_detections_into_folders.py
|
|
4
|
+
|
|
5
|
+
**Overview**
|
|
6
|
+
|
|
7
|
+
Given a .json file with batch processing results, separate the files in that
|
|
8
|
+
set of results into folders that contain animals/people/vehicles/nothing,
|
|
9
|
+
according to per-class thresholds.
|
|
10
|
+
|
|
11
|
+
Image files are copied, not moved.
|
|
12
|
+
|
|
13
|
+
**Output structure**
|
|
14
|
+
|
|
15
|
+
Preserves relative paths within each of those folders; cannot be used with .json
|
|
16
|
+
files that have absolute paths in them.
|
|
17
|
+
|
|
18
|
+
For example, if your .json file has these images:
|
|
19
|
+
|
|
20
|
+
* a/b/c/1.jpg
|
|
21
|
+
* a/b/d/2.jpg
|
|
22
|
+
* a/b/e/3.jpg
|
|
23
|
+
* a/b/f/4.jpg
|
|
24
|
+
* a/x/y/5.jpg
|
|
25
|
+
|
|
26
|
+
And let's say:
|
|
27
|
+
|
|
28
|
+
* The results say that the first three images are empty/person/vehicle, respectively
|
|
29
|
+
* The fourth image is above threshold for "animal" and "person"
|
|
30
|
+
* The fifth image contains an animal
|
|
31
|
+
|
|
32
|
+
* You specify an output base folder of c:/out
|
|
33
|
+
|
|
34
|
+
You will get the following files:
|
|
35
|
+
|
|
36
|
+
* c:/out/empty/a/b/c/1.jpg
|
|
37
|
+
* c:/out/people/a/b/d/2.jpg
|
|
38
|
+
* c:/out/vehicles/a/b/e/3.jpg
|
|
39
|
+
* c:/out/animal_person/a/b/f/4.jpg
|
|
40
|
+
* c:/out/animals/a/x/y/5.jpg
|
|
41
|
+
|
|
42
|
+
**Rendering bounding boxes**
|
|
43
|
+
|
|
44
|
+
By default, images are just copied to the target output folder. If you specify --render_boxes,
|
|
45
|
+
bounding boxes will be rendered on the output images. Because this is no longer strictly
|
|
46
|
+
a copy operation, this may result in the loss of metadata. More accurately, this *may*
|
|
47
|
+
result in the loss of some EXIF metadata; this *will* result in the loss of IPTC/XMP metadata.
|
|
48
|
+
|
|
49
|
+
Rendering boxes also makes this script a lot slower.
|
|
50
|
+
|
|
51
|
+
**Classification-based separation**
|
|
52
|
+
|
|
53
|
+
If you have a results file with classification data, you can also specify classes to put
|
|
54
|
+
in their own folders, within the "animals" folder, like this:
|
|
55
|
+
|
|
56
|
+
``--classification_thresholds "deer=0.75,cow=0.75"``
|
|
57
|
+
|
|
58
|
+
So, e.g., you might get:
|
|
59
|
+
|
|
60
|
+
c:/out/animals/deer/a/x/y/5.jpg
|
|
61
|
+
|
|
62
|
+
In this scenario, the folders within "animals" will be:
|
|
63
|
+
|
|
64
|
+
deer, cow, multiple, unclassified
|
|
65
|
+
|
|
66
|
+
"multiple" in this case only means "deer and cow"; if an image is classified as containing a
|
|
67
|
+
bird and a bear, that would end up in "unclassified", since the folder separation is based only
|
|
68
|
+
on the categories you provide at the command line.
|
|
69
|
+
|
|
70
|
+
No classification-based separation is done within the animal_person, animal_vehicle, or
|
|
71
|
+
animal_person_vehicle folders.
|
|
72
|
+
|
|
73
|
+
"""
|
|
74
74
|
|
|
75
75
|
#%% Constants and imports
|
|
76
76
|
|
|
@@ -85,7 +85,7 @@ from multiprocessing.pool import ThreadPool
|
|
|
85
85
|
from functools import partial
|
|
86
86
|
from tqdm import tqdm
|
|
87
87
|
|
|
88
|
-
from md_utils.ct_utils import args_to_object
|
|
88
|
+
from md_utils.ct_utils import args_to_object, is_float
|
|
89
89
|
from detection.run_detector import get_typical_confidence_threshold_from_results
|
|
90
90
|
|
|
91
91
|
import md_visualization.visualization_utils as vis_utils
|
|
@@ -104,47 +104,91 @@ default_box_expansion = 3
|
|
|
104
104
|
#%% Options class
|
|
105
105
|
|
|
106
106
|
class SeparateDetectionsIntoFoldersOptions:
|
|
107
|
-
|
|
107
|
+
"""
|
|
108
|
+
Options used to parameterize separate_detections_into_folders()
|
|
109
|
+
"""
|
|
110
|
+
|
|
108
111
|
def __init__(self,threshold=None):
|
|
109
112
|
|
|
113
|
+
#: Default threshold for categories not specified in category_name_to_threshold
|
|
110
114
|
self.threshold = None
|
|
111
115
|
|
|
116
|
+
#: Dict mapping category names to thresholds; for example, an image with only a detection of class
|
|
117
|
+
#: "animal" whose confidence is greater than or equal to category_name_to_threshold['animal']
|
|
118
|
+
#: will be put in the "animal" folder.
|
|
112
119
|
self.category_name_to_threshold = {
|
|
113
120
|
'animal': self.threshold,
|
|
114
121
|
'person': self.threshold,
|
|
115
122
|
'vehicle': self.threshold
|
|
116
123
|
}
|
|
117
124
|
|
|
125
|
+
#: Number of workers to use, set to <= 1 to disable parallelization
|
|
118
126
|
self.n_threads = 1
|
|
119
127
|
|
|
128
|
+
#: By default, this function errors if you try to output to an existing folder
|
|
120
129
|
self.allow_existing_directory = False
|
|
130
|
+
|
|
131
|
+
#: By default, this function errors if any of the images specified in the results file don't
|
|
132
|
+
#: exist in the source folder.
|
|
121
133
|
self.allow_missing_files = False
|
|
134
|
+
|
|
135
|
+
#: Whether to overwrite images that already exist in the target folder; only relevant if
|
|
136
|
+
#: [allow_existing_directory] is True
|
|
122
137
|
self.overwrite = True
|
|
138
|
+
|
|
139
|
+
#: Whether to skip empty images; if this is False, empty images (i.e., images with no detections
|
|
140
|
+
#: above the corresponding threshold) will be copied to an "empty" folder.
|
|
123
141
|
self.skip_empty_images = False
|
|
124
142
|
|
|
143
|
+
#: The MD results .json file to process
|
|
125
144
|
self.results_file = None
|
|
145
|
+
|
|
146
|
+
#: The folder containing source images; filenames in [results_file] should be relative to this
|
|
147
|
+
#: folder.
|
|
126
148
|
self.base_input_folder = None
|
|
149
|
+
|
|
150
|
+
#: The folder to which we should write output images; see the module header comment for information
|
|
151
|
+
#: about how that folder will be structured.
|
|
127
152
|
self.base_output_folder = None
|
|
128
153
|
|
|
129
|
-
|
|
130
|
-
self.
|
|
131
|
-
self.category_id_to_category_name = None
|
|
132
|
-
self.debug_max_images = None
|
|
154
|
+
#: Should we move rather than copy?
|
|
155
|
+
self.move_images = False
|
|
133
156
|
|
|
134
|
-
|
|
135
|
-
self.classification_category_id_to_name = None
|
|
136
|
-
self.classification_categories = None
|
|
137
|
-
|
|
157
|
+
#: Should we render boxes on the output images? Makes everything a lot slower.
|
|
138
158
|
self.render_boxes = False
|
|
159
|
+
|
|
160
|
+
#: Line thickness in pixels; only relevant if [render_boxes] is True
|
|
139
161
|
self.line_thickness = default_line_thickness
|
|
140
|
-
self.box_expansion = default_box_expansion
|
|
141
162
|
|
|
142
|
-
|
|
143
|
-
self.
|
|
163
|
+
#: Box expansion in pixels; only relevant if [render_boxes] is True
|
|
164
|
+
self.box_expansion = default_box_expansion
|
|
144
165
|
|
|
145
|
-
|
|
166
|
+
#: Originally specified as a string that looks like this:
|
|
167
|
+
#:
|
|
168
|
+
#: deer=0.75,cow=0.75
|
|
169
|
+
#:
|
|
170
|
+
#: Converted internally to a dict mapping name:threshold
|
|
146
171
|
self.classification_thresholds = None
|
|
147
172
|
|
|
173
|
+
## Debug or internal attributes
|
|
174
|
+
|
|
175
|
+
#: Do not set explicitly; populated from data when using classification results
|
|
176
|
+
self.classification_category_id_to_name = None
|
|
177
|
+
|
|
178
|
+
#: Do not set explicitly; populated from data when using classification results
|
|
179
|
+
self.classification_categories = None
|
|
180
|
+
|
|
181
|
+
#: Used to test this script; sets a limit on the number of images to process.
|
|
182
|
+
self.debug_max_images = None
|
|
183
|
+
|
|
184
|
+
#: Do not set explicitly; this gets created based on [results_file]
|
|
185
|
+
#:
|
|
186
|
+
#:Dictionary mapping categories (plus combinations of categories, and 'empty') to output folders
|
|
187
|
+
self.category_name_to_folder = None
|
|
188
|
+
|
|
189
|
+
#: Do not set explicitly; this gets loaded from [results_file]
|
|
190
|
+
self.category_id_to_category_name = None
|
|
191
|
+
|
|
148
192
|
# ...__init__()
|
|
149
193
|
|
|
150
194
|
# ...class SeparateDetectionsIntoFoldersOptions
|
|
@@ -152,21 +196,11 @@ class SeparateDetectionsIntoFoldersOptions:
|
|
|
152
196
|
|
|
153
197
|
#%% Support functions
|
|
154
198
|
|
|
155
|
-
def
|
|
156
|
-
|
|
157
|
-
def is_float(v):
|
|
158
|
-
"""
|
|
159
|
-
Determines whether v is either a float or a string representation of a float.
|
|
160
|
-
"""
|
|
161
|
-
try:
|
|
162
|
-
_ = float(v)
|
|
163
|
-
return True
|
|
164
|
-
except ValueError:
|
|
165
|
-
return False
|
|
199
|
+
def _path_is_abs(p): return (len(p) > 1) and (p[0] == '/' or p[1] == ':')
|
|
166
200
|
|
|
167
201
|
printed_missing_file_warning = False
|
|
168
202
|
|
|
169
|
-
def
|
|
203
|
+
def _process_detections(im,options):
|
|
170
204
|
"""
|
|
171
205
|
Process all detections for a single image
|
|
172
206
|
|
|
@@ -393,13 +427,24 @@ def process_detections(im,options):
|
|
|
393
427
|
|
|
394
428
|
# ...if we don't/do need to render boxes
|
|
395
429
|
|
|
396
|
-
# ...def
|
|
430
|
+
# ...def _process_detections()
|
|
397
431
|
|
|
398
432
|
|
|
399
433
|
#%% Main function
|
|
400
434
|
|
|
401
435
|
def separate_detections_into_folders(options):
|
|
402
|
-
|
|
436
|
+
"""
|
|
437
|
+
Given a .json file with batch processing results, separate the files in that
|
|
438
|
+
set of results into folders that contain animals/people/vehicles/nothing,
|
|
439
|
+
according to per-class thresholds. See the header comment of this module for
|
|
440
|
+
more details about the output folder structure.
|
|
441
|
+
|
|
442
|
+
Args:
|
|
443
|
+
options (SeparateDetectionsIntoFoldersOptions): parameters guiding image
|
|
444
|
+
separation, see the SeparateDetectionsIntoFoldersOptions documentation for specific
|
|
445
|
+
options.
|
|
446
|
+
"""
|
|
447
|
+
|
|
403
448
|
# Input validation
|
|
404
449
|
|
|
405
450
|
# Currently we don't support moving (instead of copying) when we're also rendering
|
|
@@ -424,7 +469,7 @@ def separate_detections_into_folders(options):
|
|
|
424
469
|
|
|
425
470
|
for im in images:
|
|
426
471
|
fn = im['file']
|
|
427
|
-
assert not
|
|
472
|
+
assert not _path_is_abs(fn), 'Cannot process results with absolute image paths'
|
|
428
473
|
|
|
429
474
|
print('Processing detections for {} images'.format(len(images)))
|
|
430
475
|
|
|
@@ -532,15 +577,15 @@ def separate_detections_into_folders(options):
|
|
|
532
577
|
for i_image,im in enumerate(tqdm(images)):
|
|
533
578
|
if options.debug_max_images is not None and i_image > options.debug_max_images:
|
|
534
579
|
break
|
|
535
|
-
|
|
580
|
+
_process_detections(im,options)
|
|
536
581
|
# ...for each image
|
|
537
582
|
|
|
538
583
|
else:
|
|
539
584
|
|
|
540
585
|
print('Starting a pool with {} threads'.format(options.n_threads))
|
|
541
586
|
pool = ThreadPool(options.n_threads)
|
|
542
|
-
process_detections_with_options = partial(
|
|
543
|
-
|
|
587
|
+
process_detections_with_options = partial(_process_detections, options=options)
|
|
588
|
+
_ = list(tqdm(pool.imap(process_detections_with_options, images), total=len(images)))
|
|
544
589
|
|
|
545
590
|
# ...def separate_detections_into_folders
|
|
546
591
|
|
|
@@ -595,7 +640,7 @@ if False:
|
|
|
595
640
|
python separate_detections_into_folders.py ~/data/ena24-2022-06-15-v5a.0.0_megaclassifier.json ~/data/ENA24/images ~/data/ENA24-separated --threshold 0.17 --animal_threshold 0.2 --n_threads 10 --allow_existing_directory --classification_thresholds "deer=0.75,cow=0.75,bird=0.75"
|
|
596
641
|
"""
|
|
597
642
|
|
|
598
|
-
#%% Command-line driver
|
|
643
|
+
#%% Command-line driver
|
|
599
644
|
|
|
600
645
|
def main():
|
|
601
646
|
|
|
@@ -620,27 +665,29 @@ def main():
|
|
|
620
665
|
|
|
621
666
|
parser.add_argument('--n_threads', type=int, default=1,
|
|
622
667
|
help='Number of threads to use for parallel operation (default=1)')
|
|
668
|
+
|
|
623
669
|
parser.add_argument('--allow_existing_directory', action='store_true',
|
|
624
670
|
help='Proceed even if the target directory exists and is not empty')
|
|
625
671
|
parser.add_argument('--no_overwrite', action='store_true',
|
|
626
672
|
help='Skip images that already exist in the target folder, must also ' + \
|
|
627
673
|
'specify --allow_existing_directory')
|
|
628
674
|
parser.add_argument('--skip_empty_images', action='store_true',
|
|
629
|
-
help='
|
|
675
|
+
help='Do not copy empty images to the output folder')
|
|
630
676
|
parser.add_argument('--move_images', action='store_true',
|
|
631
|
-
help='Move images (rather than
|
|
677
|
+
help='Move images (rather than copying) (not recommended this if you have not ' + \
|
|
632
678
|
'backed up your data!)')
|
|
679
|
+
|
|
633
680
|
parser.add_argument('--render_boxes', action='store_true',
|
|
634
681
|
help='Render bounding boxes on output images; may result in some ' + \
|
|
635
682
|
'metadata not being transferred')
|
|
636
683
|
parser.add_argument('--line_thickness', type=int, default=default_line_thickness,
|
|
637
684
|
help='Line thickness (in pixels) for rendering, only meaningful if ' + \
|
|
638
685
|
'using render_boxes (defaults to {})'.format(
|
|
639
|
-
|
|
686
|
+
default_line_thickness))
|
|
640
687
|
parser.add_argument('--box_expansion', type=int, default=default_line_thickness,
|
|
641
688
|
help='Box expansion (in pixels) for rendering, only meaningful if ' + \
|
|
642
|
-
|
|
643
|
-
|
|
689
|
+
'using render_boxes (defaults to {})'.format(
|
|
690
|
+
default_box_expansion))
|
|
644
691
|
|
|
645
692
|
if len(sys.argv[1:])==0:
|
|
646
693
|
parser.print_help()
|
|
@@ -680,7 +727,5 @@ def main():
|
|
|
680
727
|
|
|
681
728
|
separate_detections_into_folders(options)
|
|
682
729
|
|
|
683
|
-
if __name__ == '__main__':
|
|
684
|
-
|
|
730
|
+
if __name__ == '__main__':
|
|
685
731
|
main()
|
|
686
|
-
|