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

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

Potentially problematic release.


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

Files changed (176) hide show
  1. megadetector/api/batch_processing/api_core/batch_service/score.py +4 -5
  2. megadetector/api/batch_processing/api_core_support/aggregate_results_manually.py +1 -1
  3. megadetector/api/batch_processing/api_support/summarize_daily_activity.py +1 -1
  4. megadetector/api/batch_processing/integration/digiKam/xmp_integration.py +2 -2
  5. megadetector/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +1 -1
  6. megadetector/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +1 -1
  7. megadetector/api/synchronous/api_core/tests/load_test.py +2 -3
  8. megadetector/classification/aggregate_classifier_probs.py +3 -3
  9. megadetector/classification/analyze_failed_images.py +5 -5
  10. megadetector/classification/cache_batchapi_outputs.py +5 -5
  11. megadetector/classification/create_classification_dataset.py +11 -12
  12. megadetector/classification/crop_detections.py +10 -10
  13. megadetector/classification/csv_to_json.py +8 -8
  14. megadetector/classification/detect_and_crop.py +13 -15
  15. megadetector/classification/evaluate_model.py +7 -7
  16. megadetector/classification/identify_mislabeled_candidates.py +6 -6
  17. megadetector/classification/json_to_azcopy_list.py +1 -1
  18. megadetector/classification/json_validator.py +29 -32
  19. megadetector/classification/map_classification_categories.py +9 -9
  20. megadetector/classification/merge_classification_detection_output.py +12 -9
  21. megadetector/classification/prepare_classification_script.py +19 -19
  22. megadetector/classification/prepare_classification_script_mc.py +23 -23
  23. megadetector/classification/run_classifier.py +4 -4
  24. megadetector/classification/save_mislabeled.py +6 -6
  25. megadetector/classification/train_classifier.py +1 -1
  26. megadetector/classification/train_classifier_tf.py +9 -9
  27. megadetector/classification/train_utils.py +10 -10
  28. megadetector/data_management/annotations/annotation_constants.py +1 -1
  29. megadetector/data_management/camtrap_dp_to_coco.py +45 -45
  30. megadetector/data_management/cct_json_utils.py +101 -101
  31. megadetector/data_management/cct_to_md.py +49 -49
  32. megadetector/data_management/cct_to_wi.py +33 -33
  33. megadetector/data_management/coco_to_labelme.py +75 -75
  34. megadetector/data_management/coco_to_yolo.py +189 -189
  35. megadetector/data_management/databases/add_width_and_height_to_db.py +3 -2
  36. megadetector/data_management/databases/combine_coco_camera_traps_files.py +38 -38
  37. megadetector/data_management/databases/integrity_check_json_db.py +202 -188
  38. megadetector/data_management/databases/subset_json_db.py +33 -33
  39. megadetector/data_management/generate_crops_from_cct.py +38 -38
  40. megadetector/data_management/get_image_sizes.py +54 -49
  41. megadetector/data_management/labelme_to_coco.py +130 -124
  42. megadetector/data_management/labelme_to_yolo.py +78 -72
  43. megadetector/data_management/lila/create_lila_blank_set.py +81 -83
  44. megadetector/data_management/lila/create_lila_test_set.py +32 -31
  45. megadetector/data_management/lila/create_links_to_md_results_files.py +18 -18
  46. megadetector/data_management/lila/download_lila_subset.py +21 -24
  47. megadetector/data_management/lila/generate_lila_per_image_labels.py +91 -91
  48. megadetector/data_management/lila/get_lila_annotation_counts.py +30 -30
  49. megadetector/data_management/lila/get_lila_image_counts.py +22 -22
  50. megadetector/data_management/lila/lila_common.py +70 -70
  51. megadetector/data_management/lila/test_lila_metadata_urls.py +13 -14
  52. megadetector/data_management/mewc_to_md.py +339 -340
  53. megadetector/data_management/ocr_tools.py +258 -252
  54. megadetector/data_management/read_exif.py +232 -223
  55. megadetector/data_management/remap_coco_categories.py +26 -26
  56. megadetector/data_management/remove_exif.py +31 -20
  57. megadetector/data_management/rename_images.py +187 -187
  58. megadetector/data_management/resize_coco_dataset.py +41 -41
  59. megadetector/data_management/speciesnet_to_md.py +41 -41
  60. megadetector/data_management/wi_download_csv_to_coco.py +55 -55
  61. megadetector/data_management/yolo_output_to_md_output.py +117 -120
  62. megadetector/data_management/yolo_to_coco.py +195 -188
  63. megadetector/detection/change_detection.py +831 -0
  64. megadetector/detection/process_video.py +341 -338
  65. megadetector/detection/pytorch_detector.py +308 -266
  66. megadetector/detection/run_detector.py +186 -166
  67. megadetector/detection/run_detector_batch.py +366 -364
  68. megadetector/detection/run_inference_with_yolov5_val.py +328 -325
  69. megadetector/detection/run_tiled_inference.py +312 -253
  70. megadetector/detection/tf_detector.py +24 -24
  71. megadetector/detection/video_utils.py +291 -283
  72. megadetector/postprocessing/add_max_conf.py +15 -11
  73. megadetector/postprocessing/categorize_detections_by_size.py +44 -44
  74. megadetector/postprocessing/classification_postprocessing.py +808 -311
  75. megadetector/postprocessing/combine_batch_outputs.py +20 -21
  76. megadetector/postprocessing/compare_batch_results.py +528 -517
  77. megadetector/postprocessing/convert_output_format.py +97 -97
  78. megadetector/postprocessing/create_crop_folder.py +220 -147
  79. megadetector/postprocessing/detector_calibration.py +173 -168
  80. megadetector/postprocessing/generate_csv_report.py +508 -0
  81. megadetector/postprocessing/load_api_results.py +25 -22
  82. megadetector/postprocessing/md_to_coco.py +129 -98
  83. megadetector/postprocessing/md_to_labelme.py +89 -83
  84. megadetector/postprocessing/md_to_wi.py +40 -40
  85. megadetector/postprocessing/merge_detections.py +87 -114
  86. megadetector/postprocessing/postprocess_batch_results.py +319 -302
  87. megadetector/postprocessing/remap_detection_categories.py +36 -36
  88. megadetector/postprocessing/render_detection_confusion_matrix.py +205 -199
  89. megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py +57 -57
  90. megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +27 -28
  91. megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +702 -677
  92. megadetector/postprocessing/separate_detections_into_folders.py +226 -211
  93. megadetector/postprocessing/subset_json_detector_output.py +265 -262
  94. megadetector/postprocessing/top_folders_to_bottom.py +45 -45
  95. megadetector/postprocessing/validate_batch_results.py +70 -70
  96. megadetector/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +52 -52
  97. megadetector/taxonomy_mapping/map_new_lila_datasets.py +15 -15
  98. megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +14 -14
  99. megadetector/taxonomy_mapping/preview_lila_taxonomy.py +66 -69
  100. megadetector/taxonomy_mapping/retrieve_sample_image.py +16 -16
  101. megadetector/taxonomy_mapping/simple_image_download.py +8 -8
  102. megadetector/taxonomy_mapping/species_lookup.py +33 -33
  103. megadetector/taxonomy_mapping/taxonomy_csv_checker.py +14 -14
  104. megadetector/taxonomy_mapping/taxonomy_graph.py +11 -11
  105. megadetector/taxonomy_mapping/validate_lila_category_mappings.py +13 -13
  106. megadetector/utils/azure_utils.py +22 -22
  107. megadetector/utils/ct_utils.py +1019 -200
  108. megadetector/utils/directory_listing.py +21 -77
  109. megadetector/utils/gpu_test.py +22 -22
  110. megadetector/utils/md_tests.py +541 -518
  111. megadetector/utils/path_utils.py +1511 -406
  112. megadetector/utils/process_utils.py +41 -41
  113. megadetector/utils/sas_blob_utils.py +53 -49
  114. megadetector/utils/split_locations_into_train_val.py +73 -60
  115. megadetector/utils/string_utils.py +147 -26
  116. megadetector/utils/url_utils.py +463 -173
  117. megadetector/utils/wi_utils.py +2629 -2868
  118. megadetector/utils/write_html_image_list.py +137 -137
  119. megadetector/visualization/plot_utils.py +21 -21
  120. megadetector/visualization/render_images_with_thumbnails.py +37 -73
  121. megadetector/visualization/visualization_utils.py +424 -404
  122. megadetector/visualization/visualize_db.py +197 -190
  123. megadetector/visualization/visualize_detector_output.py +126 -98
  124. {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/METADATA +6 -3
  125. megadetector-5.0.29.dist-info/RECORD +163 -0
  126. {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/WHEEL +1 -1
  127. megadetector/data_management/importers/add_nacti_sizes.py +0 -52
  128. megadetector/data_management/importers/add_timestamps_to_icct.py +0 -79
  129. megadetector/data_management/importers/animl_results_to_md_results.py +0 -158
  130. megadetector/data_management/importers/auckland_doc_test_to_json.py +0 -373
  131. megadetector/data_management/importers/auckland_doc_to_json.py +0 -201
  132. megadetector/data_management/importers/awc_to_json.py +0 -191
  133. megadetector/data_management/importers/bellevue_to_json.py +0 -272
  134. megadetector/data_management/importers/cacophony-thermal-importer.py +0 -793
  135. megadetector/data_management/importers/carrizo_shrubfree_2018.py +0 -269
  136. megadetector/data_management/importers/carrizo_trail_cam_2017.py +0 -289
  137. megadetector/data_management/importers/cct_field_adjustments.py +0 -58
  138. megadetector/data_management/importers/channel_islands_to_cct.py +0 -913
  139. megadetector/data_management/importers/eMammal/copy_and_unzip_emammal.py +0 -180
  140. megadetector/data_management/importers/eMammal/eMammal_helpers.py +0 -249
  141. megadetector/data_management/importers/eMammal/make_eMammal_json.py +0 -223
  142. megadetector/data_management/importers/ena24_to_json.py +0 -276
  143. megadetector/data_management/importers/filenames_to_json.py +0 -386
  144. megadetector/data_management/importers/helena_to_cct.py +0 -283
  145. megadetector/data_management/importers/idaho-camera-traps.py +0 -1407
  146. megadetector/data_management/importers/idfg_iwildcam_lila_prep.py +0 -294
  147. megadetector/data_management/importers/import_desert_lion_conservation_camera_traps.py +0 -387
  148. megadetector/data_management/importers/jb_csv_to_json.py +0 -150
  149. megadetector/data_management/importers/mcgill_to_json.py +0 -250
  150. megadetector/data_management/importers/missouri_to_json.py +0 -490
  151. megadetector/data_management/importers/nacti_fieldname_adjustments.py +0 -79
  152. megadetector/data_management/importers/noaa_seals_2019.py +0 -181
  153. megadetector/data_management/importers/osu-small-animals-to-json.py +0 -364
  154. megadetector/data_management/importers/pc_to_json.py +0 -365
  155. megadetector/data_management/importers/plot_wni_giraffes.py +0 -123
  156. megadetector/data_management/importers/prepare_zsl_imerit.py +0 -131
  157. megadetector/data_management/importers/raic_csv_to_md_results.py +0 -416
  158. megadetector/data_management/importers/rspb_to_json.py +0 -356
  159. megadetector/data_management/importers/save_the_elephants_survey_A.py +0 -320
  160. megadetector/data_management/importers/save_the_elephants_survey_B.py +0 -329
  161. megadetector/data_management/importers/snapshot_safari_importer.py +0 -758
  162. megadetector/data_management/importers/snapshot_serengeti_lila.py +0 -1067
  163. megadetector/data_management/importers/snapshotserengeti/make_full_SS_json.py +0 -150
  164. megadetector/data_management/importers/snapshotserengeti/make_per_season_SS_json.py +0 -153
  165. megadetector/data_management/importers/sulross_get_exif.py +0 -65
  166. megadetector/data_management/importers/timelapse_csv_set_to_json.py +0 -490
  167. megadetector/data_management/importers/ubc_to_json.py +0 -399
  168. megadetector/data_management/importers/umn_to_json.py +0 -507
  169. megadetector/data_management/importers/wellington_to_json.py +0 -263
  170. megadetector/data_management/importers/wi_to_json.py +0 -442
  171. megadetector/data_management/importers/zamba_results_to_md_results.py +0 -180
  172. megadetector/data_management/lila/add_locations_to_island_camera_traps.py +0 -101
  173. megadetector/data_management/lila/add_locations_to_nacti.py +0 -151
  174. megadetector-5.0.27.dist-info/RECORD +0 -208
  175. {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/licenses/LICENSE +0 -0
  176. {megadetector-5.0.27.dist-info → megadetector-5.0.29.dist-info}/top_level.txt +0 -0
@@ -1,416 +0,0 @@
1
- """
2
-
3
- raic_csv_to_md_results.py
4
-
5
- Converts classification+detection results in the .csv format provided to the Snapshot
6
- Serengeti program by the RAIC team to the MD results format.
7
-
8
- The input format is two .csv files:
9
-
10
- * One with results, with columns [unnamed], filename, category, x_center, y_center,
11
- width, height, confidence, datetime
12
-
13
- * One with class IDs and names, with columns CLASS, SPECIES
14
-
15
- Filenames are relative paths to .txt files, but with slashes replaced by underscores, e.g. this
16
- file:
17
-
18
- B04_R1/I__00122.JPG
19
-
20
- ...appears in the .csv file as:
21
-
22
- B04_R1_I__00122.txt
23
-
24
- Image coordinates are in absolute floating-point units, with an upper-left origin.
25
-
26
- Unknowns at the time I'm writing this:
27
-
28
- * I don't know what the unnamed column is, but it looks like an ID I can safely ignore.
29
-
30
- * I believe that MegaDetector was run, then a classifier was run, but there is a
31
- single "confidence" column in the output. I am writing out the results as if they were a
32
- single multi-class detector. This is suspicious given the lack of a human class, which suggests
33
- that this is intended to be run in conjunection with MD.
34
-
35
- * There is no concept of "empty" in this file format, so by default I assume that images with
36
- no annotations in the .csv file were processed and determine to have no detections above some
37
- (unknown) threshold.
38
-
39
- * I'm not currently handling EXIF rotations, as part of the effort to simplify this file
40
- for conversion to R (see below).
41
-
42
- Note to self: this file should not take dependencies on other components of the MD
43
- repo, at the risk of creating some redundancy. I am going to convert this to R,
44
- which will be easier if it's not using any non-standard libraries. Anything in the
45
- "interactive driver" cells gets a pass.
46
-
47
- """
48
-
49
- #%% Imports and constants
50
-
51
- import os
52
- import glob
53
- import json
54
- import sys
55
- import argparse
56
-
57
- import pandas as pd
58
- from PIL import Image
59
-
60
-
61
- #%% Functions from the MD python package
62
-
63
- # ...that I'm choosing to copy and paste to facilitate a conversion of this
64
- # script to R.
65
-
66
- # Should all be lower-case
67
- IMG_EXTENSIONS = ('.jpg', '.jpeg', '.gif', '.png', '.tif', '.tiff', '.bmp')
68
-
69
- def _is_image_file(s, img_extensions=IMG_EXTENSIONS):
70
- """
71
- Checks a file's extension against a hard-coded set of image file
72
- extensions. Uses case-insensitive comparison.
73
-
74
- Does not check whether the file exists, only determines whether the filename
75
- implies it's an image file.
76
-
77
- Args:
78
- s (str): filename to evaluate for image-ness
79
- img_extensions (list, optional): list of known image file extensions
80
-
81
- Returns:
82
- bool: True if [s] appears to be an image file, else False
83
- """
84
-
85
- ext = os.path.splitext(s)[1]
86
- return ext.lower() in img_extensions
87
-
88
-
89
- def _find_image_strings(strings):
90
- """
91
- Given a list of strings that are potentially image file names, looks for
92
- strings that actually look like image file names (based on extension).
93
-
94
- Args:
95
- strings (list): list of filenames to check for image-ness
96
-
97
- Returns:
98
- list: the subset of [strings] that appear to be image filenames
99
- """
100
-
101
- return [s for s in strings if _is_image_file(s)]
102
-
103
-
104
- def _find_images(dirname,
105
- recursive=False,
106
- return_relative_paths=False,
107
- convert_slashes=True):
108
- """
109
- Finds all files in a directory that look like image file names. Returns
110
- absolute paths unless return_relative_paths is set. Uses the OS-native
111
- path separator unless convert_slashes is set, in which case will always
112
- use '/'.
113
-
114
- Args:
115
- dirname (str): the folder to search for images
116
- recursive (bool, optional): whether to search recursively
117
- return_relative_paths (str, optional): return paths that are relative
118
- to [dirname], rather than absolute paths
119
- convert_slashes (bool, optional): force forward slashes in return values
120
-
121
- Returns:
122
- list: list of image filenames found in [dirname]
123
- """
124
-
125
- assert os.path.isdir(dirname), '{} is not a folder'.format(dirname)
126
-
127
- if recursive:
128
- strings = glob.glob(os.path.join(dirname, '**', '*.*'), recursive=True)
129
- else:
130
- strings = glob.glob(os.path.join(dirname, '*.*'))
131
-
132
- image_files = _find_image_strings(strings)
133
-
134
- if return_relative_paths:
135
- image_files = [os.path.relpath(fn,dirname) for fn in image_files]
136
-
137
- image_files = sorted(image_files)
138
-
139
- if convert_slashes:
140
- image_files = [fn.replace('\\', '/') for fn in image_files]
141
-
142
- return image_files
143
-
144
-
145
- #%% Main conversion function
146
-
147
- def raic_csv_to_md_results(result_csv_file,
148
- class_mapping_csv_file,
149
- image_folder,
150
- output_file=None,
151
- unannotated_image_handling='empty'):
152
- """
153
- Converts a pair of .csv files (see file header for details) to MD results format.
154
-
155
- Currently errors if image filenames are ambiguous, or if any images referred to in
156
- the results are not available.
157
-
158
- Args:
159
- result_csv_file (str): the results file to read (.csv)
160
- class_mapping_csv_file (str): the class mapping file (.csv)
161
- image_folder (str): the folder containing all the images referred to in
162
- [result_csv_file]
163
- output_file (str, optional): the .json file to which we should write results. Defaults
164
- to [result_csv_file].json
165
- unannotated_image_handling (str, optional): can be "empty" (default) to assume
166
- that images without annotations are empty, "warning", "error", or "skip"
167
-
168
- Returns:
169
- str: the output file written, identical to [output_file] if [output_file] was not None
170
- """
171
-
172
- # Validate arguments
173
- assert os.path.isfile(result_csv_file), \
174
- 'Result file {} not found'.format(result_csv_file)
175
- assert os.path.isfile(class_mapping_csv_file), \
176
- 'Class mapping file {} not found'.format(class_mapping_csv_file)
177
- assert os.path.isdir(image_folder), \
178
- 'Image folder {} not found'.format(image_folder)
179
-
180
- if output_file is None:
181
- output_file = result_csv_file + '.json'
182
-
183
- image_files_relative = _find_images(image_folder,
184
- recursive=True,
185
- return_relative_paths=True,
186
- convert_slashes=True)
187
- image_file_base_flattened_to_image_file_relative = {}
188
- for fn in image_files_relative:
189
- # Convert, e.g. B04_R1/I__00108.JPG to B04_R1_I__00108
190
- fn_flattened = fn.replace('/','_')
191
- fn_flattened_base = os.path.splitext(fn_flattened)[0]
192
- image_file_base_flattened_to_image_file_relative[fn_flattened_base] = \
193
- fn
194
-
195
- # Read the .csv files
196
- df_results = pd.read_csv(result_csv_file)
197
- df_class_mapping = pd.read_csv(class_mapping_csv_file)
198
-
199
- assert 'CLASS' in df_class_mapping.columns and 'SPECIES' in df_class_mapping.columns, \
200
- 'Unexpected column names in class mapping file {}'.format(class_mapping_csv_file)
201
-
202
- category_id_to_name = {}
203
- for i_row,row in df_class_mapping.iterrows():
204
- class_id = int(row['CLASS'])
205
- assert class_id not in category_id_to_name, \
206
- 'Class ID {} occurs more than once in class mapping file {}'.format(
207
- class_id,class_mapping_csv_file)
208
- category_id_to_name[class_id] = row['SPECIES']
209
-
210
- if len(category_id_to_name) != len(set(category_id_to_name.values())):
211
- print('Warning: one or more categories are used more than once in class mapping file {}'.format(
212
- class_mapping_csv_file))
213
-
214
- # Convert results
215
-
216
- fn_relative_to_im = {}
217
-
218
- # i_row = 0; row = df_results.iloc[i_row]
219
- for i_row,row in df_results.iterrows():
220
-
221
- # Map the .txt filename base to a relative path
222
- bn = row['filename']
223
- assert bn.lower().endswith('.txt')
224
- bn_no_ext = os.path.splitext(bn)[0]
225
- assert bn_no_ext in image_file_base_flattened_to_image_file_relative, \
226
- 'No image found for result row {}'.format(row['filename'])
227
-
228
- image_fn_relative = image_file_base_flattened_to_image_file_relative[bn_no_ext]
229
-
230
- # Have we seen another detection for this image?
231
- if image_fn_relative in fn_relative_to_im:
232
-
233
- im = fn_relative_to_im[image_fn_relative]
234
-
235
- # If not, load this image so we can read its size
236
- else:
237
-
238
- image_fn_abs = os.path.join(image_folder,image_fn_relative)
239
- image = Image.open(image_fn_abs)
240
- w = image.size[0]
241
- h = image.size[1]
242
-
243
- im = {}
244
- im['file'] = image_fn_relative
245
- im['width'] = w
246
- im['height'] = h
247
- im['detections'] = []
248
- im['datetime'] = str(row['datetime'])
249
- fn_relative_to_im[image_fn_relative] = im
250
-
251
- # Convert annotation
252
- x_center_abs = row['x_center']
253
- y_center_abs = row['y_center']
254
- box_width_abs = row['width']
255
- box_height_abs = row['height']
256
-
257
- # Convert to relative coordinates
258
- box_left_abs = x_center_abs - (box_width_abs/2.0)
259
- box_top_abs = y_center_abs - (box_height_abs/2.0)
260
- bbox_normalized = [box_left_abs/im['width'],
261
- box_top_abs/im['height'],
262
- box_width_abs/im['width'],
263
- box_height_abs/im['height']]
264
-
265
- category_id = str(int(row['category']))
266
- confidence = row['confidence']
267
- assert isinstance(confidence,float) and confidence <= 1.0 and confidence >= 0.0
268
-
269
- det = {}
270
- im['detections'].append(det)
271
- det['category'] = category_id
272
- det['conf'] = confidence
273
- det['bbox'] = bbox_normalized
274
-
275
- # ...for each row
276
-
277
- n_empty_images = 0
278
-
279
- # Handle images without annotations
280
- for fn_relative in image_files_relative:
281
-
282
- if fn_relative not in fn_relative_to_im:
283
- if unannotated_image_handling == 'empty':
284
- im = {}
285
- im['file'] = fn_relative
286
- im['detections'] = []
287
- fn_relative_to_im[fn_relative] = im
288
- n_empty_images += 1
289
- # Don't bother to read width and height here
290
- elif unannotated_image_handling == 'warning':
291
- print('Warning: image {} is not represented in the .csv results file'.format(fn_relative))
292
- elif unannotated_image_handling == 'error':
293
- raise ValueError('Image {} is not represented in the .csv results file'.format(fn_relative))
294
- elif unannotated_image_handling == 'skip':
295
- continue
296
-
297
- # ...for each image file
298
-
299
- if n_empty_images > 0:
300
- print('Warning: assuming {} of {} images without annotations are empty'.format(
301
- n_empty_images,len(image_files_relative)))
302
-
303
- images = list(fn_relative_to_im.values())
304
-
305
- # The MD output format uses string-ints for category IDs, right now we have ints
306
- detection_categories = {}
307
- for category_id_int in category_id_to_name:
308
- detection_categories[str(category_id_int)] = category_id_to_name[category_id_int]
309
-
310
- info = {}
311
- info['format_version'] = '1.4'
312
- info['detector'] = 'RAIC .csv converter'
313
-
314
- d = {}
315
- d['images'] = images
316
- d['detection_categories'] = detection_categories
317
- d['info'] = info
318
-
319
- with open(output_file,'w') as f:
320
- json.dump(d,f,indent=1)
321
-
322
- return output_file
323
-
324
- # ...def raic_csv_to_md_results(...)
325
-
326
-
327
- #%% Interactive driver
328
-
329
- if False:
330
-
331
- pass
332
-
333
- #%% Test conversion
334
-
335
- base_folder = r'G:\temp\S24_B04_R1_output_annotations_for_Dan'
336
- result_csv_file = os.path.join(base_folder,'S24_B04_R1_output_annotations_for_Dan.csv')
337
- class_mapping_csv_file = os.path.join(base_folder,'categories_key.csv')
338
-
339
- # This is wrong, B04_R1 has to be part of the image paths
340
- # image_folder = os.path.join(base_folder,'B04_R1')
341
-
342
- image_folder = base_folder
343
-
344
- output_file = None
345
- unannotated_image_handling='empty'
346
-
347
- output_file = raic_csv_to_md_results(result_csv_file=result_csv_file,
348
- class_mapping_csv_file=class_mapping_csv_file,
349
- image_folder=image_folder,
350
- output_file=output_file,
351
- unannotated_image_handling=unannotated_image_handling)
352
-
353
- #%% Validate results file
354
-
355
- from megadetector.postprocessing.validate_batch_results import \
356
- ValidateBatchResultsOptions, validate_batch_results
357
-
358
- validation_options = ValidateBatchResultsOptions()
359
- validation_options.check_image_existence = True
360
- validation_options.relative_path_base = image_folder
361
- validation_options.return_data = True
362
-
363
- results = validate_batch_results(output_file,validation_options)
364
- assert len(results['validation_results']['errors']) == 0
365
- assert len(results['validation_results']['warnings']) == 0
366
-
367
-
368
- #%% Preview results
369
-
370
- from megadetector.postprocessing.postprocess_batch_results import \
371
- PostProcessingOptions, process_batch_results
372
-
373
- postprocessing_options = PostProcessingOptions()
374
-
375
- postprocessing_options.md_results_file = output_file
376
- postprocessing_options.output_dir = r'g:\temp\serengeti-conversion-preview'
377
- postprocessing_options.image_base_dir = image_folder
378
- postprocessing_options.confidence_threshold = 0.2
379
- postprocessing_options.num_images_to_sample = None
380
- postprocessing_options.viz_target_width = 1280
381
- postprocessing_options.line_thickness = 4
382
- postprocessing_options.parallelize_rendering_n_cores = 10
383
- postprocessing_options.parallelize_rendering_with_threads = True
384
-
385
- postprocessing_results = process_batch_results(postprocessing_options)
386
-
387
- from megadetector.utils.path_utils import open_file
388
- open_file(postprocessing_results.output_html_file)
389
-
390
-
391
- #%% Command-line driver
392
-
393
- def main():
394
-
395
- parser = argparse.ArgumentParser()
396
- parser.add_argument('result_csv_file', type=str,
397
- help='csv file containing AI results')
398
- parser.add_argument('class_mapping_csv_file', type=str,
399
- help='csv file containing class mappings (with columns CLASS, SPECIES)')
400
- parser.add_argument('image_folder', type=str,
401
- help='folder containing the images referred to in [result_csv_file]')
402
- parser.add_argument('--output_file', type=str, default=None,
403
- help='.json file to which we should write results (defaults to [result_csv_file].json)')
404
-
405
- if len(sys.argv[1:])==0:
406
- parser.print_help()
407
- parser.exit()
408
-
409
- args = parser.parse_args()
410
- raic_csv_to_md_results(result_csv_file=args.result_csv_file,
411
- class_mapping_csv_file=args.class_mapping_csv_file,
412
- image_folder=args.image_folder,
413
- output_file=args.output_file)
414
-
415
- if __name__ == '__main__':
416
- main()