megadetector 5.0.27__py3-none-any.whl → 5.0.29__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of megadetector might be problematic. Click here for more details.

Files changed (176) hide show
  1. megadetector/api/batch_processing/api_core/batch_service/score.py +4 -5
  2. megadetector/api/batch_processing/api_core_support/aggregate_results_manually.py +1 -1
  3. megadetector/api/batch_processing/api_support/summarize_daily_activity.py +1 -1
  4. megadetector/api/batch_processing/integration/digiKam/xmp_integration.py +2 -2
  5. megadetector/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +1 -1
  6. megadetector/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +1 -1
  7. megadetector/api/synchronous/api_core/tests/load_test.py +2 -3
  8. megadetector/classification/aggregate_classifier_probs.py +3 -3
  9. megadetector/classification/analyze_failed_images.py +5 -5
  10. megadetector/classification/cache_batchapi_outputs.py +5 -5
  11. megadetector/classification/create_classification_dataset.py +11 -12
  12. megadetector/classification/crop_detections.py +10 -10
  13. megadetector/classification/csv_to_json.py +8 -8
  14. megadetector/classification/detect_and_crop.py +13 -15
  15. megadetector/classification/evaluate_model.py +7 -7
  16. megadetector/classification/identify_mislabeled_candidates.py +6 -6
  17. megadetector/classification/json_to_azcopy_list.py +1 -1
  18. megadetector/classification/json_validator.py +29 -32
  19. megadetector/classification/map_classification_categories.py +9 -9
  20. megadetector/classification/merge_classification_detection_output.py +12 -9
  21. megadetector/classification/prepare_classification_script.py +19 -19
  22. megadetector/classification/prepare_classification_script_mc.py +23 -23
  23. megadetector/classification/run_classifier.py +4 -4
  24. megadetector/classification/save_mislabeled.py +6 -6
  25. megadetector/classification/train_classifier.py +1 -1
  26. megadetector/classification/train_classifier_tf.py +9 -9
  27. megadetector/classification/train_utils.py +10 -10
  28. megadetector/data_management/annotations/annotation_constants.py +1 -1
  29. megadetector/data_management/camtrap_dp_to_coco.py +45 -45
  30. megadetector/data_management/cct_json_utils.py +101 -101
  31. megadetector/data_management/cct_to_md.py +49 -49
  32. megadetector/data_management/cct_to_wi.py +33 -33
  33. megadetector/data_management/coco_to_labelme.py +75 -75
  34. megadetector/data_management/coco_to_yolo.py +189 -189
  35. megadetector/data_management/databases/add_width_and_height_to_db.py +3 -2
  36. megadetector/data_management/databases/combine_coco_camera_traps_files.py +38 -38
  37. megadetector/data_management/databases/integrity_check_json_db.py +202 -188
  38. megadetector/data_management/databases/subset_json_db.py +33 -33
  39. megadetector/data_management/generate_crops_from_cct.py +38 -38
  40. megadetector/data_management/get_image_sizes.py +54 -49
  41. megadetector/data_management/labelme_to_coco.py +130 -124
  42. megadetector/data_management/labelme_to_yolo.py +78 -72
  43. megadetector/data_management/lila/create_lila_blank_set.py +81 -83
  44. megadetector/data_management/lila/create_lila_test_set.py +32 -31
  45. megadetector/data_management/lila/create_links_to_md_results_files.py +18 -18
  46. megadetector/data_management/lila/download_lila_subset.py +21 -24
  47. megadetector/data_management/lila/generate_lila_per_image_labels.py +91 -91
  48. megadetector/data_management/lila/get_lila_annotation_counts.py +30 -30
  49. megadetector/data_management/lila/get_lila_image_counts.py +22 -22
  50. megadetector/data_management/lila/lila_common.py +70 -70
  51. megadetector/data_management/lila/test_lila_metadata_urls.py +13 -14
  52. megadetector/data_management/mewc_to_md.py +339 -340
  53. megadetector/data_management/ocr_tools.py +258 -252
  54. megadetector/data_management/read_exif.py +232 -223
  55. megadetector/data_management/remap_coco_categories.py +26 -26
  56. megadetector/data_management/remove_exif.py +31 -20
  57. megadetector/data_management/rename_images.py +187 -187
  58. megadetector/data_management/resize_coco_dataset.py +41 -41
  59. megadetector/data_management/speciesnet_to_md.py +41 -41
  60. megadetector/data_management/wi_download_csv_to_coco.py +55 -55
  61. megadetector/data_management/yolo_output_to_md_output.py +117 -120
  62. megadetector/data_management/yolo_to_coco.py +195 -188
  63. megadetector/detection/change_detection.py +831 -0
  64. megadetector/detection/process_video.py +341 -338
  65. megadetector/detection/pytorch_detector.py +308 -266
  66. megadetector/detection/run_detector.py +186 -166
  67. megadetector/detection/run_detector_batch.py +366 -364
  68. megadetector/detection/run_inference_with_yolov5_val.py +328 -325
  69. megadetector/detection/run_tiled_inference.py +312 -253
  70. megadetector/detection/tf_detector.py +24 -24
  71. megadetector/detection/video_utils.py +291 -283
  72. megadetector/postprocessing/add_max_conf.py +15 -11
  73. megadetector/postprocessing/categorize_detections_by_size.py +44 -44
  74. megadetector/postprocessing/classification_postprocessing.py +808 -311
  75. megadetector/postprocessing/combine_batch_outputs.py +20 -21
  76. megadetector/postprocessing/compare_batch_results.py +528 -517
  77. megadetector/postprocessing/convert_output_format.py +97 -97
  78. megadetector/postprocessing/create_crop_folder.py +220 -147
  79. megadetector/postprocessing/detector_calibration.py +173 -168
  80. megadetector/postprocessing/generate_csv_report.py +508 -0
  81. megadetector/postprocessing/load_api_results.py +25 -22
  82. megadetector/postprocessing/md_to_coco.py +129 -98
  83. megadetector/postprocessing/md_to_labelme.py +89 -83
  84. megadetector/postprocessing/md_to_wi.py +40 -40
  85. megadetector/postprocessing/merge_detections.py +87 -114
  86. megadetector/postprocessing/postprocess_batch_results.py +319 -302
  87. megadetector/postprocessing/remap_detection_categories.py +36 -36
  88. megadetector/postprocessing/render_detection_confusion_matrix.py +205 -199
  89. megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py +57 -57
  90. megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +27 -28
  91. megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +702 -677
  92. megadetector/postprocessing/separate_detections_into_folders.py +226 -211
  93. megadetector/postprocessing/subset_json_detector_output.py +265 -262
  94. megadetector/postprocessing/top_folders_to_bottom.py +45 -45
  95. megadetector/postprocessing/validate_batch_results.py +70 -70
  96. megadetector/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +52 -52
  97. megadetector/taxonomy_mapping/map_new_lila_datasets.py +15 -15
  98. megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +14 -14
  99. megadetector/taxonomy_mapping/preview_lila_taxonomy.py +66 -69
  100. megadetector/taxonomy_mapping/retrieve_sample_image.py +16 -16
  101. megadetector/taxonomy_mapping/simple_image_download.py +8 -8
  102. megadetector/taxonomy_mapping/species_lookup.py +33 -33
  103. megadetector/taxonomy_mapping/taxonomy_csv_checker.py +14 -14
  104. megadetector/taxonomy_mapping/taxonomy_graph.py +11 -11
  105. megadetector/taxonomy_mapping/validate_lila_category_mappings.py +13 -13
  106. megadetector/utils/azure_utils.py +22 -22
  107. megadetector/utils/ct_utils.py +1019 -200
  108. megadetector/utils/directory_listing.py +21 -77
  109. megadetector/utils/gpu_test.py +22 -22
  110. megadetector/utils/md_tests.py +541 -518
  111. megadetector/utils/path_utils.py +1511 -406
  112. megadetector/utils/process_utils.py +41 -41
  113. megadetector/utils/sas_blob_utils.py +53 -49
  114. megadetector/utils/split_locations_into_train_val.py +73 -60
  115. megadetector/utils/string_utils.py +147 -26
  116. megadetector/utils/url_utils.py +463 -173
  117. megadetector/utils/wi_utils.py +2629 -2868
  118. megadetector/utils/write_html_image_list.py +137 -137
  119. megadetector/visualization/plot_utils.py +21 -21
  120. megadetector/visualization/render_images_with_thumbnails.py +37 -73
  121. megadetector/visualization/visualization_utils.py +424 -404
  122. megadetector/visualization/visualize_db.py +197 -190
  123. megadetector/visualization/visualize_detector_output.py +126 -98
  124. {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/METADATA +6 -3
  125. megadetector-5.0.29.dist-info/RECORD +163 -0
  126. {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/WHEEL +1 -1
  127. megadetector/data_management/importers/add_nacti_sizes.py +0 -52
  128. megadetector/data_management/importers/add_timestamps_to_icct.py +0 -79
  129. megadetector/data_management/importers/animl_results_to_md_results.py +0 -158
  130. megadetector/data_management/importers/auckland_doc_test_to_json.py +0 -373
  131. megadetector/data_management/importers/auckland_doc_to_json.py +0 -201
  132. megadetector/data_management/importers/awc_to_json.py +0 -191
  133. megadetector/data_management/importers/bellevue_to_json.py +0 -272
  134. megadetector/data_management/importers/cacophony-thermal-importer.py +0 -793
  135. megadetector/data_management/importers/carrizo_shrubfree_2018.py +0 -269
  136. megadetector/data_management/importers/carrizo_trail_cam_2017.py +0 -289
  137. megadetector/data_management/importers/cct_field_adjustments.py +0 -58
  138. megadetector/data_management/importers/channel_islands_to_cct.py +0 -913
  139. megadetector/data_management/importers/eMammal/copy_and_unzip_emammal.py +0 -180
  140. megadetector/data_management/importers/eMammal/eMammal_helpers.py +0 -249
  141. megadetector/data_management/importers/eMammal/make_eMammal_json.py +0 -223
  142. megadetector/data_management/importers/ena24_to_json.py +0 -276
  143. megadetector/data_management/importers/filenames_to_json.py +0 -386
  144. megadetector/data_management/importers/helena_to_cct.py +0 -283
  145. megadetector/data_management/importers/idaho-camera-traps.py +0 -1407
  146. megadetector/data_management/importers/idfg_iwildcam_lila_prep.py +0 -294
  147. megadetector/data_management/importers/import_desert_lion_conservation_camera_traps.py +0 -387
  148. megadetector/data_management/importers/jb_csv_to_json.py +0 -150
  149. megadetector/data_management/importers/mcgill_to_json.py +0 -250
  150. megadetector/data_management/importers/missouri_to_json.py +0 -490
  151. megadetector/data_management/importers/nacti_fieldname_adjustments.py +0 -79
  152. megadetector/data_management/importers/noaa_seals_2019.py +0 -181
  153. megadetector/data_management/importers/osu-small-animals-to-json.py +0 -364
  154. megadetector/data_management/importers/pc_to_json.py +0 -365
  155. megadetector/data_management/importers/plot_wni_giraffes.py +0 -123
  156. megadetector/data_management/importers/prepare_zsl_imerit.py +0 -131
  157. megadetector/data_management/importers/raic_csv_to_md_results.py +0 -416
  158. megadetector/data_management/importers/rspb_to_json.py +0 -356
  159. megadetector/data_management/importers/save_the_elephants_survey_A.py +0 -320
  160. megadetector/data_management/importers/save_the_elephants_survey_B.py +0 -329
  161. megadetector/data_management/importers/snapshot_safari_importer.py +0 -758
  162. megadetector/data_management/importers/snapshot_serengeti_lila.py +0 -1067
  163. megadetector/data_management/importers/snapshotserengeti/make_full_SS_json.py +0 -150
  164. megadetector/data_management/importers/snapshotserengeti/make_per_season_SS_json.py +0 -153
  165. megadetector/data_management/importers/sulross_get_exif.py +0 -65
  166. megadetector/data_management/importers/timelapse_csv_set_to_json.py +0 -490
  167. megadetector/data_management/importers/ubc_to_json.py +0 -399
  168. megadetector/data_management/importers/umn_to_json.py +0 -507
  169. megadetector/data_management/importers/wellington_to_json.py +0 -263
  170. megadetector/data_management/importers/wi_to_json.py +0 -442
  171. megadetector/data_management/importers/zamba_results_to_md_results.py +0 -180
  172. megadetector/data_management/lila/add_locations_to_island_camera_traps.py +0 -101
  173. megadetector/data_management/lila/add_locations_to_nacti.py +0 -151
  174. megadetector-5.0.27.dist-info/RECORD +0 -208
  175. {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/licenses/LICENSE +0 -0
  176. {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/top_level.txt +0 -0
@@ -1,365 +0,0 @@
1
- """
2
-
3
- pc_to_json.py
4
-
5
- Convert a particular collection of .csv files from Parks Canada to CCT format.
6
-
7
- """
8
-
9
- #%% Constants and environment
10
-
11
- import pandas as pd
12
- import uuid
13
- import json
14
- import time
15
-
16
- import numpy as np
17
- from tqdm import tqdm
18
-
19
- import humanfriendly
20
- import os
21
- import PIL
22
-
23
- from megadetector.data_management.databases import integrity_check_json_db
24
- from megadetector.data_management.cct_json_utils import IndexedJsonDb
25
- from megadetector.data_management import cct_json_to_filename_json
26
- from megadetector.visualization import visualize_db
27
- from megadetector.utils import path_utils
28
-
29
- input_base = r"g:\20190715"
30
- output_file = r"D:\wildlife_data\parks_canada\pc_20190715.json"
31
- preview_base = r"D:\wildlife_data\parks_canada\preview"
32
-
33
- filename_replacements = {}
34
- category_mappings = {'':'unlabeled'}
35
-
36
- csv_prefix = 'ImageData_Microsoft___'
37
-
38
- expected_columns = 'Location,DateImage,TimeImage,Species,Total,Horses,DogsOnLeash,DogsOffLeash,AdultFemale,AdultMale,AdultUnknown,Subadult,YLY,YOY,ImageName'.split(',')
39
- columns_to_copy = {'Total':'count','Horses':'horses','DogsOnLeash':'dogsonleash','DogsOffLeash':'dogsoffleash',
40
- 'AdultFemale':'adultfemale','AdultMale':'adultmale','AdultUnknown':'adultunknown',
41
- 'Subadult':'subadult','YLY':'yearling','YOY':'youngofyear'}
42
-
43
- retrieve_image_sizes = False
44
-
45
- max_num_csvs = -1
46
-
47
- db_sampling_scheme = 'preview' # 'labeled','all'
48
- n_unlabeled_to_sample = -1
49
- cap_unlabeled_to_labeled = True
50
-
51
-
52
- #%% Read and concatenate source data
53
-
54
- # List files
55
- input_files = os.listdir(input_base)
56
-
57
- # List of dataframes, one per .csv file; we'll concatenate later
58
- all_input_metadata = []
59
-
60
- # i_file = 87; fn = input_files[i_file]
61
- for i_file,fn in enumerate(input_files):
62
-
63
- if max_num_csvs > 0 and len(all_input_metadata) >= max_num_csvs:
64
- break
65
-
66
- if not fn.endswith('.csv'):
67
- continue
68
- if not fn.startswith(csv_prefix):
69
- continue
70
- dirname = fn.replace(csv_prefix,'').replace('.csv','')
71
- dirfullpath = os.path.join(input_base,dirname)
72
- if not os.path.isdir(dirfullpath):
73
- dirname = fn.replace(csv_prefix,'').replace('.csv','').replace(' ',' ')
74
- dirfullpath = os.path.join(input_base,dirname)
75
- assert(os.path.isdir(dirfullpath))
76
-
77
- metadata_fullpath = os.path.join(input_base,fn)
78
- print('Reading {}'.format(metadata_fullpath))
79
- df = pd.read_csv(metadata_fullpath)
80
- assert list(df.columns) == expected_columns
81
- df['DirName'] = dirname
82
- all_input_metadata.append(df)
83
-
84
- # Concatenate into a giant data frame
85
- input_metadata = pd.concat(all_input_metadata)
86
-
87
- print('Read {} rows total'.format(len(input_metadata)))
88
-
89
-
90
- #%% List files
91
-
92
- print('Listing images...')
93
- image_full_paths = path_utils.find_images(input_base,bRecursive=True)
94
- print('Finished listing {} images'.format(len(image_full_paths)))
95
-
96
- image_relative_paths = []
97
- for s in image_full_paths:
98
- image_relative_paths.append(os.path.relpath(s,input_base))
99
- image_relative_paths = set(image_relative_paths)
100
-
101
- image_relative_paths_lower = set()
102
- for s in image_relative_paths:
103
- image_relative_paths_lower.add(s.lower())
104
-
105
-
106
- #%% Main loop over labels (prep)
107
-
108
- start_time = time.time()
109
-
110
- relative_path_to_image = {}
111
-
112
- images = []
113
- annotations = []
114
- category_name_to_category = {}
115
- missing_files = []
116
-
117
- # Force the empty category to be ID 0
118
- empty_category = {}
119
- empty_category['name'] = 'empty'
120
- empty_category['id'] = 0
121
- category_name_to_category['empty'] = empty_category
122
- next_category_id = 1
123
-
124
- labeled_images = []
125
- unlabeled_images = []
126
-
127
-
128
- #%% Main loop over labels (loop)
129
-
130
- # iRow = 0; row = input_metadata.iloc[iRow]
131
- for iRow,row in tqdm(input_metadata.iterrows(),total=len(input_metadata)):
132
-
133
- # ImageID,FileName,FilePath,SpeciesID,CommonName
134
- image_id = str(uuid.uuid1())
135
- relative_path = os.path.normpath(row['ImageName'])
136
-
137
- if relative_path not in image_relative_paths:
138
- if relative_path.lower() in image_relative_paths_lower:
139
- print('Warning: lower-case version of {} in path list'.format(relative_path))
140
- else:
141
- missing_files.append(relative_path)
142
- continue
143
-
144
- full_path = os.path.join(input_base,relative_path)
145
-
146
- # assert os.path.isfile(full_path)
147
-
148
- if relative_path in relative_path_to_image:
149
-
150
- im = relative_path_to_image[relative_path]
151
-
152
- else:
153
-
154
- im = {}
155
- im['id'] = image_id
156
- im['file_name'] = relative_path
157
- im['seq_id'] = '-1'
158
- im['location'] = row['Location']
159
- im['datetime'] = row['DateImage'] + ' ' + row['TimeImage']
160
-
161
- images.append(im)
162
- relative_path_to_image[relative_path] = im
163
-
164
- if retrieve_image_sizes:
165
-
166
- # Retrieve image width and height
167
- pil_im = PIL.Image.open(full_path)
168
- width, height = pil_im.size
169
- im['width'] = width
170
- im['height'] = height
171
-
172
- species = row['Species']
173
- if isinstance(species,float):
174
- assert np.isnan(species)
175
- species = 'unlabeled'
176
-
177
- category_name = species.lower().strip()
178
- if category_name in category_mappings:
179
- category_name = category_mappings[category_name]
180
-
181
- if category_name not in category_name_to_category:
182
- category = {}
183
- category['name'] = category_name
184
- category['id'] = next_category_id
185
- next_category_id += 1
186
- category_name_to_category[category_name] = category
187
- else:
188
- category = category_name_to_category[category_name]
189
- assert category['name'] == category_name
190
-
191
- category_id = category['id']
192
-
193
- if category_name == 'unlabeled':
194
- unlabeled_images.append(im)
195
- else:
196
- labeled_images.append(im)
197
-
198
- # Create an annotation
199
- ann = {}
200
-
201
- # The Internet tells me this guarantees uniqueness to a reasonable extent, even
202
- # beyond the sheer improbability of collisions.
203
- ann['id'] = str(uuid.uuid1())
204
- ann['image_id'] = im['id']
205
- ann['category_id'] = category_id
206
-
207
- for col in columns_to_copy:
208
- ann[columns_to_copy[col]] = row[col]
209
-
210
- annotations.append(ann)
211
-
212
- # ...for each image
213
-
214
- categories = list(category_name_to_category.values())
215
-
216
- elapsed = time.time() - start_time
217
- print('Finished verifying file loop in {}, {} matched images, {} missing images, {} unlabeled images'.format(
218
- humanfriendly.format_timespan(elapsed), len(images), len(missing_files), len(unlabeled_images)))
219
-
220
-
221
- #%% See what's up with missing files
222
-
223
- dirnames = set()
224
- # s = list(image_relative_paths)[0]
225
- for s in image_relative_paths:
226
- image_dir = os.path.dirname(s)
227
- dirnames.add(image_dir)
228
-
229
- missing_images_with_missing_dirs = []
230
- missing_images_with_non_missing_dirs = []
231
-
232
- missing_dirs = set()
233
-
234
- # s = missing_files[0]
235
- for s in missing_files:
236
- assert s not in image_relative_paths
237
- dirname = os.path.dirname(s)
238
- if dirname not in dirnames:
239
- missing_images_with_missing_dirs.append(s)
240
- missing_dirs.add(dirname)
241
- else:
242
- missing_images_with_non_missing_dirs.append(s)
243
-
244
- print('Of {} missing files, {} are due to {} missing folders'.format(
245
- len(missing_files),len(missing_images_with_missing_dirs),len(missing_dirs)))
246
-
247
-
248
- #%% Check for images that aren't included in the metadata file
249
-
250
- unmatched_files = []
251
-
252
- for i_image,relative_path in tqdm(enumerate(image_relative_paths),total=len(image_relative_paths)):
253
-
254
- if relative_path not in relative_path_to_image:
255
- unmatched_files.append(relative_path)
256
-
257
- print('Finished checking {} images to make sure they\'re in the metadata, found {} mismatches'.format(
258
- len(image_relative_paths),len(unmatched_files)))
259
-
260
-
261
- #%% Sample the database
262
-
263
- images_all = images
264
- annotations_all = annotations
265
-
266
- #%%
267
-
268
- if db_sampling_scheme == 'all':
269
-
270
- pass
271
-
272
- elif db_sampling_scheme == 'labeled' or db_sampling_scheme == 'preview':
273
-
274
- json_data = {}
275
- json_data['images'] = images
276
- json_data['annotations'] = annotations
277
- json_data['categories'] = categories
278
-
279
- indexed_db = IndexedJsonDb(json_data)
280
-
281
- # Collect the images we want
282
- sampled_images = []
283
- for im in images:
284
- classes = indexed_db.get_classes_for_image(im)
285
- if 'unlabeled' in classes and len(classes) == 1:
286
- pass
287
- else:
288
- sampled_images.append(im)
289
-
290
- if db_sampling_scheme == 'preview':
291
- n_sample = n_unlabeled_to_sample
292
- if n_sample == -1:
293
- n_sample = len(labeled_images)
294
- if n_sample > len(labeled_images) and cap_unlabeled_to_labeled:
295
- n_sample = len(labeled_images)
296
- if n_sample > len(unlabeled_images):
297
- n_sample = len(unlabeled_images)
298
- print('Sampling {} of {} unlabeled images'.format(n_sample,len(unlabeled_images)))
299
- from random import sample
300
- sampled_images.extend(sample(unlabeled_images,n_sample))
301
-
302
- sampled_annotations = []
303
- for im in sampled_images:
304
- sampled_annotations.extend(indexed_db.get_annotations_for_image(im))
305
-
306
- print('Sampling {} of {} images, {} of {} annotations'.format(
307
- len(sampled_images),len(images),len(sampled_annotations),len(annotations)))
308
-
309
- images = sampled_images
310
- annotations = sampled_annotations
311
-
312
- else:
313
-
314
- raise ValueError('Unrecognized DB sampling scheme {}'.format(db_sampling_scheme))
315
-
316
-
317
- #%% Create info struct
318
-
319
- info = {}
320
- info['year'] = 2019
321
- info['version'] = 1
322
- info['description'] = 'COCO style database'
323
- info['secondary_contributor'] = 'Converted to COCO .json by Dan Morris'
324
- info['contributor'] = 'Parks Canada'
325
-
326
-
327
- #%% Write output
328
-
329
- json_data = {}
330
- json_data['images'] = images
331
- json_data['annotations'] = annotations
332
- json_data['categories'] = categories
333
- json_data['info'] = info
334
- json.dump(json_data, open(output_file,'w'), indent=4)
335
-
336
- print('Finished writing .json file with {} images, {} annotations, and {} categories'.format(
337
- len(images),len(annotations),len(categories)))
338
-
339
-
340
- #%% Validate the database's integrity
341
-
342
- json_data = json.load(open(output_file))
343
- options = integrity_check_json_db.IntegrityCheckOptions()
344
- sortedCategories,data = integrity_check_json_db.integrity_check_json_db(json_data, options)
345
-
346
-
347
- #%% Render a bunch of images to make sure the labels got carried along correctly
348
-
349
- output_dir = preview_base
350
-
351
- options = visualize_db.DbVizOptions()
352
- options.num_to_visualize = 100
353
- options.sort_by_filename = False
354
- # options.classes_to_exclude = ['unlabeled']
355
- options.classes_to_exclude = None
356
-
357
- htmlOutputFile,_ = visualize_db.visualize_db(json_data,output_dir,input_base,options)
358
- os.startfile(htmlOutputFile)
359
-
360
-
361
- #%% Write out a list of files to annotate
362
-
363
- _,file_list = cct_json_to_filename_json.convertJsonToStringList(output_file,prepend="20190715/")
364
- os.startfile(file_list)
365
-
@@ -1,123 +0,0 @@
1
- """
2
-
3
- plot_wni_giraffes.py
4
-
5
- Plot keypoints on a random sample of images from the wni-giraffes data set.
6
-
7
- """
8
-
9
- #%% Constants and imports
10
-
11
- import os
12
- import json
13
- import random
14
-
15
- from PIL import Image
16
- from PIL import ImageDraw
17
- from tqdm import tqdm
18
-
19
- input_file = r"G:\data_staging\wni-out\wni_giraffes_train.json"
20
- image_base = r"G:\data_staging\wni-out\images"
21
- output_base = r"G:\data_staging\wni-out\test-plots"
22
- os.makedirs(output_base,exist_ok=True)
23
-
24
- tool_colors = ['red','green','blue','magenta']
25
- use_fancy_ellipses = True
26
- draw_individual_samples = False
27
-
28
- median_radius = 20
29
- median_linewidth = 8
30
-
31
- sample_radius = 10
32
-
33
- n_images_to_plot = 100
34
-
35
-
36
- #%% Load and select data
37
-
38
- with open(input_file,'r') as f:
39
- d = json.load(f)
40
- annotations = d['annotations']
41
- print(d['info'])
42
-
43
- short_tool_names = list(d['info']['tool_names'].keys())
44
- annotations_to_plot = random.sample(annotations,n_images_to_plot)
45
-
46
-
47
- #%% Support functions
48
-
49
- # https://stackoverflow.com/questions/32504246/draw-ellipse-in-python-pil-with-line-thickness
50
- def draw_fancy_ellipse(image, x, y, radius, width=1, outline='white', antialias=4):
51
-
52
- bounds = (x-radius,y-radius,x+radius,y+radius)
53
-
54
- # Use a single channel image (mode='L') as mask.
55
- # The size of the mask can be increased relative to the input image
56
- # to get smoother looking results.
57
- mask = Image.new(
58
- size=[int(dim * antialias) for dim in image.size],
59
- mode='L', color='black')
60
- draw = ImageDraw.Draw(mask)
61
-
62
- # draw outer shape in white (color) and inner shape in black (transparent)
63
- for offset, fill in (width/-2.0, 'white'), (width/2.0, 'black'):
64
- left, top = [(value + offset) * antialias for value in bounds[:2]]
65
- right, bottom = [(value - offset) * antialias for value in bounds[2:]]
66
- draw.ellipse([left, top, right, bottom], fill=fill)
67
-
68
- # downsample the mask using PIL.Image.LANCZOS
69
- # (a high-quality downsampling filter).
70
- mask = mask.resize(image.size, Image.LANCZOS)
71
-
72
- # paste outline color to input image through the mask
73
- image.paste(outline, mask=mask)
74
-
75
-
76
- def draw_ellipse(image, x, y, radius, linewidth, color_index, use_imagedraw=False):
77
-
78
- if use_imagedraw:
79
- draw_fancy_ellipse(image, x, y, radius=radius, width=linewidth, outline=tool_colors[color_index])
80
- else:
81
- draw = ImageDraw.Draw(image)
82
- bounds = (x-radius,y-radius,x+radius,y+radius)
83
- draw.ellipse(bounds, fill=tool_colors[color_index])
84
-
85
-
86
- #%% Plot some images
87
-
88
- # ann = annotations_to_plot[0]
89
- for ann in tqdm(annotations_to_plot):
90
-
91
- input_path = os.path.join(image_base,ann['filename'])
92
- output_path = os.path.join(output_base,ann['filename'].replace('/','_'))
93
-
94
- im = None
95
- im = Image.open(input_path)
96
-
97
- # i_tool = 0; tool_name = short_tool_names[i_tool]
98
- for i_tool,tool_name in enumerate(short_tool_names):
99
-
100
- tool_keypoints = ann['keypoints'][tool_name]
101
-
102
- # Don't plot tools that don't have a consensus annotation
103
- if tool_keypoints['median_x'] is None:
104
- continue
105
-
106
- median_x = tool_keypoints['median_x']
107
- median_y = tool_keypoints['median_y']
108
-
109
- draw_ellipse(im, median_x, median_y, median_radius, median_linewidth, color_index=i_tool,
110
- use_imagedraw=use_fancy_ellipses)
111
-
112
- if draw_individual_samples:
113
- for i_sample in range(0,len(tool_keypoints['x'])):
114
- x = tool_keypoints['x'][i_sample]
115
- y = tool_keypoints['y'][i_sample]
116
- draw_ellipse(im, x, y, sample_radius, None, color_index=i_tool,
117
- use_imagedraw=False)
118
-
119
- # ...for each tool
120
-
121
- im.save(output_path)
122
-
123
- # ...for each annotation
@@ -1,131 +0,0 @@
1
- """
2
-
3
- prepare_zsl_imerit.py
4
-
5
- Prepare ZSL Borneo data for annotation (convert input data to iMerit-friendly format).
6
-
7
- """
8
-
9
- #%% Imports and constants
10
-
11
- import json
12
- import os
13
-
14
- from tqdm import tqdm
15
- from operator import itemgetter
16
- from shutil import copyfile
17
-
18
- from megadetector.visualization import visualize_db
19
- from megadetector.data_management.databases import integrity_check_json_db
20
- from megadetector.data_management.cct_json_utils import IndexedJsonDb
21
-
22
- annotation_list_filename = r'd:\wildlife_data\zsl_borneo\all_img_ids_to_bbox.json'
23
- image_json = r'd:\wildlife_data\zsl_borneo\201906cameratraps\0.5\zsl_camera_traps_201906.json'
24
- image_base = r'd:\wildlife_data\zsl_borneo\201906cameratraps\0.5'
25
- output_base = r'd:\wildlife_data\zsl_borneo'
26
-
27
- human_classes = ['human','hunter']
28
-
29
-
30
- #%% Load data
31
-
32
- with open(annotation_list_filename,'r') as f:
33
- annotation_list = json.load(f)
34
-
35
- # with open(image_json,'r') as f:
36
- # data = json.load(f)
37
- indexedData = IndexedJsonDb(image_json)
38
-
39
- print('Done loading data')
40
-
41
-
42
- #%% Validate data
43
-
44
- options = integrity_check_json_db.IntegrityCheckOptions()
45
- options.baseDir = image_base
46
- options.bCheckImageSizes = False
47
- options.bCheckImageExistence = True
48
- options.bFindUnusedImages = False
49
-
50
- sortedCategories = integrity_check_json_db.integrity_check_json_db(indexedData.db,options)
51
-
52
-
53
- #%% Label previews
54
-
55
- viz_options = visualize_db.DbVizOptions()
56
- viz_options.num_to_visualize = 500
57
- viz_options.trim_to_images_with_bboxes = False
58
- viz_options.add_search_links = True
59
- viz_options.sort_by_filename = False
60
- html_output_file,image_db = visualize_db.visualize_db(indexedData.db,
61
- os.path.join(output_base,'preview'),
62
- image_base,viz_options)
63
- os.startfile(html_output_file)
64
-
65
-
66
- #%% Collect images to annotate
67
-
68
- images_to_annotate = []
69
-
70
- annotation_list = set(annotation_list)
71
- n_humans = 0
72
-
73
- for im in tqdm(indexedData.db['images']):
74
-
75
- class_names = indexedData.get_classes_for_image(im)
76
- b_human = False
77
- for cn in class_names:
78
- if cn.lower() in human_classes:
79
- b_human = True
80
- n_humans += 1
81
- break
82
-
83
- if b_human or im['id'] in annotation_list:
84
- images_to_annotate.append(im)
85
-
86
-
87
- print('Found {} of {} images ({} humans)'.format(len(images_to_annotate),len(annotation_list),n_humans))
88
- assert len(images_to_annotate) >= len(annotation_list)
89
-
90
-
91
-
92
- #%% Sort by sequence and frame
93
-
94
- images_to_annotate = sorted(images_to_annotate, key=itemgetter('seq_id', 'frame_num'))
95
-
96
-
97
- #%% Copy to a folder by GUID
98
-
99
- # dataset[dataset_id].seq[sequence_id].frame[frame_number].img[img_id].extension
100
-
101
- imerit_output_base = os.path.join(output_base,'imerit_batch_9')
102
- os.makedirs(imerit_output_base,exist_ok=True)
103
-
104
- # im = images_to_annotate[0]
105
- for im in tqdm(images_to_annotate):
106
-
107
- relative_path = im['file_name']
108
- extension = os.path.splitext(relative_path)[1]
109
- frame_num = im['frame_num']
110
- seq_id = im['seq_id']
111
- id = im['id']
112
- assert '.' not in id
113
- input_full_path = os.path.join(image_base,relative_path)
114
- assert os.path.isfile(input_full_path)
115
- output_filename = 'datasetzslborneo.seq' + '{0:0>8d}'.format(seq_id) + '.frame' + \
116
- '{0:0>4d}'.format(frame_num) + '.img' + id + extension
117
- im['imerit_filename'] = output_filename
118
- output_full_path = os.path.join(imerit_output_base,output_filename)
119
- assert not os.path.isfile(output_full_path)
120
- copyfile(input_full_path,output_full_path)
121
-
122
- # ...for each image
123
-
124
-
125
- #%% Write out the annotation list
126
-
127
- imerit_batch9_json_filename = os.path.join(imerit_output_base,'imerit_batch_9.json')
128
- with open(imerit_batch9_json_filename,'w') as f:
129
- json.dump(images_to_annotate, f, indent=2)
130
-
131
-