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,162 +1,188 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
#%% Constants and imports
|
|
11
|
-
|
|
12
|
-
import argparse
|
|
13
|
-
import json
|
|
14
|
-
import os
|
|
15
|
-
from PIL import Image
|
|
16
|
-
import sys
|
|
17
|
-
|
|
18
|
-
from
|
|
19
|
-
|
|
20
|
-
from
|
|
21
|
-
from
|
|
22
|
-
|
|
23
|
-
from
|
|
24
|
-
|
|
25
|
-
image_base = ''
|
|
26
|
-
default_n_threads = 1
|
|
27
|
-
use_threads = False
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
#%% Processing functions
|
|
31
|
-
|
|
32
|
-
def _get_image_size(image_path,image_prefix=None):
|
|
33
|
-
"""
|
|
34
|
-
Support function to get the size of a single image. Returns a (path,w,h) tuple.
|
|
35
|
-
w and h will be -1 if the image fails to load.
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
if image_prefix is not None:
|
|
39
|
-
full_path = os.path.join(image_prefix,image_path)
|
|
40
|
-
else:
|
|
41
|
-
full_path = image_path
|
|
42
|
-
|
|
43
|
-
# Is this image on disk?
|
|
44
|
-
if not os.path.isfile(full_path):
|
|
45
|
-
print('Could not find image {}'.format(full_path))
|
|
46
|
-
return (image_path,-1,-1)
|
|
47
|
-
|
|
48
|
-
try:
|
|
49
|
-
pil_im = Image.open(full_path)
|
|
50
|
-
w = pil_im.width
|
|
51
|
-
h = pil_im.height
|
|
52
|
-
return (image_path,w,h)
|
|
53
|
-
except Exception as e:
|
|
54
|
-
print('Error reading image {}: {}'.format(full_path,str(e)))
|
|
55
|
-
return (image_path,-1,-1)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def get_image_sizes(filenames,image_prefix=None,output_file=None,
|
|
59
|
-
n_workers=default_n_threads,use_threads=True,
|
|
60
|
-
recursive=True):
|
|
61
|
-
"""
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
* A .json-formatted file
|
|
65
|
-
* A folder
|
|
66
|
-
* A list of files
|
|
67
|
-
|
|
68
|
-
...returning a list of (path,w,h) tuples, and optionally writing the results to [output_file].
|
|
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
|
-
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
get_image_sizes.py
|
|
4
|
+
|
|
5
|
+
Given a json-formatted list of image filenames, retrieves the width and height of
|
|
6
|
+
every image, optionally writing the results to a new .json file.
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
#%% Constants and imports
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
from PIL import Image
|
|
16
|
+
import sys
|
|
17
|
+
|
|
18
|
+
from multiprocessing.pool import ThreadPool
|
|
19
|
+
from multiprocessing.pool import Pool
|
|
20
|
+
from functools import partial
|
|
21
|
+
from tqdm import tqdm
|
|
22
|
+
|
|
23
|
+
from md_utils.path_utils import find_images
|
|
24
|
+
|
|
25
|
+
image_base = ''
|
|
26
|
+
default_n_threads = 1
|
|
27
|
+
use_threads = False
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
#%% Processing functions
|
|
31
|
+
|
|
32
|
+
def _get_image_size(image_path,image_prefix=None):
|
|
33
|
+
"""
|
|
34
|
+
Support function to get the size of a single image. Returns a (path,w,h) tuple.
|
|
35
|
+
w and h will be -1 if the image fails to load.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
if image_prefix is not None:
|
|
39
|
+
full_path = os.path.join(image_prefix,image_path)
|
|
40
|
+
else:
|
|
41
|
+
full_path = image_path
|
|
42
|
+
|
|
43
|
+
# Is this image on disk?
|
|
44
|
+
if not os.path.isfile(full_path):
|
|
45
|
+
print('Could not find image {}'.format(full_path))
|
|
46
|
+
return (image_path,-1,-1)
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
pil_im = Image.open(full_path)
|
|
50
|
+
w = pil_im.width
|
|
51
|
+
h = pil_im.height
|
|
52
|
+
return (image_path,w,h)
|
|
53
|
+
except Exception as e:
|
|
54
|
+
print('Error reading image {}: {}'.format(full_path,str(e)))
|
|
55
|
+
return (image_path,-1,-1)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def get_image_sizes(filenames,image_prefix=None,output_file=None,
|
|
59
|
+
n_workers=default_n_threads,use_threads=True,
|
|
60
|
+
recursive=True):
|
|
61
|
+
"""
|
|
62
|
+
Gets the width and height of all images in [filenames], which can be:
|
|
63
|
+
|
|
64
|
+
* A .json-formatted file containing list of strings
|
|
65
|
+
* A folder
|
|
66
|
+
* A list of files
|
|
67
|
+
|
|
68
|
+
...returning a list of (path,w,h) tuples, and optionally writing the results to [output_file].
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
filenames (str or list): the image filenames for which we should retrieve sizes,
|
|
72
|
+
can be the name of a .json-formatted file containing list of strings, a folder
|
|
73
|
+
in which we should enumerate images, or a list of files.
|
|
74
|
+
image_prefix (str, optional): optional prefix to add to images to get to full paths;
|
|
75
|
+
useful when [filenames] contains relative files, in which case [image_prefix] is the
|
|
76
|
+
base folder for the source images.
|
|
77
|
+
output_file (str, optional): a .json file to write the imgae sizes
|
|
78
|
+
n_workers (int, optional): number of parallel workers to use, set to <=1 to
|
|
79
|
+
disable parallelization
|
|
80
|
+
use_threads (bool, optional): whether to use threads (True) or processes (False)
|
|
81
|
+
for parallelization; not relevant if [n_workers] <= 1
|
|
82
|
+
recursive (bool, optional): only relevant if [filenames] is actually a folder,
|
|
83
|
+
determines whether image enumeration within that folder will be recursive
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
list: list of (path,w,h) tuples
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
if output_file is not None:
|
|
90
|
+
assert os.path.isdir(os.path.dirname(output_file)), \
|
|
91
|
+
'Illegal output file {}, parent folder does not exist'.format(output_file)
|
|
92
|
+
|
|
93
|
+
if isinstance(filenames,str) and os.path.isfile(filenames):
|
|
94
|
+
with open(filenames,'r') as f:
|
|
95
|
+
filenames = json.load(f)
|
|
96
|
+
filenames = [s.strip() for s in filenames]
|
|
97
|
+
elif isinstance(filenames,str) and os.path.isdir(filenames):
|
|
98
|
+
filenames = find_images(filenames,recursive=recursive,
|
|
99
|
+
return_relative_paths=False,convert_slashes=True)
|
|
100
|
+
else:
|
|
101
|
+
assert isinstance(filenames,list)
|
|
102
|
+
|
|
103
|
+
if n_workers <= 1:
|
|
104
|
+
|
|
105
|
+
all_results = []
|
|
106
|
+
for i_file,fn in tqdm(enumerate(filenames),total=len(filenames)):
|
|
107
|
+
all_results.append(_get_image_size(fn,image_prefix=image_prefix))
|
|
108
|
+
|
|
109
|
+
else:
|
|
110
|
+
|
|
111
|
+
print('Creating a pool with {} workers'.format(n_workers))
|
|
112
|
+
if use_threads:
|
|
113
|
+
pool = ThreadPool(n_workers)
|
|
114
|
+
else:
|
|
115
|
+
pool = Pool(n_workers)
|
|
116
|
+
# all_results = list(tqdm(pool.imap(process_image, filenames), total=len(filenames)))
|
|
117
|
+
all_results = list(tqdm(pool.imap(
|
|
118
|
+
partial(_get_image_size,image_prefix=image_prefix), filenames), total=len(filenames)))
|
|
119
|
+
|
|
120
|
+
if output_file is not None:
|
|
121
|
+
with open(output_file,'w') as f:
|
|
122
|
+
json.dump(all_results,f,indent=1)
|
|
123
|
+
|
|
124
|
+
return all_results
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
#%% Interactive driver
|
|
128
|
+
|
|
129
|
+
if False:
|
|
130
|
+
|
|
131
|
+
pass
|
|
132
|
+
|
|
133
|
+
#%%
|
|
134
|
+
|
|
135
|
+
# List images in a test folder
|
|
136
|
+
base_dir = r'c:\temp\test_images'
|
|
137
|
+
image_list_file = os.path.join(base_dir,'images.json')
|
|
138
|
+
relative_image_list_file = os.path.join(base_dir,'images_relative.json')
|
|
139
|
+
image_size_file = os.path.join(base_dir,'image_sizes.json')
|
|
140
|
+
from md_utils import path_utils
|
|
141
|
+
image_names = path_utils.find_images(base_dir,recursive=True)
|
|
142
|
+
|
|
143
|
+
with open(image_list_file,'w') as f:
|
|
144
|
+
json.dump(image_names,f,indent=1)
|
|
145
|
+
|
|
146
|
+
relative_image_names = []
|
|
147
|
+
for s in image_names:
|
|
148
|
+
relative_image_names.append(os.path.relpath(s,base_dir))
|
|
149
|
+
|
|
150
|
+
with open(relative_image_list_file,'w') as f:
|
|
151
|
+
json.dump(relative_image_names,f,indent=1)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
#%%
|
|
155
|
+
|
|
156
|
+
get_image_sizes(relative_image_list_file,image_size_file,image_prefix=base_dir,n_threads=4)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
#%% Command-line driver
|
|
160
|
+
|
|
161
|
+
def main():
|
|
162
|
+
|
|
163
|
+
parser = argparse.ArgumentParser()
|
|
164
|
+
parser.add_argument('filenames',type=str,
|
|
165
|
+
help='Folder from which we should fetch image sizes, or .json file with a list of filenames')
|
|
166
|
+
parser.add_argument('output_file',type=str,
|
|
167
|
+
help='Output file (.json) to which we should write image size information')
|
|
168
|
+
parser.add_argument('--image_prefix', type=str, default=None,
|
|
169
|
+
help='Prefix to append to image filenames, only relevant if [filenames] points to a list of ' + \
|
|
170
|
+
'relative paths')
|
|
171
|
+
parser.add_argument('--n_threads', type=int, default=default_n_threads,
|
|
172
|
+
help='Number of concurrent workers, set to <=1 to disable parallelization (default {})'.format(
|
|
173
|
+
default_n_threads))
|
|
174
|
+
|
|
175
|
+
if len(sys.argv[1:])==0:
|
|
176
|
+
parser.print_help()
|
|
177
|
+
parser.exit()
|
|
178
|
+
|
|
179
|
+
args = parser.parse_args()
|
|
180
|
+
|
|
181
|
+
_ = get_image_sizes(filenames=args.filenames,
|
|
182
|
+
output_file=args.output_file,
|
|
183
|
+
image_prefix=args.image_prefix,
|
|
184
|
+
n_workers=args.n_threads)
|
|
185
|
+
|
|
186
|
+
if __name__ == '__main__':
|
|
187
|
+
|
|
188
|
+
main()
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
add_nacti_sizes.py
|
|
4
|
+
|
|
5
|
+
NACTI bounding box metadata was posted before we inclduded width and height as semi-standard
|
|
6
|
+
fields; pull size information from the main metadata file and add to the bbox file.
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
9
|
|
|
10
10
|
#%% Constants and environment
|
|
11
11
|
|
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
#%% Imports and constants
|
|
12
|
-
|
|
13
|
-
import json
|
|
14
|
-
|
|
15
|
-
ocr_results_file = r'g:\temp\ocr_results.2023.10.31.07.37.54.json'
|
|
16
|
-
input_metadata_file = r'd:\lila\islandconservationcameratraps\island_conservation.json'
|
|
17
|
-
output_metadata_file = r'g:\temp\island_conservation_camera_traps_1.02.json'
|
|
18
|
-
ocr_results_file_base = 'g:/temp/island_conservation_camera_traps/'
|
|
19
|
-
assert ocr_results_file_base.endswith('/')
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
#%% Read input metadata
|
|
23
|
-
|
|
24
|
-
with open(input_metadata_file,'r') as f:
|
|
25
|
-
input_metadata = json.load(f)
|
|
26
|
-
|
|
27
|
-
assert input_metadata['info']['version'] == '1.01'
|
|
28
|
-
|
|
29
|
-
# im = input_metadata['images'][0]
|
|
30
|
-
for im in input_metadata['images']:
|
|
31
|
-
assert 'datetime' not in im
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
#%% Read OCR results
|
|
35
|
-
|
|
36
|
-
with open(ocr_results_file,'r') as f:
|
|
37
|
-
abs_filename_to_ocr_results = json.load(f)
|
|
38
|
-
|
|
39
|
-
relative_filename_to_ocr_results = {}
|
|
40
|
-
|
|
41
|
-
for fn_abs in abs_filename_to_ocr_results:
|
|
42
|
-
assert ocr_results_file_base in fn_abs
|
|
43
|
-
fn_relative = fn_abs.replace(ocr_results_file_base,'')
|
|
44
|
-
relative_filename_to_ocr_results[fn_relative] = abs_filename_to_ocr_results[fn_abs]
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
#%% Add datetimes to metadata
|
|
48
|
-
|
|
49
|
-
images_not_in_datetime_results = []
|
|
50
|
-
images_with_failed_datetimes = []
|
|
51
|
-
|
|
52
|
-
for i_image,im in enumerate(input_metadata['images']):
|
|
53
|
-
if im['file_name'] not in relative_filename_to_ocr_results:
|
|
54
|
-
images_not_in_datetime_results.append(im)
|
|
55
|
-
im['datetime'] = None
|
|
56
|
-
continue
|
|
57
|
-
ocr_results = relative_filename_to_ocr_results[im['file_name']]
|
|
58
|
-
if ocr_results['datetime'] is None:
|
|
59
|
-
images_with_failed_datetimes.append(im)
|
|
60
|
-
im['datetime'] = None
|
|
61
|
-
continue
|
|
62
|
-
im['datetime'] = ocr_results['datetime']
|
|
63
|
-
|
|
64
|
-
print('{} of {} images were not in datetime results'.format(
|
|
65
|
-
len(images_not_in_datetime_results),len(input_metadata['images'])))
|
|
66
|
-
|
|
67
|
-
print('{} of {} images were had failed datetime results'.format(
|
|
68
|
-
len(images_with_failed_datetimes),len(input_metadata['images'])))
|
|
69
|
-
|
|
70
|
-
for im in input_metadata['images']:
|
|
71
|
-
assert 'datetime' in im
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
#%% Write output
|
|
75
|
-
|
|
76
|
-
input_metadata['info']['version'] = '1.02'
|
|
77
|
-
|
|
78
|
-
with open(output_metadata_file,'w') as f:
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
add_timestamps_to_icct.py
|
|
4
|
+
|
|
5
|
+
The Island Conservation Camera Traps dataset was originally posted without timestamps
|
|
6
|
+
in either .json metadata or EXIF metadata. We pulled timestamps out using ocr_tools.py,
|
|
7
|
+
this script adds those timestamps into the .json metadata.
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
#%% Imports and constants
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
|
|
15
|
+
ocr_results_file = r'g:\temp\ocr_results.2023.10.31.07.37.54.json'
|
|
16
|
+
input_metadata_file = r'd:\lila\islandconservationcameratraps\island_conservation.json'
|
|
17
|
+
output_metadata_file = r'g:\temp\island_conservation_camera_traps_1.02.json'
|
|
18
|
+
ocr_results_file_base = 'g:/temp/island_conservation_camera_traps/'
|
|
19
|
+
assert ocr_results_file_base.endswith('/')
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
#%% Read input metadata
|
|
23
|
+
|
|
24
|
+
with open(input_metadata_file,'r') as f:
|
|
25
|
+
input_metadata = json.load(f)
|
|
26
|
+
|
|
27
|
+
assert input_metadata['info']['version'] == '1.01'
|
|
28
|
+
|
|
29
|
+
# im = input_metadata['images'][0]
|
|
30
|
+
for im in input_metadata['images']:
|
|
31
|
+
assert 'datetime' not in im
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
#%% Read OCR results
|
|
35
|
+
|
|
36
|
+
with open(ocr_results_file,'r') as f:
|
|
37
|
+
abs_filename_to_ocr_results = json.load(f)
|
|
38
|
+
|
|
39
|
+
relative_filename_to_ocr_results = {}
|
|
40
|
+
|
|
41
|
+
for fn_abs in abs_filename_to_ocr_results:
|
|
42
|
+
assert ocr_results_file_base in fn_abs
|
|
43
|
+
fn_relative = fn_abs.replace(ocr_results_file_base,'')
|
|
44
|
+
relative_filename_to_ocr_results[fn_relative] = abs_filename_to_ocr_results[fn_abs]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
#%% Add datetimes to metadata
|
|
48
|
+
|
|
49
|
+
images_not_in_datetime_results = []
|
|
50
|
+
images_with_failed_datetimes = []
|
|
51
|
+
|
|
52
|
+
for i_image,im in enumerate(input_metadata['images']):
|
|
53
|
+
if im['file_name'] not in relative_filename_to_ocr_results:
|
|
54
|
+
images_not_in_datetime_results.append(im)
|
|
55
|
+
im['datetime'] = None
|
|
56
|
+
continue
|
|
57
|
+
ocr_results = relative_filename_to_ocr_results[im['file_name']]
|
|
58
|
+
if ocr_results['datetime'] is None:
|
|
59
|
+
images_with_failed_datetimes.append(im)
|
|
60
|
+
im['datetime'] = None
|
|
61
|
+
continue
|
|
62
|
+
im['datetime'] = ocr_results['datetime']
|
|
63
|
+
|
|
64
|
+
print('{} of {} images were not in datetime results'.format(
|
|
65
|
+
len(images_not_in_datetime_results),len(input_metadata['images'])))
|
|
66
|
+
|
|
67
|
+
print('{} of {} images were had failed datetime results'.format(
|
|
68
|
+
len(images_with_failed_datetimes),len(input_metadata['images'])))
|
|
69
|
+
|
|
70
|
+
for im in input_metadata['images']:
|
|
71
|
+
assert 'datetime' in im
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
#%% Write output
|
|
75
|
+
|
|
76
|
+
input_metadata['info']['version'] = '1.02'
|
|
77
|
+
|
|
78
|
+
with open(output_metadata_file,'w') as f:
|
|
79
79
|
json.dump(input_metadata,f,indent=1)
|