megadetector 5.0.24__py3-none-any.whl → 5.0.25__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/data_management/lila/add_locations_to_island_camera_traps.py +73 -69
- megadetector/data_management/lila/add_locations_to_nacti.py +114 -110
- megadetector/data_management/{wi_to_md.py → speciesnet_to_md.py} +2 -2
- megadetector/detection/run_detector.py +1 -0
- megadetector/detection/run_detector_batch.py +5 -4
- megadetector/postprocessing/compare_batch_results.py +176 -9
- megadetector/postprocessing/create_crop_folder.py +358 -0
- megadetector/postprocessing/postprocess_batch_results.py +2 -2
- megadetector/utils/ct_utils.py +72 -1
- megadetector/utils/directory_listing.py +3 -3
- megadetector/utils/gpu_test.py +21 -3
- megadetector/utils/md_tests.py +141 -49
- megadetector/utils/path_utils.py +34 -0
- megadetector/utils/wi_utils.py +959 -62
- megadetector/visualization/visualization_utils.py +14 -3
- {megadetector-5.0.24.dist-info → megadetector-5.0.25.dist-info}/METADATA +3 -1
- {megadetector-5.0.24.dist-info → megadetector-5.0.25.dist-info}/RECORD +20 -19
- {megadetector-5.0.24.dist-info → megadetector-5.0.25.dist-info}/WHEEL +1 -1
- {megadetector-5.0.24.dist-info → megadetector-5.0.25.dist-info}/LICENSE +0 -0
- {megadetector-5.0.24.dist-info → megadetector-5.0.25.dist-info}/top_level.txt +0 -0
|
@@ -20,78 +20,82 @@ preview_folder = os.path.expanduser('~/tmp/island_conservation_preview')
|
|
|
20
20
|
image_directory = os.path.expanduser('~/data/icct/public/')
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
#%%
|
|
23
|
+
#%% Prevent imports during testing
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
d = json.load(f)
|
|
27
|
-
|
|
28
|
-
d['info']
|
|
29
|
-
d['info']['version'] = '1.01'
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
#%% Find locations
|
|
33
|
-
|
|
34
|
-
images = d['images']
|
|
35
|
-
|
|
36
|
-
locations = set()
|
|
25
|
+
if False:
|
|
37
26
|
|
|
38
|
-
|
|
39
|
-
tokens_fn = im['file_name'].split('/')
|
|
40
|
-
tokens_id = im['id'].split('_')
|
|
41
|
-
assert tokens_fn[0] == tokens_id[0]
|
|
42
|
-
assert tokens_fn[1] == tokens_id[1]
|
|
43
|
-
location = tokens_fn[0] + '_' + tokens_fn[1]
|
|
44
|
-
im['location'] = location
|
|
45
|
-
locations.add(location)
|
|
46
|
-
|
|
47
|
-
locations = sorted(list(locations))
|
|
27
|
+
#%% Read input file
|
|
48
28
|
|
|
49
|
-
|
|
50
|
-
|
|
29
|
+
with open(input_fn,'r') as f:
|
|
30
|
+
d = json.load(f)
|
|
31
|
+
|
|
32
|
+
d['info']
|
|
33
|
+
d['info']['version'] = '1.01'
|
|
51
34
|
|
|
52
35
|
|
|
53
|
-
#%%
|
|
54
|
-
|
|
55
|
-
with open(output_fn,'w') as f:
|
|
56
|
-
json.dump(d,f,indent=1)
|
|
36
|
+
#%% Find locations
|
|
57
37
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
38
|
+
images = d['images']
|
|
39
|
+
|
|
40
|
+
locations = set()
|
|
41
|
+
|
|
42
|
+
for i_image,im in tqdm(enumerate(images),total=len(images)):
|
|
43
|
+
tokens_fn = im['file_name'].split('/')
|
|
44
|
+
tokens_id = im['id'].split('_')
|
|
45
|
+
assert tokens_fn[0] == tokens_id[0]
|
|
46
|
+
assert tokens_fn[1] == tokens_id[1]
|
|
47
|
+
location = tokens_fn[0] + '_' + tokens_fn[1]
|
|
48
|
+
im['location'] = location
|
|
49
|
+
locations.add(location)
|
|
50
|
+
|
|
51
|
+
locations = sorted(list(locations))
|
|
52
|
+
|
|
53
|
+
for s in locations:
|
|
54
|
+
print(s)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
#%% Write output file
|
|
58
|
+
|
|
59
|
+
with open(output_fn,'w') as f:
|
|
60
|
+
json.dump(d,f,indent=1)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
#%% Validate .json files
|
|
64
|
+
|
|
65
|
+
from megadetector.data_management.databases import integrity_check_json_db
|
|
66
|
+
|
|
67
|
+
options = integrity_check_json_db.IntegrityCheckOptions()
|
|
68
|
+
options.baseDir = image_directory
|
|
69
|
+
options.bCheckImageSizes = False
|
|
70
|
+
options.bCheckImageExistence = True
|
|
71
|
+
options.bFindUnusedImages = True
|
|
72
|
+
|
|
73
|
+
sorted_categories, data, error_info = integrity_check_json_db.integrity_check_json_db(output_fn, options)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
#%% Preview labels
|
|
77
|
+
|
|
78
|
+
from megadetector.visualization import visualize_db
|
|
79
|
+
|
|
80
|
+
viz_options = visualize_db.DbVizOptions()
|
|
81
|
+
viz_options.num_to_visualize = 2000
|
|
82
|
+
viz_options.trim_to_images_with_bboxes = False
|
|
83
|
+
viz_options.add_search_links = False
|
|
84
|
+
viz_options.sort_by_filename = False
|
|
85
|
+
viz_options.parallelize_rendering = True
|
|
86
|
+
viz_options.classes_to_exclude = ['test']
|
|
87
|
+
html_output_file, image_db = visualize_db.visualize_db(db_path=output_fn,
|
|
88
|
+
output_dir=preview_folder,
|
|
89
|
+
image_base_dir=image_directory,
|
|
90
|
+
options=viz_options)
|
|
91
|
+
|
|
92
|
+
from megadetector.utils import path_utils
|
|
93
|
+
path_utils.open_file(html_output_file)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
#%% Zip output file
|
|
97
|
+
|
|
98
|
+
from megadetector.utils.path_utils import zip_file
|
|
99
|
+
|
|
100
|
+
zip_file(output_fn, verbose=True)
|
|
101
|
+
assert os.path.isfile(output_fn + '.zip')
|
|
@@ -21,127 +21,131 @@ input_file = r'd:\lila\nacti\nacti_metadata.json.1.13\nacti_metadata.json'
|
|
|
21
21
|
output_file = r'g:\temp\nacti_metadata.1.14.json'
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
#%%
|
|
24
|
+
#%% Prevent execution during testing
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
d = json.load(f)
|
|
28
|
-
|
|
29
|
-
assert d['info']['version'] == 1.13
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
#%% Map images to locations (according to the metadata)
|
|
33
|
-
|
|
34
|
-
file_name_to_original_location = {}
|
|
35
|
-
|
|
36
|
-
# im = dataset_labels['images'][0]
|
|
37
|
-
for im in tqdm(d['images']):
|
|
38
|
-
file_name_to_original_location[im['file_name']] = im['location']
|
|
39
|
-
|
|
40
|
-
original_locations = set(file_name_to_original_location.values())
|
|
41
|
-
|
|
42
|
-
print('Found {} locations in the original metadata:'.format(len(original_locations)))
|
|
43
|
-
for loc in original_locations:
|
|
44
|
-
print('[{}]'.format(loc))
|
|
26
|
+
if False:
|
|
45
27
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
28
|
+
#%% Read metadata
|
|
29
|
+
|
|
30
|
+
with open(input_file,'r') as f:
|
|
31
|
+
d = json.load(f)
|
|
32
|
+
|
|
33
|
+
assert d['info']['version'] == 1.13
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
#%% Map images to locations (according to the metadata)
|
|
37
|
+
|
|
38
|
+
file_name_to_original_location = {}
|
|
39
|
+
|
|
40
|
+
# im = dataset_labels['images'][0]
|
|
41
|
+
for im in tqdm(d['images']):
|
|
42
|
+
file_name_to_original_location[im['file_name']] = im['location']
|
|
43
|
+
|
|
44
|
+
original_locations = set(file_name_to_original_location.values())
|
|
45
|
+
|
|
46
|
+
print('Found {} locations in the original metadata:'.format(len(original_locations)))
|
|
47
|
+
for loc in original_locations:
|
|
48
|
+
print('[{}]'.format(loc))
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
#%% Map images to new locations
|
|
52
|
+
|
|
53
|
+
def path_to_location(relative_path):
|
|
54
|
+
|
|
55
|
+
relative_path = relative_path.replace('\\','/')
|
|
56
|
+
if relative_path in file_name_to_original_location:
|
|
57
|
+
location_name = file_name_to_original_location[relative_path]
|
|
58
|
+
if location_name == 'San Juan Mntns, Colorado':
|
|
59
|
+
# "part0/sub000/2010_Unit150_Ivan097_img0003.jpg"
|
|
60
|
+
tokens = relative_path.split('/')[-1].split('_')
|
|
61
|
+
assert tokens[1].startswith('Unit')
|
|
62
|
+
location_name = 'sanjuan_{}_{}_{}'.format(tokens[0],tokens[1],tokens[2])
|
|
63
|
+
elif location_name == 'Lebec, California':
|
|
64
|
+
# "part0/sub035/CA-03_08_13_2015_CA-03_0009738.jpg"
|
|
65
|
+
tokens = relative_path.split('/')[-1].split('_')
|
|
66
|
+
assert tokens[0].startswith('CA-') or tokens[0].startswith('TAG-')
|
|
67
|
+
location_name = 'lebec_{}'.format(tokens[0])
|
|
68
|
+
elif location_name == 'Archbold, FL':
|
|
69
|
+
# "part1/sub110/FL-01_01_25_2016_FL-01_0040421.jpg"
|
|
70
|
+
tokens = relative_path.split('/')[-1].split('_')
|
|
71
|
+
assert tokens[0].startswith('FL-')
|
|
72
|
+
location_name = 'archbold_{}'.format(tokens[0])
|
|
73
|
+
else:
|
|
74
|
+
assert location_name == ''
|
|
75
|
+
tokens = relative_path.split('/')[-1].split('_')
|
|
76
|
+
if tokens[0].startswith('CA-') or tokens[0].startswith('TAG-') or tokens[0].startswith('FL-'):
|
|
77
|
+
location_name = '{}'.format(tokens[0])
|
|
78
|
+
|
|
69
79
|
else:
|
|
70
|
-
assert location_name == ''
|
|
71
|
-
tokens = relative_path.split('/')[-1].split('_')
|
|
72
|
-
if tokens[0].startswith('CA-') or tokens[0].startswith('TAG-') or tokens[0].startswith('FL-'):
|
|
73
|
-
location_name = '{}'.format(tokens[0])
|
|
74
80
|
|
|
75
|
-
|
|
81
|
+
location_name = 'unknown'
|
|
76
82
|
|
|
77
|
-
|
|
83
|
+
# print('Returning location {} for file {}'.format(location_name,relative_path))
|
|
78
84
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return location_name
|
|
82
|
-
|
|
83
|
-
file_name_to_updated_location = {}
|
|
84
|
-
updated_location_to_count = defaultdict(int)
|
|
85
|
-
for im in tqdm(d['images']):
|
|
85
|
+
return location_name
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
updated_locations = set(file_name_to_updated_location.values())
|
|
96
|
-
|
|
97
|
-
print('Found {} updated locations in the original metadata:'.format(len(updated_locations)))
|
|
98
|
-
for loc in updated_location_to_count:
|
|
99
|
-
print('{}: {}'.format(loc,updated_location_to_count[loc]))
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
#%% Re-write metadata
|
|
103
|
-
|
|
104
|
-
for im in d['images']:
|
|
105
|
-
im['location'] = file_name_to_updated_location[im['file_name']]
|
|
106
|
-
d['info']['version'] = 1.14
|
|
107
|
-
|
|
108
|
-
with open(output_file,'w') as f:
|
|
109
|
-
json.dump(d,f,indent=1)
|
|
87
|
+
file_name_to_updated_location = {}
|
|
88
|
+
updated_location_to_count = defaultdict(int)
|
|
89
|
+
for im in tqdm(d['images']):
|
|
90
|
+
|
|
91
|
+
updated_location = path_to_location(im['file_name'])
|
|
92
|
+
file_name_to_updated_location[im['file_name']] = updated_location
|
|
93
|
+
updated_location_to_count[updated_location] += 1
|
|
110
94
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
input_base = r'd:\lila\nacti-unzipped'
|
|
115
|
-
assert os.path.isdir(input_base)
|
|
116
|
-
|
|
117
|
-
location_to_images = defaultdict(list)
|
|
118
|
-
|
|
119
|
-
for im in d['images']:
|
|
120
|
-
location_to_images[im['location']].append(im)
|
|
95
|
+
updated_location_to_count = {k: v for k, v in sorted(updated_location_to_count.items(),
|
|
96
|
+
key=lambda item: item[1],
|
|
97
|
+
reverse=True)}
|
|
121
98
|
|
|
122
|
-
|
|
123
|
-
import random
|
|
124
|
-
random.seed(0)
|
|
125
|
-
sampling_folder_base = r'g:\temp\nacti_samples'
|
|
126
|
-
|
|
127
|
-
for location in tqdm(location_to_images):
|
|
99
|
+
updated_locations = set(file_name_to_updated_location.values())
|
|
128
100
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
101
|
+
print('Found {} updated locations in the original metadata:'.format(len(updated_locations)))
|
|
102
|
+
for loc in updated_location_to_count:
|
|
103
|
+
print('{}: {}'.format(loc,updated_location_to_count[loc]))
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
#%% Re-write metadata
|
|
107
|
+
|
|
108
|
+
for im in d['images']:
|
|
109
|
+
im['location'] = file_name_to_updated_location[im['file_name']]
|
|
110
|
+
d['info']['version'] = 1.14
|
|
111
|
+
|
|
112
|
+
with open(output_file,'w') as f:
|
|
113
|
+
json.dump(d,f,indent=1)
|
|
134
114
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
115
|
+
|
|
116
|
+
#%% For each location, sample some random images to make sure they look consistent
|
|
117
|
+
|
|
118
|
+
input_base = r'd:\lila\nacti-unzipped'
|
|
119
|
+
assert os.path.isdir(input_base)
|
|
120
|
+
|
|
121
|
+
location_to_images = defaultdict(list)
|
|
122
|
+
|
|
123
|
+
for im in d['images']:
|
|
124
|
+
location_to_images[im['location']].append(im)
|
|
143
125
|
|
|
144
|
-
|
|
126
|
+
n_to_sample = 10
|
|
127
|
+
import random
|
|
128
|
+
random.seed(0)
|
|
129
|
+
sampling_folder_base = r'g:\temp\nacti_samples'
|
|
145
130
|
|
|
146
|
-
|
|
131
|
+
for location in tqdm(location_to_images):
|
|
132
|
+
|
|
133
|
+
images_this_location = location_to_images[location]
|
|
134
|
+
if len(images_this_location) > n_to_sample:
|
|
135
|
+
images_this_location = random.sample(images_this_location,n_to_sample)
|
|
147
136
|
|
|
137
|
+
for i_image,im in enumerate(images_this_location):
|
|
138
|
+
|
|
139
|
+
fn_relative = im['file_name']
|
|
140
|
+
source_fn_abs = os.path.join(input_base,fn_relative)
|
|
141
|
+
assert os.path.isfile(source_fn_abs)
|
|
142
|
+
ext = os.path.splitext(fn_relative)[1]
|
|
143
|
+
target_fn_abs = os.path.join(sampling_folder_base,'{}/{}'.format(
|
|
144
|
+
location,'image_{}{}'.format(str(i_image).zfill(2),ext)))
|
|
145
|
+
os.makedirs(os.path.dirname(target_fn_abs),exist_ok=True)
|
|
146
|
+
shutil.copyfile(source_fn_abs,target_fn_abs)
|
|
147
|
+
|
|
148
|
+
# ...for each image
|
|
149
|
+
|
|
150
|
+
# ...for each location
|
|
151
|
+
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
wi_to_md.py
|
|
4
4
|
|
|
5
|
-
Converts the WI predictions.json format to MD .json format. This is just a
|
|
5
|
+
Converts the WI (SpeciesNet) predictions.json format to MD .json format. This is just a
|
|
6
6
|
command-line wrapper around utils.wi_utils.generate_md_results_from_predictions_json.
|
|
7
7
|
|
|
8
8
|
"""
|
|
@@ -20,7 +20,7 @@ def main():
|
|
|
20
20
|
|
|
21
21
|
parser = argparse.ArgumentParser()
|
|
22
22
|
parser.add_argument('predictions_json_file', action='store', type=str,
|
|
23
|
-
help='.json file to convert from predictions.json format to MD format')
|
|
23
|
+
help='.json file to convert from SpeciesNet predictions.json format to MD format')
|
|
24
24
|
parser.add_argument('md_results_file', action='store', type=str,
|
|
25
25
|
help='output file to write in MD format')
|
|
26
26
|
parser.add_argument('--base_folder', action='store', type=str, default=None,
|
|
@@ -735,7 +735,7 @@ def load_and_run_detector_batch(model_file,
|
|
|
735
735
|
"""
|
|
736
736
|
|
|
737
737
|
# Validate input arguments
|
|
738
|
-
if n_cores is None:
|
|
738
|
+
if n_cores is None or n_cores <= 0:
|
|
739
739
|
n_cores = 1
|
|
740
740
|
|
|
741
741
|
if confidence_threshold is None:
|
|
@@ -1331,13 +1331,14 @@ def main():
|
|
|
1331
1331
|
parser.add_argument(
|
|
1332
1332
|
'--ncores',
|
|
1333
1333
|
type=int,
|
|
1334
|
-
default=
|
|
1335
|
-
help='Number of cores to use for inference; only applies to CPU-based inference')
|
|
1334
|
+
default=1,
|
|
1335
|
+
help='Number of cores to use for inference; only applies to CPU-based inference (default 1)')
|
|
1336
1336
|
parser.add_argument(
|
|
1337
1337
|
'--loader_workers',
|
|
1338
1338
|
type=int,
|
|
1339
1339
|
default=default_loaders,
|
|
1340
|
-
help='Number of image loader workers to use; only relevant when --use_image_queue
|
|
1340
|
+
help='Number of image loader workers to use; only relevant when --use_image_queue ' + \
|
|
1341
|
+
'is set (default {})'.format(default_loaders))
|
|
1341
1342
|
parser.add_argument(
|
|
1342
1343
|
'--class_mapping_filename',
|
|
1343
1344
|
type=str,
|