megadetector 10.0.13__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/__init__.py +0 -0
- megadetector/api/__init__.py +0 -0
- megadetector/api/batch_processing/integration/digiKam/setup.py +6 -0
- megadetector/api/batch_processing/integration/digiKam/xmp_integration.py +465 -0
- megadetector/api/batch_processing/integration/eMammal/test_scripts/config_template.py +5 -0
- megadetector/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +125 -0
- megadetector/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +55 -0
- megadetector/classification/__init__.py +0 -0
- megadetector/classification/aggregate_classifier_probs.py +108 -0
- megadetector/classification/analyze_failed_images.py +227 -0
- megadetector/classification/cache_batchapi_outputs.py +198 -0
- megadetector/classification/create_classification_dataset.py +626 -0
- megadetector/classification/crop_detections.py +516 -0
- megadetector/classification/csv_to_json.py +226 -0
- megadetector/classification/detect_and_crop.py +853 -0
- megadetector/classification/efficientnet/__init__.py +9 -0
- megadetector/classification/efficientnet/model.py +415 -0
- megadetector/classification/efficientnet/utils.py +608 -0
- megadetector/classification/evaluate_model.py +520 -0
- megadetector/classification/identify_mislabeled_candidates.py +152 -0
- megadetector/classification/json_to_azcopy_list.py +63 -0
- megadetector/classification/json_validator.py +696 -0
- megadetector/classification/map_classification_categories.py +276 -0
- megadetector/classification/merge_classification_detection_output.py +509 -0
- megadetector/classification/prepare_classification_script.py +194 -0
- megadetector/classification/prepare_classification_script_mc.py +228 -0
- megadetector/classification/run_classifier.py +287 -0
- megadetector/classification/save_mislabeled.py +110 -0
- megadetector/classification/train_classifier.py +827 -0
- megadetector/classification/train_classifier_tf.py +725 -0
- megadetector/classification/train_utils.py +323 -0
- megadetector/data_management/__init__.py +0 -0
- megadetector/data_management/animl_to_md.py +161 -0
- megadetector/data_management/annotations/__init__.py +0 -0
- megadetector/data_management/annotations/annotation_constants.py +33 -0
- megadetector/data_management/camtrap_dp_to_coco.py +270 -0
- megadetector/data_management/cct_json_utils.py +566 -0
- megadetector/data_management/cct_to_md.py +184 -0
- megadetector/data_management/cct_to_wi.py +293 -0
- megadetector/data_management/coco_to_labelme.py +284 -0
- megadetector/data_management/coco_to_yolo.py +702 -0
- megadetector/data_management/databases/__init__.py +0 -0
- megadetector/data_management/databases/add_width_and_height_to_db.py +107 -0
- megadetector/data_management/databases/combine_coco_camera_traps_files.py +210 -0
- megadetector/data_management/databases/integrity_check_json_db.py +528 -0
- megadetector/data_management/databases/subset_json_db.py +195 -0
- megadetector/data_management/generate_crops_from_cct.py +200 -0
- megadetector/data_management/get_image_sizes.py +164 -0
- megadetector/data_management/labelme_to_coco.py +559 -0
- megadetector/data_management/labelme_to_yolo.py +349 -0
- megadetector/data_management/lila/__init__.py +0 -0
- megadetector/data_management/lila/create_lila_blank_set.py +556 -0
- megadetector/data_management/lila/create_lila_test_set.py +187 -0
- megadetector/data_management/lila/create_links_to_md_results_files.py +106 -0
- megadetector/data_management/lila/download_lila_subset.py +182 -0
- megadetector/data_management/lila/generate_lila_per_image_labels.py +777 -0
- megadetector/data_management/lila/get_lila_annotation_counts.py +174 -0
- megadetector/data_management/lila/get_lila_image_counts.py +112 -0
- megadetector/data_management/lila/lila_common.py +319 -0
- megadetector/data_management/lila/test_lila_metadata_urls.py +164 -0
- megadetector/data_management/mewc_to_md.py +344 -0
- megadetector/data_management/ocr_tools.py +873 -0
- megadetector/data_management/read_exif.py +964 -0
- megadetector/data_management/remap_coco_categories.py +195 -0
- megadetector/data_management/remove_exif.py +156 -0
- megadetector/data_management/rename_images.py +194 -0
- megadetector/data_management/resize_coco_dataset.py +663 -0
- megadetector/data_management/speciesnet_to_md.py +41 -0
- megadetector/data_management/wi_download_csv_to_coco.py +247 -0
- megadetector/data_management/yolo_output_to_md_output.py +594 -0
- megadetector/data_management/yolo_to_coco.py +876 -0
- megadetector/data_management/zamba_to_md.py +188 -0
- megadetector/detection/__init__.py +0 -0
- megadetector/detection/change_detection.py +840 -0
- megadetector/detection/process_video.py +479 -0
- megadetector/detection/pytorch_detector.py +1451 -0
- megadetector/detection/run_detector.py +1267 -0
- megadetector/detection/run_detector_batch.py +2159 -0
- megadetector/detection/run_inference_with_yolov5_val.py +1314 -0
- megadetector/detection/run_md_and_speciesnet.py +1494 -0
- megadetector/detection/run_tiled_inference.py +1038 -0
- megadetector/detection/tf_detector.py +209 -0
- megadetector/detection/video_utils.py +1379 -0
- megadetector/postprocessing/__init__.py +0 -0
- megadetector/postprocessing/add_max_conf.py +72 -0
- megadetector/postprocessing/categorize_detections_by_size.py +166 -0
- megadetector/postprocessing/classification_postprocessing.py +1752 -0
- megadetector/postprocessing/combine_batch_outputs.py +249 -0
- megadetector/postprocessing/compare_batch_results.py +2110 -0
- megadetector/postprocessing/convert_output_format.py +403 -0
- megadetector/postprocessing/create_crop_folder.py +629 -0
- megadetector/postprocessing/detector_calibration.py +570 -0
- megadetector/postprocessing/generate_csv_report.py +522 -0
- megadetector/postprocessing/load_api_results.py +223 -0
- megadetector/postprocessing/md_to_coco.py +428 -0
- megadetector/postprocessing/md_to_labelme.py +351 -0
- megadetector/postprocessing/md_to_wi.py +41 -0
- megadetector/postprocessing/merge_detections.py +392 -0
- megadetector/postprocessing/postprocess_batch_results.py +2077 -0
- megadetector/postprocessing/remap_detection_categories.py +226 -0
- megadetector/postprocessing/render_detection_confusion_matrix.py +677 -0
- megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py +206 -0
- megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +82 -0
- megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +1665 -0
- megadetector/postprocessing/separate_detections_into_folders.py +795 -0
- megadetector/postprocessing/subset_json_detector_output.py +964 -0
- megadetector/postprocessing/top_folders_to_bottom.py +238 -0
- megadetector/postprocessing/validate_batch_results.py +332 -0
- megadetector/taxonomy_mapping/__init__.py +0 -0
- megadetector/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +491 -0
- megadetector/taxonomy_mapping/map_new_lila_datasets.py +213 -0
- megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +165 -0
- megadetector/taxonomy_mapping/preview_lila_taxonomy.py +543 -0
- megadetector/taxonomy_mapping/retrieve_sample_image.py +71 -0
- megadetector/taxonomy_mapping/simple_image_download.py +224 -0
- megadetector/taxonomy_mapping/species_lookup.py +1008 -0
- megadetector/taxonomy_mapping/taxonomy_csv_checker.py +159 -0
- megadetector/taxonomy_mapping/taxonomy_graph.py +346 -0
- megadetector/taxonomy_mapping/validate_lila_category_mappings.py +83 -0
- megadetector/tests/__init__.py +0 -0
- megadetector/tests/test_nms_synthetic.py +335 -0
- megadetector/utils/__init__.py +0 -0
- megadetector/utils/ct_utils.py +1857 -0
- megadetector/utils/directory_listing.py +199 -0
- megadetector/utils/extract_frames_from_video.py +307 -0
- megadetector/utils/gpu_test.py +125 -0
- megadetector/utils/md_tests.py +2072 -0
- megadetector/utils/path_utils.py +2832 -0
- megadetector/utils/process_utils.py +172 -0
- megadetector/utils/split_locations_into_train_val.py +237 -0
- megadetector/utils/string_utils.py +234 -0
- megadetector/utils/url_utils.py +825 -0
- megadetector/utils/wi_platform_utils.py +968 -0
- megadetector/utils/wi_taxonomy_utils.py +1759 -0
- megadetector/utils/write_html_image_list.py +239 -0
- megadetector/visualization/__init__.py +0 -0
- megadetector/visualization/plot_utils.py +309 -0
- megadetector/visualization/render_images_with_thumbnails.py +243 -0
- megadetector/visualization/visualization_utils.py +1940 -0
- megadetector/visualization/visualize_db.py +630 -0
- megadetector/visualization/visualize_detector_output.py +479 -0
- megadetector/visualization/visualize_video_output.py +705 -0
- megadetector-10.0.13.dist-info/METADATA +134 -0
- megadetector-10.0.13.dist-info/RECORD +147 -0
- megadetector-10.0.13.dist-info/WHEEL +5 -0
- megadetector-10.0.13.dist-info/licenses/LICENSE +19 -0
- megadetector-10.0.13.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
speciesnet_to_md.py
|
|
4
|
+
|
|
5
|
+
Converts the WI (SpeciesNet) predictions.json format to MD .json format. This is just a
|
|
6
|
+
command-line wrapper around utils.wi_taxonomy_utils.generate_md_results_from_predictions_json.
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
#%% Imports and constants
|
|
11
|
+
|
|
12
|
+
import sys
|
|
13
|
+
import argparse
|
|
14
|
+
from megadetector.utils.wi_taxonomy_utils import generate_md_results_from_predictions_json
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
#%% Command-line driver
|
|
18
|
+
|
|
19
|
+
def main(): # noqa
|
|
20
|
+
|
|
21
|
+
parser = argparse.ArgumentParser()
|
|
22
|
+
parser.add_argument('predictions_json_file', action='store', type=str,
|
|
23
|
+
help='.json file to convert from SpeciesNet predictions.json format to MD format')
|
|
24
|
+
parser.add_argument('md_results_file', action='store', type=str,
|
|
25
|
+
help='output file to write in MD format')
|
|
26
|
+
parser.add_argument('--base_folder', action='store', type=str, default=None,
|
|
27
|
+
help='leading string to remove from each path in the predictions.json ' + \
|
|
28
|
+
'file (to convert from absolute to relative paths)')
|
|
29
|
+
|
|
30
|
+
if len(sys.argv[1:]) == 0:
|
|
31
|
+
parser.print_help()
|
|
32
|
+
parser.exit()
|
|
33
|
+
|
|
34
|
+
args = parser.parse_args()
|
|
35
|
+
|
|
36
|
+
generate_md_results_from_predictions_json(predictions_json_file=args.predictions_json_file,
|
|
37
|
+
md_results_file=args.md_results_file,
|
|
38
|
+
base_folder=args.base_folder)
|
|
39
|
+
|
|
40
|
+
if __name__ == '__main__':
|
|
41
|
+
main()
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
wi_download_csv_to_coco.py
|
|
4
|
+
|
|
5
|
+
Converts a .csv file from a Wildlife Insights project export to a COCO camera traps .json file.
|
|
6
|
+
|
|
7
|
+
Currently assumes that common names are unique identifiers, which is convenient but unreliable.
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
#%% Imports and constants
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
import json
|
|
15
|
+
import pandas as pd
|
|
16
|
+
|
|
17
|
+
from tqdm import tqdm
|
|
18
|
+
from collections import defaultdict
|
|
19
|
+
|
|
20
|
+
from megadetector.visualization import visualization_utils as vis_utils
|
|
21
|
+
from megadetector.utils.ct_utils import isnan
|
|
22
|
+
|
|
23
|
+
wi_extra_annotation_columns = \
|
|
24
|
+
('is_blank','identified_by','wi_taxon_id','class','order','family','genus','species','uncertainty',
|
|
25
|
+
'number_of_objects','age','sex','animal_recognizable','individual_id','individual_animal_notes',
|
|
26
|
+
'behavior','highlighted','markings')
|
|
27
|
+
|
|
28
|
+
wi_extra_image_columns = ('project_id','deployment_id')
|
|
29
|
+
|
|
30
|
+
def _make_location_id(project_id,deployment_id):
|
|
31
|
+
return 'project_' + str(project_id) + '_deployment_' + deployment_id
|
|
32
|
+
|
|
33
|
+
default_category_remappings = {
|
|
34
|
+
'Homo Species':'Human',
|
|
35
|
+
'Human-Camera Trapper':'Human',
|
|
36
|
+
'No CV Result':'Unknown'
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
#%% Main function
|
|
41
|
+
|
|
42
|
+
def wi_download_csv_to_coco(csv_file_in,
|
|
43
|
+
coco_file_out=None,
|
|
44
|
+
image_folder=None,
|
|
45
|
+
validate_images=False,
|
|
46
|
+
gs_prefix=None,
|
|
47
|
+
verbose=True,
|
|
48
|
+
category_remappings=default_category_remappings):
|
|
49
|
+
"""
|
|
50
|
+
Converts a .csv file from a Wildlife Insights project export to a COCO
|
|
51
|
+
Camera Traps .json file.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
csv_file_in (str): the downloaded .csv file we should convert to COCO
|
|
55
|
+
coco_file_out (str, optional): the .json file we should write; if [coco_file_out] is None,
|
|
56
|
+
uses [csv_file_in].json
|
|
57
|
+
image_folder (str, optional): the folder where images live, only relevant if
|
|
58
|
+
[validate_images] is True
|
|
59
|
+
validate_images (bool, optional): whether to check images for corruption and load
|
|
60
|
+
image sizes; if this is True, [image_folder] must be a valid folder
|
|
61
|
+
gs_prefix (str, optional): a string to remove from GS URLs to convert to path names...
|
|
62
|
+
for example, if your gs:// URLs look like:
|
|
63
|
+
|
|
64
|
+
`gs://11234134_xyz/deployment/55554/dfadfasdfs.jpg`
|
|
65
|
+
|
|
66
|
+
...and you specify gs_prefix='11234134_xyz/deployment/', the filenames in
|
|
67
|
+
the .json file will look like:
|
|
68
|
+
|
|
69
|
+
`55554/dfadfasdfs.jpg`
|
|
70
|
+
verbose (bool, optional): enable additional debug console output
|
|
71
|
+
category_remappings (dict, optional): str --> str dict that maps any number of
|
|
72
|
+
WI category names to output category names; for example defaults to mapping
|
|
73
|
+
"Homo Species" to "Human", but leaves 99.99% of categories unchanged.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
dict: COCO-formatted data, identical to what's written to [coco_file_out]
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
##%% Create COCO dictionaries
|
|
80
|
+
|
|
81
|
+
category_name_to_id = {}
|
|
82
|
+
category_name_to_id['empty'] = 0
|
|
83
|
+
|
|
84
|
+
df = pd.read_csv(csv_file_in)
|
|
85
|
+
|
|
86
|
+
print('Read {} rows from {}'.format(len(df),csv_file_in))
|
|
87
|
+
|
|
88
|
+
image_id_to_image = {}
|
|
89
|
+
image_id_to_annotations = defaultdict(list)
|
|
90
|
+
|
|
91
|
+
# i_row = 0; row = df.iloc[i_row]
|
|
92
|
+
for i_row,row in df.iterrows():
|
|
93
|
+
|
|
94
|
+
image_id = row['image_id']
|
|
95
|
+
|
|
96
|
+
if image_id not in image_id_to_image:
|
|
97
|
+
|
|
98
|
+
im = {}
|
|
99
|
+
image_id_to_image[image_id] = im
|
|
100
|
+
|
|
101
|
+
im['id'] = image_id
|
|
102
|
+
|
|
103
|
+
gs_url = row['location']
|
|
104
|
+
assert gs_url.startswith('gs://')
|
|
105
|
+
|
|
106
|
+
file_name = gs_url.replace('gs://','')
|
|
107
|
+
if gs_prefix is not None:
|
|
108
|
+
file_name = file_name.replace(gs_prefix,'')
|
|
109
|
+
|
|
110
|
+
location_id = _make_location_id(row['project_id'],row['deployment_id'])
|
|
111
|
+
im['file_name'] = file_name
|
|
112
|
+
im['location'] = location_id
|
|
113
|
+
im['datetime'] = row['timestamp']
|
|
114
|
+
|
|
115
|
+
im['wi_image_info'] = {}
|
|
116
|
+
for s in wi_extra_image_columns:
|
|
117
|
+
im['wi_image_info'][s] = str(row[s])
|
|
118
|
+
|
|
119
|
+
else:
|
|
120
|
+
|
|
121
|
+
im = image_id_to_image[image_id]
|
|
122
|
+
assert im['datetime'] == row['timestamp']
|
|
123
|
+
location_id = _make_location_id(row['project_id'],row['deployment_id'])
|
|
124
|
+
assert im['location'] == location_id
|
|
125
|
+
|
|
126
|
+
category_name = row['common_name']
|
|
127
|
+
if category_remappings is not None and category_name in category_remappings:
|
|
128
|
+
category_name = category_remappings[category_name]
|
|
129
|
+
|
|
130
|
+
if category_name == 'Blank':
|
|
131
|
+
category_name = 'empty'
|
|
132
|
+
assert row['is_blank'] == 1
|
|
133
|
+
else:
|
|
134
|
+
assert row['is_blank'] == 0
|
|
135
|
+
assert isinstance(category_name,str)
|
|
136
|
+
if category_name in category_name_to_id:
|
|
137
|
+
category_id = category_name_to_id[category_name]
|
|
138
|
+
else:
|
|
139
|
+
category_id = len(category_name_to_id)
|
|
140
|
+
category_name_to_id[category_name] = category_id
|
|
141
|
+
|
|
142
|
+
ann = {}
|
|
143
|
+
ann['image_id'] = image_id
|
|
144
|
+
annotations_this_image = image_id_to_annotations[image_id]
|
|
145
|
+
annotation_number = len(annotations_this_image)
|
|
146
|
+
ann['id'] = image_id + '_' + str(annotation_number).zfill(2)
|
|
147
|
+
ann['category_id'] = category_id
|
|
148
|
+
annotations_this_image.append(ann)
|
|
149
|
+
|
|
150
|
+
extra_info = {}
|
|
151
|
+
for s in wi_extra_annotation_columns:
|
|
152
|
+
v = row[s]
|
|
153
|
+
if not isnan(v):
|
|
154
|
+
extra_info[s] = v
|
|
155
|
+
ann['wi_extra_info'] = extra_info
|
|
156
|
+
|
|
157
|
+
# ...for each row
|
|
158
|
+
|
|
159
|
+
images = list(image_id_to_image.values())
|
|
160
|
+
categories = []
|
|
161
|
+
for category_name in category_name_to_id:
|
|
162
|
+
category_id = category_name_to_id[category_name]
|
|
163
|
+
categories.append({'id':category_id,'name':category_name})
|
|
164
|
+
annotations = []
|
|
165
|
+
for image_id in image_id_to_annotations:
|
|
166
|
+
annotations_this_image = image_id_to_annotations[image_id]
|
|
167
|
+
for ann in annotations_this_image:
|
|
168
|
+
annotations.append(ann)
|
|
169
|
+
info = {'version':'1.00','description':'converted from WI export'}
|
|
170
|
+
info['source_file'] = csv_file_in
|
|
171
|
+
coco_data = {}
|
|
172
|
+
coco_data['info'] = info
|
|
173
|
+
coco_data['images'] = images
|
|
174
|
+
coco_data['annotations'] = annotations
|
|
175
|
+
coco_data['categories'] = categories
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
##%% Validate images, add sizes
|
|
179
|
+
|
|
180
|
+
if validate_images:
|
|
181
|
+
|
|
182
|
+
print('Validating images')
|
|
183
|
+
|
|
184
|
+
assert os.path.isdir(image_folder), \
|
|
185
|
+
'Must specify a valid image folder if you specify validate_images=True'
|
|
186
|
+
|
|
187
|
+
# TODO: trivially parallelizable
|
|
188
|
+
#
|
|
189
|
+
# im = images[0]
|
|
190
|
+
for im in tqdm(images):
|
|
191
|
+
file_name_relative = im['file_name']
|
|
192
|
+
file_name_abs = os.path.join(image_folder,file_name_relative)
|
|
193
|
+
assert os.path.isfile(file_name_abs)
|
|
194
|
+
|
|
195
|
+
im['corrupt'] = False
|
|
196
|
+
try:
|
|
197
|
+
pil_im = vis_utils.load_image(file_name_abs)
|
|
198
|
+
except Exception:
|
|
199
|
+
im['corrupt'] = True
|
|
200
|
+
if not im['corrupt']:
|
|
201
|
+
im['width'] = pil_im.width
|
|
202
|
+
im['height'] = pil_im.height
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
##%% Write output json
|
|
206
|
+
|
|
207
|
+
if coco_file_out is None:
|
|
208
|
+
coco_file_out = csv_file_in + '.json'
|
|
209
|
+
|
|
210
|
+
with open(coco_file_out,'w') as f:
|
|
211
|
+
json.dump(coco_data,f,indent=1)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
##%% Validate output
|
|
215
|
+
|
|
216
|
+
from megadetector.data_management.databases.integrity_check_json_db import \
|
|
217
|
+
IntegrityCheckOptions,integrity_check_json_db
|
|
218
|
+
options = IntegrityCheckOptions()
|
|
219
|
+
options.baseDir = image_folder
|
|
220
|
+
options.bCheckImageExistence = True
|
|
221
|
+
options.verbose = verbose
|
|
222
|
+
_ = integrity_check_json_db(coco_file_out,options)
|
|
223
|
+
|
|
224
|
+
return coco_data
|
|
225
|
+
|
|
226
|
+
# ...def wi_download_csv_to_coco(...)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
#%% Interactive driver
|
|
230
|
+
|
|
231
|
+
if False:
|
|
232
|
+
|
|
233
|
+
#%%
|
|
234
|
+
|
|
235
|
+
base_folder = r'a/b/c'
|
|
236
|
+
csv_file_in = os.path.join(base_folder,'images.csv')
|
|
237
|
+
coco_file_out = None
|
|
238
|
+
gs_prefix = 'a_b_c_main/'
|
|
239
|
+
image_folder = os.path.join(base_folder,'images')
|
|
240
|
+
validate_images = False
|
|
241
|
+
verbose = True
|
|
242
|
+
category_remappings = default_category_remappings
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
#%% Command-line driver
|
|
246
|
+
|
|
247
|
+
# TODO
|