megadetector 5.0.7__py3-none-any.whl → 5.0.9__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.

Files changed (191) hide show
  1. api/__init__.py +0 -0
  2. api/batch_processing/__init__.py +0 -0
  3. api/batch_processing/api_core/__init__.py +0 -0
  4. api/batch_processing/api_core/batch_service/__init__.py +0 -0
  5. api/batch_processing/api_core/batch_service/score.py +0 -1
  6. api/batch_processing/api_core/server_job_status_table.py +0 -1
  7. api/batch_processing/api_core_support/__init__.py +0 -0
  8. api/batch_processing/api_core_support/aggregate_results_manually.py +0 -1
  9. api/batch_processing/api_support/__init__.py +0 -0
  10. api/batch_processing/api_support/summarize_daily_activity.py +0 -1
  11. api/batch_processing/data_preparation/__init__.py +0 -0
  12. api/batch_processing/data_preparation/manage_local_batch.py +93 -79
  13. api/batch_processing/data_preparation/manage_video_batch.py +8 -8
  14. api/batch_processing/integration/digiKam/xmp_integration.py +0 -1
  15. api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +0 -1
  16. api/batch_processing/postprocessing/__init__.py +0 -0
  17. api/batch_processing/postprocessing/add_max_conf.py +12 -12
  18. api/batch_processing/postprocessing/categorize_detections_by_size.py +32 -14
  19. api/batch_processing/postprocessing/combine_api_outputs.py +69 -55
  20. api/batch_processing/postprocessing/compare_batch_results.py +114 -44
  21. api/batch_processing/postprocessing/convert_output_format.py +62 -19
  22. api/batch_processing/postprocessing/load_api_results.py +17 -20
  23. api/batch_processing/postprocessing/md_to_coco.py +31 -21
  24. api/batch_processing/postprocessing/md_to_labelme.py +165 -68
  25. api/batch_processing/postprocessing/merge_detections.py +40 -15
  26. api/batch_processing/postprocessing/postprocess_batch_results.py +270 -186
  27. api/batch_processing/postprocessing/remap_detection_categories.py +170 -0
  28. api/batch_processing/postprocessing/render_detection_confusion_matrix.py +75 -39
  29. api/batch_processing/postprocessing/repeat_detection_elimination/find_repeat_detections.py +53 -44
  30. api/batch_processing/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +25 -14
  31. api/batch_processing/postprocessing/repeat_detection_elimination/repeat_detections_core.py +244 -160
  32. api/batch_processing/postprocessing/separate_detections_into_folders.py +159 -114
  33. api/batch_processing/postprocessing/subset_json_detector_output.py +146 -169
  34. api/batch_processing/postprocessing/top_folders_to_bottom.py +77 -43
  35. api/synchronous/__init__.py +0 -0
  36. api/synchronous/api_core/animal_detection_api/__init__.py +0 -0
  37. api/synchronous/api_core/animal_detection_api/api_backend.py +0 -2
  38. api/synchronous/api_core/animal_detection_api/api_frontend.py +266 -268
  39. api/synchronous/api_core/animal_detection_api/config.py +35 -35
  40. api/synchronous/api_core/tests/__init__.py +0 -0
  41. api/synchronous/api_core/tests/load_test.py +109 -109
  42. classification/__init__.py +0 -0
  43. classification/aggregate_classifier_probs.py +21 -24
  44. classification/analyze_failed_images.py +11 -13
  45. classification/cache_batchapi_outputs.py +51 -51
  46. classification/create_classification_dataset.py +69 -68
  47. classification/crop_detections.py +54 -53
  48. classification/csv_to_json.py +97 -100
  49. classification/detect_and_crop.py +105 -105
  50. classification/evaluate_model.py +43 -42
  51. classification/identify_mislabeled_candidates.py +47 -46
  52. classification/json_to_azcopy_list.py +10 -10
  53. classification/json_validator.py +72 -71
  54. classification/map_classification_categories.py +44 -43
  55. classification/merge_classification_detection_output.py +68 -68
  56. classification/prepare_classification_script.py +157 -154
  57. classification/prepare_classification_script_mc.py +228 -228
  58. classification/run_classifier.py +27 -26
  59. classification/save_mislabeled.py +30 -30
  60. classification/train_classifier.py +20 -20
  61. classification/train_classifier_tf.py +21 -22
  62. classification/train_utils.py +10 -10
  63. data_management/__init__.py +0 -0
  64. data_management/annotations/__init__.py +0 -0
  65. data_management/annotations/annotation_constants.py +18 -31
  66. data_management/camtrap_dp_to_coco.py +238 -0
  67. data_management/cct_json_utils.py +107 -59
  68. data_management/cct_to_md.py +176 -158
  69. data_management/cct_to_wi.py +247 -219
  70. data_management/coco_to_labelme.py +272 -0
  71. data_management/coco_to_yolo.py +86 -62
  72. data_management/databases/__init__.py +0 -0
  73. data_management/databases/add_width_and_height_to_db.py +20 -16
  74. data_management/databases/combine_coco_camera_traps_files.py +35 -31
  75. data_management/databases/integrity_check_json_db.py +130 -83
  76. data_management/databases/subset_json_db.py +25 -16
  77. data_management/generate_crops_from_cct.py +27 -45
  78. data_management/get_image_sizes.py +188 -144
  79. data_management/importers/add_nacti_sizes.py +8 -8
  80. data_management/importers/add_timestamps_to_icct.py +78 -78
  81. data_management/importers/animl_results_to_md_results.py +158 -160
  82. data_management/importers/auckland_doc_test_to_json.py +9 -9
  83. data_management/importers/auckland_doc_to_json.py +8 -8
  84. data_management/importers/awc_to_json.py +7 -7
  85. data_management/importers/bellevue_to_json.py +15 -15
  86. data_management/importers/cacophony-thermal-importer.py +13 -13
  87. data_management/importers/carrizo_shrubfree_2018.py +8 -8
  88. data_management/importers/carrizo_trail_cam_2017.py +8 -8
  89. data_management/importers/cct_field_adjustments.py +9 -9
  90. data_management/importers/channel_islands_to_cct.py +10 -10
  91. data_management/importers/eMammal/copy_and_unzip_emammal.py +1 -0
  92. data_management/importers/ena24_to_json.py +7 -7
  93. data_management/importers/filenames_to_json.py +8 -8
  94. data_management/importers/helena_to_cct.py +7 -7
  95. data_management/importers/idaho-camera-traps.py +7 -7
  96. data_management/importers/idfg_iwildcam_lila_prep.py +10 -10
  97. data_management/importers/jb_csv_to_json.py +9 -9
  98. data_management/importers/mcgill_to_json.py +8 -8
  99. data_management/importers/missouri_to_json.py +18 -18
  100. data_management/importers/nacti_fieldname_adjustments.py +10 -10
  101. data_management/importers/noaa_seals_2019.py +8 -8
  102. data_management/importers/pc_to_json.py +7 -7
  103. data_management/importers/plot_wni_giraffes.py +7 -7
  104. data_management/importers/prepare-noaa-fish-data-for-lila.py +359 -359
  105. data_management/importers/prepare_zsl_imerit.py +7 -7
  106. data_management/importers/rspb_to_json.py +8 -8
  107. data_management/importers/save_the_elephants_survey_A.py +8 -8
  108. data_management/importers/save_the_elephants_survey_B.py +9 -9
  109. data_management/importers/snapshot_safari_importer.py +26 -26
  110. data_management/importers/snapshot_safari_importer_reprise.py +665 -665
  111. data_management/importers/snapshot_serengeti_lila.py +14 -14
  112. data_management/importers/sulross_get_exif.py +8 -9
  113. data_management/importers/timelapse_csv_set_to_json.py +11 -11
  114. data_management/importers/ubc_to_json.py +13 -13
  115. data_management/importers/umn_to_json.py +7 -7
  116. data_management/importers/wellington_to_json.py +8 -8
  117. data_management/importers/wi_to_json.py +9 -9
  118. data_management/importers/zamba_results_to_md_results.py +181 -181
  119. data_management/labelme_to_coco.py +309 -159
  120. data_management/labelme_to_yolo.py +103 -60
  121. data_management/lila/__init__.py +0 -0
  122. data_management/lila/add_locations_to_island_camera_traps.py +9 -9
  123. data_management/lila/add_locations_to_nacti.py +147 -147
  124. data_management/lila/create_lila_blank_set.py +114 -31
  125. data_management/lila/create_lila_test_set.py +8 -8
  126. data_management/lila/create_links_to_md_results_files.py +106 -106
  127. data_management/lila/download_lila_subset.py +92 -90
  128. data_management/lila/generate_lila_per_image_labels.py +56 -43
  129. data_management/lila/get_lila_annotation_counts.py +18 -15
  130. data_management/lila/get_lila_image_counts.py +11 -11
  131. data_management/lila/lila_common.py +103 -70
  132. data_management/lila/test_lila_metadata_urls.py +132 -116
  133. data_management/ocr_tools.py +173 -128
  134. data_management/read_exif.py +161 -99
  135. data_management/remap_coco_categories.py +84 -0
  136. data_management/remove_exif.py +58 -62
  137. data_management/resize_coco_dataset.py +32 -44
  138. data_management/wi_download_csv_to_coco.py +246 -0
  139. data_management/yolo_output_to_md_output.py +86 -73
  140. data_management/yolo_to_coco.py +535 -95
  141. detection/__init__.py +0 -0
  142. detection/detector_training/__init__.py +0 -0
  143. detection/process_video.py +85 -33
  144. detection/pytorch_detector.py +43 -25
  145. detection/run_detector.py +157 -72
  146. detection/run_detector_batch.py +189 -114
  147. detection/run_inference_with_yolov5_val.py +118 -51
  148. detection/run_tiled_inference.py +113 -42
  149. detection/tf_detector.py +51 -28
  150. detection/video_utils.py +606 -521
  151. docs/source/conf.py +43 -0
  152. md_utils/__init__.py +0 -0
  153. md_utils/azure_utils.py +9 -9
  154. md_utils/ct_utils.py +249 -70
  155. md_utils/directory_listing.py +59 -64
  156. md_utils/md_tests.py +968 -862
  157. md_utils/path_utils.py +655 -155
  158. md_utils/process_utils.py +157 -133
  159. md_utils/sas_blob_utils.py +20 -20
  160. md_utils/split_locations_into_train_val.py +45 -32
  161. md_utils/string_utils.py +33 -10
  162. md_utils/url_utils.py +208 -27
  163. md_utils/write_html_image_list.py +51 -35
  164. md_visualization/__init__.py +0 -0
  165. md_visualization/plot_utils.py +102 -109
  166. md_visualization/render_images_with_thumbnails.py +34 -34
  167. md_visualization/visualization_utils.py +908 -311
  168. md_visualization/visualize_db.py +109 -58
  169. md_visualization/visualize_detector_output.py +61 -42
  170. {megadetector-5.0.7.dist-info → megadetector-5.0.9.dist-info}/METADATA +21 -17
  171. megadetector-5.0.9.dist-info/RECORD +224 -0
  172. {megadetector-5.0.7.dist-info → megadetector-5.0.9.dist-info}/WHEEL +1 -1
  173. {megadetector-5.0.7.dist-info → megadetector-5.0.9.dist-info}/top_level.txt +1 -0
  174. taxonomy_mapping/__init__.py +0 -0
  175. taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +342 -335
  176. taxonomy_mapping/map_new_lila_datasets.py +154 -154
  177. taxonomy_mapping/prepare_lila_taxonomy_release.py +142 -134
  178. taxonomy_mapping/preview_lila_taxonomy.py +591 -591
  179. taxonomy_mapping/retrieve_sample_image.py +12 -12
  180. taxonomy_mapping/simple_image_download.py +11 -11
  181. taxonomy_mapping/species_lookup.py +10 -10
  182. taxonomy_mapping/taxonomy_csv_checker.py +18 -18
  183. taxonomy_mapping/taxonomy_graph.py +47 -47
  184. taxonomy_mapping/validate_lila_category_mappings.py +83 -76
  185. data_management/cct_json_to_filename_json.py +0 -89
  186. data_management/cct_to_csv.py +0 -140
  187. data_management/databases/remove_corrupted_images_from_db.py +0 -191
  188. detection/detector_training/copy_checkpoints.py +0 -43
  189. md_visualization/visualize_megadb.py +0 -183
  190. megadetector-5.0.7.dist-info/RECORD +0 -202
  191. {megadetector-5.0.7.dist-info → megadetector-5.0.9.dist-info}/LICENSE +0 -0
@@ -1,17 +1,22 @@
1
- ########
2
- #
3
- # cct_to_wi.py
4
- #
5
- # Converts COCO Camera Traps .json files to the Wildlife Insights
6
- # batch upload format
7
- #
8
- # Also see:
9
- #
10
- # https://github.com/ConservationInternational/Wildlife-Insights----Data-Migration
11
- #
12
- # https://data.naturalsciences.org/wildlife-insights/taxonomy/search
13
- #
14
- ########
1
+ """
2
+
3
+ cct_to_wi.py
4
+
5
+ Converts COCO Camera Traps .json files to the Wildlife Insights
6
+ batch upload format.
7
+
8
+ **This is very much just a demo script; all the relevant constants are hard-coded
9
+ at the top of main().**
10
+
11
+ But given that caveat, it works. You need to set up all the paths in the "paths" cell
12
+ at the top of main().
13
+
14
+ Also see:
15
+
16
+ * https://github.com/ConservationInternational/Wildlife-Insights----Data-Migration
17
+ * https://data.naturalsciences.org/wildlife-insights/taxonomy/search
18
+
19
+ """
15
20
 
16
21
  #%% Imports
17
22
 
@@ -21,241 +26,264 @@ import pandas as pd
21
26
  from collections import defaultdict
22
27
 
23
28
 
24
- #%% Paths
25
-
26
- # A COCO camera traps file with information about this dataset
27
- input_file = r'c:\temp\camera_trap_images_no_people\bellevue_camera_traps.2020-12-26.json'
28
- assert os.path.isfile(input_file)
29
-
30
- # A .json dictionary mapping common names in this dataset to dictionaries with the
31
- # WI taxonomy fields: common_name, wi_taxon_id, class, orer, family, genus, species
32
- taxonomy_file = r'c:\temp\camera_trap_images_no_people\belleve_camera_traps_to_wi.json'
33
- assert os.path.isfile(taxonomy_file)
29
+ #%% Main wrapper
34
30
 
35
- templates_dir = r'c:\temp\wi_batch_upload_templates'
36
- assert os.path.isdir(templates_dir)
31
+ def main():
32
+ """
33
+ Converts COCO Camera Traps .json files to the Wildlife Insights
34
+ batch upload format; to use this, you need to modify all the paths in the "Paths"
35
+ cell.
36
+ """
37
+
38
+ #%% Paths
37
39
 
38
- output_base = r'c:\temp\wi_output'
39
- os.makedirs(output_base,exist_ok = True)
40
+ # A COCO camera traps file with information about this dataset
41
+ input_file = r'c:\temp\camera_trap_images_no_people\bellevue_camera_traps.2020-12-26.json'
42
+
43
+ # A .json dictionary mapping common names in this dataset to dictionaries with the
44
+ # WI taxonomy fields: common_name, wi_taxon_id, class, order, family, genus, species
45
+ taxonomy_file = r'c:\temp\camera_trap_images_no_people\bellevue_camera_traps_to_wi.json'
40
46
 
47
+ # The folder where the .csv template files live
48
+ templates_dir = r'c:\temp\wi_batch_upload_templates'
49
+
50
+ # The folder to which you want to write WI-formatted .csv files
51
+ output_base = r'c:\temp\wi_output'
41
52
 
42
- #%% Constants
43
-
44
- projects_file_name = 'Template Wildlife Insights Batch Upload - Projectv1.0.csv'
45
- deployments_file_name = 'Template Wildlife Insights Batch Upload - Deploymentv1.0.csv'
46
- images_file_name = 'Template Wildlife Insights Batch Upload - Imagev1.0.csv'
47
- cameras_file_name = 'Template Wildlife Insights Batch Upload - Camerav1.0.csv'
48
-
49
- assert all([os.path.isfile(os.path.join(templates_dir,fn)) for fn in \
50
- [projects_file_name,deployments_file_name,images_file_name,cameras_file_name]])
51
-
52
-
53
- #%% Project information
54
-
55
- project_info = {}
56
- project_info['project_name'] = 'Bellevue Camera Traps'
57
- project_info['project_id'] = 'bct_001'
58
- project_info['project_short_name'] = 'BCT'
59
- project_info['project_objectives'] = 'none'
60
- project_info['project_species'] = 'Multiple'
61
- project_info['project_species_individual'] = ''
62
- project_info['project_sensor_layout'] = 'Convenience'
63
- project_info['project_sensor_layout_targeted_type'] = ''
64
- project_info['project_bait_use'] = 'No'
65
- project_info['project_bait_type'] = 'None'
66
- project_info['project_stratification'] = 'No'
67
- project_info['project_stratification_type'] = ''
68
- project_info['project_sensor_method'] = 'Sensor Detection'
69
- project_info['project_individual_animals'] = 'No'
70
- project_info['project_admin'] = 'Dan Morris'
71
- project_info['project_admin_email'] = 'cameratraps@lila.science'
72
- project_info['country_code'] = 'USA'
73
- project_info['embargo'] = str(0)
74
- project_info['initiative_id'] = ''
75
- project_info['metadata_license'] = 'CC0'
76
- project_info['image_license'] = 'CC0'
77
-
78
- project_info['project_blank_images'] = 'No'
79
- project_info['project_sensor_cluster'] = 'No'
80
-
81
- camera_info = {}
82
- camera_info['project_id'] = project_info['project_id']
83
- camera_info['camera_id'] = '0000'
84
- camera_info['make'] = ''
85
- camera_info['model'] = ''
86
- camera_info['serial_number'] = ''
87
- camera_info['year_purchased'] = ''
88
-
89
- deployment_info = {}
90
-
91
- deployment_info['project_id'] = project_info['project_id']
92
- deployment_info['deployment_id'] = 'test_deployment'
93
- deployment_info['subproject_name'] = 'test_subproject'
94
- deployment_info['subproject_design'] = ''
95
- deployment_info['placename'] = 'yard'
96
- deployment_info['longitude'] = '47.6101'
97
- deployment_info['latitude'] = '-122.2015'
98
- deployment_info['start_date'] = '2016-01-01 00:00:00'
99
- deployment_info['end_date'] = '2026-01-01 00:00:00'
100
- deployment_info['event_name'] = ''
101
- deployment_info['event_description'] = ''
102
- deployment_info['event_type'] = ''
103
- deployment_info['bait_type'] = ''
104
- deployment_info['bait_description'] = ''
105
- deployment_info['feature_type'] = 'None'
106
- deployment_info['feature_type_methodology'] = ''
107
- deployment_info['camera_id'] = camera_info['camera_id']
108
- deployment_info['quiet_period'] = str(60)
109
- deployment_info['camera_functioning'] = 'Camera Functioning'
110
- deployment_info['sensor_height'] = 'Chest height'
111
- deployment_info['height_other'] = ''
112
- deployment_info['sensor_orientation'] = 'Parallel'
113
- deployment_info['orientation_other'] = ''
114
- deployment_info['recorded_by'] = 'Dan Morris'
115
-
116
- image_info = {}
117
- image_info['identified_by'] = 'Dan Morris'
118
-
119
-
120
- #%% Read templates
121
-
122
- def parse_fields(templates_dir,file_name):
123
53
 
124
- with open(os.path.join(templates_dir,file_name),'r') as f:
125
- lines = f.readlines()
126
- lines = [s.strip() for s in lines if len(s.strip().replace(',','')) > 0]
127
- assert len(lines) == 1, 'Error processing template {}'.format(file_name)
128
- fields = lines[0].split(',')
129
- print('Parsed {} columns from {}'.format(len(fields),file_name))
130
- return fields
54
+ #%% Path validation
55
+
56
+ assert os.path.isfile(input_file)
57
+ assert os.path.isfile(taxonomy_file)
58
+ assert os.path.isdir(templates_dir)
59
+ os.makedirs(output_base,exist_ok = True)
131
60
 
132
- projects_fields = parse_fields(templates_dir,projects_file_name)
133
- deployments_fields = parse_fields(templates_dir,deployments_file_name)
134
- images_fields = parse_fields(templates_dir,images_file_name)
135
- cameras_fields = parse_fields(templates_dir,cameras_file_name)
61
+
62
+ #%% Constants
63
+
64
+ projects_file_name = 'Template Wildlife Insights Batch Upload - Projectv1.0.csv'
65
+ deployments_file_name = 'Template Wildlife Insights Batch Upload - Deploymentv1.0.csv'
66
+ images_file_name = 'Template Wildlife Insights Batch Upload - Imagev1.0.csv'
67
+ cameras_file_name = 'Template Wildlife Insights Batch Upload - Camerav1.0.csv'
68
+
69
+ assert all([os.path.isfile(os.path.join(templates_dir,fn)) for fn in \
70
+ [projects_file_name,deployments_file_name,images_file_name,cameras_file_name]])
71
+
72
+
73
+ #%% Project information
74
+
75
+ project_info = {}
76
+ project_info['project_name'] = 'Bellevue Camera Traps'
77
+ project_info['project_id'] = 'bct_001'
78
+ project_info['project_short_name'] = 'BCT'
79
+ project_info['project_objectives'] = 'none'
80
+ project_info['project_species'] = 'Multiple'
81
+ project_info['project_species_individual'] = ''
82
+ project_info['project_sensor_layout'] = 'Convenience'
83
+ project_info['project_sensor_layout_targeted_type'] = ''
84
+ project_info['project_bait_use'] = 'No'
85
+ project_info['project_bait_type'] = 'None'
86
+ project_info['project_stratification'] = 'No'
87
+ project_info['project_stratification_type'] = ''
88
+ project_info['project_sensor_method'] = 'Sensor Detection'
89
+ project_info['project_individual_animals'] = 'No'
90
+ project_info['project_admin'] = 'Dan Morris'
91
+ project_info['project_admin_email'] = 'cameratraps@lila.science'
92
+ project_info['country_code'] = 'USA'
93
+ project_info['embargo'] = str(0)
94
+ project_info['initiative_id'] = ''
95
+ project_info['metadata_license'] = 'CC0'
96
+ project_info['image_license'] = 'CC0'
97
+
98
+ project_info['project_blank_images'] = 'No'
99
+ project_info['project_sensor_cluster'] = 'No'
100
+
101
+ camera_info = {}
102
+ camera_info['project_id'] = project_info['project_id']
103
+ camera_info['camera_id'] = '0000'
104
+ camera_info['make'] = ''
105
+ camera_info['model'] = ''
106
+ camera_info['serial_number'] = ''
107
+ camera_info['year_purchased'] = ''
108
+
109
+ deployment_info = {}
110
+
111
+ deployment_info['project_id'] = project_info['project_id']
112
+ deployment_info['deployment_id'] = 'test_deployment'
113
+ deployment_info['subproject_name'] = 'test_subproject'
114
+ deployment_info['subproject_design'] = ''
115
+ deployment_info['placename'] = 'yard'
116
+ deployment_info['longitude'] = '47.6101'
117
+ deployment_info['latitude'] = '-122.2015'
118
+ deployment_info['start_date'] = '2016-01-01 00:00:00'
119
+ deployment_info['end_date'] = '2026-01-01 00:00:00'
120
+ deployment_info['event_name'] = ''
121
+ deployment_info['event_description'] = ''
122
+ deployment_info['event_type'] = ''
123
+ deployment_info['bait_type'] = ''
124
+ deployment_info['bait_description'] = ''
125
+ deployment_info['feature_type'] = 'None'
126
+ deployment_info['feature_type_methodology'] = ''
127
+ deployment_info['camera_id'] = camera_info['camera_id']
128
+ deployment_info['quiet_period'] = str(60)
129
+ deployment_info['camera_functioning'] = 'Camera Functioning'
130
+ deployment_info['sensor_height'] = 'Chest height'
131
+ deployment_info['height_other'] = ''
132
+ deployment_info['sensor_orientation'] = 'Parallel'
133
+ deployment_info['orientation_other'] = ''
134
+ deployment_info['recorded_by'] = 'Dan Morris'
135
+
136
+ image_info = {}
137
+ image_info['identified_by'] = 'Dan Morris'
138
+
139
+
140
+ #%% Read templates
141
+
142
+ def parse_fields(templates_dir,file_name):
143
+
144
+ with open(os.path.join(templates_dir,file_name),'r') as f:
145
+ lines = f.readlines()
146
+ lines = [s.strip() for s in lines if len(s.strip().replace(',','')) > 0]
147
+ assert len(lines) == 1, 'Error processing template {}'.format(file_name)
148
+ fields = lines[0].split(',')
149
+ print('Parsed {} columns from {}'.format(len(fields),file_name))
150
+ return fields
136
151
 
152
+ projects_fields = parse_fields(templates_dir,projects_file_name)
153
+ deployments_fields = parse_fields(templates_dir,deployments_file_name)
154
+ images_fields = parse_fields(templates_dir,images_file_name)
155
+ cameras_fields = parse_fields(templates_dir,cameras_file_name)
137
156
 
138
- #%% Compare dictionary to template lists
139
157
 
140
- def compare_info_to_template(info,template_fields,name):
141
-
142
- for s in info.keys():
143
- assert s in template_fields,'Field {} not specified in {}_fields'.format(s,name)
144
- for s in template_fields:
145
- assert s in info.keys(),'Field {} not specified in {}_info'.format(s,name)
158
+ #%% Compare dictionary to template lists
146
159
 
160
+ def compare_info_to_template(info,template_fields,name):
161
+
162
+ for s in info.keys():
163
+ assert s in template_fields,'Field {} not specified in {}_fields'.format(s,name)
164
+ for s in template_fields:
165
+ assert s in info.keys(),'Field {} not specified in {}_info'.format(s,name)
147
166
 
148
- def write_table(file_name,info,template_fields):
149
-
150
- assert len(info) == len(template_fields)
151
-
152
- project_output_file = os.path.join(output_base,file_name)
153
- with open(project_output_file,'w') as f:
154
-
155
- # Write the header
156
- for i_field,s in enumerate(template_fields):
157
- f.write(s)
158
- if i_field != len(template_fields)-1:
159
- f.write(',')
160
- f.write('\n')
167
+
168
+ def write_table(file_name,info,template_fields):
169
+
170
+ assert len(info) == len(template_fields)
171
+
172
+ project_output_file = os.path.join(output_base,file_name)
173
+ with open(project_output_file,'w') as f:
174
+
175
+ # Write the header
176
+ for i_field,s in enumerate(template_fields):
177
+ f.write(s)
178
+ if i_field != len(template_fields)-1:
179
+ f.write(',')
180
+ f.write('\n')
181
+
182
+ # Write values
183
+ for i_field,s in enumerate(template_fields):
184
+ f.write(info[s])
185
+ if i_field != len(template_fields)-1:
186
+ f.write(',')
187
+ f.write('\n')
161
188
 
162
- # Write values
163
- for i_field,s in enumerate(template_fields):
164
- f.write(info[s])
165
- if i_field != len(template_fields)-1:
166
- f.write(',')
167
- f.write('\n')
168
-
169
189
 
170
- #%% Project file
190
+ #%% Project file
171
191
 
172
- compare_info_to_template(project_info,projects_fields,'project')
173
- write_table(projects_file_name,project_info,projects_fields)
192
+ compare_info_to_template(project_info,projects_fields,'project')
193
+ write_table(projects_file_name,project_info,projects_fields)
174
194
 
175
195
 
176
- #%% Camera file
196
+ #%% Camera file
177
197
 
178
- compare_info_to_template(camera_info,cameras_fields,'camera')
179
- write_table(cameras_file_name,camera_info,cameras_fields)
198
+ compare_info_to_template(camera_info,cameras_fields,'camera')
199
+ write_table(cameras_file_name,camera_info,cameras_fields)
180
200
 
181
201
 
182
- #%% Deployment file
202
+ #%% Deployment file
183
203
 
184
- compare_info_to_template(deployment_info,deployments_fields,'deployment')
185
- write_table(deployments_file_name,deployment_info,deployments_fields)
204
+ compare_info_to_template(deployment_info,deployments_fields,'deployment')
205
+ write_table(deployments_file_name,deployment_info,deployments_fields)
186
206
 
187
207
 
188
- #%% Images file
208
+ #%% Images file
189
209
 
190
- # Read .json file with image information
191
- with open(input_file,'r') as f:
192
- input_data = json.load(f)
210
+ # Read .json file with image information
211
+ with open(input_file,'r') as f:
212
+ input_data = json.load(f)
193
213
 
194
- # Read taxonomy dictionary
195
- with open(taxonomy_file,'r') as f:
196
- taxonomy_mapping = json.load(f)
197
-
198
- url_base = taxonomy_mapping['url_base']
199
- taxonomy_mapping = taxonomy_mapping['taxonomy']
214
+ # Read taxonomy dictionary
215
+ with open(taxonomy_file,'r') as f:
216
+ taxonomy_mapping = json.load(f)
217
+
218
+ url_base = taxonomy_mapping['url_base']
219
+ taxonomy_mapping = taxonomy_mapping['taxonomy']
200
220
 
201
- # Populate output information
202
- # df = pd.DataFrame(columns = images_fields)
221
+ # Populate output information
222
+ # df = pd.DataFrame(columns = images_fields)
203
223
 
204
- category_id_to_name = {cat['id']:cat['name'] for cat in input_data['categories']}
224
+ category_id_to_name = {cat['id']:cat['name'] for cat in input_data['categories']}
205
225
 
206
- image_id_to_annotations = defaultdict(list)
226
+ image_id_to_annotations = defaultdict(list)
207
227
 
208
- annotations = input_data['annotations']
209
-
210
- # annotation = annotations[0]
211
- for annotation in annotations:
212
- image_id_to_annotations[annotation['image_id']].append(
213
- category_id_to_name[annotation['category_id']])
228
+ annotations = input_data['annotations']
229
+
230
+ # annotation = annotations[0]
231
+ for annotation in annotations:
232
+ image_id_to_annotations[annotation['image_id']].append(
233
+ category_id_to_name[annotation['category_id']])
214
234
 
215
- rows = []
235
+ rows = []
216
236
 
217
- # im = input_data['images'][0]
218
- for im in input_data['images']:
237
+ # im = input_data['images'][0]
238
+ for im in input_data['images']:
219
239
 
220
- row = {}
221
-
222
- url = url_base + im['file_name'].replace('\\','/')
223
- row['project_id'] = project_info['project_id']
224
- row['deployment_id'] = deployment_info['deployment_id']
225
- row['image_id'] = im['id']
226
- row['location'] = url
227
- row['identified_by'] = image_info['identified_by']
228
-
229
- category_names = image_id_to_annotations[im['id']]
230
- assert len(category_names) == 1
231
- category_name = category_names[0]
232
-
233
- taxon_info = taxonomy_mapping[category_name]
234
-
235
- assert len(taxon_info.keys()) == 7
236
-
237
- for s in taxon_info.keys():
238
- row[s] = taxon_info[s]
239
-
240
- # We don't have counts, but we can differentiate between zero and 1
241
- if category_name == 'empty':
242
- row['number_of_objects'] = 0
243
- else:
244
- row['number_of_objects'] = 1
240
+ row = {}
245
241
 
246
- row['uncertainty'] = None
247
- row['timestamp'] = im['datetime']; assert isinstance(im['datetime'],str)
248
- row['highlighted'] = 0
249
- row['age'] = None
250
- row['sex'] = None
251
- row['animal_recognizable'] = 'No'
252
- row['individual_id'] = None
253
- row['individual_animal_notes'] = None
254
- row['markings'] = None
255
-
256
- assert len(row) == len(images_fields)
257
- rows.append(row)
258
-
259
- df = pd.DataFrame(rows)
242
+ url = url_base + im['file_name'].replace('\\','/')
243
+ row['project_id'] = project_info['project_id']
244
+ row['deployment_id'] = deployment_info['deployment_id']
245
+ row['image_id'] = im['id']
246
+ row['location'] = url
247
+ row['identified_by'] = image_info['identified_by']
248
+
249
+ category_names = image_id_to_annotations[im['id']]
250
+ assert len(category_names) == 1
251
+ category_name = category_names[0]
252
+
253
+ taxon_info = taxonomy_mapping[category_name]
254
+
255
+ assert len(taxon_info.keys()) == 7
256
+
257
+ for s in taxon_info.keys():
258
+ row[s] = taxon_info[s]
259
+
260
+ # We don't have counts, but we can differentiate between zero and 1
261
+ if category_name == 'empty':
262
+ row['number_of_objects'] = 0
263
+ else:
264
+ row['number_of_objects'] = 1
265
+
266
+ row['uncertainty'] = None
267
+ row['timestamp'] = im['datetime']; assert isinstance(im['datetime'],str)
268
+ row['highlighted'] = 0
269
+ row['age'] = None
270
+ row['sex'] = None
271
+ row['animal_recognizable'] = 'No'
272
+ row['individual_id'] = None
273
+ row['individual_animal_notes'] = None
274
+ row['markings'] = None
275
+
276
+ assert len(row) == len(images_fields)
277
+ rows.append(row)
278
+
279
+ df = pd.DataFrame(rows)
280
+
281
+ df.to_csv(os.path.join(output_base,images_file_name),index=False)
282
+
283
+ # ...main()
284
+
285
+
286
+ #%% Command-line driver
260
287
 
261
- df.to_csv(os.path.join(output_base,images_file_name),index=False)
288
+ if __name__ == '__main__':
289
+ main()