megadetector 5.0.9__py3-none-any.whl → 5.0.11__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (226) hide show
  1. {megadetector-5.0.9.dist-info → megadetector-5.0.11.dist-info}/LICENSE +0 -0
  2. {megadetector-5.0.9.dist-info → megadetector-5.0.11.dist-info}/METADATA +12 -11
  3. megadetector-5.0.11.dist-info/RECORD +5 -0
  4. megadetector-5.0.11.dist-info/top_level.txt +1 -0
  5. api/__init__.py +0 -0
  6. api/batch_processing/__init__.py +0 -0
  7. api/batch_processing/api_core/__init__.py +0 -0
  8. api/batch_processing/api_core/batch_service/__init__.py +0 -0
  9. api/batch_processing/api_core/batch_service/score.py +0 -439
  10. api/batch_processing/api_core/server.py +0 -294
  11. api/batch_processing/api_core/server_api_config.py +0 -98
  12. api/batch_processing/api_core/server_app_config.py +0 -55
  13. api/batch_processing/api_core/server_batch_job_manager.py +0 -220
  14. api/batch_processing/api_core/server_job_status_table.py +0 -152
  15. api/batch_processing/api_core/server_orchestration.py +0 -360
  16. api/batch_processing/api_core/server_utils.py +0 -92
  17. api/batch_processing/api_core_support/__init__.py +0 -0
  18. api/batch_processing/api_core_support/aggregate_results_manually.py +0 -46
  19. api/batch_processing/api_support/__init__.py +0 -0
  20. api/batch_processing/api_support/summarize_daily_activity.py +0 -152
  21. api/batch_processing/data_preparation/__init__.py +0 -0
  22. api/batch_processing/data_preparation/manage_local_batch.py +0 -2391
  23. api/batch_processing/data_preparation/manage_video_batch.py +0 -327
  24. api/batch_processing/integration/digiKam/setup.py +0 -6
  25. api/batch_processing/integration/digiKam/xmp_integration.py +0 -465
  26. api/batch_processing/integration/eMammal/test_scripts/config_template.py +0 -5
  27. api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +0 -126
  28. api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +0 -55
  29. api/batch_processing/postprocessing/__init__.py +0 -0
  30. api/batch_processing/postprocessing/add_max_conf.py +0 -64
  31. api/batch_processing/postprocessing/categorize_detections_by_size.py +0 -163
  32. api/batch_processing/postprocessing/combine_api_outputs.py +0 -249
  33. api/batch_processing/postprocessing/compare_batch_results.py +0 -958
  34. api/batch_processing/postprocessing/convert_output_format.py +0 -397
  35. api/batch_processing/postprocessing/load_api_results.py +0 -195
  36. api/batch_processing/postprocessing/md_to_coco.py +0 -310
  37. api/batch_processing/postprocessing/md_to_labelme.py +0 -330
  38. api/batch_processing/postprocessing/merge_detections.py +0 -401
  39. api/batch_processing/postprocessing/postprocess_batch_results.py +0 -1904
  40. api/batch_processing/postprocessing/remap_detection_categories.py +0 -170
  41. api/batch_processing/postprocessing/render_detection_confusion_matrix.py +0 -661
  42. api/batch_processing/postprocessing/repeat_detection_elimination/find_repeat_detections.py +0 -211
  43. api/batch_processing/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +0 -82
  44. api/batch_processing/postprocessing/repeat_detection_elimination/repeat_detections_core.py +0 -1631
  45. api/batch_processing/postprocessing/separate_detections_into_folders.py +0 -731
  46. api/batch_processing/postprocessing/subset_json_detector_output.py +0 -696
  47. api/batch_processing/postprocessing/top_folders_to_bottom.py +0 -223
  48. api/synchronous/__init__.py +0 -0
  49. api/synchronous/api_core/animal_detection_api/__init__.py +0 -0
  50. api/synchronous/api_core/animal_detection_api/api_backend.py +0 -152
  51. api/synchronous/api_core/animal_detection_api/api_frontend.py +0 -266
  52. api/synchronous/api_core/animal_detection_api/config.py +0 -35
  53. api/synchronous/api_core/animal_detection_api/data_management/annotations/annotation_constants.py +0 -47
  54. api/synchronous/api_core/animal_detection_api/detection/detector_training/copy_checkpoints.py +0 -43
  55. api/synchronous/api_core/animal_detection_api/detection/detector_training/model_main_tf2.py +0 -114
  56. api/synchronous/api_core/animal_detection_api/detection/process_video.py +0 -543
  57. api/synchronous/api_core/animal_detection_api/detection/pytorch_detector.py +0 -304
  58. api/synchronous/api_core/animal_detection_api/detection/run_detector.py +0 -627
  59. api/synchronous/api_core/animal_detection_api/detection/run_detector_batch.py +0 -1029
  60. api/synchronous/api_core/animal_detection_api/detection/run_inference_with_yolov5_val.py +0 -581
  61. api/synchronous/api_core/animal_detection_api/detection/run_tiled_inference.py +0 -754
  62. api/synchronous/api_core/animal_detection_api/detection/tf_detector.py +0 -165
  63. api/synchronous/api_core/animal_detection_api/detection/video_utils.py +0 -495
  64. api/synchronous/api_core/animal_detection_api/md_utils/azure_utils.py +0 -174
  65. api/synchronous/api_core/animal_detection_api/md_utils/ct_utils.py +0 -262
  66. api/synchronous/api_core/animal_detection_api/md_utils/directory_listing.py +0 -251
  67. api/synchronous/api_core/animal_detection_api/md_utils/matlab_porting_tools.py +0 -97
  68. api/synchronous/api_core/animal_detection_api/md_utils/path_utils.py +0 -416
  69. api/synchronous/api_core/animal_detection_api/md_utils/process_utils.py +0 -110
  70. api/synchronous/api_core/animal_detection_api/md_utils/sas_blob_utils.py +0 -509
  71. api/synchronous/api_core/animal_detection_api/md_utils/string_utils.py +0 -59
  72. api/synchronous/api_core/animal_detection_api/md_utils/url_utils.py +0 -144
  73. api/synchronous/api_core/animal_detection_api/md_utils/write_html_image_list.py +0 -226
  74. api/synchronous/api_core/animal_detection_api/md_visualization/visualization_utils.py +0 -841
  75. api/synchronous/api_core/tests/__init__.py +0 -0
  76. api/synchronous/api_core/tests/load_test.py +0 -110
  77. classification/__init__.py +0 -0
  78. classification/aggregate_classifier_probs.py +0 -108
  79. classification/analyze_failed_images.py +0 -227
  80. classification/cache_batchapi_outputs.py +0 -198
  81. classification/create_classification_dataset.py +0 -627
  82. classification/crop_detections.py +0 -516
  83. classification/csv_to_json.py +0 -226
  84. classification/detect_and_crop.py +0 -855
  85. classification/efficientnet/__init__.py +0 -9
  86. classification/efficientnet/model.py +0 -415
  87. classification/efficientnet/utils.py +0 -610
  88. classification/evaluate_model.py +0 -520
  89. classification/identify_mislabeled_candidates.py +0 -152
  90. classification/json_to_azcopy_list.py +0 -63
  91. classification/json_validator.py +0 -695
  92. classification/map_classification_categories.py +0 -276
  93. classification/merge_classification_detection_output.py +0 -506
  94. classification/prepare_classification_script.py +0 -194
  95. classification/prepare_classification_script_mc.py +0 -228
  96. classification/run_classifier.py +0 -286
  97. classification/save_mislabeled.py +0 -110
  98. classification/train_classifier.py +0 -825
  99. classification/train_classifier_tf.py +0 -724
  100. classification/train_utils.py +0 -322
  101. data_management/__init__.py +0 -0
  102. data_management/annotations/__init__.py +0 -0
  103. data_management/annotations/annotation_constants.py +0 -34
  104. data_management/camtrap_dp_to_coco.py +0 -238
  105. data_management/cct_json_utils.py +0 -395
  106. data_management/cct_to_md.py +0 -176
  107. data_management/cct_to_wi.py +0 -289
  108. data_management/coco_to_labelme.py +0 -272
  109. data_management/coco_to_yolo.py +0 -662
  110. data_management/databases/__init__.py +0 -0
  111. data_management/databases/add_width_and_height_to_db.py +0 -33
  112. data_management/databases/combine_coco_camera_traps_files.py +0 -206
  113. data_management/databases/integrity_check_json_db.py +0 -477
  114. data_management/databases/subset_json_db.py +0 -115
  115. data_management/generate_crops_from_cct.py +0 -149
  116. data_management/get_image_sizes.py +0 -188
  117. data_management/importers/add_nacti_sizes.py +0 -52
  118. data_management/importers/add_timestamps_to_icct.py +0 -79
  119. data_management/importers/animl_results_to_md_results.py +0 -158
  120. data_management/importers/auckland_doc_test_to_json.py +0 -372
  121. data_management/importers/auckland_doc_to_json.py +0 -200
  122. data_management/importers/awc_to_json.py +0 -189
  123. data_management/importers/bellevue_to_json.py +0 -273
  124. data_management/importers/cacophony-thermal-importer.py +0 -796
  125. data_management/importers/carrizo_shrubfree_2018.py +0 -268
  126. data_management/importers/carrizo_trail_cam_2017.py +0 -287
  127. data_management/importers/cct_field_adjustments.py +0 -57
  128. data_management/importers/channel_islands_to_cct.py +0 -913
  129. data_management/importers/eMammal/copy_and_unzip_emammal.py +0 -180
  130. data_management/importers/eMammal/eMammal_helpers.py +0 -249
  131. data_management/importers/eMammal/make_eMammal_json.py +0 -223
  132. data_management/importers/ena24_to_json.py +0 -275
  133. data_management/importers/filenames_to_json.py +0 -385
  134. data_management/importers/helena_to_cct.py +0 -282
  135. data_management/importers/idaho-camera-traps.py +0 -1407
  136. data_management/importers/idfg_iwildcam_lila_prep.py +0 -294
  137. data_management/importers/jb_csv_to_json.py +0 -150
  138. data_management/importers/mcgill_to_json.py +0 -250
  139. data_management/importers/missouri_to_json.py +0 -489
  140. data_management/importers/nacti_fieldname_adjustments.py +0 -79
  141. data_management/importers/noaa_seals_2019.py +0 -181
  142. data_management/importers/pc_to_json.py +0 -365
  143. data_management/importers/plot_wni_giraffes.py +0 -123
  144. data_management/importers/prepare-noaa-fish-data-for-lila.py +0 -359
  145. data_management/importers/prepare_zsl_imerit.py +0 -131
  146. data_management/importers/rspb_to_json.py +0 -356
  147. data_management/importers/save_the_elephants_survey_A.py +0 -320
  148. data_management/importers/save_the_elephants_survey_B.py +0 -332
  149. data_management/importers/snapshot_safari_importer.py +0 -758
  150. data_management/importers/snapshot_safari_importer_reprise.py +0 -665
  151. data_management/importers/snapshot_serengeti_lila.py +0 -1067
  152. data_management/importers/snapshotserengeti/make_full_SS_json.py +0 -150
  153. data_management/importers/snapshotserengeti/make_per_season_SS_json.py +0 -153
  154. data_management/importers/sulross_get_exif.py +0 -65
  155. data_management/importers/timelapse_csv_set_to_json.py +0 -490
  156. data_management/importers/ubc_to_json.py +0 -399
  157. data_management/importers/umn_to_json.py +0 -507
  158. data_management/importers/wellington_to_json.py +0 -263
  159. data_management/importers/wi_to_json.py +0 -441
  160. data_management/importers/zamba_results_to_md_results.py +0 -181
  161. data_management/labelme_to_coco.py +0 -548
  162. data_management/labelme_to_yolo.py +0 -272
  163. data_management/lila/__init__.py +0 -0
  164. data_management/lila/add_locations_to_island_camera_traps.py +0 -97
  165. data_management/lila/add_locations_to_nacti.py +0 -147
  166. data_management/lila/create_lila_blank_set.py +0 -557
  167. data_management/lila/create_lila_test_set.py +0 -151
  168. data_management/lila/create_links_to_md_results_files.py +0 -106
  169. data_management/lila/download_lila_subset.py +0 -177
  170. data_management/lila/generate_lila_per_image_labels.py +0 -515
  171. data_management/lila/get_lila_annotation_counts.py +0 -170
  172. data_management/lila/get_lila_image_counts.py +0 -111
  173. data_management/lila/lila_common.py +0 -300
  174. data_management/lila/test_lila_metadata_urls.py +0 -132
  175. data_management/ocr_tools.py +0 -874
  176. data_management/read_exif.py +0 -681
  177. data_management/remap_coco_categories.py +0 -84
  178. data_management/remove_exif.py +0 -66
  179. data_management/resize_coco_dataset.py +0 -189
  180. data_management/wi_download_csv_to_coco.py +0 -246
  181. data_management/yolo_output_to_md_output.py +0 -441
  182. data_management/yolo_to_coco.py +0 -676
  183. detection/__init__.py +0 -0
  184. detection/detector_training/__init__.py +0 -0
  185. detection/detector_training/model_main_tf2.py +0 -114
  186. detection/process_video.py +0 -703
  187. detection/pytorch_detector.py +0 -337
  188. detection/run_detector.py +0 -779
  189. detection/run_detector_batch.py +0 -1219
  190. detection/run_inference_with_yolov5_val.py +0 -917
  191. detection/run_tiled_inference.py +0 -935
  192. detection/tf_detector.py +0 -188
  193. detection/video_utils.py +0 -606
  194. docs/source/conf.py +0 -43
  195. md_utils/__init__.py +0 -0
  196. md_utils/azure_utils.py +0 -174
  197. md_utils/ct_utils.py +0 -612
  198. md_utils/directory_listing.py +0 -246
  199. md_utils/md_tests.py +0 -968
  200. md_utils/path_utils.py +0 -1044
  201. md_utils/process_utils.py +0 -157
  202. md_utils/sas_blob_utils.py +0 -509
  203. md_utils/split_locations_into_train_val.py +0 -228
  204. md_utils/string_utils.py +0 -92
  205. md_utils/url_utils.py +0 -323
  206. md_utils/write_html_image_list.py +0 -225
  207. md_visualization/__init__.py +0 -0
  208. md_visualization/plot_utils.py +0 -293
  209. md_visualization/render_images_with_thumbnails.py +0 -275
  210. md_visualization/visualization_utils.py +0 -1537
  211. md_visualization/visualize_db.py +0 -551
  212. md_visualization/visualize_detector_output.py +0 -406
  213. megadetector-5.0.9.dist-info/RECORD +0 -224
  214. megadetector-5.0.9.dist-info/top_level.txt +0 -8
  215. taxonomy_mapping/__init__.py +0 -0
  216. taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +0 -491
  217. taxonomy_mapping/map_new_lila_datasets.py +0 -154
  218. taxonomy_mapping/prepare_lila_taxonomy_release.py +0 -142
  219. taxonomy_mapping/preview_lila_taxonomy.py +0 -591
  220. taxonomy_mapping/retrieve_sample_image.py +0 -71
  221. taxonomy_mapping/simple_image_download.py +0 -218
  222. taxonomy_mapping/species_lookup.py +0 -834
  223. taxonomy_mapping/taxonomy_csv_checker.py +0 -159
  224. taxonomy_mapping/taxonomy_graph.py +0 -346
  225. taxonomy_mapping/validate_lila_category_mappings.py +0 -83
  226. {megadetector-5.0.9.dist-info → megadetector-5.0.11.dist-info}/WHEEL +0 -0
@@ -1,581 +0,0 @@
1
- ########
2
- #
3
- # run_inference_with_yolov5_val.py
4
- #
5
- # Runs a folder of images through MegaDetector (or another YOLOv5 model) with YOLOv5's
6
- # val.py, converting the output to the standard MD format. The main goal is to leverage
7
- # YOLO's test-time augmentation tools.
8
- #
9
- # YOLOv5's val.py uses each file's base name as a unique identifier, which doesn't work
10
- # when you have typical camera trap images like:
11
- #
12
- # a/b/c/RECONYX0001.JPG
13
- # d/e/f/RECONYX0001.JPG
14
- #
15
- # ...so this script jumps through a bunch of hoops to put a symlinks in a flat
16
- # folder, run YOLOv5 on that folder, and map the results back to the real files.
17
- #
18
- # Currently requires the user to supply the path where a working YOLOv5 install lives,
19
- # and assumes that the current conda environment is all set up for YOLOv5.
20
- #
21
- # By default, this script uses symlinks to format the input images in a way that YOLOv5's
22
- # val.py likes. This requires admin privileges on Windows... actually technically this only
23
- # requires permissions to create symbolic links, but I've never seen a case where someone has
24
- # that permission and *doesn't* have admin privileges. If you are running this script on
25
- # Windows and you don't have admin privileges, use --no_use_symlinks.
26
- #
27
- # TODO:
28
- #
29
- # * Multiple GPU support
30
- #
31
- # * Checkpointing
32
- #
33
- # * Support alternative class names at the command line (currently defaults to MD classes,
34
- # though other class names can be supplied programmatically)
35
- #
36
- ########
37
-
38
- #%% Imports
39
-
40
- import os
41
- import uuid
42
- import glob
43
- import tempfile
44
- import shutil
45
- import json
46
-
47
- from tqdm import tqdm
48
-
49
- from md_utils import path_utils
50
- from md_utils import process_utils
51
- from data_management import yolo_output_to_md_output
52
-
53
-
54
- #%% Options class
55
-
56
- class YoloInferenceOptions:
57
-
58
- ## Required ##
59
-
60
- input_folder = None
61
- model_filename = None
62
- yolo_working_folder = None
63
- output_file = None
64
-
65
- ## Optional ##
66
-
67
- image_size = 1280 * 1.3
68
- conf_thres = '0.001'
69
- batch_size = 1
70
- device_string = '0'
71
- augment = True
72
-
73
- symlink_folder = None
74
- use_symlinks = True
75
-
76
- yolo_results_folder = None
77
-
78
- remove_symlink_folder = True
79
- remove_yolo_results_folder = True
80
-
81
- # These are deliberately offset from the standard MD categories; YOLOv5
82
- # needs categories IDs to start at 0.
83
- yolo_category_id_to_name = {0:'animal',1:'person',2:'vehicle'}
84
-
85
- # 'error','skip','overwrite'
86
- overwrite_handling = 'skip'
87
-
88
-
89
- #%% Main function
90
-
91
- def run_inference_with_yolo_val(options):
92
-
93
- ##%% Path handling
94
-
95
- assert os.path.isdir(options.input_folder) or os.path.isfile(options.input_folder), \
96
- 'Could not find input {}'.format(options.input_folder)
97
- assert os.path.isdir(options.yolo_working_folder), \
98
- 'Could not find working folder {}'.format(options.yolo_working_folder)
99
- assert os.path.isfile(options.model_filename), \
100
- 'Could not find model file {}'.format(options.model_filename)
101
-
102
- if os.path.exists(options.output_file):
103
- if options.overwrite_handling == 'skip':
104
- print('Warning: output file {} exists, skipping'.format(options.output_file))
105
- return
106
- elif options.overwrite_handling == 'overwrite':
107
- print('Warning: output file {} exists, overwriting'.format(options.output_file))
108
- elif options.overwrite_handling == 'error':
109
- raise ValueError('Output file {} exists'.format(options.output_file))
110
- else:
111
- raise ValueError('Unknown output handling method {}'.format(options.overwrite_handling))
112
-
113
- os.makedirs(os.path.dirname(options.output_file),exist_ok=True)
114
-
115
- temporary_folder = None
116
- symlink_folder_is_temp_folder = False
117
- yolo_folder_is_temp_folder = False
118
-
119
- job_id = str(uuid.uuid1())
120
-
121
- def get_job_temporary_folder(tf):
122
- if tf is not None:
123
- return tf
124
- tempdir_base = tempfile.gettempdir()
125
- tf = os.path.join(tempdir_base,'md_to_yolo','md_to_yolo_' + job_id)
126
- os.makedirs(tf,exist_ok=True)
127
- return tf
128
-
129
- symlink_folder = options.symlink_folder
130
- yolo_results_folder = options.yolo_results_folder
131
-
132
- if symlink_folder is None:
133
- temporary_folder = get_job_temporary_folder(temporary_folder)
134
- symlink_folder = os.path.join(temporary_folder,'symlinks')
135
- symlink_folder_is_temp_folder = True
136
-
137
- if yolo_results_folder is None:
138
- temporary_folder = get_job_temporary_folder(temporary_folder)
139
- yolo_results_folder = os.path.join(temporary_folder,'yolo_results')
140
- yolo_folder_is_temp_folder = True
141
-
142
- # Attach a GUID to the symlink folder, regardless of whether we created it
143
- symlink_folder_inner = os.path.join(symlink_folder,job_id)
144
-
145
- os.makedirs(symlink_folder_inner,exist_ok=True)
146
- os.makedirs(yolo_results_folder,exist_ok=True)
147
-
148
-
149
- ##%% Enumerate images
150
-
151
- if os.path.isdir(options.input_folder):
152
- image_files_absolute = path_utils.find_images(options.input_folder,recursive=True)
153
- else:
154
- assert os.path.isfile(options.input_folder)
155
- with open(options.input_folder,'r') as f:
156
- image_files_absolute = json.load(f)
157
- assert isinstance(image_files_absolute,list)
158
- for fn in image_files_absolute:
159
- assert os.path.isfile(fn), 'Could not find image file {}'.format(fn)
160
-
161
-
162
- ##%% Create symlinks to give a unique ID to each image
163
-
164
- image_id_to_file = {}
165
- image_id_to_error = {}
166
-
167
- if options.use_symlinks:
168
- print('Creating {} symlinks in {}'.format(len(image_files_absolute),symlink_folder_inner))
169
- else:
170
- print('Symlinks disabled, copying {} images to {}'.format(len(image_files_absolute),symlink_folder_inner))
171
-
172
- # i_image = 0; image_fn = image_files_absolute[i_image]
173
- for i_image,image_fn in tqdm(enumerate(image_files_absolute),total=len(image_files_absolute)):
174
-
175
- ext = os.path.splitext(image_fn)[1]
176
-
177
- image_id = str(i_image).zfill(10)
178
- image_id_to_file[image_id] = image_fn
179
- symlink_name = image_id + ext
180
- symlink_full_path = os.path.join(symlink_folder_inner,symlink_name)
181
-
182
- try:
183
- if options.use_symlinks:
184
- path_utils.safe_create_link(image_fn,symlink_full_path)
185
- else:
186
- shutil.copyfile(image_fn,symlink_full_path)
187
- except Exception as e:
188
- image_id_to_error[image_id] = str(e)
189
- print('Warning: error copying/creating link for input file {}: {}'.format(
190
- image_fn,str(e)))
191
- continue
192
-
193
- # ...for each image
194
-
195
-
196
- ##%% Create the dataset file
197
-
198
- # Category IDs need to be continuous integers starting at 0
199
- category_ids = sorted(list(options.yolo_category_id_to_name.keys()))
200
- assert category_ids[0] == 0
201
- assert len(category_ids) == 1 + category_ids[-1]
202
-
203
- dataset_file = os.path.join(yolo_results_folder,'dataset.yaml')
204
-
205
- with open(dataset_file,'w') as f:
206
- f.write('path: {}\n'.format(symlink_folder_inner))
207
- f.write('train: .\n')
208
- f.write('val: .\n')
209
- f.write('test: .\n')
210
- f.write('\n')
211
- f.write('nc: {}\n'.format(len(options.yolo_category_id_to_name)))
212
- f.write('\n')
213
- f.write('names:\n')
214
- for category_id in category_ids:
215
- assert isinstance(category_id,int)
216
- f.write(' {}: {}\n'.format(category_id,
217
- options.yolo_category_id_to_name[category_id]))
218
-
219
-
220
- ##%% Prepare YOLOv5 command
221
-
222
- image_size_string = str(round(options.image_size))
223
- cmd = 'python val.py --data "{}"'.format(dataset_file)
224
- cmd += ' --weights "{}"'.format(options.model_filename)
225
- cmd += ' --batch-size {} --imgsz {} --conf-thres {} --task test'.format(
226
- options.batch_size,image_size_string,options.conf_thres)
227
- cmd += ' --device "{}" --save-json'.format(options.device_string)
228
- cmd += ' --project "{}" --name "{}" --exist-ok'.format(yolo_results_folder,'yolo_results')
229
-
230
- if options.augment:
231
- cmd += ' --augment'
232
-
233
-
234
- ##%% Run YOLOv5 command
235
-
236
- current_dir = os.getcwd()
237
- os.chdir(options.yolo_working_folder)
238
- execution_result = process_utils.execute_and_print(cmd)
239
- assert execution_result['status'] == 0, 'Error running YOLOv5'
240
- yolo_console_output = execution_result['output']
241
-
242
- yolo_read_failures = []
243
- for line in yolo_console_output:
244
- if 'cannot identify image file' in line:
245
- tokens = line.split('cannot identify image file')
246
- image_name = tokens[-1].strip()
247
- assert image_name[0] == "'" and image_name [-1] == "'"
248
- image_name = image_name[1:-1]
249
- yolo_read_failures.append(image_name)
250
-
251
- # image_file = yolo_read_failures[0]
252
- for image_file in yolo_read_failures:
253
- image_id = os.path.splitext(os.path.basename(image_file))[0]
254
- assert image_id in image_id_to_file
255
- if image_id not in image_id_to_error:
256
- image_id_to_error[image_id] = 'YOLOv5 read failure'
257
-
258
- os.chdir(current_dir)
259
-
260
-
261
- ##%% Convert results to MD format
262
-
263
- json_files = glob.glob(yolo_results_folder+ '/yolo_results/*.json')
264
- assert len(json_files) == 1
265
- yolo_json_file = json_files[0]
266
-
267
- image_id_to_relative_path = {}
268
- for image_id in image_id_to_file:
269
- fn = image_id_to_file[image_id]
270
- if os.path.isdir(options.input_folder):
271
- assert options.input_folder in fn
272
- relative_path = os.path.relpath(fn,options.input_folder)
273
- else:
274
- assert os.path.isfile(options.input_folder)
275
- # We'll use the absolute path as a relative path, and pass '/'
276
- # as the base path in this case.
277
- relative_path = fn
278
- image_id_to_relative_path[image_id] = relative_path
279
-
280
- if os.path.isdir(options.input_folder):
281
- image_base = options.input_folder
282
- else:
283
- assert os.path.isfile(options.input_folder)
284
- image_base = '/'
285
-
286
- yolo_output_to_md_output.yolo_json_output_to_md_output(
287
- yolo_json_file=yolo_json_file,
288
- image_folder=image_base,
289
- output_file=options.output_file,
290
- yolo_category_id_to_name=options.yolo_category_id_to_name,
291
- detector_name=os.path.basename(options.model_filename),
292
- image_id_to_relative_path=image_id_to_relative_path,
293
- image_id_to_error=image_id_to_error)
294
-
295
-
296
- ##%% Clean up
297
-
298
- if options.remove_symlink_folder:
299
- shutil.rmtree(symlink_folder)
300
- elif symlink_folder_is_temp_folder:
301
- print('Warning: using temporary symlink folder {}, but not removing it'.format(
302
- symlink_folder))
303
-
304
- if options.remove_yolo_results_folder:
305
- shutil.rmtree(yolo_results_folder)
306
- elif yolo_folder_is_temp_folder:
307
- print('Warning: using temporary YOLO results folder {}, but not removing it'.format(
308
- yolo_results_folder))
309
-
310
- # ...def run_inference_with_yolo_val()
311
-
312
-
313
- #%% Command-line driver
314
-
315
- import argparse,sys
316
- from md_utils.ct_utils import args_to_object
317
-
318
- def main():
319
-
320
- options = YoloInferenceOptions()
321
-
322
- parser = argparse.ArgumentParser()
323
- parser.add_argument(
324
- 'model_filename',type=str,
325
- help='model file name')
326
- parser.add_argument(
327
- 'input_folder',type=str,
328
- help='folder on which to recursively run the model, or a .json list of filenames')
329
- parser.add_argument(
330
- 'output_file',type=str,
331
- help='.json file where output will be written')
332
- parser.add_argument(
333
- 'yolo_working_folder',type=str,
334
- help='folder in which to execute val.py')
335
-
336
- parser.add_argument(
337
- '--image_size', default=options.image_size, type=int,
338
- help='image size for model execution (default {})'.format(
339
- options.image_size))
340
- parser.add_argument(
341
- '--conf_thres', default=options.conf_thres, type=float,
342
- help='confidence threshold for including detections in the output file (default {})'.format(
343
- options.conf_thres))
344
- parser.add_argument(
345
- '--batch_size', default=options.batch_size, type=int,
346
- help='inference batch size (default {})'.format(options.batch_size))
347
- parser.add_argument(
348
- '--device_string', default=options.device_string, type=str,
349
- help='CUDA device specifier, e.g. "0" or "cpu" (default {})'.format(options.device_string))
350
- parser.add_argument(
351
- '--overwrite_handling', default=options.overwrite_handling, type=str,
352
- help='action to take if the output file exists (skip, error, overwrite) (default {})'.format(
353
- options.overwrite_handling) )
354
-
355
- parser.add_argument(
356
- '--symlink_folder', type=str,
357
- help='temporary folder for symlinks (defaults to a folder in the system temp dir)')
358
- parser.add_argument(
359
- '--yolo_results_folder', type=str,
360
- help='temporary folder for YOLO intermediate output (defaults to a folder in the system temp dir)')
361
- parser.add_argument(
362
- '--no_use_symlinks', action='store_true',
363
- help='copy files instead of creating symlinks when preparing the yolo input folder')
364
- parser.add_argument(
365
- '--no_remove_symlink_folder', action='store_true',
366
- help='don\'t remove the temporary folder full of symlinks')
367
- parser.add_argument(
368
- '--no_remove_yolo_results_folder', action='store_true',
369
- help='don\'t remove the temporary folder full of YOLO intermediate files')
370
-
371
- if options.augment:
372
- default_augment_enabled = 1
373
- else:
374
- default_augment_enabled = 0
375
- parser.add_argument(
376
- '--augment_enabled', default=default_augment_enabled, type=int,
377
- help='enable/disable augmentation (default {})'.format(default_augment_enabled))
378
-
379
- if len(sys.argv[1:]) == 0:
380
- parser.print_help()
381
- parser.exit()
382
-
383
- args = parser.parse_args()
384
-
385
- args_to_object(args, options)
386
- options.remove_symlink_folder = (not options.no_remove_symlink_folder)
387
- options.remove_yolo_results_folder = (not options.no_remove_yolo_results_folder)
388
- options.use_symlinks = (not options.no_use_symlinks)
389
- options.augment = (options.augment_enabled > 0)
390
-
391
- print(options.__dict__)
392
-
393
- run_inference_with_yolo_val(options)
394
-
395
-
396
- if __name__ == '__main__':
397
- main()
398
-
399
-
400
- #%% Scrap
401
-
402
- if False:
403
-
404
- #%% Run from a set of options
405
-
406
- options = YoloInferenceOptions()
407
-
408
- args = {'augment': 1, 'batch_size': 1, 'conf_thres': 0.005, 'device_string': '1', 'image_size': 1664.0, 'input_folder': '/home/user/postprocessing/usgs-kissel/usgs-kissel-2023-09-11-aug-v5a.0.0/chunk031.json', 'model_filename': '/home/user/models/camera_traps/megadetector/md_v5.0.0/md_v5a.0.0.pt', 'output_file': '/home/user/postprocessing/usgs-kissel/usgs-kissel-2023-09-11-aug-v5a.0.0/chunk031_results.json', 'overwrite_handling': 'skip', 'symlink_folder': '/home/user/postprocessing/usgs-kissel/usgs-kissel-2023-09-11-aug-v5a.0.0/symlinks/symlinks_031', 'yolo_results_folder': '/home/user/postprocessing/usgs-kissel/usgs-kissel-2023-09-11-aug-v5a.0.0/yolo_results/yolo_results_031', 'yolo_working_folder': '/home/user/git/yolov5', 'remove_symlink_folder': True, 'remove_yolo_results_folder': True, 'use_symlinks': False, 'augment': True}
409
-
410
- for k in args:
411
- setattr(options, k, args[k])
412
-
413
-
414
- #%% Test driver (folder)
415
-
416
- project_name = 'KRU-test-corrupted'
417
- input_folder = os.path.expanduser(f'~/data/{project_name}')
418
- output_folder = os.path.expanduser(f'~/tmp/{project_name}')
419
- model_filename = os.path.expanduser('~/models/camera_traps/megadetector/md_v5.0.0/md_v5a.0.0.pt')
420
- yolo_working_folder = os.path.expanduser('~/git/yolov5')
421
- model_name = os.path.splitext(os.path.basename(model_filename))[0]
422
-
423
- symlink_folder = os.path.join(output_folder,'symlinks')
424
- yolo_results_folder = os.path.join(output_folder,'yolo_results')
425
-
426
- output_file = os.path.join(output_folder,'{}_{}-md_format.json'.format(
427
- project_name,model_name))
428
-
429
- options = YoloInferenceOptions()
430
-
431
- options.yolo_working_folder = yolo_working_folder
432
-
433
- options.output_file = output_file
434
-
435
- options.augment = False
436
- options.conf_thres = '0.001'
437
- options.batch_size = 1
438
- options.device_string = '0'
439
-
440
- if options.augment:
441
- options.image_size = round(1280 * 1.3)
442
- else:
443
- options.image_size = 1280
444
-
445
- options.input_folder = input_folder
446
- options.model_filename = model_filename
447
-
448
- options.yolo_results_folder = yolo_results_folder # os.path.join(output_folder + 'yolo_results')
449
- options.symlink_folder = symlink_folder # os.path.join(output_folder,'symlinks')
450
- options.use_symlinks = False
451
-
452
- options.remove_temporary_symlink_folder = False
453
- options.remove_yolo_results_file = False
454
-
455
- cmd = f'python run_inference_with_yolov5_val.py {model_filename} {input_folder} {output_file} {yolo_working_folder} ' + \
456
- f' --image_size {options.image_size} --conf_thres {options.conf_thres} --batch_size {options.batch_size} ' + \
457
- f' --symlink_folder {options.symlink_folder} --yolo_results_folder {options.yolo_results_folder} ' + \
458
- ' --no_remove_symlink_folder --no_remove_yolo_results_folder'
459
-
460
- if not options.use_symlinks:
461
- cmd += ' --no_use_symlinks'
462
- if not options.augment:
463
- cmd += ' --augment_enabled 0'
464
-
465
- print(cmd)
466
- execute_in_python = False
467
- if execute_in_python:
468
- run_inference_with_yolo_val(options)
469
- else:
470
- import clipboard; clipboard.copy(cmd)
471
-
472
-
473
- #%% Preview results
474
-
475
- postprocessing_output_folder = os.path.join(output_folder,'yolo-val-preview')
476
- md_json_file = options.output_file
477
-
478
- from api.batch_processing.postprocessing.postprocess_batch_results import (
479
- PostProcessingOptions, process_batch_results)
480
-
481
- with open(md_json_file,'r') as f:
482
- d = json.load(f)
483
-
484
- base_task_name = os.path.basename(md_json_file)
485
-
486
- pp_options = PostProcessingOptions()
487
- pp_options.image_base_dir = input_folder
488
- pp_options.include_almost_detections = True
489
- pp_options.num_images_to_sample = None
490
- pp_options.confidence_threshold = 0.1
491
- pp_options.almost_detection_confidence_threshold = pp_options.confidence_threshold - 0.025
492
- pp_options.ground_truth_json_file = None
493
- pp_options.separate_detections_by_category = True
494
- # pp_options.sample_seed = 0
495
-
496
- pp_options.parallelize_rendering = True
497
- pp_options.parallelize_rendering_n_cores = 16
498
- pp_options.parallelize_rendering_with_threads = False
499
-
500
- output_base = os.path.join(postprocessing_output_folder,
501
- base_task_name + '_{:.3f}'.format(pp_options.confidence_threshold))
502
-
503
- os.makedirs(output_base, exist_ok=True)
504
- print('Processing to {}'.format(output_base))
505
-
506
- pp_options.api_output_file = md_json_file
507
- pp_options.output_dir = output_base
508
- ppresults = process_batch_results(pp_options)
509
- html_output_file = ppresults.output_html_file
510
-
511
- path_utils.open_file(html_output_file)
512
-
513
- # ...for each prediction file
514
-
515
-
516
- #%% Compare results
517
-
518
- import itertools
519
-
520
- from api.batch_processing.postprocessing.compare_batch_results import (
521
- BatchComparisonOptions,PairwiseBatchComparisonOptions,compare_batch_results)
522
-
523
- options = BatchComparisonOptions()
524
-
525
- organization_name = ''
526
- project_name = ''
527
-
528
- options.job_name = f'{organization_name}-comparison'
529
- options.output_folder = os.path.join(output_folder,'model_comparison')
530
- options.image_folder = input_folder
531
-
532
- options.pairwise_options = []
533
-
534
- filenames = [
535
- f'/home/user/tmp/{project_name}/{project_name}_md_v5a.0.0-md_format.json',
536
- f'/home/user/postprocessing/{organization_name}/{organization_name}-2023-04-06-v5a.0.0/combined_api_outputs/{organization_name}-2023-04-06-v5a.0.0_detections.json',
537
- f'/home/user/postprocessing/{organization_name}/{organization_name}-2023-04-06-v5b.0.0/combined_api_outputs/{organization_name}-2023-04-06-v5b.0.0_detections.json'
538
- ]
539
-
540
- descriptions = ['YOLO w/augment','MDv5a','MDv5b']
541
-
542
- if False:
543
- results = []
544
-
545
- for fn in filenames:
546
- with open(fn,'r') as f:
547
- d = json.load(f)
548
- results.append(d)
549
-
550
- detection_thresholds = [0.1,0.1,0.1]
551
-
552
- assert len(detection_thresholds) == len(filenames)
553
-
554
- rendering_thresholds = [(x*0.6666) for x in detection_thresholds]
555
-
556
- # Choose all pairwise combinations of the files in [filenames]
557
- for i, j in itertools.combinations(list(range(0,len(filenames))),2):
558
-
559
- pairwise_options = PairwiseBatchComparisonOptions()
560
-
561
- pairwise_options.results_filename_a = filenames[i]
562
- pairwise_options.results_filename_b = filenames[j]
563
-
564
- pairwise_options.results_description_a = descriptions[i]
565
- pairwise_options.results_description_b = descriptions[j]
566
-
567
- pairwise_options.rendering_confidence_threshold_a = rendering_thresholds[i]
568
- pairwise_options.rendering_confidence_threshold_b = rendering_thresholds[j]
569
-
570
- pairwise_options.detection_thresholds_a = {'animal':detection_thresholds[i],
571
- 'person':detection_thresholds[i],
572
- 'vehicle':detection_thresholds[i]}
573
- pairwise_options.detection_thresholds_b = {'animal':detection_thresholds[j],
574
- 'person':detection_thresholds[j],
575
- 'vehicle':detection_thresholds[j]}
576
- options.pairwise_options.append(pairwise_options)
577
-
578
- results = compare_batch_results(options)
579
-
580
- from md_utils.path_utils import open_file
581
- open_file(results.html_output_file)