megadetector 5.0.28__py3-none-any.whl → 10.0.0__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 (197) hide show
  1. megadetector/api/batch_processing/integration/digiKam/xmp_integration.py +2 -2
  2. megadetector/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +1 -1
  3. megadetector/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +1 -1
  4. megadetector/classification/aggregate_classifier_probs.py +3 -3
  5. megadetector/classification/analyze_failed_images.py +5 -5
  6. megadetector/classification/cache_batchapi_outputs.py +5 -5
  7. megadetector/classification/create_classification_dataset.py +11 -12
  8. megadetector/classification/crop_detections.py +10 -10
  9. megadetector/classification/csv_to_json.py +8 -8
  10. megadetector/classification/detect_and_crop.py +13 -15
  11. megadetector/classification/efficientnet/model.py +8 -8
  12. megadetector/classification/efficientnet/utils.py +6 -5
  13. megadetector/classification/evaluate_model.py +7 -7
  14. megadetector/classification/identify_mislabeled_candidates.py +6 -6
  15. megadetector/classification/json_to_azcopy_list.py +1 -1
  16. megadetector/classification/json_validator.py +29 -32
  17. megadetector/classification/map_classification_categories.py +9 -9
  18. megadetector/classification/merge_classification_detection_output.py +12 -9
  19. megadetector/classification/prepare_classification_script.py +19 -19
  20. megadetector/classification/prepare_classification_script_mc.py +26 -26
  21. megadetector/classification/run_classifier.py +4 -4
  22. megadetector/classification/save_mislabeled.py +6 -6
  23. megadetector/classification/train_classifier.py +1 -1
  24. megadetector/classification/train_classifier_tf.py +9 -9
  25. megadetector/classification/train_utils.py +10 -10
  26. megadetector/data_management/annotations/annotation_constants.py +1 -2
  27. megadetector/data_management/camtrap_dp_to_coco.py +79 -46
  28. megadetector/data_management/cct_json_utils.py +103 -103
  29. megadetector/data_management/cct_to_md.py +49 -49
  30. megadetector/data_management/cct_to_wi.py +33 -33
  31. megadetector/data_management/coco_to_labelme.py +75 -75
  32. megadetector/data_management/coco_to_yolo.py +210 -193
  33. megadetector/data_management/databases/add_width_and_height_to_db.py +86 -12
  34. megadetector/data_management/databases/combine_coco_camera_traps_files.py +40 -40
  35. megadetector/data_management/databases/integrity_check_json_db.py +228 -200
  36. megadetector/data_management/databases/subset_json_db.py +33 -33
  37. megadetector/data_management/generate_crops_from_cct.py +88 -39
  38. megadetector/data_management/get_image_sizes.py +54 -49
  39. megadetector/data_management/labelme_to_coco.py +133 -125
  40. megadetector/data_management/labelme_to_yolo.py +159 -73
  41. megadetector/data_management/lila/create_lila_blank_set.py +81 -83
  42. megadetector/data_management/lila/create_lila_test_set.py +32 -31
  43. megadetector/data_management/lila/create_links_to_md_results_files.py +18 -18
  44. megadetector/data_management/lila/download_lila_subset.py +21 -24
  45. megadetector/data_management/lila/generate_lila_per_image_labels.py +365 -107
  46. megadetector/data_management/lila/get_lila_annotation_counts.py +35 -33
  47. megadetector/data_management/lila/get_lila_image_counts.py +22 -22
  48. megadetector/data_management/lila/lila_common.py +73 -70
  49. megadetector/data_management/lila/test_lila_metadata_urls.py +28 -19
  50. megadetector/data_management/mewc_to_md.py +344 -340
  51. megadetector/data_management/ocr_tools.py +262 -255
  52. megadetector/data_management/read_exif.py +249 -227
  53. megadetector/data_management/remap_coco_categories.py +90 -28
  54. megadetector/data_management/remove_exif.py +81 -21
  55. megadetector/data_management/rename_images.py +187 -187
  56. megadetector/data_management/resize_coco_dataset.py +588 -120
  57. megadetector/data_management/speciesnet_to_md.py +41 -41
  58. megadetector/data_management/wi_download_csv_to_coco.py +55 -55
  59. megadetector/data_management/yolo_output_to_md_output.py +248 -122
  60. megadetector/data_management/yolo_to_coco.py +333 -191
  61. megadetector/detection/change_detection.py +832 -0
  62. megadetector/detection/process_video.py +340 -337
  63. megadetector/detection/pytorch_detector.py +358 -278
  64. megadetector/detection/run_detector.py +399 -186
  65. megadetector/detection/run_detector_batch.py +404 -377
  66. megadetector/detection/run_inference_with_yolov5_val.py +340 -327
  67. megadetector/detection/run_tiled_inference.py +257 -249
  68. megadetector/detection/tf_detector.py +24 -24
  69. megadetector/detection/video_utils.py +332 -295
  70. megadetector/postprocessing/add_max_conf.py +19 -11
  71. megadetector/postprocessing/categorize_detections_by_size.py +45 -45
  72. megadetector/postprocessing/classification_postprocessing.py +468 -433
  73. megadetector/postprocessing/combine_batch_outputs.py +23 -23
  74. megadetector/postprocessing/compare_batch_results.py +590 -525
  75. megadetector/postprocessing/convert_output_format.py +106 -102
  76. megadetector/postprocessing/create_crop_folder.py +347 -147
  77. megadetector/postprocessing/detector_calibration.py +173 -168
  78. megadetector/postprocessing/generate_csv_report.py +508 -499
  79. megadetector/postprocessing/load_api_results.py +48 -27
  80. megadetector/postprocessing/md_to_coco.py +133 -102
  81. megadetector/postprocessing/md_to_labelme.py +107 -90
  82. megadetector/postprocessing/md_to_wi.py +40 -40
  83. megadetector/postprocessing/merge_detections.py +92 -114
  84. megadetector/postprocessing/postprocess_batch_results.py +319 -301
  85. megadetector/postprocessing/remap_detection_categories.py +91 -38
  86. megadetector/postprocessing/render_detection_confusion_matrix.py +214 -205
  87. megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py +57 -57
  88. megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +27 -28
  89. megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +704 -679
  90. megadetector/postprocessing/separate_detections_into_folders.py +226 -211
  91. megadetector/postprocessing/subset_json_detector_output.py +265 -262
  92. megadetector/postprocessing/top_folders_to_bottom.py +45 -45
  93. megadetector/postprocessing/validate_batch_results.py +70 -70
  94. megadetector/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +52 -52
  95. megadetector/taxonomy_mapping/map_new_lila_datasets.py +18 -19
  96. megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +54 -33
  97. megadetector/taxonomy_mapping/preview_lila_taxonomy.py +67 -67
  98. megadetector/taxonomy_mapping/retrieve_sample_image.py +16 -16
  99. megadetector/taxonomy_mapping/simple_image_download.py +8 -8
  100. megadetector/taxonomy_mapping/species_lookup.py +156 -74
  101. megadetector/taxonomy_mapping/taxonomy_csv_checker.py +14 -14
  102. megadetector/taxonomy_mapping/taxonomy_graph.py +10 -10
  103. megadetector/taxonomy_mapping/validate_lila_category_mappings.py +13 -13
  104. megadetector/utils/ct_utils.py +1049 -211
  105. megadetector/utils/directory_listing.py +21 -77
  106. megadetector/utils/gpu_test.py +22 -22
  107. megadetector/utils/md_tests.py +632 -529
  108. megadetector/utils/path_utils.py +1520 -431
  109. megadetector/utils/process_utils.py +41 -41
  110. megadetector/utils/split_locations_into_train_val.py +62 -62
  111. megadetector/utils/string_utils.py +148 -27
  112. megadetector/utils/url_utils.py +489 -176
  113. megadetector/utils/wi_utils.py +2658 -2526
  114. megadetector/utils/write_html_image_list.py +137 -137
  115. megadetector/visualization/plot_utils.py +34 -30
  116. megadetector/visualization/render_images_with_thumbnails.py +39 -74
  117. megadetector/visualization/visualization_utils.py +487 -435
  118. megadetector/visualization/visualize_db.py +232 -198
  119. megadetector/visualization/visualize_detector_output.py +82 -76
  120. {megadetector-5.0.28.dist-info → megadetector-10.0.0.dist-info}/METADATA +5 -2
  121. megadetector-10.0.0.dist-info/RECORD +139 -0
  122. {megadetector-5.0.28.dist-info → megadetector-10.0.0.dist-info}/WHEEL +1 -1
  123. megadetector/api/batch_processing/api_core/__init__.py +0 -0
  124. megadetector/api/batch_processing/api_core/batch_service/__init__.py +0 -0
  125. megadetector/api/batch_processing/api_core/batch_service/score.py +0 -439
  126. megadetector/api/batch_processing/api_core/server.py +0 -294
  127. megadetector/api/batch_processing/api_core/server_api_config.py +0 -97
  128. megadetector/api/batch_processing/api_core/server_app_config.py +0 -55
  129. megadetector/api/batch_processing/api_core/server_batch_job_manager.py +0 -220
  130. megadetector/api/batch_processing/api_core/server_job_status_table.py +0 -149
  131. megadetector/api/batch_processing/api_core/server_orchestration.py +0 -360
  132. megadetector/api/batch_processing/api_core/server_utils.py +0 -88
  133. megadetector/api/batch_processing/api_core_support/__init__.py +0 -0
  134. megadetector/api/batch_processing/api_core_support/aggregate_results_manually.py +0 -46
  135. megadetector/api/batch_processing/api_support/__init__.py +0 -0
  136. megadetector/api/batch_processing/api_support/summarize_daily_activity.py +0 -152
  137. megadetector/api/batch_processing/data_preparation/__init__.py +0 -0
  138. megadetector/api/synchronous/__init__.py +0 -0
  139. megadetector/api/synchronous/api_core/animal_detection_api/__init__.py +0 -0
  140. megadetector/api/synchronous/api_core/animal_detection_api/api_backend.py +0 -151
  141. megadetector/api/synchronous/api_core/animal_detection_api/api_frontend.py +0 -263
  142. megadetector/api/synchronous/api_core/animal_detection_api/config.py +0 -35
  143. megadetector/api/synchronous/api_core/tests/__init__.py +0 -0
  144. megadetector/api/synchronous/api_core/tests/load_test.py +0 -110
  145. megadetector/data_management/importers/add_nacti_sizes.py +0 -52
  146. megadetector/data_management/importers/add_timestamps_to_icct.py +0 -79
  147. megadetector/data_management/importers/animl_results_to_md_results.py +0 -158
  148. megadetector/data_management/importers/auckland_doc_test_to_json.py +0 -373
  149. megadetector/data_management/importers/auckland_doc_to_json.py +0 -201
  150. megadetector/data_management/importers/awc_to_json.py +0 -191
  151. megadetector/data_management/importers/bellevue_to_json.py +0 -272
  152. megadetector/data_management/importers/cacophony-thermal-importer.py +0 -793
  153. megadetector/data_management/importers/carrizo_shrubfree_2018.py +0 -269
  154. megadetector/data_management/importers/carrizo_trail_cam_2017.py +0 -289
  155. megadetector/data_management/importers/cct_field_adjustments.py +0 -58
  156. megadetector/data_management/importers/channel_islands_to_cct.py +0 -913
  157. megadetector/data_management/importers/eMammal/copy_and_unzip_emammal.py +0 -180
  158. megadetector/data_management/importers/eMammal/eMammal_helpers.py +0 -249
  159. megadetector/data_management/importers/eMammal/make_eMammal_json.py +0 -223
  160. megadetector/data_management/importers/ena24_to_json.py +0 -276
  161. megadetector/data_management/importers/filenames_to_json.py +0 -386
  162. megadetector/data_management/importers/helena_to_cct.py +0 -283
  163. megadetector/data_management/importers/idaho-camera-traps.py +0 -1407
  164. megadetector/data_management/importers/idfg_iwildcam_lila_prep.py +0 -294
  165. megadetector/data_management/importers/import_desert_lion_conservation_camera_traps.py +0 -387
  166. megadetector/data_management/importers/jb_csv_to_json.py +0 -150
  167. megadetector/data_management/importers/mcgill_to_json.py +0 -250
  168. megadetector/data_management/importers/missouri_to_json.py +0 -490
  169. megadetector/data_management/importers/nacti_fieldname_adjustments.py +0 -79
  170. megadetector/data_management/importers/noaa_seals_2019.py +0 -181
  171. megadetector/data_management/importers/osu-small-animals-to-json.py +0 -364
  172. megadetector/data_management/importers/pc_to_json.py +0 -365
  173. megadetector/data_management/importers/plot_wni_giraffes.py +0 -123
  174. megadetector/data_management/importers/prepare_zsl_imerit.py +0 -131
  175. megadetector/data_management/importers/raic_csv_to_md_results.py +0 -416
  176. megadetector/data_management/importers/rspb_to_json.py +0 -356
  177. megadetector/data_management/importers/save_the_elephants_survey_A.py +0 -320
  178. megadetector/data_management/importers/save_the_elephants_survey_B.py +0 -329
  179. megadetector/data_management/importers/snapshot_safari_importer.py +0 -758
  180. megadetector/data_management/importers/snapshot_serengeti_lila.py +0 -1067
  181. megadetector/data_management/importers/snapshotserengeti/make_full_SS_json.py +0 -150
  182. megadetector/data_management/importers/snapshotserengeti/make_per_season_SS_json.py +0 -153
  183. megadetector/data_management/importers/sulross_get_exif.py +0 -65
  184. megadetector/data_management/importers/timelapse_csv_set_to_json.py +0 -490
  185. megadetector/data_management/importers/ubc_to_json.py +0 -399
  186. megadetector/data_management/importers/umn_to_json.py +0 -507
  187. megadetector/data_management/importers/wellington_to_json.py +0 -263
  188. megadetector/data_management/importers/wi_to_json.py +0 -442
  189. megadetector/data_management/importers/zamba_results_to_md_results.py +0 -180
  190. megadetector/data_management/lila/add_locations_to_island_camera_traps.py +0 -101
  191. megadetector/data_management/lila/add_locations_to_nacti.py +0 -151
  192. megadetector/utils/azure_utils.py +0 -178
  193. megadetector/utils/sas_blob_utils.py +0 -509
  194. megadetector-5.0.28.dist-info/RECORD +0 -209
  195. /megadetector/{api/batch_processing/__init__.py → __init__.py} +0 -0
  196. {megadetector-5.0.28.dist-info → megadetector-10.0.0.dist-info}/licenses/LICENSE +0 -0
  197. {megadetector-5.0.28.dist-info → megadetector-10.0.0.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
-