megadetector 5.0.10__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.10.dist-info → megadetector-5.0.11.dist-info}/LICENSE +0 -0
- {megadetector-5.0.10.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.10.dist-info/RECORD +0 -224
- megadetector-5.0.10.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.10.dist-info → megadetector-5.0.11.dist-info}/WHEEL +0 -0
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
animl_results_to_md_results.py
|
|
4
|
-
|
|
5
|
-
Convert a .csv file produced by the Animl package:
|
|
6
|
-
|
|
7
|
-
https://github.com/conservationtechlab/animl-py
|
|
8
|
-
|
|
9
|
-
...to a MD results file suitable for import into Timelapse.
|
|
10
|
-
|
|
11
|
-
Columns are expected to be:
|
|
12
|
-
|
|
13
|
-
file
|
|
14
|
-
category (MD category identifies: 1==animal, 2==person, 3==vehicle)
|
|
15
|
-
detection_conf
|
|
16
|
-
bbox1,bbox2,bbox3,bbox4
|
|
17
|
-
class
|
|
18
|
-
classification_conf
|
|
19
|
-
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
#%% Imports and constants
|
|
23
|
-
|
|
24
|
-
import pandas as pd
|
|
25
|
-
import json
|
|
26
|
-
|
|
27
|
-
# It's a little icky to hard-code this here rather than importing from elsewhere
|
|
28
|
-
# in the MD repo, but it seemed silly to take a dependency on lots of MD code
|
|
29
|
-
# just for this, so, hard-coding.
|
|
30
|
-
detection_category_id_to_name = {'1':'animal','2':'person','3':'vehicle'}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
#%% Main function
|
|
34
|
-
|
|
35
|
-
def animl_results_to_md_results(input_file,output_file=None):
|
|
36
|
-
"""
|
|
37
|
-
Converts the .csv file [input_file] to the MD-formatted .json file [output_file].
|
|
38
|
-
|
|
39
|
-
If [output_file] is None, '.json' will be appended to the input file.
|
|
40
|
-
"""
|
|
41
|
-
|
|
42
|
-
if output_file is None:
|
|
43
|
-
output_file = input_file + '.json'
|
|
44
|
-
|
|
45
|
-
df = pd.read_csv(input_file)
|
|
46
|
-
|
|
47
|
-
expected_columns = ('file','category','detection_conf',
|
|
48
|
-
'bbox1','bbox2','bbox3','bbox4','class','classification_conf')
|
|
49
|
-
|
|
50
|
-
for s in expected_columns:
|
|
51
|
-
assert s in df.columns,\
|
|
52
|
-
'Expected column {} not found'.format(s)
|
|
53
|
-
|
|
54
|
-
classification_category_name_to_id = {}
|
|
55
|
-
filename_to_results = {}
|
|
56
|
-
|
|
57
|
-
# i_row = 0; row = df.iloc[i_row]
|
|
58
|
-
for i_row,row in df.iterrows():
|
|
59
|
-
|
|
60
|
-
# Is this the first detection we've seen for this file?
|
|
61
|
-
if row['file'] in filename_to_results:
|
|
62
|
-
im = filename_to_results[row['file']]
|
|
63
|
-
else:
|
|
64
|
-
im = {}
|
|
65
|
-
im['detections'] = []
|
|
66
|
-
im['file'] = row['file']
|
|
67
|
-
filename_to_results[im['file']] = im
|
|
68
|
-
|
|
69
|
-
assert isinstance(row['category'],int),'Invalid category identifier in row {}'.format(im['file'])
|
|
70
|
-
detection_category_id = str(row['category'])
|
|
71
|
-
assert detection_category_id in detection_category_id_to_name,\
|
|
72
|
-
'Unrecognized detection category ID {}'.format(detection_category_id)
|
|
73
|
-
|
|
74
|
-
detection = {}
|
|
75
|
-
detection['category'] = detection_category_id
|
|
76
|
-
detection['conf'] = row['detection_conf']
|
|
77
|
-
bbox = [row['bbox1'],row['bbox2'],row['bbox3'],row['bbox4']]
|
|
78
|
-
detection['bbox'] = bbox
|
|
79
|
-
classification_category_name = row['class']
|
|
80
|
-
|
|
81
|
-
# Have we seen this classification category before?
|
|
82
|
-
if classification_category_name in classification_category_name_to_id:
|
|
83
|
-
classification_category_id = \
|
|
84
|
-
classification_category_name_to_id[classification_category_name]
|
|
85
|
-
else:
|
|
86
|
-
classification_category_id = str(len(classification_category_name_to_id))
|
|
87
|
-
classification_category_name_to_id[classification_category_name] = \
|
|
88
|
-
classification_category_id
|
|
89
|
-
|
|
90
|
-
classifications = [[classification_category_id,row['classification_conf']]]
|
|
91
|
-
detection['classifications'] = classifications
|
|
92
|
-
|
|
93
|
-
im['detections'].append(detection)
|
|
94
|
-
|
|
95
|
-
# ...for each row
|
|
96
|
-
|
|
97
|
-
info = {}
|
|
98
|
-
info['format_version'] = '1.3'
|
|
99
|
-
info['detector'] = 'Animl'
|
|
100
|
-
info['classifier'] = 'Animl'
|
|
101
|
-
|
|
102
|
-
results = {}
|
|
103
|
-
results['info'] = info
|
|
104
|
-
results['detection_categories'] = detection_category_id_to_name
|
|
105
|
-
results['classification_categories'] = \
|
|
106
|
-
{v: k for k, v in classification_category_name_to_id.items()}
|
|
107
|
-
results['images'] = list(filename_to_results.values())
|
|
108
|
-
|
|
109
|
-
with open(output_file,'w') as f:
|
|
110
|
-
json.dump(results,f,indent=1)
|
|
111
|
-
|
|
112
|
-
# ...animl_results_to_md_results(...)
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
#%% Interactive driver
|
|
116
|
-
|
|
117
|
-
if False:
|
|
118
|
-
|
|
119
|
-
pass
|
|
120
|
-
|
|
121
|
-
#%%
|
|
122
|
-
|
|
123
|
-
input_file = r"G:\temp\animl-runs\animl-runs\Coati_v2\manifest.csv"
|
|
124
|
-
output_file = None
|
|
125
|
-
animl_results_to_md_results(input_file,output_file)
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
#%% Command-line driver
|
|
129
|
-
|
|
130
|
-
import sys,argparse
|
|
131
|
-
|
|
132
|
-
def main():
|
|
133
|
-
|
|
134
|
-
parser = argparse.ArgumentParser(
|
|
135
|
-
description='Convert an Animl-formatted .csv results file to MD-formatted .json results file')
|
|
136
|
-
|
|
137
|
-
parser.add_argument(
|
|
138
|
-
'input_file',
|
|
139
|
-
type=str,
|
|
140
|
-
help='input .csv file')
|
|
141
|
-
|
|
142
|
-
parser.add_argument(
|
|
143
|
-
'--output_file',
|
|
144
|
-
type=str,
|
|
145
|
-
default=None,
|
|
146
|
-
help='output .json file (defaults to input file appended with ".json")')
|
|
147
|
-
|
|
148
|
-
if len(sys.argv[1:]) == 0:
|
|
149
|
-
parser.print_help()
|
|
150
|
-
parser.exit()
|
|
151
|
-
|
|
152
|
-
args = parser.parse_args()
|
|
153
|
-
|
|
154
|
-
animl_results_to_md_results(args.input_file,args.output_file)
|
|
155
|
-
|
|
156
|
-
if __name__ == '__main__':
|
|
157
|
-
main()
|
|
158
|
-
|
|
@@ -1,372 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
auckland_doc_test_to_json.py
|
|
4
|
-
|
|
5
|
-
Convert Auckland DOC data set to COCO camera traps format. This was
|
|
6
|
-
for a testing data set where a .csv file was provided with class
|
|
7
|
-
information.
|
|
8
|
-
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
#%% Constants and imports
|
|
12
|
-
|
|
13
|
-
import json
|
|
14
|
-
import os
|
|
15
|
-
import uuid
|
|
16
|
-
import pandas as pd
|
|
17
|
-
import datetime
|
|
18
|
-
import ntpath
|
|
19
|
-
import re
|
|
20
|
-
import numpy as np
|
|
21
|
-
from tqdm import tqdm
|
|
22
|
-
|
|
23
|
-
from md_visualization import visualize_db
|
|
24
|
-
from data_management.databases import integrity_check_json_db
|
|
25
|
-
from md_utils.path_utils import find_images
|
|
26
|
-
|
|
27
|
-
input_base_dir = r'e:\auckland-test\2_Testing'
|
|
28
|
-
|
|
29
|
-
input_metadata_file = r'G:\auckland-doc\Maukahuka - Auckland Island - Cat camera data Master April 2019 - DOC-5924483.xlsx'
|
|
30
|
-
|
|
31
|
-
# Filenames will be stored in the output .json relative to this base dir
|
|
32
|
-
output_base_dir = r'g:\auckland-doc'
|
|
33
|
-
output_json_filename = os.path.join(output_base_dir, 'auckland-doc-test.json')
|
|
34
|
-
|
|
35
|
-
assert os.path.isdir(input_base_dir)
|
|
36
|
-
os.makedirs(output_base_dir,exist_ok=True)
|
|
37
|
-
|
|
38
|
-
output_encoding = 'utf-8'
|
|
39
|
-
read_image_sizes = True
|
|
40
|
-
|
|
41
|
-
info = {}
|
|
42
|
-
info['year'] = 2020
|
|
43
|
-
info['version'] = '1.0'
|
|
44
|
-
info['description'] = 'Auckaland DOC Camera Traps (test)'
|
|
45
|
-
info['contributor'] = 'Auckland DOC'
|
|
46
|
-
info['date_created'] = str(datetime.date.today())
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
#%% Enumerate files
|
|
50
|
-
|
|
51
|
-
print('Enumerating files from {}'.format(input_base_dir))
|
|
52
|
-
absolute_image_paths = find_images(input_base_dir, recursive=True)
|
|
53
|
-
print('Enumerated {} images'.format(len(absolute_image_paths)))
|
|
54
|
-
|
|
55
|
-
relative_image_paths = []
|
|
56
|
-
for fn in absolute_image_paths:
|
|
57
|
-
relative_image_paths.append(os.path.relpath(fn,input_base_dir).replace('\\','/'))
|
|
58
|
-
|
|
59
|
-
relative_image_paths_set = set(relative_image_paths)
|
|
60
|
-
|
|
61
|
-
assert len(relative_image_paths_set) == len(relative_image_paths)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
#%% Create unique identifier for each image
|
|
65
|
-
|
|
66
|
-
# The ground truth doesn't have full paths in it; create unique identifiers for each image
|
|
67
|
-
# based on the camera name and filename.
|
|
68
|
-
#
|
|
69
|
-
# We store file identifiers as cameraname_filename.
|
|
70
|
-
file_identifier_to_relative_paths = {}
|
|
71
|
-
camera_names = set()
|
|
72
|
-
|
|
73
|
-
# relative_path = relative_image_paths[0]
|
|
74
|
-
for relative_path in relative_image_paths:
|
|
75
|
-
|
|
76
|
-
# Example relative paths
|
|
77
|
-
#
|
|
78
|
-
# Summer_Trial_2019/A1_1_42_SD114_20190210/AucklandIsland_A1_1_42_SD114_20190210_01300001.jpg
|
|
79
|
-
# Winter_Trial_2019/Installation/10_F4/10_F4_tmp_201908210001.JPG
|
|
80
|
-
fn = ntpath.basename(relative_path)
|
|
81
|
-
|
|
82
|
-
# Find the camera name
|
|
83
|
-
tokens = relative_path.split('/')
|
|
84
|
-
|
|
85
|
-
if tokens[1] == 'Installation' or 'Rebait' in tokens[1]:
|
|
86
|
-
camera_name = tokens[2]
|
|
87
|
-
|
|
88
|
-
else:
|
|
89
|
-
# E..g. "A1_1_42_SD114_20190210" in the above example
|
|
90
|
-
camera_token = tokens[1]
|
|
91
|
-
camera_name = None
|
|
92
|
-
m = re.search('^(.+)_SD',camera_token)
|
|
93
|
-
if m:
|
|
94
|
-
camera_name = m.group(1)
|
|
95
|
-
else:
|
|
96
|
-
# For camera tokens like C1_5_D_190207
|
|
97
|
-
m = re.search('^(.+_.+_.+)',camera_token)
|
|
98
|
-
camera_name = m.group(1)
|
|
99
|
-
|
|
100
|
-
assert camera_name
|
|
101
|
-
camera_names.add(camera_name)
|
|
102
|
-
|
|
103
|
-
file_identifier = camera_name + '_' + fn
|
|
104
|
-
if file_identifier not in file_identifier_to_relative_paths:
|
|
105
|
-
file_identifier_to_relative_paths[file_identifier] = [relative_path]
|
|
106
|
-
else:
|
|
107
|
-
file_identifier_to_relative_paths[file_identifier].append(relative_path)
|
|
108
|
-
|
|
109
|
-
print('Found {} unique camera names'.format(len(camera_names)))
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
#%% Load input data
|
|
113
|
-
|
|
114
|
-
input_metadata = pd.read_excel(input_metadata_file)
|
|
115
|
-
|
|
116
|
-
print('Read {} columns and {} rows from metadata file'.format(len(input_metadata.columns),
|
|
117
|
-
len(input_metadata)))
|
|
118
|
-
|
|
119
|
-
# The spreadsheet has a space after "Camera"
|
|
120
|
-
input_metadata = input_metadata.rename(columns={'Camera ':'Camera'})
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
#%% Assemble dictionaries
|
|
124
|
-
|
|
125
|
-
image_id_to_image = {}
|
|
126
|
-
category_name_to_category = {}
|
|
127
|
-
annotations = []
|
|
128
|
-
|
|
129
|
-
# Force the empty category to be ID 0
|
|
130
|
-
empty_category = {}
|
|
131
|
-
empty_category['name'] = 'empty'
|
|
132
|
-
empty_category['id'] = 0
|
|
133
|
-
category_name_to_category['empty'] = empty_category
|
|
134
|
-
|
|
135
|
-
rows_not_found_in_folder = []
|
|
136
|
-
rows_ambiguous = []
|
|
137
|
-
rows_no_filename = []
|
|
138
|
-
rows_no_annotation = []
|
|
139
|
-
|
|
140
|
-
image_id_to_rows = {}
|
|
141
|
-
|
|
142
|
-
next_id = 1
|
|
143
|
-
|
|
144
|
-
category_names = ['cat','mouse','unknown','human','pig','sealion','penguin','dog','openadjusted']
|
|
145
|
-
|
|
146
|
-
# array([nan, 'Blackbird', 'Bellbird', 'Tomtit', 'Song thrush', 'Pippit',
|
|
147
|
-
# 'Pippet', '?', 'Dunnock', 'Song thursh', 'Kakariki', 'Tui', ' ',
|
|
148
|
-
# 'Silvereye', 'NZ Pipit', 'Blackbird and Dunnock', 'Unknown',
|
|
149
|
-
# 'Pipit', 'Songthrush'], dtype=object)
|
|
150
|
-
|
|
151
|
-
def bird_name_to_category_name(bird_name):
|
|
152
|
-
bird_name = bird_name.lower().strip().replace(' ','_').replace('song_thursh','song_thrush')
|
|
153
|
-
bird_name = bird_name.replace('pippet','pipt').replace('pippit','pipit').replace('nz_pipit','pipit')
|
|
154
|
-
if bird_name == '?' or bird_name == '' or bird_name == 'unknown':
|
|
155
|
-
category_name = 'unknown_bird'
|
|
156
|
-
else:
|
|
157
|
-
category_name = bird_name
|
|
158
|
-
return category_name
|
|
159
|
-
|
|
160
|
-
bird_names = input_metadata.Bird_ID.unique()
|
|
161
|
-
for bird_name in bird_names:
|
|
162
|
-
if isinstance(bird_name,float):
|
|
163
|
-
continue
|
|
164
|
-
category_name = bird_name_to_category_name(bird_name)
|
|
165
|
-
if category_name not in category_names:
|
|
166
|
-
category_names.append(category_name)
|
|
167
|
-
|
|
168
|
-
for category_name in category_names:
|
|
169
|
-
cat = {}
|
|
170
|
-
cat['name'] = category_name
|
|
171
|
-
cat['id'] = next_id
|
|
172
|
-
next_id = next_id +1
|
|
173
|
-
category_name_to_category[category_name] = cat
|
|
174
|
-
|
|
175
|
-
def create_annotation(image_id,category_name,count):
|
|
176
|
-
assert isinstance(image_id,str)
|
|
177
|
-
assert isinstance(category_name,str)
|
|
178
|
-
assert isinstance(count,int) or isinstance(count,float)
|
|
179
|
-
if isinstance(count,float):
|
|
180
|
-
count = int(count)
|
|
181
|
-
ann = {}
|
|
182
|
-
ann['id'] = str(uuid.uuid1())
|
|
183
|
-
ann['image_id'] = image_id
|
|
184
|
-
category = category_name_to_category[category_name]
|
|
185
|
-
category_id = category['id']
|
|
186
|
-
ann['category_id'] = category_id
|
|
187
|
-
ann['count'] = count
|
|
188
|
-
return ann
|
|
189
|
-
|
|
190
|
-
# i_row = 0; row = input_metadata.iloc[i_row]
|
|
191
|
-
for i_row,row in tqdm(input_metadata.iterrows(),total=len(input_metadata)):
|
|
192
|
-
|
|
193
|
-
# E.g.: AucklandIsland_A1_1_42_SD114_20190210_01300009.jpg
|
|
194
|
-
filename = row['File']
|
|
195
|
-
if isinstance(filename,float):
|
|
196
|
-
rows_no_filename.append(i_row)
|
|
197
|
-
continue
|
|
198
|
-
|
|
199
|
-
camera_name = row['Camera']
|
|
200
|
-
file_identifier = camera_name + '_' + filename
|
|
201
|
-
if not file_identifier in file_identifier_to_relative_paths:
|
|
202
|
-
rows_not_found_in_folder.append(i_row)
|
|
203
|
-
continue
|
|
204
|
-
|
|
205
|
-
relative_paths_this_file_id = file_identifier_to_relative_paths[file_identifier]
|
|
206
|
-
|
|
207
|
-
if len(relative_paths_this_file_id) == 1:
|
|
208
|
-
relative_path = relative_paths_this_file_id[0]
|
|
209
|
-
else:
|
|
210
|
-
|
|
211
|
-
# We have multiple files matching this identifier, can we uniquely resolve this
|
|
212
|
-
# to one of those files based on the camera ID?
|
|
213
|
-
matches = [s for s in relative_paths_this_file_id if camera_name in s]
|
|
214
|
-
assert len(matches) > 0
|
|
215
|
-
if len(matches) > 1:
|
|
216
|
-
rows_ambiguous.append(i_row)
|
|
217
|
-
continue
|
|
218
|
-
relative_path = matches[0]
|
|
219
|
-
|
|
220
|
-
assert filename.endswith('.jpg') or filename.endswith('.JPG')
|
|
221
|
-
image_id = filename.lower().replace('.jpg','')
|
|
222
|
-
|
|
223
|
-
if image_id in image_id_to_rows:
|
|
224
|
-
image_id_to_rows[image_id].append(i_row)
|
|
225
|
-
continue
|
|
226
|
-
|
|
227
|
-
image_id_to_rows[image_id] = [i_row]
|
|
228
|
-
|
|
229
|
-
im = {}
|
|
230
|
-
im['id'] = image_id
|
|
231
|
-
im['file_name'] = relative_path
|
|
232
|
-
im['datetime'] = str(row['Date and time'])
|
|
233
|
-
im['camera'] = row['Camera']
|
|
234
|
-
im['sd_card'] = row['SD_Card']
|
|
235
|
-
im['sd_change'] = row['SD_Change']
|
|
236
|
-
im['comments'] = row['Comments']
|
|
237
|
-
|
|
238
|
-
image_id_to_image[im['id']] = im
|
|
239
|
-
|
|
240
|
-
# create_annotation(image_id,category_name,count)
|
|
241
|
-
|
|
242
|
-
# 'SD_Change', 'Cat', 'Mouse', 'Bird', 'Bird_ID', 'False_trig', 'Unknown',
|
|
243
|
-
# 'Human', 'Collared_cat', 'Cat_ID', 'Pig', 'Sea_lion', 'Open_adjusted',
|
|
244
|
-
# 'Penguin', 'Dog', 'Comments', 'Unnamed: 22']
|
|
245
|
-
|
|
246
|
-
# Each of these categories is handled a little differently...
|
|
247
|
-
|
|
248
|
-
annotations_this_image = []
|
|
249
|
-
if (not np.isnan(row['Cat'])):
|
|
250
|
-
assert np.isnan(row['Collared_cat'] )
|
|
251
|
-
annotations_this_image.append(create_annotation(im['id'],'cat',row['Cat']))
|
|
252
|
-
|
|
253
|
-
if (not np.isnan(row['Collared_cat'])):
|
|
254
|
-
assert np.isnan(row['Cat'] )
|
|
255
|
-
annotations_this_image.append(create_annotation(im['id'],'cat',row['Collared_cat']))
|
|
256
|
-
|
|
257
|
-
if (not np.isnan(row['Bird'])):
|
|
258
|
-
if isinstance(row['Bird_ID'],str):
|
|
259
|
-
category_name = bird_name_to_category_name(row['Bird_ID'])
|
|
260
|
-
else:
|
|
261
|
-
assert np.isnan(row['Bird_ID'])
|
|
262
|
-
category_name = 'unknown_bird'
|
|
263
|
-
annotations_this_image.append(create_annotation(im['id'],category_name,row['Bird']))
|
|
264
|
-
|
|
265
|
-
if (not np.isnan(row['False_trig'])):
|
|
266
|
-
annotations_this_image.append(create_annotation(im['id'],'empty',-1))
|
|
267
|
-
|
|
268
|
-
# These are straightforward
|
|
269
|
-
for s in ['Mouse','Unknown','Pig','Human','Sea_lion','Penguin','Dog','Open_adjusted']:
|
|
270
|
-
if isinstance(row[s],float) or isinstance(row[s],int):
|
|
271
|
-
if not np.isnan(row[s]):
|
|
272
|
-
annotations_this_image.append(create_annotation(im['id'],s.lower().replace('_',''),row[s]))
|
|
273
|
-
elif isinstance(row[s],str):
|
|
274
|
-
print('File {}, label {}, value {}'.format(filename,s,row[s]))
|
|
275
|
-
else:
|
|
276
|
-
raise ValueError('Error handling count value {}'.format(row[s]))
|
|
277
|
-
|
|
278
|
-
if len(annotations_this_image) > 1:
|
|
279
|
-
print('Multiple annotations for filename {}'.format(filename))
|
|
280
|
-
|
|
281
|
-
if len(annotations_this_image) == 0:
|
|
282
|
-
rows_no_annotation.append(i_row)
|
|
283
|
-
|
|
284
|
-
annotations.extend(annotations_this_image)
|
|
285
|
-
|
|
286
|
-
# ...for each image
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
#%% Summarize errors
|
|
290
|
-
|
|
291
|
-
print('Of {} rows:\n'.format(len(input_metadata)))
|
|
292
|
-
|
|
293
|
-
print('{} images not found in folder'.format(len(rows_not_found_in_folder)))
|
|
294
|
-
print('{} images ambiguously mapped'.format(len(rows_ambiguous)))
|
|
295
|
-
print('{} images no filename'.format(len(rows_no_filename)))
|
|
296
|
-
print('{} images no annotation'.format(len(rows_no_annotation)))
|
|
297
|
-
print('{} images handled successfully, {} total annotations'.format(len(image_id_to_image),len(annotations)))
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
#%% Write output .json
|
|
301
|
-
|
|
302
|
-
images = list(image_id_to_image.values())
|
|
303
|
-
categories = list(category_name_to_category.values())
|
|
304
|
-
|
|
305
|
-
data = {}
|
|
306
|
-
data['info'] = info
|
|
307
|
-
data['images'] = images
|
|
308
|
-
data['annotations'] = annotations
|
|
309
|
-
data['categories'] = categories
|
|
310
|
-
|
|
311
|
-
json.dump(data, open(output_json_filename, 'w'), indent=1)
|
|
312
|
-
print('Finished writing json to {}'.format(output_json_filename))
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
#%% Validate .json file
|
|
316
|
-
|
|
317
|
-
options = integrity_check_json_db.IntegrityCheckOptions()
|
|
318
|
-
options.baseDir = input_base_dir
|
|
319
|
-
options.bCheckImageSizes = False
|
|
320
|
-
options.bCheckImageExistence = False
|
|
321
|
-
options.bFindUnusedImages = False
|
|
322
|
-
|
|
323
|
-
sortedCategories, data, _ = integrity_check_json_db.integrity_check_json_db(output_json_filename, options)
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
#%% Preview labels
|
|
327
|
-
|
|
328
|
-
viz_options = visualize_db.DbVizOptions()
|
|
329
|
-
viz_options.num_to_visualize = 2000
|
|
330
|
-
viz_options.trim_to_images_with_bboxes = False
|
|
331
|
-
viz_options.add_search_links = False
|
|
332
|
-
viz_options.sort_by_filename = False
|
|
333
|
-
viz_options.parallelize_rendering = True
|
|
334
|
-
viz_options.classes_to_exclude = ['empty']
|
|
335
|
-
html_output_file, image_db = visualize_db.visualize_db(db_path=output_json_filename,
|
|
336
|
-
output_dir=os.path.join(
|
|
337
|
-
output_base_dir, 'preview'),
|
|
338
|
-
image_base_dir=input_base_dir,
|
|
339
|
-
options=viz_options)
|
|
340
|
-
os.startfile(html_output_file)
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
#%% Precision-recall analysis
|
|
344
|
-
|
|
345
|
-
from api.batch_processing.postprocessing.postprocess_batch_results import PostProcessingOptions
|
|
346
|
-
from api.batch_processing.postprocessing.postprocess_batch_results import process_batch_results
|
|
347
|
-
|
|
348
|
-
api_output_file = r'g:\auckland-doc\auckland-doc_20200801\combined_api_outputs\auckland-doc_202008012020.08.01_reformatMaukahuka_Auckland_Island2_TestingSummer_Trial_2019_detections.filtered_rde_0.60_0.85_5_0.05.json'
|
|
349
|
-
postprocessing_output_folder = r'G:\auckland-doc\auckland-doc_20200801\postprocessing'
|
|
350
|
-
image_base = r'E:\auckland-test\2_Testing'
|
|
351
|
-
ground_truth_json_file = output_json_filename
|
|
352
|
-
|
|
353
|
-
output_base = os.path.join(postprocessing_output_folder,'pr_analysis')
|
|
354
|
-
os.makedirs(output_base,exist_ok=True)
|
|
355
|
-
|
|
356
|
-
options = PostProcessingOptions()
|
|
357
|
-
options.unlabeled_classes.append('openadjusted')
|
|
358
|
-
options.image_base_dir = image_base
|
|
359
|
-
options.parallelize_rendering = True
|
|
360
|
-
options.include_almost_detections = True
|
|
361
|
-
options.num_images_to_sample = 2500
|
|
362
|
-
options.confidence_threshold = 0.75
|
|
363
|
-
options.almost_detection_confidence_threshold = 0.7
|
|
364
|
-
options.ground_truth_json_file = ground_truth_json_file
|
|
365
|
-
options.allow_missing_images = True
|
|
366
|
-
options.ground_truth_filename_replacements = {}
|
|
367
|
-
options.api_output_filename_replacements = {'2020.08.01_reformat\\Maukahuka_Auckland_Island\\2_Testing\\':''}
|
|
368
|
-
options.api_output_file = api_output_file
|
|
369
|
-
options.output_dir = output_base
|
|
370
|
-
ppresults = process_batch_results(options)
|
|
371
|
-
os.startfile(ppresults.output_html_file)
|
|
372
|
-
|