megadetector 5.0.9__py3-none-any.whl → 5.0.11__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-5.0.9.dist-info → megadetector-5.0.11.dist-info}/LICENSE +0 -0
- {megadetector-5.0.9.dist-info → megadetector-5.0.11.dist-info}/METADATA +12 -11
- megadetector-5.0.11.dist-info/RECORD +5 -0
- megadetector-5.0.11.dist-info/top_level.txt +1 -0
- api/__init__.py +0 -0
- api/batch_processing/__init__.py +0 -0
- api/batch_processing/api_core/__init__.py +0 -0
- api/batch_processing/api_core/batch_service/__init__.py +0 -0
- api/batch_processing/api_core/batch_service/score.py +0 -439
- api/batch_processing/api_core/server.py +0 -294
- api/batch_processing/api_core/server_api_config.py +0 -98
- api/batch_processing/api_core/server_app_config.py +0 -55
- api/batch_processing/api_core/server_batch_job_manager.py +0 -220
- api/batch_processing/api_core/server_job_status_table.py +0 -152
- api/batch_processing/api_core/server_orchestration.py +0 -360
- api/batch_processing/api_core/server_utils.py +0 -92
- api/batch_processing/api_core_support/__init__.py +0 -0
- api/batch_processing/api_core_support/aggregate_results_manually.py +0 -46
- api/batch_processing/api_support/__init__.py +0 -0
- api/batch_processing/api_support/summarize_daily_activity.py +0 -152
- api/batch_processing/data_preparation/__init__.py +0 -0
- api/batch_processing/data_preparation/manage_local_batch.py +0 -2391
- api/batch_processing/data_preparation/manage_video_batch.py +0 -327
- api/batch_processing/integration/digiKam/setup.py +0 -6
- api/batch_processing/integration/digiKam/xmp_integration.py +0 -465
- api/batch_processing/integration/eMammal/test_scripts/config_template.py +0 -5
- api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +0 -126
- api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +0 -55
- api/batch_processing/postprocessing/__init__.py +0 -0
- api/batch_processing/postprocessing/add_max_conf.py +0 -64
- api/batch_processing/postprocessing/categorize_detections_by_size.py +0 -163
- api/batch_processing/postprocessing/combine_api_outputs.py +0 -249
- api/batch_processing/postprocessing/compare_batch_results.py +0 -958
- api/batch_processing/postprocessing/convert_output_format.py +0 -397
- api/batch_processing/postprocessing/load_api_results.py +0 -195
- api/batch_processing/postprocessing/md_to_coco.py +0 -310
- api/batch_processing/postprocessing/md_to_labelme.py +0 -330
- api/batch_processing/postprocessing/merge_detections.py +0 -401
- api/batch_processing/postprocessing/postprocess_batch_results.py +0 -1904
- api/batch_processing/postprocessing/remap_detection_categories.py +0 -170
- api/batch_processing/postprocessing/render_detection_confusion_matrix.py +0 -661
- api/batch_processing/postprocessing/repeat_detection_elimination/find_repeat_detections.py +0 -211
- api/batch_processing/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +0 -82
- api/batch_processing/postprocessing/repeat_detection_elimination/repeat_detections_core.py +0 -1631
- api/batch_processing/postprocessing/separate_detections_into_folders.py +0 -731
- api/batch_processing/postprocessing/subset_json_detector_output.py +0 -696
- api/batch_processing/postprocessing/top_folders_to_bottom.py +0 -223
- api/synchronous/__init__.py +0 -0
- api/synchronous/api_core/animal_detection_api/__init__.py +0 -0
- api/synchronous/api_core/animal_detection_api/api_backend.py +0 -152
- api/synchronous/api_core/animal_detection_api/api_frontend.py +0 -266
- api/synchronous/api_core/animal_detection_api/config.py +0 -35
- api/synchronous/api_core/animal_detection_api/data_management/annotations/annotation_constants.py +0 -47
- api/synchronous/api_core/animal_detection_api/detection/detector_training/copy_checkpoints.py +0 -43
- api/synchronous/api_core/animal_detection_api/detection/detector_training/model_main_tf2.py +0 -114
- api/synchronous/api_core/animal_detection_api/detection/process_video.py +0 -543
- api/synchronous/api_core/animal_detection_api/detection/pytorch_detector.py +0 -304
- api/synchronous/api_core/animal_detection_api/detection/run_detector.py +0 -627
- api/synchronous/api_core/animal_detection_api/detection/run_detector_batch.py +0 -1029
- api/synchronous/api_core/animal_detection_api/detection/run_inference_with_yolov5_val.py +0 -581
- api/synchronous/api_core/animal_detection_api/detection/run_tiled_inference.py +0 -754
- api/synchronous/api_core/animal_detection_api/detection/tf_detector.py +0 -165
- api/synchronous/api_core/animal_detection_api/detection/video_utils.py +0 -495
- api/synchronous/api_core/animal_detection_api/md_utils/azure_utils.py +0 -174
- api/synchronous/api_core/animal_detection_api/md_utils/ct_utils.py +0 -262
- api/synchronous/api_core/animal_detection_api/md_utils/directory_listing.py +0 -251
- api/synchronous/api_core/animal_detection_api/md_utils/matlab_porting_tools.py +0 -97
- api/synchronous/api_core/animal_detection_api/md_utils/path_utils.py +0 -416
- api/synchronous/api_core/animal_detection_api/md_utils/process_utils.py +0 -110
- api/synchronous/api_core/animal_detection_api/md_utils/sas_blob_utils.py +0 -509
- api/synchronous/api_core/animal_detection_api/md_utils/string_utils.py +0 -59
- api/synchronous/api_core/animal_detection_api/md_utils/url_utils.py +0 -144
- api/synchronous/api_core/animal_detection_api/md_utils/write_html_image_list.py +0 -226
- api/synchronous/api_core/animal_detection_api/md_visualization/visualization_utils.py +0 -841
- api/synchronous/api_core/tests/__init__.py +0 -0
- api/synchronous/api_core/tests/load_test.py +0 -110
- classification/__init__.py +0 -0
- classification/aggregate_classifier_probs.py +0 -108
- classification/analyze_failed_images.py +0 -227
- classification/cache_batchapi_outputs.py +0 -198
- classification/create_classification_dataset.py +0 -627
- classification/crop_detections.py +0 -516
- classification/csv_to_json.py +0 -226
- classification/detect_and_crop.py +0 -855
- classification/efficientnet/__init__.py +0 -9
- classification/efficientnet/model.py +0 -415
- classification/efficientnet/utils.py +0 -610
- classification/evaluate_model.py +0 -520
- classification/identify_mislabeled_candidates.py +0 -152
- classification/json_to_azcopy_list.py +0 -63
- classification/json_validator.py +0 -695
- classification/map_classification_categories.py +0 -276
- classification/merge_classification_detection_output.py +0 -506
- classification/prepare_classification_script.py +0 -194
- classification/prepare_classification_script_mc.py +0 -228
- classification/run_classifier.py +0 -286
- classification/save_mislabeled.py +0 -110
- classification/train_classifier.py +0 -825
- classification/train_classifier_tf.py +0 -724
- classification/train_utils.py +0 -322
- data_management/__init__.py +0 -0
- data_management/annotations/__init__.py +0 -0
- data_management/annotations/annotation_constants.py +0 -34
- data_management/camtrap_dp_to_coco.py +0 -238
- data_management/cct_json_utils.py +0 -395
- data_management/cct_to_md.py +0 -176
- data_management/cct_to_wi.py +0 -289
- data_management/coco_to_labelme.py +0 -272
- data_management/coco_to_yolo.py +0 -662
- data_management/databases/__init__.py +0 -0
- data_management/databases/add_width_and_height_to_db.py +0 -33
- data_management/databases/combine_coco_camera_traps_files.py +0 -206
- data_management/databases/integrity_check_json_db.py +0 -477
- data_management/databases/subset_json_db.py +0 -115
- data_management/generate_crops_from_cct.py +0 -149
- data_management/get_image_sizes.py +0 -188
- data_management/importers/add_nacti_sizes.py +0 -52
- data_management/importers/add_timestamps_to_icct.py +0 -79
- data_management/importers/animl_results_to_md_results.py +0 -158
- data_management/importers/auckland_doc_test_to_json.py +0 -372
- data_management/importers/auckland_doc_to_json.py +0 -200
- data_management/importers/awc_to_json.py +0 -189
- data_management/importers/bellevue_to_json.py +0 -273
- data_management/importers/cacophony-thermal-importer.py +0 -796
- data_management/importers/carrizo_shrubfree_2018.py +0 -268
- data_management/importers/carrizo_trail_cam_2017.py +0 -287
- data_management/importers/cct_field_adjustments.py +0 -57
- data_management/importers/channel_islands_to_cct.py +0 -913
- data_management/importers/eMammal/copy_and_unzip_emammal.py +0 -180
- data_management/importers/eMammal/eMammal_helpers.py +0 -249
- data_management/importers/eMammal/make_eMammal_json.py +0 -223
- data_management/importers/ena24_to_json.py +0 -275
- data_management/importers/filenames_to_json.py +0 -385
- data_management/importers/helena_to_cct.py +0 -282
- data_management/importers/idaho-camera-traps.py +0 -1407
- data_management/importers/idfg_iwildcam_lila_prep.py +0 -294
- data_management/importers/jb_csv_to_json.py +0 -150
- data_management/importers/mcgill_to_json.py +0 -250
- data_management/importers/missouri_to_json.py +0 -489
- data_management/importers/nacti_fieldname_adjustments.py +0 -79
- data_management/importers/noaa_seals_2019.py +0 -181
- data_management/importers/pc_to_json.py +0 -365
- data_management/importers/plot_wni_giraffes.py +0 -123
- data_management/importers/prepare-noaa-fish-data-for-lila.py +0 -359
- data_management/importers/prepare_zsl_imerit.py +0 -131
- data_management/importers/rspb_to_json.py +0 -356
- data_management/importers/save_the_elephants_survey_A.py +0 -320
- data_management/importers/save_the_elephants_survey_B.py +0 -332
- data_management/importers/snapshot_safari_importer.py +0 -758
- data_management/importers/snapshot_safari_importer_reprise.py +0 -665
- data_management/importers/snapshot_serengeti_lila.py +0 -1067
- data_management/importers/snapshotserengeti/make_full_SS_json.py +0 -150
- data_management/importers/snapshotserengeti/make_per_season_SS_json.py +0 -153
- data_management/importers/sulross_get_exif.py +0 -65
- data_management/importers/timelapse_csv_set_to_json.py +0 -490
- data_management/importers/ubc_to_json.py +0 -399
- data_management/importers/umn_to_json.py +0 -507
- data_management/importers/wellington_to_json.py +0 -263
- data_management/importers/wi_to_json.py +0 -441
- data_management/importers/zamba_results_to_md_results.py +0 -181
- data_management/labelme_to_coco.py +0 -548
- data_management/labelme_to_yolo.py +0 -272
- data_management/lila/__init__.py +0 -0
- data_management/lila/add_locations_to_island_camera_traps.py +0 -97
- data_management/lila/add_locations_to_nacti.py +0 -147
- data_management/lila/create_lila_blank_set.py +0 -557
- data_management/lila/create_lila_test_set.py +0 -151
- data_management/lila/create_links_to_md_results_files.py +0 -106
- data_management/lila/download_lila_subset.py +0 -177
- data_management/lila/generate_lila_per_image_labels.py +0 -515
- data_management/lila/get_lila_annotation_counts.py +0 -170
- data_management/lila/get_lila_image_counts.py +0 -111
- data_management/lila/lila_common.py +0 -300
- data_management/lila/test_lila_metadata_urls.py +0 -132
- data_management/ocr_tools.py +0 -874
- data_management/read_exif.py +0 -681
- data_management/remap_coco_categories.py +0 -84
- data_management/remove_exif.py +0 -66
- data_management/resize_coco_dataset.py +0 -189
- data_management/wi_download_csv_to_coco.py +0 -246
- data_management/yolo_output_to_md_output.py +0 -441
- data_management/yolo_to_coco.py +0 -676
- detection/__init__.py +0 -0
- detection/detector_training/__init__.py +0 -0
- detection/detector_training/model_main_tf2.py +0 -114
- detection/process_video.py +0 -703
- detection/pytorch_detector.py +0 -337
- detection/run_detector.py +0 -779
- detection/run_detector_batch.py +0 -1219
- detection/run_inference_with_yolov5_val.py +0 -917
- detection/run_tiled_inference.py +0 -935
- detection/tf_detector.py +0 -188
- detection/video_utils.py +0 -606
- docs/source/conf.py +0 -43
- md_utils/__init__.py +0 -0
- md_utils/azure_utils.py +0 -174
- md_utils/ct_utils.py +0 -612
- md_utils/directory_listing.py +0 -246
- md_utils/md_tests.py +0 -968
- md_utils/path_utils.py +0 -1044
- md_utils/process_utils.py +0 -157
- md_utils/sas_blob_utils.py +0 -509
- md_utils/split_locations_into_train_val.py +0 -228
- md_utils/string_utils.py +0 -92
- md_utils/url_utils.py +0 -323
- md_utils/write_html_image_list.py +0 -225
- md_visualization/__init__.py +0 -0
- md_visualization/plot_utils.py +0 -293
- md_visualization/render_images_with_thumbnails.py +0 -275
- md_visualization/visualization_utils.py +0 -1537
- md_visualization/visualize_db.py +0 -551
- md_visualization/visualize_detector_output.py +0 -406
- megadetector-5.0.9.dist-info/RECORD +0 -224
- megadetector-5.0.9.dist-info/top_level.txt +0 -8
- taxonomy_mapping/__init__.py +0 -0
- taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +0 -491
- taxonomy_mapping/map_new_lila_datasets.py +0 -154
- taxonomy_mapping/prepare_lila_taxonomy_release.py +0 -142
- taxonomy_mapping/preview_lila_taxonomy.py +0 -591
- taxonomy_mapping/retrieve_sample_image.py +0 -71
- taxonomy_mapping/simple_image_download.py +0 -218
- taxonomy_mapping/species_lookup.py +0 -834
- taxonomy_mapping/taxonomy_csv_checker.py +0 -159
- taxonomy_mapping/taxonomy_graph.py +0 -346
- taxonomy_mapping/validate_lila_category_mappings.py +0 -83
- {megadetector-5.0.9.dist-info → megadetector-5.0.11.dist-info}/WHEEL +0 -0
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
subset_json_db.py
|
|
4
|
-
|
|
5
|
-
Select a subset of images (and associated annotations) from a .json file in COCO
|
|
6
|
-
Camera Traps format based on a string query.
|
|
7
|
-
|
|
8
|
-
To subset .json files in the MegaDetector output format, see
|
|
9
|
-
subset_json_detector_output.py.
|
|
10
|
-
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
#%% Constants and imports
|
|
14
|
-
|
|
15
|
-
import sys
|
|
16
|
-
import json
|
|
17
|
-
import argparse
|
|
18
|
-
|
|
19
|
-
from tqdm import tqdm
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
#%% Functions
|
|
23
|
-
|
|
24
|
-
def subset_json_db(input_json, query, output_json=None, ignore_case=False):
|
|
25
|
-
"""
|
|
26
|
-
Given a json file (or dictionary already loaded from a json file), produce a new
|
|
27
|
-
database containing only the images whose filenames contain the string 'query',
|
|
28
|
-
optionally writing that DB output to a new json file.
|
|
29
|
-
|
|
30
|
-
Args:
|
|
31
|
-
input_json (str): COCO Camera Traps .json file to load, or an already-loaded dict
|
|
32
|
-
query (str): string to query for, only include images in the output whose filenames
|
|
33
|
-
contain this string.
|
|
34
|
-
output_json (str, optional): file to write the resulting .json file to
|
|
35
|
-
ignore_case (bool, optional): whether to perform a case-insensitive search for [query]
|
|
36
|
-
|
|
37
|
-
Returns:
|
|
38
|
-
dict: possibly-modified CCT dictionary
|
|
39
|
-
"""
|
|
40
|
-
|
|
41
|
-
if ignore_case:
|
|
42
|
-
query = query.lower()
|
|
43
|
-
|
|
44
|
-
# Load the input file if necessary
|
|
45
|
-
if isinstance(input_json,str):
|
|
46
|
-
print('Loading input .json...')
|
|
47
|
-
with open(input_json, 'r') as f:
|
|
48
|
-
data = json.load(f)
|
|
49
|
-
else:
|
|
50
|
-
data = input_json
|
|
51
|
-
|
|
52
|
-
# Find images matching the query
|
|
53
|
-
images = []
|
|
54
|
-
image_ids = set()
|
|
55
|
-
|
|
56
|
-
for im in tqdm(data['images']):
|
|
57
|
-
fn = im['file_name']
|
|
58
|
-
if ignore_case:
|
|
59
|
-
fn = fn.lower()
|
|
60
|
-
if query in fn:
|
|
61
|
-
images.append(im)
|
|
62
|
-
image_ids.add(im['id'])
|
|
63
|
-
|
|
64
|
-
# Find annotations referring to those images
|
|
65
|
-
annotations = []
|
|
66
|
-
|
|
67
|
-
for ann in tqdm(data['annotations']):
|
|
68
|
-
if ann['image_id'] in image_ids:
|
|
69
|
-
annotations.append(ann)
|
|
70
|
-
|
|
71
|
-
output_data = data
|
|
72
|
-
output_data['images'] = images
|
|
73
|
-
output_data['annotations'] = annotations
|
|
74
|
-
|
|
75
|
-
# Write the output file if requested
|
|
76
|
-
if output_json is not None:
|
|
77
|
-
print('Writing output .json...')
|
|
78
|
-
json.dump(output_data,open(output_json,'w'),indent=1)
|
|
79
|
-
|
|
80
|
-
return output_data
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
#%% Interactive driver
|
|
84
|
-
|
|
85
|
-
if False:
|
|
86
|
-
|
|
87
|
-
#%%
|
|
88
|
-
|
|
89
|
-
input_json = r"e:\Statewide_wolf_container\idfg_20190409.json"
|
|
90
|
-
output_json = r"e:\Statewide_wolf_container\idfg_20190409_clearcreek.json"
|
|
91
|
-
query = 'clearcreek'
|
|
92
|
-
ignore_case = True
|
|
93
|
-
db = subset_json_db(input_json, query, output_json, ignore_case)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
#%% Command-line driver
|
|
97
|
-
|
|
98
|
-
def main():
|
|
99
|
-
|
|
100
|
-
parser = argparse.ArgumentParser()
|
|
101
|
-
parser.add_argument('input_json', type=str, help='Input file (a COCO Camera Traps .json file)')
|
|
102
|
-
parser.add_argument('output_json', type=str, help='Output file')
|
|
103
|
-
parser.add_argument('query', type=str, help='Filename query')
|
|
104
|
-
parser.add_argument('--ignore_case', action='store_true')
|
|
105
|
-
|
|
106
|
-
if len(sys.argv[1:]) == 0:
|
|
107
|
-
parser.print_help()
|
|
108
|
-
parser.exit()
|
|
109
|
-
|
|
110
|
-
args = parser.parse_args()
|
|
111
|
-
|
|
112
|
-
subset_json_db(args.input_json,args.query,args.output_json,args.ignore_case)
|
|
113
|
-
|
|
114
|
-
if __name__ == '__main__':
|
|
115
|
-
main()
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
generate_crops_from_cct.py
|
|
4
|
-
|
|
5
|
-
Given a .json file in COCO Camera Traps format, creates a cropped image for
|
|
6
|
-
each bounding box.
|
|
7
|
-
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
#%% Imports and constants
|
|
11
|
-
|
|
12
|
-
import os
|
|
13
|
-
import json
|
|
14
|
-
|
|
15
|
-
from tqdm import tqdm
|
|
16
|
-
from PIL import Image
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
#%% Functions
|
|
20
|
-
|
|
21
|
-
def generate_crops_from_cct(cct_file,image_dir,output_dir,padding=0,flat_output=True):
|
|
22
|
-
"""
|
|
23
|
-
Given a .json file in COCO Camera Traps format, creates a cropped image for
|
|
24
|
-
each bounding box.
|
|
25
|
-
|
|
26
|
-
Args:
|
|
27
|
-
cct_file (str): the COCO .json file from which we should load data
|
|
28
|
-
image_dir (str): the folder where the images live; filenames in the .json
|
|
29
|
-
file should be relative to this folder
|
|
30
|
-
output_dir (str): the folder where we should write cropped images
|
|
31
|
-
padding (float, optional): number of pixels we should expand each box before
|
|
32
|
-
cropping
|
|
33
|
-
flat_output (bool, optional): if False, folder structure will be preserved
|
|
34
|
-
in the output, e.g. the image a/b/c/d.jpg will result in image files
|
|
35
|
-
in the output folder called, e.g., a/b/c/d_crop_000_id_12345.jpg. If
|
|
36
|
-
[flat_output] is True, the corresponding output image will be
|
|
37
|
-
a_b_c_d_crop_000_id_12345.jpg.
|
|
38
|
-
"""
|
|
39
|
-
|
|
40
|
-
## Read and validate input
|
|
41
|
-
|
|
42
|
-
assert os.path.isfile(cct_file)
|
|
43
|
-
assert os.path.isdir(image_dir)
|
|
44
|
-
os.makedirs(output_dir,exist_ok=True)
|
|
45
|
-
|
|
46
|
-
with open(cct_file,'r') as f:
|
|
47
|
-
d = json.load(f)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
## Find annotations for each image
|
|
51
|
-
|
|
52
|
-
from collections import defaultdict
|
|
53
|
-
|
|
54
|
-
# This actually maps image IDs to annotations, but only to annotations
|
|
55
|
-
# containing boxes
|
|
56
|
-
image_id_to_boxes = defaultdict(list)
|
|
57
|
-
|
|
58
|
-
n_boxes = 0
|
|
59
|
-
|
|
60
|
-
for ann in d['annotations']:
|
|
61
|
-
if 'bbox' in ann:
|
|
62
|
-
image_id_to_boxes[ann['image_id']].append(ann)
|
|
63
|
-
n_boxes += 1
|
|
64
|
-
|
|
65
|
-
print('Found {} boxes in {} annotations for {} images'.format(
|
|
66
|
-
n_boxes,len(d['annotations']),len(d['images'])))
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
## Generate crops
|
|
70
|
-
|
|
71
|
-
# im = d['images'][0]
|
|
72
|
-
for im in tqdm(d['images']):
|
|
73
|
-
|
|
74
|
-
input_image_fn = os.path.join(os.path.join(image_dir,im['file_name']))
|
|
75
|
-
assert os.path.isfile(input_image_fn), 'Could not find image {}'.format(input_image_fn)
|
|
76
|
-
|
|
77
|
-
if im['id'] not in image_id_to_boxes:
|
|
78
|
-
continue
|
|
79
|
-
|
|
80
|
-
annotations_this_image = image_id_to_boxes[im['id']]
|
|
81
|
-
|
|
82
|
-
# Load the image
|
|
83
|
-
img = Image.open(input_image_fn)
|
|
84
|
-
|
|
85
|
-
# Generate crops
|
|
86
|
-
# i_ann = 0; ann = annotations_this_image[i_ann]
|
|
87
|
-
for i_ann,ann in enumerate(annotations_this_image):
|
|
88
|
-
|
|
89
|
-
# x/y/w/h, origin at the upper-left
|
|
90
|
-
bbox = ann['bbox']
|
|
91
|
-
|
|
92
|
-
xmin = bbox[0]
|
|
93
|
-
ymin = bbox[1]
|
|
94
|
-
xmax = xmin + bbox[2]
|
|
95
|
-
ymax = ymin + bbox[3]
|
|
96
|
-
|
|
97
|
-
xmin -= padding / 2
|
|
98
|
-
ymin -= padding / 2
|
|
99
|
-
xmax += padding / 2
|
|
100
|
-
ymax += padding / 2
|
|
101
|
-
|
|
102
|
-
xmin = max(xmin,0)
|
|
103
|
-
ymin = max(ymin,0)
|
|
104
|
-
xmax = min(xmax,img.width-1)
|
|
105
|
-
ymax = min(ymax,img.height-1)
|
|
106
|
-
|
|
107
|
-
crop = img.crop(box=[xmin, ymin, xmax, ymax])
|
|
108
|
-
|
|
109
|
-
output_fn = os.path.splitext(im['file_name'])[0].replace('\\','/')
|
|
110
|
-
if flat_output:
|
|
111
|
-
output_fn = output_fn.replace('/','_')
|
|
112
|
-
output_fn = output_fn + '_crop' + str(i_ann).zfill(3) + '_id_' + ann['id']
|
|
113
|
-
output_fn = output_fn + '.jpg'
|
|
114
|
-
|
|
115
|
-
output_full_path = os.path.join(output_dir,output_fn)
|
|
116
|
-
|
|
117
|
-
if not flat_output:
|
|
118
|
-
os.makedirs(os.path.dirname(output_full_path),exist_ok=True)
|
|
119
|
-
|
|
120
|
-
crop.save(output_full_path)
|
|
121
|
-
|
|
122
|
-
# ...for each box
|
|
123
|
-
|
|
124
|
-
# ...for each image
|
|
125
|
-
|
|
126
|
-
# ...generate_crops_from_cct()
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
#%% Interactive driver
|
|
130
|
-
|
|
131
|
-
if False:
|
|
132
|
-
|
|
133
|
-
pass
|
|
134
|
-
|
|
135
|
-
#%%
|
|
136
|
-
|
|
137
|
-
cct_file = os.path.expanduser('~/data/noaa/noaa_estuary_fish.json')
|
|
138
|
-
image_dir = os.path.expanduser('~/data/noaa/JPEGImages')
|
|
139
|
-
padding = 50
|
|
140
|
-
flat_output = True
|
|
141
|
-
output_dir = '/home/user/tmp/noaa-fish-crops'
|
|
142
|
-
|
|
143
|
-
generate_crops_from_cct(cct_file,image_dir,output_dir,padding,flat_output=True)
|
|
144
|
-
files = os.listdir(output_dir)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
#%% Command-line driver
|
|
148
|
-
|
|
149
|
-
# TODO
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
get_image_sizes.py
|
|
4
|
-
|
|
5
|
-
Given a json-formatted list of image filenames, retrieves the width and height of
|
|
6
|
-
every image, optionally writing the results to a new .json file.
|
|
7
|
-
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
#%% Constants and imports
|
|
11
|
-
|
|
12
|
-
import argparse
|
|
13
|
-
import json
|
|
14
|
-
import os
|
|
15
|
-
from PIL import Image
|
|
16
|
-
import sys
|
|
17
|
-
|
|
18
|
-
from multiprocessing.pool import ThreadPool
|
|
19
|
-
from multiprocessing.pool import Pool
|
|
20
|
-
from functools import partial
|
|
21
|
-
from tqdm import tqdm
|
|
22
|
-
|
|
23
|
-
from md_utils.path_utils import find_images
|
|
24
|
-
|
|
25
|
-
image_base = ''
|
|
26
|
-
default_n_threads = 1
|
|
27
|
-
use_threads = False
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
#%% Processing functions
|
|
31
|
-
|
|
32
|
-
def _get_image_size(image_path,image_prefix=None):
|
|
33
|
-
"""
|
|
34
|
-
Support function to get the size of a single image. Returns a (path,w,h) tuple.
|
|
35
|
-
w and h will be -1 if the image fails to load.
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
if image_prefix is not None:
|
|
39
|
-
full_path = os.path.join(image_prefix,image_path)
|
|
40
|
-
else:
|
|
41
|
-
full_path = image_path
|
|
42
|
-
|
|
43
|
-
# Is this image on disk?
|
|
44
|
-
if not os.path.isfile(full_path):
|
|
45
|
-
print('Could not find image {}'.format(full_path))
|
|
46
|
-
return (image_path,-1,-1)
|
|
47
|
-
|
|
48
|
-
try:
|
|
49
|
-
pil_im = Image.open(full_path)
|
|
50
|
-
w = pil_im.width
|
|
51
|
-
h = pil_im.height
|
|
52
|
-
return (image_path,w,h)
|
|
53
|
-
except Exception as e:
|
|
54
|
-
print('Error reading image {}: {}'.format(full_path,str(e)))
|
|
55
|
-
return (image_path,-1,-1)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def get_image_sizes(filenames,image_prefix=None,output_file=None,
|
|
59
|
-
n_workers=default_n_threads,use_threads=True,
|
|
60
|
-
recursive=True):
|
|
61
|
-
"""
|
|
62
|
-
Gets the width and height of all images in [filenames], which can be:
|
|
63
|
-
|
|
64
|
-
* A .json-formatted file containing list of strings
|
|
65
|
-
* A folder
|
|
66
|
-
* A list of files
|
|
67
|
-
|
|
68
|
-
...returning a list of (path,w,h) tuples, and optionally writing the results to [output_file].
|
|
69
|
-
|
|
70
|
-
Args:
|
|
71
|
-
filenames (str or list): the image filenames for which we should retrieve sizes,
|
|
72
|
-
can be the name of a .json-formatted file containing list of strings, a folder
|
|
73
|
-
in which we should enumerate images, or a list of files.
|
|
74
|
-
image_prefix (str, optional): optional prefix to add to images to get to full paths;
|
|
75
|
-
useful when [filenames] contains relative files, in which case [image_prefix] is the
|
|
76
|
-
base folder for the source images.
|
|
77
|
-
output_file (str, optional): a .json file to write the imgae sizes
|
|
78
|
-
n_workers (int, optional): number of parallel workers to use, set to <=1 to
|
|
79
|
-
disable parallelization
|
|
80
|
-
use_threads (bool, optional): whether to use threads (True) or processes (False)
|
|
81
|
-
for parallelization; not relevant if [n_workers] <= 1
|
|
82
|
-
recursive (bool, optional): only relevant if [filenames] is actually a folder,
|
|
83
|
-
determines whether image enumeration within that folder will be recursive
|
|
84
|
-
|
|
85
|
-
Returns:
|
|
86
|
-
list: list of (path,w,h) tuples
|
|
87
|
-
"""
|
|
88
|
-
|
|
89
|
-
if output_file is not None:
|
|
90
|
-
assert os.path.isdir(os.path.dirname(output_file)), \
|
|
91
|
-
'Illegal output file {}, parent folder does not exist'.format(output_file)
|
|
92
|
-
|
|
93
|
-
if isinstance(filenames,str) and os.path.isfile(filenames):
|
|
94
|
-
with open(filenames,'r') as f:
|
|
95
|
-
filenames = json.load(f)
|
|
96
|
-
filenames = [s.strip() for s in filenames]
|
|
97
|
-
elif isinstance(filenames,str) and os.path.isdir(filenames):
|
|
98
|
-
filenames = find_images(filenames,recursive=recursive,
|
|
99
|
-
return_relative_paths=False,convert_slashes=True)
|
|
100
|
-
else:
|
|
101
|
-
assert isinstance(filenames,list)
|
|
102
|
-
|
|
103
|
-
if n_workers <= 1:
|
|
104
|
-
|
|
105
|
-
all_results = []
|
|
106
|
-
for i_file,fn in tqdm(enumerate(filenames),total=len(filenames)):
|
|
107
|
-
all_results.append(_get_image_size(fn,image_prefix=image_prefix))
|
|
108
|
-
|
|
109
|
-
else:
|
|
110
|
-
|
|
111
|
-
print('Creating a pool with {} workers'.format(n_workers))
|
|
112
|
-
if use_threads:
|
|
113
|
-
pool = ThreadPool(n_workers)
|
|
114
|
-
else:
|
|
115
|
-
pool = Pool(n_workers)
|
|
116
|
-
# all_results = list(tqdm(pool.imap(process_image, filenames), total=len(filenames)))
|
|
117
|
-
all_results = list(tqdm(pool.imap(
|
|
118
|
-
partial(_get_image_size,image_prefix=image_prefix), filenames), total=len(filenames)))
|
|
119
|
-
|
|
120
|
-
if output_file is not None:
|
|
121
|
-
with open(output_file,'w') as f:
|
|
122
|
-
json.dump(all_results,f,indent=1)
|
|
123
|
-
|
|
124
|
-
return all_results
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
#%% Interactive driver
|
|
128
|
-
|
|
129
|
-
if False:
|
|
130
|
-
|
|
131
|
-
pass
|
|
132
|
-
|
|
133
|
-
#%%
|
|
134
|
-
|
|
135
|
-
# List images in a test folder
|
|
136
|
-
base_dir = r'c:\temp\test_images'
|
|
137
|
-
image_list_file = os.path.join(base_dir,'images.json')
|
|
138
|
-
relative_image_list_file = os.path.join(base_dir,'images_relative.json')
|
|
139
|
-
image_size_file = os.path.join(base_dir,'image_sizes.json')
|
|
140
|
-
from md_utils import path_utils
|
|
141
|
-
image_names = path_utils.find_images(base_dir,recursive=True)
|
|
142
|
-
|
|
143
|
-
with open(image_list_file,'w') as f:
|
|
144
|
-
json.dump(image_names,f,indent=1)
|
|
145
|
-
|
|
146
|
-
relative_image_names = []
|
|
147
|
-
for s in image_names:
|
|
148
|
-
relative_image_names.append(os.path.relpath(s,base_dir))
|
|
149
|
-
|
|
150
|
-
with open(relative_image_list_file,'w') as f:
|
|
151
|
-
json.dump(relative_image_names,f,indent=1)
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
#%%
|
|
155
|
-
|
|
156
|
-
get_image_sizes(relative_image_list_file,image_size_file,image_prefix=base_dir,n_threads=4)
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
#%% Command-line driver
|
|
160
|
-
|
|
161
|
-
def main():
|
|
162
|
-
|
|
163
|
-
parser = argparse.ArgumentParser()
|
|
164
|
-
parser.add_argument('filenames',type=str,
|
|
165
|
-
help='Folder from which we should fetch image sizes, or .json file with a list of filenames')
|
|
166
|
-
parser.add_argument('output_file',type=str,
|
|
167
|
-
help='Output file (.json) to which we should write image size information')
|
|
168
|
-
parser.add_argument('--image_prefix', type=str, default=None,
|
|
169
|
-
help='Prefix to append to image filenames, only relevant if [filenames] points to a list of ' + \
|
|
170
|
-
'relative paths')
|
|
171
|
-
parser.add_argument('--n_threads', type=int, default=default_n_threads,
|
|
172
|
-
help='Number of concurrent workers, set to <=1 to disable parallelization (default {})'.format(
|
|
173
|
-
default_n_threads))
|
|
174
|
-
|
|
175
|
-
if len(sys.argv[1:])==0:
|
|
176
|
-
parser.print_help()
|
|
177
|
-
parser.exit()
|
|
178
|
-
|
|
179
|
-
args = parser.parse_args()
|
|
180
|
-
|
|
181
|
-
_ = get_image_sizes(filenames=args.filenames,
|
|
182
|
-
output_file=args.output_file,
|
|
183
|
-
image_prefix=args.image_prefix,
|
|
184
|
-
n_workers=args.n_threads)
|
|
185
|
-
|
|
186
|
-
if __name__ == '__main__':
|
|
187
|
-
|
|
188
|
-
main()
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
add_nacti_sizes.py
|
|
4
|
-
|
|
5
|
-
NACTI bounding box metadata was posted before we inclduded width and height as semi-standard
|
|
6
|
-
fields; pull size information from the main metadata file and add to the bbox file.
|
|
7
|
-
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
#%% Constants and environment
|
|
11
|
-
|
|
12
|
-
import json
|
|
13
|
-
from tqdm import tqdm
|
|
14
|
-
|
|
15
|
-
input_file = 'G:/temp/nacti_metadata.json'
|
|
16
|
-
input_bbox_file = 'G:/temp/nacti_20200401_bboxes.json'
|
|
17
|
-
output_bbox_file = 'G:/temp/nacti_20230920_bboxes.json'
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
#%% Read .json files
|
|
21
|
-
|
|
22
|
-
with open(input_file,'r') as f:
|
|
23
|
-
input_data = json.load(f)
|
|
24
|
-
|
|
25
|
-
with open(input_bbox_file,'r') as f:
|
|
26
|
-
input_bbox_data = json.load(f)
|
|
27
|
-
|
|
28
|
-
print('Finished reading .json data')
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
#%% Map image names to width and height
|
|
32
|
-
|
|
33
|
-
filename_to_size = {}
|
|
34
|
-
for im in tqdm(input_data['images']):
|
|
35
|
-
filename_to_size[im['file_name']] = (im['width'],im['height'])
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
#%% Add to output data
|
|
39
|
-
|
|
40
|
-
for im in tqdm(input_bbox_data['images']):
|
|
41
|
-
size = filename_to_size[im['file_name']]
|
|
42
|
-
im['width'] = size[0]
|
|
43
|
-
im['height'] = size[1]
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
#%% Write output
|
|
47
|
-
|
|
48
|
-
output_bbox_data = input_bbox_data
|
|
49
|
-
output_bbox_data['version'] = '2023-09-20'
|
|
50
|
-
|
|
51
|
-
with open(output_bbox_file,'w') as f:
|
|
52
|
-
json.dump(output_bbox_data,f,indent=1)
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
add_timestamps_to_icct.py
|
|
4
|
-
|
|
5
|
-
The Island Conservation Camera Traps dataset was originally posted without timestamps
|
|
6
|
-
in either .json metadata or EXIF metadata. We pulled timestamps out using ocr_tools.py,
|
|
7
|
-
this script adds those timestamps into the .json metadata.
|
|
8
|
-
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
#%% Imports and constants
|
|
12
|
-
|
|
13
|
-
import json
|
|
14
|
-
|
|
15
|
-
ocr_results_file = r'g:\temp\ocr_results.2023.10.31.07.37.54.json'
|
|
16
|
-
input_metadata_file = r'd:\lila\islandconservationcameratraps\island_conservation.json'
|
|
17
|
-
output_metadata_file = r'g:\temp\island_conservation_camera_traps_1.02.json'
|
|
18
|
-
ocr_results_file_base = 'g:/temp/island_conservation_camera_traps/'
|
|
19
|
-
assert ocr_results_file_base.endswith('/')
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
#%% Read input metadata
|
|
23
|
-
|
|
24
|
-
with open(input_metadata_file,'r') as f:
|
|
25
|
-
input_metadata = json.load(f)
|
|
26
|
-
|
|
27
|
-
assert input_metadata['info']['version'] == '1.01'
|
|
28
|
-
|
|
29
|
-
# im = input_metadata['images'][0]
|
|
30
|
-
for im in input_metadata['images']:
|
|
31
|
-
assert 'datetime' not in im
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
#%% Read OCR results
|
|
35
|
-
|
|
36
|
-
with open(ocr_results_file,'r') as f:
|
|
37
|
-
abs_filename_to_ocr_results = json.load(f)
|
|
38
|
-
|
|
39
|
-
relative_filename_to_ocr_results = {}
|
|
40
|
-
|
|
41
|
-
for fn_abs in abs_filename_to_ocr_results:
|
|
42
|
-
assert ocr_results_file_base in fn_abs
|
|
43
|
-
fn_relative = fn_abs.replace(ocr_results_file_base,'')
|
|
44
|
-
relative_filename_to_ocr_results[fn_relative] = abs_filename_to_ocr_results[fn_abs]
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
#%% Add datetimes to metadata
|
|
48
|
-
|
|
49
|
-
images_not_in_datetime_results = []
|
|
50
|
-
images_with_failed_datetimes = []
|
|
51
|
-
|
|
52
|
-
for i_image,im in enumerate(input_metadata['images']):
|
|
53
|
-
if im['file_name'] not in relative_filename_to_ocr_results:
|
|
54
|
-
images_not_in_datetime_results.append(im)
|
|
55
|
-
im['datetime'] = None
|
|
56
|
-
continue
|
|
57
|
-
ocr_results = relative_filename_to_ocr_results[im['file_name']]
|
|
58
|
-
if ocr_results['datetime'] is None:
|
|
59
|
-
images_with_failed_datetimes.append(im)
|
|
60
|
-
im['datetime'] = None
|
|
61
|
-
continue
|
|
62
|
-
im['datetime'] = ocr_results['datetime']
|
|
63
|
-
|
|
64
|
-
print('{} of {} images were not in datetime results'.format(
|
|
65
|
-
len(images_not_in_datetime_results),len(input_metadata['images'])))
|
|
66
|
-
|
|
67
|
-
print('{} of {} images were had failed datetime results'.format(
|
|
68
|
-
len(images_with_failed_datetimes),len(input_metadata['images'])))
|
|
69
|
-
|
|
70
|
-
for im in input_metadata['images']:
|
|
71
|
-
assert 'datetime' in im
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
#%% Write output
|
|
75
|
-
|
|
76
|
-
input_metadata['info']['version'] = '1.02'
|
|
77
|
-
|
|
78
|
-
with open(output_metadata_file,'w') as f:
|
|
79
|
-
json.dump(input_metadata,f,indent=1)
|