megadetector 5.0.28__py3-none-any.whl → 5.0.29__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/api/batch_processing/api_core/batch_service/score.py +4 -5
- megadetector/api/batch_processing/api_core_support/aggregate_results_manually.py +1 -1
- megadetector/api/batch_processing/api_support/summarize_daily_activity.py +1 -1
- megadetector/api/batch_processing/integration/digiKam/xmp_integration.py +2 -2
- megadetector/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +1 -1
- megadetector/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +1 -1
- megadetector/api/synchronous/api_core/tests/load_test.py +2 -3
- megadetector/classification/aggregate_classifier_probs.py +3 -3
- megadetector/classification/analyze_failed_images.py +5 -5
- megadetector/classification/cache_batchapi_outputs.py +5 -5
- megadetector/classification/create_classification_dataset.py +11 -12
- megadetector/classification/crop_detections.py +10 -10
- megadetector/classification/csv_to_json.py +8 -8
- megadetector/classification/detect_and_crop.py +13 -15
- megadetector/classification/evaluate_model.py +7 -7
- megadetector/classification/identify_mislabeled_candidates.py +6 -6
- megadetector/classification/json_to_azcopy_list.py +1 -1
- megadetector/classification/json_validator.py +29 -32
- megadetector/classification/map_classification_categories.py +9 -9
- megadetector/classification/merge_classification_detection_output.py +12 -9
- megadetector/classification/prepare_classification_script.py +19 -19
- megadetector/classification/prepare_classification_script_mc.py +23 -23
- megadetector/classification/run_classifier.py +4 -4
- megadetector/classification/save_mislabeled.py +6 -6
- megadetector/classification/train_classifier.py +1 -1
- megadetector/classification/train_classifier_tf.py +9 -9
- megadetector/classification/train_utils.py +10 -10
- megadetector/data_management/annotations/annotation_constants.py +1 -1
- megadetector/data_management/camtrap_dp_to_coco.py +45 -45
- megadetector/data_management/cct_json_utils.py +101 -101
- megadetector/data_management/cct_to_md.py +49 -49
- megadetector/data_management/cct_to_wi.py +33 -33
- megadetector/data_management/coco_to_labelme.py +75 -75
- megadetector/data_management/coco_to_yolo.py +189 -189
- megadetector/data_management/databases/add_width_and_height_to_db.py +3 -2
- megadetector/data_management/databases/combine_coco_camera_traps_files.py +38 -38
- megadetector/data_management/databases/integrity_check_json_db.py +202 -188
- megadetector/data_management/databases/subset_json_db.py +33 -33
- megadetector/data_management/generate_crops_from_cct.py +38 -38
- megadetector/data_management/get_image_sizes.py +54 -49
- megadetector/data_management/labelme_to_coco.py +130 -124
- megadetector/data_management/labelme_to_yolo.py +78 -72
- megadetector/data_management/lila/create_lila_blank_set.py +81 -83
- megadetector/data_management/lila/create_lila_test_set.py +32 -31
- megadetector/data_management/lila/create_links_to_md_results_files.py +18 -18
- megadetector/data_management/lila/download_lila_subset.py +21 -24
- megadetector/data_management/lila/generate_lila_per_image_labels.py +91 -91
- megadetector/data_management/lila/get_lila_annotation_counts.py +30 -30
- megadetector/data_management/lila/get_lila_image_counts.py +22 -22
- megadetector/data_management/lila/lila_common.py +70 -70
- megadetector/data_management/lila/test_lila_metadata_urls.py +13 -14
- megadetector/data_management/mewc_to_md.py +339 -340
- megadetector/data_management/ocr_tools.py +258 -252
- megadetector/data_management/read_exif.py +231 -224
- megadetector/data_management/remap_coco_categories.py +26 -26
- megadetector/data_management/remove_exif.py +31 -20
- megadetector/data_management/rename_images.py +187 -187
- megadetector/data_management/resize_coco_dataset.py +41 -41
- megadetector/data_management/speciesnet_to_md.py +41 -41
- megadetector/data_management/wi_download_csv_to_coco.py +55 -55
- megadetector/data_management/yolo_output_to_md_output.py +117 -120
- megadetector/data_management/yolo_to_coco.py +195 -188
- megadetector/detection/change_detection.py +831 -0
- megadetector/detection/process_video.py +340 -337
- megadetector/detection/pytorch_detector.py +304 -262
- megadetector/detection/run_detector.py +177 -164
- megadetector/detection/run_detector_batch.py +364 -363
- megadetector/detection/run_inference_with_yolov5_val.py +328 -325
- megadetector/detection/run_tiled_inference.py +256 -249
- megadetector/detection/tf_detector.py +24 -24
- megadetector/detection/video_utils.py +290 -282
- megadetector/postprocessing/add_max_conf.py +15 -11
- megadetector/postprocessing/categorize_detections_by_size.py +44 -44
- megadetector/postprocessing/classification_postprocessing.py +415 -415
- megadetector/postprocessing/combine_batch_outputs.py +20 -21
- megadetector/postprocessing/compare_batch_results.py +528 -517
- megadetector/postprocessing/convert_output_format.py +97 -97
- megadetector/postprocessing/create_crop_folder.py +219 -146
- megadetector/postprocessing/detector_calibration.py +173 -168
- megadetector/postprocessing/generate_csv_report.py +508 -499
- megadetector/postprocessing/load_api_results.py +23 -20
- megadetector/postprocessing/md_to_coco.py +129 -98
- megadetector/postprocessing/md_to_labelme.py +89 -83
- megadetector/postprocessing/md_to_wi.py +40 -40
- megadetector/postprocessing/merge_detections.py +87 -114
- megadetector/postprocessing/postprocess_batch_results.py +313 -298
- megadetector/postprocessing/remap_detection_categories.py +36 -36
- megadetector/postprocessing/render_detection_confusion_matrix.py +205 -199
- megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py +57 -57
- megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +27 -28
- megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +702 -677
- megadetector/postprocessing/separate_detections_into_folders.py +226 -211
- megadetector/postprocessing/subset_json_detector_output.py +265 -262
- megadetector/postprocessing/top_folders_to_bottom.py +45 -45
- megadetector/postprocessing/validate_batch_results.py +70 -70
- megadetector/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +52 -52
- megadetector/taxonomy_mapping/map_new_lila_datasets.py +15 -15
- megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +14 -14
- megadetector/taxonomy_mapping/preview_lila_taxonomy.py +66 -66
- megadetector/taxonomy_mapping/retrieve_sample_image.py +16 -16
- megadetector/taxonomy_mapping/simple_image_download.py +8 -8
- megadetector/taxonomy_mapping/species_lookup.py +33 -33
- megadetector/taxonomy_mapping/taxonomy_csv_checker.py +14 -14
- megadetector/taxonomy_mapping/taxonomy_graph.py +10 -10
- megadetector/taxonomy_mapping/validate_lila_category_mappings.py +13 -13
- megadetector/utils/azure_utils.py +22 -22
- megadetector/utils/ct_utils.py +1018 -200
- megadetector/utils/directory_listing.py +21 -77
- megadetector/utils/gpu_test.py +22 -22
- megadetector/utils/md_tests.py +541 -518
- megadetector/utils/path_utils.py +1457 -398
- megadetector/utils/process_utils.py +41 -41
- megadetector/utils/sas_blob_utils.py +53 -49
- megadetector/utils/split_locations_into_train_val.py +61 -61
- megadetector/utils/string_utils.py +147 -26
- megadetector/utils/url_utils.py +463 -173
- megadetector/utils/wi_utils.py +2629 -2526
- megadetector/utils/write_html_image_list.py +137 -137
- megadetector/visualization/plot_utils.py +21 -21
- megadetector/visualization/render_images_with_thumbnails.py +37 -73
- megadetector/visualization/visualization_utils.py +401 -397
- megadetector/visualization/visualize_db.py +197 -190
- megadetector/visualization/visualize_detector_output.py +79 -73
- {megadetector-5.0.28.dist-info → megadetector-5.0.29.dist-info}/METADATA +135 -132
- megadetector-5.0.29.dist-info/RECORD +163 -0
- {megadetector-5.0.28.dist-info → megadetector-5.0.29.dist-info}/WHEEL +1 -1
- {megadetector-5.0.28.dist-info → megadetector-5.0.29.dist-info}/licenses/LICENSE +0 -0
- {megadetector-5.0.28.dist-info → megadetector-5.0.29.dist-info}/top_level.txt +0 -0
- megadetector/data_management/importers/add_nacti_sizes.py +0 -52
- megadetector/data_management/importers/add_timestamps_to_icct.py +0 -79
- megadetector/data_management/importers/animl_results_to_md_results.py +0 -158
- megadetector/data_management/importers/auckland_doc_test_to_json.py +0 -373
- megadetector/data_management/importers/auckland_doc_to_json.py +0 -201
- megadetector/data_management/importers/awc_to_json.py +0 -191
- megadetector/data_management/importers/bellevue_to_json.py +0 -272
- megadetector/data_management/importers/cacophony-thermal-importer.py +0 -793
- megadetector/data_management/importers/carrizo_shrubfree_2018.py +0 -269
- megadetector/data_management/importers/carrizo_trail_cam_2017.py +0 -289
- megadetector/data_management/importers/cct_field_adjustments.py +0 -58
- megadetector/data_management/importers/channel_islands_to_cct.py +0 -913
- megadetector/data_management/importers/eMammal/copy_and_unzip_emammal.py +0 -180
- megadetector/data_management/importers/eMammal/eMammal_helpers.py +0 -249
- megadetector/data_management/importers/eMammal/make_eMammal_json.py +0 -223
- megadetector/data_management/importers/ena24_to_json.py +0 -276
- megadetector/data_management/importers/filenames_to_json.py +0 -386
- megadetector/data_management/importers/helena_to_cct.py +0 -283
- megadetector/data_management/importers/idaho-camera-traps.py +0 -1407
- megadetector/data_management/importers/idfg_iwildcam_lila_prep.py +0 -294
- megadetector/data_management/importers/import_desert_lion_conservation_camera_traps.py +0 -387
- megadetector/data_management/importers/jb_csv_to_json.py +0 -150
- megadetector/data_management/importers/mcgill_to_json.py +0 -250
- megadetector/data_management/importers/missouri_to_json.py +0 -490
- megadetector/data_management/importers/nacti_fieldname_adjustments.py +0 -79
- megadetector/data_management/importers/noaa_seals_2019.py +0 -181
- megadetector/data_management/importers/osu-small-animals-to-json.py +0 -364
- megadetector/data_management/importers/pc_to_json.py +0 -365
- megadetector/data_management/importers/plot_wni_giraffes.py +0 -123
- megadetector/data_management/importers/prepare_zsl_imerit.py +0 -131
- megadetector/data_management/importers/raic_csv_to_md_results.py +0 -416
- megadetector/data_management/importers/rspb_to_json.py +0 -356
- megadetector/data_management/importers/save_the_elephants_survey_A.py +0 -320
- megadetector/data_management/importers/save_the_elephants_survey_B.py +0 -329
- megadetector/data_management/importers/snapshot_safari_importer.py +0 -758
- megadetector/data_management/importers/snapshot_serengeti_lila.py +0 -1067
- megadetector/data_management/importers/snapshotserengeti/make_full_SS_json.py +0 -150
- megadetector/data_management/importers/snapshotserengeti/make_per_season_SS_json.py +0 -153
- megadetector/data_management/importers/sulross_get_exif.py +0 -65
- megadetector/data_management/importers/timelapse_csv_set_to_json.py +0 -490
- megadetector/data_management/importers/ubc_to_json.py +0 -399
- megadetector/data_management/importers/umn_to_json.py +0 -507
- megadetector/data_management/importers/wellington_to_json.py +0 -263
- megadetector/data_management/importers/wi_to_json.py +0 -442
- megadetector/data_management/importers/zamba_results_to_md_results.py +0 -180
- megadetector/data_management/lila/add_locations_to_island_camera_traps.py +0 -101
- megadetector/data_management/lila/add_locations_to_nacti.py +0 -151
- megadetector-5.0.28.dist-info/RECORD +0 -209
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
noaa_seals_2019.py
|
|
4
|
-
|
|
5
|
-
Prepare the NOAA Arctic Seals 2019 metadata for LILA.
|
|
6
|
-
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
#%% Imports and constants
|
|
10
|
-
|
|
11
|
-
import os
|
|
12
|
-
import pandas as pd
|
|
13
|
-
from tqdm import tqdm
|
|
14
|
-
|
|
15
|
-
from megadetector.utils import url_utils
|
|
16
|
-
from megadetector.visualization import visualization_utils
|
|
17
|
-
|
|
18
|
-
# A list of files in the lilablobssc container for this data set
|
|
19
|
-
container_file_list = r'C:\temp\seals\seal_files.txt'
|
|
20
|
-
|
|
21
|
-
# The raw detection files provided by NOAA
|
|
22
|
-
detections_fn = r'C:\temp\seals\surv_test_kamera_detections_20210212.csv'
|
|
23
|
-
|
|
24
|
-
# A version of the above with filename columns added
|
|
25
|
-
detections_fn_full_paths = detections_fn.replace('.csv','_full_paths.csv')
|
|
26
|
-
|
|
27
|
-
base_url = 'https://lilablobssc.blob.core.windows.net/noaa-kotz'
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
#%% Read input .csv
|
|
31
|
-
|
|
32
|
-
df = pd.read_csv(detections_fn)
|
|
33
|
-
df['rgb_image_path'] = ''
|
|
34
|
-
df['ir_image_path'] = ''
|
|
35
|
-
print('Read {} rows from {}'.format(len(df),detections_fn))
|
|
36
|
-
|
|
37
|
-
camera_view_to_path = {}
|
|
38
|
-
camera_view_to_path['C'] = 'CENT'
|
|
39
|
-
camera_view_to_path['L'] = 'LEFT'
|
|
40
|
-
|
|
41
|
-
valid_flights = set(['fl04','fl05','fl06','fl07'])
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
#%% Read list of files
|
|
45
|
-
|
|
46
|
-
with open(container_file_list,'r') as f:
|
|
47
|
-
all_files = f.readlines()
|
|
48
|
-
all_files = [s.strip() for s in all_files]
|
|
49
|
-
all_files = set(all_files)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
#%% Convert paths to full paths
|
|
53
|
-
|
|
54
|
-
missing_ir_files = []
|
|
55
|
-
|
|
56
|
-
# i_row = 0; row = df.iloc[i_row]
|
|
57
|
-
for i_row,row in tqdm(df.iterrows(),total=len(df)):
|
|
58
|
-
|
|
59
|
-
assert row['flight'] in valid_flights
|
|
60
|
-
assert row['camera_view'] in camera_view_to_path
|
|
61
|
-
|
|
62
|
-
assert isinstance(row['rgb_image_name'],str)
|
|
63
|
-
rgb_image_path = 'Images/{}/{}/{}'.format(row['flight'],camera_view_to_path[row['camera_view']],
|
|
64
|
-
row['rgb_image_name'])
|
|
65
|
-
assert rgb_image_path in all_files
|
|
66
|
-
df.loc[i_row,'rgb_image_path'] = rgb_image_path
|
|
67
|
-
|
|
68
|
-
if not isinstance(row['ir_image_name'],str):
|
|
69
|
-
continue
|
|
70
|
-
|
|
71
|
-
ir_image_path = 'Images/{}/{}/{}'.format(row['flight'],camera_view_to_path[row['camera_view']],
|
|
72
|
-
row['ir_image_name'])
|
|
73
|
-
# assert ir_image_path in all_files
|
|
74
|
-
if ir_image_path not in all_files:
|
|
75
|
-
missing_ir_files.append(ir_image_path)
|
|
76
|
-
df.loc[i_row,'ir_image_path'] = ir_image_path
|
|
77
|
-
|
|
78
|
-
# ...for each row
|
|
79
|
-
|
|
80
|
-
missing_ir_files = list(set(missing_ir_files))
|
|
81
|
-
missing_ir_files.sort()
|
|
82
|
-
print('{} missing IR files (of {})'.format(len(missing_ir_files),len(df)))
|
|
83
|
-
|
|
84
|
-
for s in missing_ir_files:
|
|
85
|
-
print(s)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
#%% Write results
|
|
89
|
-
|
|
90
|
-
df.to_csv(detections_fn_full_paths,index=False)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
#%% Load output file, just to be sure
|
|
94
|
-
|
|
95
|
-
df = pd.read_csv(detections_fn_full_paths)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
#%% Render annotations on an image
|
|
99
|
-
|
|
100
|
-
import random; i_image = random.randint(0,len(df))
|
|
101
|
-
# i_image = 2004
|
|
102
|
-
row = df.iloc[i_image]
|
|
103
|
-
rgb_image_path = row['rgb_image_path']
|
|
104
|
-
rgb_image_url = base_url + '/' + rgb_image_path
|
|
105
|
-
ir_image_path = row['ir_image_path']
|
|
106
|
-
ir_image_url = base_url + '/' + ir_image_path
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
#%% Download the image
|
|
110
|
-
|
|
111
|
-
rgb_image_fn = url_utils.download_url(rgb_image_url,progress_updater=True)
|
|
112
|
-
ir_image_fn = url_utils.download_url(ir_image_url,progress_updater=True)
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
#%% Find all the rows (detections) associated with this image
|
|
116
|
-
|
|
117
|
-
# as l,r,t,b
|
|
118
|
-
rgb_boxes = []
|
|
119
|
-
ir_boxes = []
|
|
120
|
-
|
|
121
|
-
for i_row,row in df.iterrows():
|
|
122
|
-
|
|
123
|
-
if row['rgb_image_path'] == rgb_image_path:
|
|
124
|
-
box_l = row['rgb_left']
|
|
125
|
-
box_r = row['rgb_right']
|
|
126
|
-
box_t = row['rgb_top']
|
|
127
|
-
box_b = row['rgb_bottom']
|
|
128
|
-
rgb_boxes.append([box_l,box_r,box_t,box_b])
|
|
129
|
-
|
|
130
|
-
if row['ir_image_path'] == ir_image_path:
|
|
131
|
-
box_l = row['ir_left']
|
|
132
|
-
box_r = row['ir_right']
|
|
133
|
-
box_t = row['ir_top']
|
|
134
|
-
box_b = row['ir_bottom']
|
|
135
|
-
ir_boxes.append([box_l,box_r,box_t,box_b])
|
|
136
|
-
|
|
137
|
-
print('Found {} RGB, {} IR annotations for this image'.format(len(rgb_boxes),
|
|
138
|
-
len(ir_boxes)))
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
#%% Render the detections on the image(s)
|
|
142
|
-
|
|
143
|
-
img_rgb = visualization_utils.load_image(rgb_image_fn)
|
|
144
|
-
img_ir = visualization_utils.load_image(ir_image_fn)
|
|
145
|
-
|
|
146
|
-
for b in rgb_boxes:
|
|
147
|
-
|
|
148
|
-
# In pixel coordinates
|
|
149
|
-
box_left = b[0]; box_right = b[1]; box_top = b[2]; box_bottom = b[3]
|
|
150
|
-
assert box_top > box_bottom; assert box_right > box_left
|
|
151
|
-
ymin = box_bottom; ymax = box_top; xmin = box_left; xmax = box_right
|
|
152
|
-
|
|
153
|
-
visualization_utils.draw_bounding_box_on_image(img_rgb,ymin,xmin,ymax,xmax,
|
|
154
|
-
use_normalized_coordinates=False,
|
|
155
|
-
thickness=3)
|
|
156
|
-
|
|
157
|
-
for b in ir_boxes:
|
|
158
|
-
|
|
159
|
-
# In pixel coordinates
|
|
160
|
-
box_left = b[0]; box_right = b[1]; box_top = b[2]; box_bottom = b[3]
|
|
161
|
-
assert box_top > box_bottom; assert box_right > box_left
|
|
162
|
-
ymin = box_bottom; ymax = box_top; xmin = box_left; xmax = box_right
|
|
163
|
-
|
|
164
|
-
visualization_utils.draw_bounding_box_on_image(img_ir,ymin,xmin,ymax,xmax,
|
|
165
|
-
use_normalized_coordinates=False,
|
|
166
|
-
thickness=3)
|
|
167
|
-
|
|
168
|
-
# visualization_utils.show_images_in_a_row([img_rgb,img_ir])
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
#%% Save images
|
|
172
|
-
|
|
173
|
-
img_rgb.save(r'c:\temp\seals_rgb.png')
|
|
174
|
-
img_ir.save(r'c:\temp\seals_ir.png')
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
#%% Clean up
|
|
178
|
-
|
|
179
|
-
import shutil
|
|
180
|
-
tmp_dir = os.path.dirname(rgb_image_fn)
|
|
181
|
-
shutil.rmtree(tmp_dir)
|
|
@@ -1,364 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
Prepare the OSU Small Animals dataset for LILA release:
|
|
4
|
-
|
|
5
|
-
1. Convert metadata to COCO
|
|
6
|
-
2. Extract location, datestamp, and sequence information
|
|
7
|
-
3. Remove redundant or excluded images
|
|
8
|
-
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
#%% Imports and constants
|
|
12
|
-
|
|
13
|
-
import os
|
|
14
|
-
|
|
15
|
-
input_folder = os.path.expanduser('~/osu-small-animals')
|
|
16
|
-
assert os.path.isdir(input_folder)
|
|
17
|
-
|
|
18
|
-
output_folder = os.path.expanduser('~/osu-small-animals-lila')
|
|
19
|
-
os.makedirs(output_folder,exist_ok=True)
|
|
20
|
-
output_file = os.path.join(output_folder,'osu-small-animals.json')
|
|
21
|
-
|
|
22
|
-
preview_folder = os.path.expanduser('~/osu-small-animals-preview')
|
|
23
|
-
os.makedirs(preview_folder,exist_ok=True)
|
|
24
|
-
|
|
25
|
-
common_to_latin_file = r'osu-small-animals-common-to-latin.txt'
|
|
26
|
-
assert os.path.isfile(common_to_latin_file)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
#%% Support functions
|
|
30
|
-
|
|
31
|
-
def custom_relative_path_to_location(relative_path):
|
|
32
|
-
|
|
33
|
-
bn = os.path.basename(relative_path).upper()
|
|
34
|
-
|
|
35
|
-
# This only impacted six images
|
|
36
|
-
if bn.startswith('RCNX'):
|
|
37
|
-
site = 'OSTN'
|
|
38
|
-
return site
|
|
39
|
-
|
|
40
|
-
# FCS1__2019-07-08__10-37-46(1).JPG
|
|
41
|
-
# BIWA4S2020-06-25_16-19-56.JPG
|
|
42
|
-
# GRN3c__2019-05-05__01-39-23(1).JPG
|
|
43
|
-
|
|
44
|
-
tokens = bn.split('_')
|
|
45
|
-
site = tokens[0]
|
|
46
|
-
if '2020' in site:
|
|
47
|
-
site = site.split('2020')[0]
|
|
48
|
-
|
|
49
|
-
assert len(site) <= 8
|
|
50
|
-
assert site.isalnum()
|
|
51
|
-
|
|
52
|
-
return site
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
#%% Read EXIF data from all images
|
|
56
|
-
|
|
57
|
-
from megadetector.data_management.read_exif import \
|
|
58
|
-
ReadExifOptions, read_exif_from_folder
|
|
59
|
-
import json
|
|
60
|
-
|
|
61
|
-
exif_cache_file = os.path.join(input_folder,'exif_info.json')
|
|
62
|
-
|
|
63
|
-
if os.path.isfile(exif_cache_file):
|
|
64
|
-
|
|
65
|
-
print('Reading EXIF data from cache')
|
|
66
|
-
with open(exif_cache_file,'r') as f:
|
|
67
|
-
exif_info = json.load(f)
|
|
68
|
-
|
|
69
|
-
else:
|
|
70
|
-
|
|
71
|
-
read_exif_options = ReadExifOptions()
|
|
72
|
-
read_exif_options.n_workers = 8
|
|
73
|
-
|
|
74
|
-
exif_info = read_exif_from_folder(input_folder=input_folder,
|
|
75
|
-
output_file=exif_cache_file,
|
|
76
|
-
options=read_exif_options,
|
|
77
|
-
filenames=None,
|
|
78
|
-
recursive=True)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
#%% Verify that no GPS data is present
|
|
82
|
-
|
|
83
|
-
from megadetector.data_management.read_exif import has_gps_info
|
|
84
|
-
|
|
85
|
-
missing_exif_tags = []
|
|
86
|
-
|
|
87
|
-
# im = exif_info[0]
|
|
88
|
-
for im in exif_info:
|
|
89
|
-
if im['exif_tags'] is None:
|
|
90
|
-
missing_exif_tags.append(im['file_name'])
|
|
91
|
-
continue
|
|
92
|
-
else:
|
|
93
|
-
assert not has_gps_info(im)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
#%% Read common --> latin mapping
|
|
97
|
-
|
|
98
|
-
with open(common_to_latin_file,'r') as f:
|
|
99
|
-
lines = f.readlines()
|
|
100
|
-
|
|
101
|
-
common_to_latin = {}
|
|
102
|
-
|
|
103
|
-
# s = lines[0]
|
|
104
|
-
for s in lines:
|
|
105
|
-
s = s.strip()
|
|
106
|
-
tokens = s.split('\t')
|
|
107
|
-
assert len(tokens) == 2
|
|
108
|
-
common = tokens[0].lower().replace(' ','_')
|
|
109
|
-
latin = tokens[1].replace('_',' ').lower()
|
|
110
|
-
assert common not in common_to_latin.keys()
|
|
111
|
-
assert latin not in common_to_latin.values()
|
|
112
|
-
common_to_latin[common] = latin
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
#%% Convert non-excluded, non-split images to COCO format
|
|
116
|
-
|
|
117
|
-
from datetime import datetime
|
|
118
|
-
|
|
119
|
-
from tqdm import tqdm
|
|
120
|
-
|
|
121
|
-
# One-off typo fix
|
|
122
|
-
name_replacements = \
|
|
123
|
-
{
|
|
124
|
-
'common_five-linked_skink':'common_five-lined_skink'
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
category_name_to_category = {}
|
|
128
|
-
# Force the empty category to be ID 0
|
|
129
|
-
empty_category = {}
|
|
130
|
-
empty_category['id'] = 0
|
|
131
|
-
empty_category['name'] = 'empty'
|
|
132
|
-
category_name_to_category['empty'] = empty_category
|
|
133
|
-
next_category_id = 1
|
|
134
|
-
|
|
135
|
-
images = []
|
|
136
|
-
annotations = []
|
|
137
|
-
|
|
138
|
-
error_images = []
|
|
139
|
-
excluded_images = []
|
|
140
|
-
|
|
141
|
-
# exif_im = exif_info[0]
|
|
142
|
-
for exif_im in tqdm(exif_info):
|
|
143
|
-
|
|
144
|
-
fn_relative = exif_im['file_name']
|
|
145
|
-
assert '\\' not in fn_relative
|
|
146
|
-
|
|
147
|
-
if 'Split_images' in fn_relative or 'Exclusions' in fn_relative:
|
|
148
|
-
excluded_images.append(fn_relative)
|
|
149
|
-
continue
|
|
150
|
-
|
|
151
|
-
if 'error' in exif_im:
|
|
152
|
-
assert exif_im['error'] is not None
|
|
153
|
-
error_images.append(fn_relative)
|
|
154
|
-
continue
|
|
155
|
-
|
|
156
|
-
location_name = custom_relative_path_to_location(fn_relative)
|
|
157
|
-
|
|
158
|
-
exif_tags = exif_im['exif_tags']
|
|
159
|
-
|
|
160
|
-
# Convert '2021:05:27 14:42:00' to '2021-05-27 14:42:00'
|
|
161
|
-
datestamp = exif_tags['DateTime']
|
|
162
|
-
datestamp_tokens = datestamp.split(' ')
|
|
163
|
-
assert len(datestamp_tokens) == 2
|
|
164
|
-
date_string = datestamp_tokens[0]
|
|
165
|
-
time_string = datestamp_tokens[1]
|
|
166
|
-
assert len(date_string) == 10 and len(date_string.split(':')) == 3
|
|
167
|
-
date_string = date_string.replace(':','-')
|
|
168
|
-
assert len(time_string) == 8 and len(time_string.split(':')) == 3
|
|
169
|
-
datestamp_string = date_string + ' ' + time_string
|
|
170
|
-
datestamp_object = datetime.strptime(datestamp_string, '%Y-%m-%d %H:%M:%S')
|
|
171
|
-
assert str(datestamp_object) == datestamp_string
|
|
172
|
-
|
|
173
|
-
# E.g.:
|
|
174
|
-
#
|
|
175
|
-
# Images/Sorted_by_species/Testudines/Snapping Turtle/CBG10__2021-05-27__14-42-00(1).JPG'
|
|
176
|
-
common_name = os.path.basename(os.path.dirname(fn_relative)).lower().replace(' ','_')
|
|
177
|
-
|
|
178
|
-
if common_name in name_replacements:
|
|
179
|
-
common_name = name_replacements[common_name]
|
|
180
|
-
|
|
181
|
-
if common_name == 'blanks':
|
|
182
|
-
common_name = 'empty'
|
|
183
|
-
else:
|
|
184
|
-
assert common_name in common_to_latin
|
|
185
|
-
|
|
186
|
-
if common_name in category_name_to_category:
|
|
187
|
-
|
|
188
|
-
category = category_name_to_category[common_name]
|
|
189
|
-
|
|
190
|
-
else:
|
|
191
|
-
|
|
192
|
-
category = {}
|
|
193
|
-
category['name'] = common_name
|
|
194
|
-
category['latin_name'] = common_to_latin[common_name]
|
|
195
|
-
category['id'] = next_category_id
|
|
196
|
-
next_category_id += 1
|
|
197
|
-
category_name_to_category[common_name] = category
|
|
198
|
-
|
|
199
|
-
im = {}
|
|
200
|
-
im['id'] = fn_relative
|
|
201
|
-
im['file_name'] = fn_relative
|
|
202
|
-
im['datetime'] = datestamp_object
|
|
203
|
-
im['location'] = location_name
|
|
204
|
-
|
|
205
|
-
annotation = {}
|
|
206
|
-
annotation['id'] = 'ann_' + fn_relative
|
|
207
|
-
annotation['image_id'] = im['id']
|
|
208
|
-
annotation['category_id'] = category['id']
|
|
209
|
-
annotation['sequence_level_annotation'] = False
|
|
210
|
-
|
|
211
|
-
images.append(im)
|
|
212
|
-
annotations.append(annotation)
|
|
213
|
-
|
|
214
|
-
# ...for each image
|
|
215
|
-
|
|
216
|
-
cct_dict = {}
|
|
217
|
-
cct_dict['images'] = images
|
|
218
|
-
cct_dict['annotations'] = annotations
|
|
219
|
-
cct_dict['categories'] = list(category_name_to_category.values())
|
|
220
|
-
|
|
221
|
-
cct_dict['info'] = {}
|
|
222
|
-
cct_dict['info']['version'] = '2024.10.03'
|
|
223
|
-
cct_dict['info']['description'] = 'OSU small animals dataset'
|
|
224
|
-
|
|
225
|
-
print('\nExcluded {} of {} images ({} errors)'.format(
|
|
226
|
-
len(excluded_images),
|
|
227
|
-
len(exif_info),
|
|
228
|
-
len(error_images)))
|
|
229
|
-
|
|
230
|
-
assert len(images) == len(exif_info) - (len(error_images) + len(excluded_images))
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
#%% Create sequences from timestamps
|
|
234
|
-
|
|
235
|
-
from megadetector.data_management import cct_json_utils
|
|
236
|
-
|
|
237
|
-
print('Assembling images into sequences')
|
|
238
|
-
cct_json_utils.create_sequences(cct_dict)
|
|
239
|
-
|
|
240
|
-
# Convert datetimes to strings so we can serialize to json
|
|
241
|
-
for im in cct_dict['images']:
|
|
242
|
-
im['datetime'] = str(im['datetime'])
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
#%% Write COCO data
|
|
246
|
-
|
|
247
|
-
with open(output_file,'w') as f:
|
|
248
|
-
json.dump(cct_dict,f,indent=1)
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
#%% Copy images (prep)
|
|
252
|
-
|
|
253
|
-
from megadetector.utils.path_utils import parallel_copy_files
|
|
254
|
-
|
|
255
|
-
input_file_to_output_file = {}
|
|
256
|
-
|
|
257
|
-
# im = cct_dict['images'][0]
|
|
258
|
-
for im in tqdm(cct_dict['images']):
|
|
259
|
-
fn_relative = im['file_name']
|
|
260
|
-
fn_source_abs = os.path.join(input_folder,fn_relative)
|
|
261
|
-
assert os.path.isfile(fn_source_abs)
|
|
262
|
-
fn_dest_abs = os.path.join(output_folder,fn_relative)
|
|
263
|
-
assert fn_source_abs not in input_file_to_output_file
|
|
264
|
-
input_file_to_output_file[fn_source_abs] = fn_dest_abs
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
#%% Copy images (execution)
|
|
268
|
-
|
|
269
|
-
parallel_copy_files(input_file_to_output_file, max_workers=10,
|
|
270
|
-
use_threads=True, overwrite=False, verbose=False)
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
#%% Validate .json file
|
|
274
|
-
|
|
275
|
-
from megadetector.data_management.databases import integrity_check_json_db
|
|
276
|
-
|
|
277
|
-
options = integrity_check_json_db.IntegrityCheckOptions()
|
|
278
|
-
options.baseDir = input_folder
|
|
279
|
-
options.bCheckImageSizes = False
|
|
280
|
-
options.bCheckImageExistence = True
|
|
281
|
-
options.bFindUnusedImages = True
|
|
282
|
-
options.bRequireLocation = True
|
|
283
|
-
|
|
284
|
-
sorted_categories, data, _ = integrity_check_json_db.integrity_check_json_db(output_file, options)
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
#%% Preview labels
|
|
288
|
-
|
|
289
|
-
from megadetector.visualization import visualize_db
|
|
290
|
-
|
|
291
|
-
viz_options = visualize_db.DbVizOptions()
|
|
292
|
-
viz_options.num_to_visualize = 5000
|
|
293
|
-
viz_options.parallelize_rendering = True
|
|
294
|
-
viz_options.htmlOptions['maxFiguresPerHtmlFile'] = 2500
|
|
295
|
-
viz_options.parallelize_rendering_with_threads = True
|
|
296
|
-
|
|
297
|
-
html_output_file, image_db = visualize_db.visualize_db(db_path=output_file,
|
|
298
|
-
output_dir=preview_folder,
|
|
299
|
-
image_base_dir=input_folder,
|
|
300
|
-
options=viz_options)
|
|
301
|
-
|
|
302
|
-
os.startfile(html_output_file)
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
#%% Print unique locations
|
|
306
|
-
|
|
307
|
-
all_locations = set()
|
|
308
|
-
|
|
309
|
-
for im in cct_dict['images']:
|
|
310
|
-
all_locations.add(im['location'])
|
|
311
|
-
|
|
312
|
-
all_locations = sorted(list(all_locations))
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
#%% Notes
|
|
316
|
-
|
|
317
|
-
"""
|
|
318
|
-
31899 eastern_gartersnake
|
|
319
|
-
14567 song_sparrow
|
|
320
|
-
14169 meadow_vole
|
|
321
|
-
11448 empty
|
|
322
|
-
10548 white-footed_mouse
|
|
323
|
-
5934 northern_house_wren
|
|
324
|
-
5075 invertebrate
|
|
325
|
-
5045 common_five-lined_skink
|
|
326
|
-
4242 masked_shrew
|
|
327
|
-
3263 eastern_cottontail
|
|
328
|
-
2325 long-tailed_weasel
|
|
329
|
-
1510 woodland_jumping_mouse
|
|
330
|
-
1272 plains_gartersnake
|
|
331
|
-
1189 eastern_massasauga
|
|
332
|
-
985 virginia_opossum
|
|
333
|
-
802 common_yellowthroat
|
|
334
|
-
746 n._short-tailed_shrew
|
|
335
|
-
529 dekay's_brownsnake
|
|
336
|
-
425 american_mink
|
|
337
|
-
340 american_toad
|
|
338
|
-
293 eastern_racer_snake
|
|
339
|
-
264 smooth_greensnake
|
|
340
|
-
198 eastern_chipmunk
|
|
341
|
-
193 northern_leopard_frog
|
|
342
|
-
160 meadow_jumping_mouse
|
|
343
|
-
155 butler's_gartersnake
|
|
344
|
-
133 eastern_ribbonsnake
|
|
345
|
-
121 northern_watersnake
|
|
346
|
-
111 star-nosed_mole
|
|
347
|
-
104 striped_skunk
|
|
348
|
-
72 eastern_milksnake
|
|
349
|
-
68 gray_ratsnake
|
|
350
|
-
67 eastern_hog-nosed_snake
|
|
351
|
-
62 raccoon
|
|
352
|
-
47 green_frog
|
|
353
|
-
44 woodchuck
|
|
354
|
-
44 kirtland's_snake
|
|
355
|
-
23 indigo_bunting
|
|
356
|
-
23 painted_turtle
|
|
357
|
-
13 sora
|
|
358
|
-
12 american_bullfrog
|
|
359
|
-
10 gray_catbird
|
|
360
|
-
9 red-bellied_snake
|
|
361
|
-
8 brown_rat
|
|
362
|
-
6 snapping_turtle
|
|
363
|
-
1 eastern_bluebird
|
|
364
|
-
"""
|