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

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

Potentially problematic release.


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

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 +231 -224
  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 +340 -337
  65. megadetector/detection/pytorch_detector.py +304 -262
  66. megadetector/detection/run_detector.py +177 -164
  67. megadetector/detection/run_detector_batch.py +364 -363
  68. megadetector/detection/run_inference_with_yolov5_val.py +328 -325
  69. megadetector/detection/run_tiled_inference.py +256 -249
  70. megadetector/detection/tf_detector.py +24 -24
  71. megadetector/detection/video_utils.py +290 -282
  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 +415 -415
  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 +219 -146
  79. megadetector/postprocessing/detector_calibration.py +173 -168
  80. megadetector/postprocessing/generate_csv_report.py +508 -499
  81. megadetector/postprocessing/load_api_results.py +23 -20
  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 +313 -298
  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 -66
  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 +10 -10
  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 +1018 -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 +1457 -398
  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 +61 -61
  115. megadetector/utils/string_utils.py +147 -26
  116. megadetector/utils/url_utils.py +463 -173
  117. megadetector/utils/wi_utils.py +2629 -2526
  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 +401 -397
  122. megadetector/visualization/visualize_db.py +197 -190
  123. megadetector/visualization/visualize_detector_output.py +79 -73
  124. {megadetector-5.0.28.dist-info → megadetector-5.0.29.dist-info}/METADATA +135 -132
  125. megadetector-5.0.29.dist-info/RECORD +163 -0
  126. {megadetector-5.0.28.dist-info → megadetector-5.0.29.dist-info}/WHEEL +1 -1
  127. {megadetector-5.0.28.dist-info → megadetector-5.0.29.dist-info}/licenses/LICENSE +0 -0
  128. {megadetector-5.0.28.dist-info → megadetector-5.0.29.dist-info}/top_level.txt +0 -0
  129. megadetector/data_management/importers/add_nacti_sizes.py +0 -52
  130. megadetector/data_management/importers/add_timestamps_to_icct.py +0 -79
  131. megadetector/data_management/importers/animl_results_to_md_results.py +0 -158
  132. megadetector/data_management/importers/auckland_doc_test_to_json.py +0 -373
  133. megadetector/data_management/importers/auckland_doc_to_json.py +0 -201
  134. megadetector/data_management/importers/awc_to_json.py +0 -191
  135. megadetector/data_management/importers/bellevue_to_json.py +0 -272
  136. megadetector/data_management/importers/cacophony-thermal-importer.py +0 -793
  137. megadetector/data_management/importers/carrizo_shrubfree_2018.py +0 -269
  138. megadetector/data_management/importers/carrizo_trail_cam_2017.py +0 -289
  139. megadetector/data_management/importers/cct_field_adjustments.py +0 -58
  140. megadetector/data_management/importers/channel_islands_to_cct.py +0 -913
  141. megadetector/data_management/importers/eMammal/copy_and_unzip_emammal.py +0 -180
  142. megadetector/data_management/importers/eMammal/eMammal_helpers.py +0 -249
  143. megadetector/data_management/importers/eMammal/make_eMammal_json.py +0 -223
  144. megadetector/data_management/importers/ena24_to_json.py +0 -276
  145. megadetector/data_management/importers/filenames_to_json.py +0 -386
  146. megadetector/data_management/importers/helena_to_cct.py +0 -283
  147. megadetector/data_management/importers/idaho-camera-traps.py +0 -1407
  148. megadetector/data_management/importers/idfg_iwildcam_lila_prep.py +0 -294
  149. megadetector/data_management/importers/import_desert_lion_conservation_camera_traps.py +0 -387
  150. megadetector/data_management/importers/jb_csv_to_json.py +0 -150
  151. megadetector/data_management/importers/mcgill_to_json.py +0 -250
  152. megadetector/data_management/importers/missouri_to_json.py +0 -490
  153. megadetector/data_management/importers/nacti_fieldname_adjustments.py +0 -79
  154. megadetector/data_management/importers/noaa_seals_2019.py +0 -181
  155. megadetector/data_management/importers/osu-small-animals-to-json.py +0 -364
  156. megadetector/data_management/importers/pc_to_json.py +0 -365
  157. megadetector/data_management/importers/plot_wni_giraffes.py +0 -123
  158. megadetector/data_management/importers/prepare_zsl_imerit.py +0 -131
  159. megadetector/data_management/importers/raic_csv_to_md_results.py +0 -416
  160. megadetector/data_management/importers/rspb_to_json.py +0 -356
  161. megadetector/data_management/importers/save_the_elephants_survey_A.py +0 -320
  162. megadetector/data_management/importers/save_the_elephants_survey_B.py +0 -329
  163. megadetector/data_management/importers/snapshot_safari_importer.py +0 -758
  164. megadetector/data_management/importers/snapshot_serengeti_lila.py +0 -1067
  165. megadetector/data_management/importers/snapshotserengeti/make_full_SS_json.py +0 -150
  166. megadetector/data_management/importers/snapshotserengeti/make_per_season_SS_json.py +0 -153
  167. megadetector/data_management/importers/sulross_get_exif.py +0 -65
  168. megadetector/data_management/importers/timelapse_csv_set_to_json.py +0 -490
  169. megadetector/data_management/importers/ubc_to_json.py +0 -399
  170. megadetector/data_management/importers/umn_to_json.py +0 -507
  171. megadetector/data_management/importers/wellington_to_json.py +0 -263
  172. megadetector/data_management/importers/wi_to_json.py +0 -442
  173. megadetector/data_management/importers/zamba_results_to_md_results.py +0 -180
  174. megadetector/data_management/lila/add_locations_to_island_camera_traps.py +0 -101
  175. megadetector/data_management/lila/add_locations_to_nacti.py +0 -151
  176. megadetector-5.0.28.dist-info/RECORD +0 -209
@@ -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
-