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,184 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
cct_to_md.py
|
|
4
|
+
|
|
5
|
+
"Converts" a COCO Camera Traps file to a MD results file. Currently ignores
|
|
6
|
+
non-bounding-box annotations, and gives all annotations a confidence of 1.0.
|
|
7
|
+
|
|
8
|
+
The only reason to do this is if you are going to add information to an existing
|
|
9
|
+
CCT-formatted dataset, and you want to do that in Timelapse.
|
|
10
|
+
|
|
11
|
+
Currently assumes that width and height are present in the input data, does not
|
|
12
|
+
read them from images.
|
|
13
|
+
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
#%% Constants and imports
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
import json
|
|
20
|
+
|
|
21
|
+
from collections import defaultdict
|
|
22
|
+
from tqdm import tqdm
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
#%% Functions
|
|
26
|
+
|
|
27
|
+
def cct_to_md(input_filename,output_filename=None):
|
|
28
|
+
"""
|
|
29
|
+
"Converts" a COCO Camera Traps file to a MD results file. Currently ignores
|
|
30
|
+
non-bounding-box annotations. If the semi-standard "score" field is present in
|
|
31
|
+
an annotation, or the totally non-standard "conf" field is present, it will be
|
|
32
|
+
transferred to the output, otherwise a confidence value of 1.0 is assumed for
|
|
33
|
+
all annotations.
|
|
34
|
+
|
|
35
|
+
The main reason to run this script the scenario where you are going to add information
|
|
36
|
+
to an existing CCT-formatted dataset, and you want to do that in Timelapse.
|
|
37
|
+
|
|
38
|
+
Currently assumes that width and height are present in the input data, does not
|
|
39
|
+
read them from images.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
input_filename (str): the COCO Camera Traps .json file to read
|
|
43
|
+
output_filename (str, optional): the .json file to write in MD results format
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
dict: MD-formatted results, identical to the content of [output_filename] if
|
|
47
|
+
[output_filename] is not None
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
## Validate input
|
|
51
|
+
|
|
52
|
+
assert os.path.isfile(input_filename)
|
|
53
|
+
|
|
54
|
+
if (output_filename is None):
|
|
55
|
+
|
|
56
|
+
tokens = os.path.splitext(input_filename)
|
|
57
|
+
assert len(tokens) == 2
|
|
58
|
+
output_filename = tokens[0] + '_md-format' + tokens[1]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
## Read input
|
|
62
|
+
|
|
63
|
+
with open(input_filename,'r') as f:
|
|
64
|
+
d = json.load(f)
|
|
65
|
+
|
|
66
|
+
for s in ['annotations','images','categories']:
|
|
67
|
+
assert s in d.keys(), 'Cannot find key {} in input file, is this a CCT file?'.format(s)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
## Prepare metadata
|
|
71
|
+
|
|
72
|
+
image_id_to_annotations = defaultdict(list)
|
|
73
|
+
|
|
74
|
+
# ann = d['annotations'][0]
|
|
75
|
+
for ann in tqdm(d['annotations']):
|
|
76
|
+
image_id_to_annotations[ann['image_id']].append(ann)
|
|
77
|
+
|
|
78
|
+
category_id_to_name = {}
|
|
79
|
+
for cat in d['categories']:
|
|
80
|
+
category_id_to_name[str(cat['id'])] = cat['name']
|
|
81
|
+
|
|
82
|
+
results = {}
|
|
83
|
+
|
|
84
|
+
info = {}
|
|
85
|
+
info['format_version'] = '1.4'
|
|
86
|
+
info['detector'] = 'cct_to_md'
|
|
87
|
+
results['info'] = info
|
|
88
|
+
results['detection_categories'] = category_id_to_name
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
## Process images
|
|
92
|
+
|
|
93
|
+
images_out = []
|
|
94
|
+
|
|
95
|
+
# im = d['images'][0]
|
|
96
|
+
for im in tqdm(d['images']):
|
|
97
|
+
|
|
98
|
+
im_out = {}
|
|
99
|
+
im_out['file'] = im['file_name']
|
|
100
|
+
im_out['location'] = im['location']
|
|
101
|
+
im_out['id'] = im['id']
|
|
102
|
+
|
|
103
|
+
image_h = im['height']
|
|
104
|
+
image_w = im['width']
|
|
105
|
+
|
|
106
|
+
detections = []
|
|
107
|
+
|
|
108
|
+
annotations_this_image = image_id_to_annotations[im['id']]
|
|
109
|
+
|
|
110
|
+
# This field is no longer included in MD output files by default
|
|
111
|
+
# max_detection_conf = 0
|
|
112
|
+
|
|
113
|
+
for ann in annotations_this_image:
|
|
114
|
+
|
|
115
|
+
if 'bbox' in ann:
|
|
116
|
+
|
|
117
|
+
det = {}
|
|
118
|
+
det['category'] = str(ann['category_id'])
|
|
119
|
+
if 'score' in ann:
|
|
120
|
+
det['conf'] = ann['score']
|
|
121
|
+
elif 'conf' in ann:
|
|
122
|
+
det['conf'] = ann['conf']
|
|
123
|
+
else:
|
|
124
|
+
det['conf'] = 1.0
|
|
125
|
+
|
|
126
|
+
# MegaDetector: [x,y,width,height] (normalized, origin upper-left)
|
|
127
|
+
# CCT: [x,y,width,height] (absolute, origin upper-left)
|
|
128
|
+
bbox_in = ann['bbox']
|
|
129
|
+
bbox_out = [bbox_in[0]/image_w,bbox_in[1]/image_h,
|
|
130
|
+
bbox_in[2]/image_w,bbox_in[3]/image_h]
|
|
131
|
+
det['bbox'] = bbox_out
|
|
132
|
+
detections.append(det)
|
|
133
|
+
|
|
134
|
+
# ...if there's a bounding box
|
|
135
|
+
|
|
136
|
+
# ...for each annotation
|
|
137
|
+
|
|
138
|
+
im_out['detections'] = detections
|
|
139
|
+
|
|
140
|
+
# This field is no longer included in MD output files by default
|
|
141
|
+
# im_out['max_detection_conf'] = max_detection_conf
|
|
142
|
+
|
|
143
|
+
images_out.append(im_out)
|
|
144
|
+
|
|
145
|
+
# ...for each image
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
## Write output
|
|
149
|
+
|
|
150
|
+
results['images'] = images_out
|
|
151
|
+
|
|
152
|
+
if output_filename is not None:
|
|
153
|
+
with open(output_filename,'w') as f:
|
|
154
|
+
json.dump(results, f, indent=1)
|
|
155
|
+
|
|
156
|
+
return results
|
|
157
|
+
|
|
158
|
+
# ...cct_to_md()
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
#%% Interactive driver
|
|
162
|
+
|
|
163
|
+
if False:
|
|
164
|
+
|
|
165
|
+
pass
|
|
166
|
+
|
|
167
|
+
#%%
|
|
168
|
+
|
|
169
|
+
input_filename = r"G:\temp\noaa_estuary_fish.json"
|
|
170
|
+
output_filename = None
|
|
171
|
+
output_filename = cct_to_md(input_filename,output_filename)
|
|
172
|
+
|
|
173
|
+
#%%
|
|
174
|
+
|
|
175
|
+
from megadetector.visualization import visualize_detector_output
|
|
176
|
+
|
|
177
|
+
visualize_detector_output.visualize_detector_output(
|
|
178
|
+
detector_output_path=output_filename,
|
|
179
|
+
out_dir=r'g:\temp\fish_output',
|
|
180
|
+
images_dir=r'g:\temp\noaa_estuary_fish-images\JPEGImages',
|
|
181
|
+
output_image_width=-1,
|
|
182
|
+
sample=100,
|
|
183
|
+
render_detections_only=True)
|
|
184
|
+
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
cct_to_wi.py
|
|
4
|
+
|
|
5
|
+
Converts COCO Camera Traps .json files to the Wildlife Insights
|
|
6
|
+
batch upload format.
|
|
7
|
+
|
|
8
|
+
**This is very much just a demo script; all the relevant constants are hard-coded
|
|
9
|
+
at the top of main().**
|
|
10
|
+
|
|
11
|
+
But given that caveat, it works. You need to set up all the paths in the "paths" cell
|
|
12
|
+
at the top of main().
|
|
13
|
+
|
|
14
|
+
Also see:
|
|
15
|
+
|
|
16
|
+
* https://github.com/ConservationInternational/Wildlife-Insights----Data-Migration
|
|
17
|
+
* https://data.naturalsciences.org/wildlife-insights/taxonomy/search
|
|
18
|
+
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
#%% Imports
|
|
22
|
+
|
|
23
|
+
import os
|
|
24
|
+
import json
|
|
25
|
+
import pandas as pd
|
|
26
|
+
from collections import defaultdict
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
#%% Main wrapper
|
|
30
|
+
|
|
31
|
+
def main(): # noqa
|
|
32
|
+
"""
|
|
33
|
+
Converts COCO Camera Traps .json files to the Wildlife Insights
|
|
34
|
+
batch upload format; to use this, you need to modify all the paths in the "Paths"
|
|
35
|
+
cell.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
#%% Paths
|
|
39
|
+
|
|
40
|
+
# A COCO camera traps file with information about this dataset
|
|
41
|
+
input_file = r'c:\temp\camera_trap_images_no_people\bellevue_camera_traps.2020-12-26.json'
|
|
42
|
+
|
|
43
|
+
# A .json dictionary mapping common names in this dataset to dictionaries with the
|
|
44
|
+
# WI taxonomy fields: common_name, wi_taxon_id, class, order, family, genus, species
|
|
45
|
+
taxonomy_file = r'c:\temp\camera_trap_images_no_people\bellevue_camera_traps_to_wi.json'
|
|
46
|
+
|
|
47
|
+
# The folder where the .csv template files live
|
|
48
|
+
templates_dir = r'c:\temp\wi_batch_upload_templates'
|
|
49
|
+
|
|
50
|
+
# The folder to which you want to write WI-formatted .csv files
|
|
51
|
+
output_base = r'c:\temp\wi_output'
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
#%% Path validation
|
|
55
|
+
|
|
56
|
+
assert os.path.isfile(input_file)
|
|
57
|
+
assert os.path.isfile(taxonomy_file)
|
|
58
|
+
assert os.path.isdir(templates_dir)
|
|
59
|
+
os.makedirs(output_base,exist_ok = True)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
#%% Constants
|
|
63
|
+
|
|
64
|
+
projects_file_name = 'Template Wildlife Insights Batch Upload - Projectv1.0.csv'
|
|
65
|
+
deployments_file_name = 'Template Wildlife Insights Batch Upload - Deploymentv1.0.csv'
|
|
66
|
+
images_file_name = 'Template Wildlife Insights Batch Upload - Imagev1.0.csv'
|
|
67
|
+
cameras_file_name = 'Template Wildlife Insights Batch Upload - Camerav1.0.csv'
|
|
68
|
+
|
|
69
|
+
assert all([os.path.isfile(os.path.join(templates_dir,fn)) for fn in \
|
|
70
|
+
[projects_file_name,deployments_file_name,images_file_name,cameras_file_name]])
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
#%% Project information
|
|
74
|
+
|
|
75
|
+
project_info = {}
|
|
76
|
+
project_info['project_name'] = 'Bellevue Camera Traps'
|
|
77
|
+
project_info['project_id'] = 'bct_001'
|
|
78
|
+
project_info['project_short_name'] = 'BCT'
|
|
79
|
+
project_info['project_objectives'] = 'none'
|
|
80
|
+
project_info['project_species'] = 'Multiple'
|
|
81
|
+
project_info['project_species_individual'] = ''
|
|
82
|
+
project_info['project_sensor_layout'] = 'Convenience'
|
|
83
|
+
project_info['project_sensor_layout_targeted_type'] = ''
|
|
84
|
+
project_info['project_bait_use'] = 'No'
|
|
85
|
+
project_info['project_bait_type'] = 'None'
|
|
86
|
+
project_info['project_stratification'] = 'No'
|
|
87
|
+
project_info['project_stratification_type'] = ''
|
|
88
|
+
project_info['project_sensor_method'] = 'Sensor Detection'
|
|
89
|
+
project_info['project_individual_animals'] = 'No'
|
|
90
|
+
project_info['project_admin'] = 'Dan Morris'
|
|
91
|
+
project_info['project_admin_email'] = 'cameratraps@lila.science'
|
|
92
|
+
project_info['country_code'] = 'USA'
|
|
93
|
+
project_info['embargo'] = str(0)
|
|
94
|
+
project_info['initiative_id'] = ''
|
|
95
|
+
project_info['metadata_license'] = 'CC0'
|
|
96
|
+
project_info['image_license'] = 'CC0'
|
|
97
|
+
|
|
98
|
+
project_info['project_blank_images'] = 'No'
|
|
99
|
+
project_info['project_sensor_cluster'] = 'No'
|
|
100
|
+
|
|
101
|
+
camera_info = {}
|
|
102
|
+
camera_info['project_id'] = project_info['project_id']
|
|
103
|
+
camera_info['camera_id'] = '0000'
|
|
104
|
+
camera_info['make'] = ''
|
|
105
|
+
camera_info['model'] = ''
|
|
106
|
+
camera_info['serial_number'] = ''
|
|
107
|
+
camera_info['year_purchased'] = ''
|
|
108
|
+
|
|
109
|
+
deployment_info = {}
|
|
110
|
+
|
|
111
|
+
deployment_info['project_id'] = project_info['project_id']
|
|
112
|
+
deployment_info['deployment_id'] = 'test_deployment'
|
|
113
|
+
deployment_info['subproject_name'] = 'test_subproject'
|
|
114
|
+
deployment_info['subproject_design'] = ''
|
|
115
|
+
deployment_info['placename'] = 'yard'
|
|
116
|
+
deployment_info['longitude'] = '47.6101'
|
|
117
|
+
deployment_info['latitude'] = '-122.2015'
|
|
118
|
+
deployment_info['start_date'] = '2016-01-01 00:00:00'
|
|
119
|
+
deployment_info['end_date'] = '2026-01-01 00:00:00'
|
|
120
|
+
deployment_info['event_name'] = ''
|
|
121
|
+
deployment_info['event_description'] = ''
|
|
122
|
+
deployment_info['event_type'] = ''
|
|
123
|
+
deployment_info['bait_type'] = ''
|
|
124
|
+
deployment_info['bait_description'] = ''
|
|
125
|
+
deployment_info['feature_type'] = 'None'
|
|
126
|
+
deployment_info['feature_type_methodology'] = ''
|
|
127
|
+
deployment_info['camera_id'] = camera_info['camera_id']
|
|
128
|
+
deployment_info['quiet_period'] = str(60)
|
|
129
|
+
deployment_info['camera_functioning'] = 'Camera Functioning'
|
|
130
|
+
deployment_info['sensor_height'] = 'Chest height'
|
|
131
|
+
deployment_info['height_other'] = ''
|
|
132
|
+
deployment_info['sensor_orientation'] = 'Parallel'
|
|
133
|
+
deployment_info['orientation_other'] = ''
|
|
134
|
+
deployment_info['recorded_by'] = 'Dan Morris'
|
|
135
|
+
|
|
136
|
+
image_info = {}
|
|
137
|
+
image_info['identified_by'] = 'Dan Morris'
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
#%% Read templates
|
|
141
|
+
|
|
142
|
+
def parse_fields(templates_dir,file_name):
|
|
143
|
+
|
|
144
|
+
with open(os.path.join(templates_dir,file_name),'r') as f:
|
|
145
|
+
lines = f.readlines()
|
|
146
|
+
lines = [s.strip() for s in lines if len(s.strip().replace(',','')) > 0]
|
|
147
|
+
assert len(lines) == 1, 'Error processing template {}'.format(file_name)
|
|
148
|
+
fields = lines[0].split(',')
|
|
149
|
+
print('Parsed {} columns from {}'.format(len(fields),file_name))
|
|
150
|
+
return fields
|
|
151
|
+
|
|
152
|
+
projects_fields = parse_fields(templates_dir,projects_file_name)
|
|
153
|
+
deployments_fields = parse_fields(templates_dir,deployments_file_name)
|
|
154
|
+
images_fields = parse_fields(templates_dir,images_file_name)
|
|
155
|
+
cameras_fields = parse_fields(templates_dir,cameras_file_name)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
#%% Compare dictionary to template lists
|
|
159
|
+
|
|
160
|
+
def compare_info_to_template(info,template_fields,name):
|
|
161
|
+
|
|
162
|
+
for s in info.keys():
|
|
163
|
+
assert s in template_fields,'Field {} not specified in {}_fields'.format(s,name)
|
|
164
|
+
for s in template_fields:
|
|
165
|
+
assert s in info.keys(),'Field {} not specified in {}_info'.format(s,name)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def write_table(file_name,info,template_fields):
|
|
169
|
+
|
|
170
|
+
assert len(info) == len(template_fields)
|
|
171
|
+
|
|
172
|
+
project_output_file = os.path.join(output_base,file_name)
|
|
173
|
+
with open(project_output_file,'w') as f:
|
|
174
|
+
|
|
175
|
+
# Write the header
|
|
176
|
+
for i_field,s in enumerate(template_fields):
|
|
177
|
+
f.write(s)
|
|
178
|
+
if i_field != len(template_fields)-1:
|
|
179
|
+
f.write(',')
|
|
180
|
+
f.write('\n')
|
|
181
|
+
|
|
182
|
+
# Write values
|
|
183
|
+
for i_field,s in enumerate(template_fields):
|
|
184
|
+
f.write(info[s])
|
|
185
|
+
if i_field != len(template_fields)-1:
|
|
186
|
+
f.write(',')
|
|
187
|
+
f.write('\n')
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
#%% Project file
|
|
191
|
+
|
|
192
|
+
compare_info_to_template(project_info,projects_fields,'project')
|
|
193
|
+
write_table(projects_file_name,project_info,projects_fields)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
#%% Camera file
|
|
197
|
+
|
|
198
|
+
compare_info_to_template(camera_info,cameras_fields,'camera')
|
|
199
|
+
write_table(cameras_file_name,camera_info,cameras_fields)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
#%% Deployment file
|
|
203
|
+
|
|
204
|
+
compare_info_to_template(deployment_info,deployments_fields,'deployment')
|
|
205
|
+
write_table(deployments_file_name,deployment_info,deployments_fields)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
#%% Images file
|
|
209
|
+
|
|
210
|
+
# Read .json file with image information
|
|
211
|
+
with open(input_file,'r') as f:
|
|
212
|
+
input_data = json.load(f)
|
|
213
|
+
|
|
214
|
+
# Read taxonomy dictionary
|
|
215
|
+
with open(taxonomy_file,'r') as f:
|
|
216
|
+
taxonomy_mapping = json.load(f)
|
|
217
|
+
|
|
218
|
+
url_base = taxonomy_mapping['url_base']
|
|
219
|
+
taxonomy_mapping = taxonomy_mapping['taxonomy']
|
|
220
|
+
|
|
221
|
+
# Populate output information
|
|
222
|
+
# df = pd.DataFrame(columns = images_fields)
|
|
223
|
+
|
|
224
|
+
category_id_to_name = {cat['id']:cat['name'] for cat in input_data['categories']}
|
|
225
|
+
|
|
226
|
+
image_id_to_annotations = defaultdict(list)
|
|
227
|
+
|
|
228
|
+
annotations = input_data['annotations']
|
|
229
|
+
|
|
230
|
+
# annotation = annotations[0]
|
|
231
|
+
for annotation in annotations:
|
|
232
|
+
image_id_to_annotations[annotation['image_id']].append(
|
|
233
|
+
category_id_to_name[annotation['category_id']])
|
|
234
|
+
|
|
235
|
+
rows = []
|
|
236
|
+
|
|
237
|
+
# im = input_data['images'][0]
|
|
238
|
+
for im in input_data['images']:
|
|
239
|
+
|
|
240
|
+
row = {}
|
|
241
|
+
|
|
242
|
+
url = url_base + im['file_name'].replace('\\','/')
|
|
243
|
+
row['project_id'] = project_info['project_id']
|
|
244
|
+
row['deployment_id'] = deployment_info['deployment_id']
|
|
245
|
+
row['image_id'] = im['id']
|
|
246
|
+
row['location'] = url
|
|
247
|
+
row['identified_by'] = image_info['identified_by']
|
|
248
|
+
|
|
249
|
+
category_names = image_id_to_annotations[im['id']]
|
|
250
|
+
assert len(category_names) == 1
|
|
251
|
+
category_name = category_names[0]
|
|
252
|
+
|
|
253
|
+
taxon_info = taxonomy_mapping[category_name]
|
|
254
|
+
|
|
255
|
+
assert len(taxon_info.keys()) == 7
|
|
256
|
+
|
|
257
|
+
for s in taxon_info.keys():
|
|
258
|
+
row[s] = taxon_info[s]
|
|
259
|
+
|
|
260
|
+
# We don't have counts, but we can differentiate between zero and 1
|
|
261
|
+
if category_name == 'empty':
|
|
262
|
+
row['number_of_objects'] = 0
|
|
263
|
+
else:
|
|
264
|
+
row['number_of_objects'] = 1
|
|
265
|
+
|
|
266
|
+
assert isinstance(im['datetime'],str)
|
|
267
|
+
|
|
268
|
+
row['uncertainty'] = None
|
|
269
|
+
row['timestamp'] = im['datetime']
|
|
270
|
+
row['highlighted'] = 0
|
|
271
|
+
row['age'] = None
|
|
272
|
+
row['sex'] = None
|
|
273
|
+
row['animal_recognizable'] = 'No'
|
|
274
|
+
row['individual_id'] = None
|
|
275
|
+
row['individual_animal_notes'] = None
|
|
276
|
+
row['markings'] = None
|
|
277
|
+
|
|
278
|
+
assert len(row) == len(images_fields)
|
|
279
|
+
rows.append(row)
|
|
280
|
+
|
|
281
|
+
# ...for each image
|
|
282
|
+
|
|
283
|
+
df = pd.DataFrame(rows)
|
|
284
|
+
|
|
285
|
+
df.to_csv(os.path.join(output_base,images_file_name),index=False)
|
|
286
|
+
|
|
287
|
+
# ...main()
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
#%% Command-line driver
|
|
291
|
+
|
|
292
|
+
if __name__ == '__main__':
|
|
293
|
+
main()
|