megadetector 5.0.5__py3-none-any.whl → 5.0.7__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 (132) hide show
  1. api/batch_processing/data_preparation/manage_local_batch.py +302 -263
  2. api/batch_processing/data_preparation/manage_video_batch.py +81 -2
  3. api/batch_processing/postprocessing/add_max_conf.py +1 -0
  4. api/batch_processing/postprocessing/categorize_detections_by_size.py +50 -19
  5. api/batch_processing/postprocessing/compare_batch_results.py +110 -60
  6. api/batch_processing/postprocessing/load_api_results.py +56 -70
  7. api/batch_processing/postprocessing/md_to_coco.py +1 -1
  8. api/batch_processing/postprocessing/md_to_labelme.py +2 -1
  9. api/batch_processing/postprocessing/postprocess_batch_results.py +240 -81
  10. api/batch_processing/postprocessing/render_detection_confusion_matrix.py +625 -0
  11. api/batch_processing/postprocessing/repeat_detection_elimination/find_repeat_detections.py +71 -23
  12. api/batch_processing/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +1 -1
  13. api/batch_processing/postprocessing/repeat_detection_elimination/repeat_detections_core.py +227 -75
  14. api/batch_processing/postprocessing/subset_json_detector_output.py +132 -5
  15. api/batch_processing/postprocessing/top_folders_to_bottom.py +1 -1
  16. api/synchronous/api_core/animal_detection_api/detection/run_detector_batch.py +2 -2
  17. classification/prepare_classification_script.py +191 -191
  18. data_management/coco_to_yolo.py +68 -45
  19. data_management/databases/integrity_check_json_db.py +7 -5
  20. data_management/generate_crops_from_cct.py +3 -3
  21. data_management/get_image_sizes.py +8 -6
  22. data_management/importers/add_timestamps_to_icct.py +79 -0
  23. data_management/importers/animl_results_to_md_results.py +160 -0
  24. data_management/importers/auckland_doc_test_to_json.py +4 -4
  25. data_management/importers/auckland_doc_to_json.py +1 -1
  26. data_management/importers/awc_to_json.py +5 -5
  27. data_management/importers/bellevue_to_json.py +5 -5
  28. data_management/importers/carrizo_shrubfree_2018.py +5 -5
  29. data_management/importers/carrizo_trail_cam_2017.py +5 -5
  30. data_management/importers/cct_field_adjustments.py +2 -3
  31. data_management/importers/channel_islands_to_cct.py +4 -4
  32. data_management/importers/ena24_to_json.py +5 -5
  33. data_management/importers/helena_to_cct.py +10 -10
  34. data_management/importers/idaho-camera-traps.py +12 -12
  35. data_management/importers/idfg_iwildcam_lila_prep.py +8 -8
  36. data_management/importers/jb_csv_to_json.py +4 -4
  37. data_management/importers/missouri_to_json.py +1 -1
  38. data_management/importers/noaa_seals_2019.py +1 -1
  39. data_management/importers/pc_to_json.py +5 -5
  40. data_management/importers/prepare-noaa-fish-data-for-lila.py +4 -4
  41. data_management/importers/prepare_zsl_imerit.py +5 -5
  42. data_management/importers/rspb_to_json.py +4 -4
  43. data_management/importers/save_the_elephants_survey_A.py +5 -5
  44. data_management/importers/save_the_elephants_survey_B.py +6 -6
  45. data_management/importers/snapshot_safari_importer.py +9 -9
  46. data_management/importers/snapshot_serengeti_lila.py +9 -9
  47. data_management/importers/timelapse_csv_set_to_json.py +5 -7
  48. data_management/importers/ubc_to_json.py +4 -4
  49. data_management/importers/umn_to_json.py +4 -4
  50. data_management/importers/wellington_to_json.py +1 -1
  51. data_management/importers/wi_to_json.py +2 -2
  52. data_management/importers/zamba_results_to_md_results.py +181 -0
  53. data_management/labelme_to_coco.py +35 -7
  54. data_management/labelme_to_yolo.py +229 -0
  55. data_management/lila/add_locations_to_island_camera_traps.py +1 -1
  56. data_management/lila/add_locations_to_nacti.py +147 -0
  57. data_management/lila/create_lila_blank_set.py +474 -0
  58. data_management/lila/create_lila_test_set.py +2 -1
  59. data_management/lila/create_links_to_md_results_files.py +106 -0
  60. data_management/lila/download_lila_subset.py +46 -21
  61. data_management/lila/generate_lila_per_image_labels.py +23 -14
  62. data_management/lila/get_lila_annotation_counts.py +17 -11
  63. data_management/lila/lila_common.py +14 -11
  64. data_management/lila/test_lila_metadata_urls.py +116 -0
  65. data_management/ocr_tools.py +829 -0
  66. data_management/resize_coco_dataset.py +13 -11
  67. data_management/yolo_output_to_md_output.py +84 -12
  68. data_management/yolo_to_coco.py +38 -20
  69. detection/process_video.py +36 -14
  70. detection/pytorch_detector.py +23 -8
  71. detection/run_detector.py +76 -19
  72. detection/run_detector_batch.py +178 -63
  73. detection/run_inference_with_yolov5_val.py +326 -57
  74. detection/run_tiled_inference.py +153 -43
  75. detection/video_utils.py +34 -8
  76. md_utils/ct_utils.py +172 -1
  77. md_utils/md_tests.py +372 -51
  78. md_utils/path_utils.py +167 -39
  79. md_utils/process_utils.py +26 -7
  80. md_utils/split_locations_into_train_val.py +215 -0
  81. md_utils/string_utils.py +10 -0
  82. md_utils/url_utils.py +0 -2
  83. md_utils/write_html_image_list.py +9 -26
  84. md_visualization/plot_utils.py +12 -8
  85. md_visualization/visualization_utils.py +106 -7
  86. md_visualization/visualize_db.py +16 -8
  87. md_visualization/visualize_detector_output.py +208 -97
  88. {megadetector-5.0.5.dist-info → megadetector-5.0.7.dist-info}/METADATA +3 -6
  89. {megadetector-5.0.5.dist-info → megadetector-5.0.7.dist-info}/RECORD +98 -121
  90. {megadetector-5.0.5.dist-info → megadetector-5.0.7.dist-info}/WHEEL +1 -1
  91. taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +1 -1
  92. taxonomy_mapping/map_new_lila_datasets.py +43 -39
  93. taxonomy_mapping/prepare_lila_taxonomy_release.py +5 -2
  94. taxonomy_mapping/preview_lila_taxonomy.py +27 -27
  95. taxonomy_mapping/species_lookup.py +33 -13
  96. taxonomy_mapping/taxonomy_csv_checker.py +7 -5
  97. api/synchronous/api_core/yolov5/detect.py +0 -252
  98. api/synchronous/api_core/yolov5/export.py +0 -607
  99. api/synchronous/api_core/yolov5/hubconf.py +0 -146
  100. api/synchronous/api_core/yolov5/models/__init__.py +0 -0
  101. api/synchronous/api_core/yolov5/models/common.py +0 -738
  102. api/synchronous/api_core/yolov5/models/experimental.py +0 -104
  103. api/synchronous/api_core/yolov5/models/tf.py +0 -574
  104. api/synchronous/api_core/yolov5/models/yolo.py +0 -338
  105. api/synchronous/api_core/yolov5/train.py +0 -670
  106. api/synchronous/api_core/yolov5/utils/__init__.py +0 -36
  107. api/synchronous/api_core/yolov5/utils/activations.py +0 -103
  108. api/synchronous/api_core/yolov5/utils/augmentations.py +0 -284
  109. api/synchronous/api_core/yolov5/utils/autoanchor.py +0 -170
  110. api/synchronous/api_core/yolov5/utils/autobatch.py +0 -66
  111. api/synchronous/api_core/yolov5/utils/aws/__init__.py +0 -0
  112. api/synchronous/api_core/yolov5/utils/aws/resume.py +0 -40
  113. api/synchronous/api_core/yolov5/utils/benchmarks.py +0 -148
  114. api/synchronous/api_core/yolov5/utils/callbacks.py +0 -71
  115. api/synchronous/api_core/yolov5/utils/dataloaders.py +0 -1087
  116. api/synchronous/api_core/yolov5/utils/downloads.py +0 -178
  117. api/synchronous/api_core/yolov5/utils/flask_rest_api/example_request.py +0 -19
  118. api/synchronous/api_core/yolov5/utils/flask_rest_api/restapi.py +0 -46
  119. api/synchronous/api_core/yolov5/utils/general.py +0 -1018
  120. api/synchronous/api_core/yolov5/utils/loggers/__init__.py +0 -187
  121. api/synchronous/api_core/yolov5/utils/loggers/wandb/__init__.py +0 -0
  122. api/synchronous/api_core/yolov5/utils/loggers/wandb/log_dataset.py +0 -27
  123. api/synchronous/api_core/yolov5/utils/loggers/wandb/sweep.py +0 -41
  124. api/synchronous/api_core/yolov5/utils/loggers/wandb/wandb_utils.py +0 -577
  125. api/synchronous/api_core/yolov5/utils/loss.py +0 -234
  126. api/synchronous/api_core/yolov5/utils/metrics.py +0 -355
  127. api/synchronous/api_core/yolov5/utils/plots.py +0 -489
  128. api/synchronous/api_core/yolov5/utils/torch_utils.py +0 -314
  129. api/synchronous/api_core/yolov5/val.py +0 -394
  130. md_utils/matlab_porting_tools.py +0 -97
  131. {megadetector-5.0.5.dist-info → megadetector-5.0.7.dist-info}/LICENSE +0 -0
  132. {megadetector-5.0.5.dist-info → megadetector-5.0.7.dist-info}/top_level.txt +0 -0
@@ -228,7 +228,7 @@ if False:
228
228
  seq_id_to_annotations,annotations,categories,species_to_category = cct_cache
229
229
 
230
230
 
231
- #%% Take a look at categories (just sanity-checking)
231
+ #%% Take a look at categories
232
232
 
233
233
  if False:
234
234
 
@@ -365,7 +365,7 @@ print('\nOf {} images: {} missing, {} corrupt, {} no annotation'.format(len(imag
365
365
  n_missing, n_corrupt, n_no_annotation))
366
366
 
367
367
 
368
- #%% Print distribution of sequence lengths (sanity-check)
368
+ #%% Print distribution of sequence lengths
369
369
 
370
370
  seq_id_to_sequence_length = {}
371
371
 
@@ -508,7 +508,7 @@ for iSeason,season_mismatches in enumerate(mismatches_by_season):
508
508
  print('Size mismatches in season {}: {}'.format(iSeason+1,len(mismatches_by_season[iSeason])))
509
509
 
510
510
 
511
- #%% Sanity-check image and annotation uniqueness
511
+ #%% Validate image and annotation uniqueness
512
512
 
513
513
  tmp_img_ids = set()
514
514
  tmp_ann_ids = set()
@@ -852,22 +852,22 @@ for i_season in seasons_to_zip:
852
852
  # ...for each season
853
853
 
854
854
 
855
- #%% Sanity-check .json files
855
+ #%% Validate .json files
856
856
 
857
857
  # %logstart -o r'E:\snapshot_temp\python.txt'
858
858
 
859
- from data_management.databases import sanity_check_json_db
859
+ from data_management.databases import integrity_check_json_db
860
860
 
861
861
  files_to_check = glob.glob(os.path.join(output_base,'*.json'))
862
862
 
863
- options = sanity_check_json_db.SanityCheckOptions()
863
+ options = integrity_check_json_db.IntegrityCheckOptions()
864
864
  options.baseDir = image_base
865
865
  options.bCheckImageSizes = False
866
866
  options.bCheckImageExistence = True
867
867
  options.bFindUnusedImages = False
868
868
 
869
869
  for fn in files_to_check:
870
- sortedCategories, data = sanity_check_json_db.sanity_check_json_db(fn,options)
870
+ sortedCategories, data = integrity_check_json_db.integrity_check_json_db(fn,options)
871
871
 
872
872
 
873
873
  #%% Zip up .json and .csv files
@@ -894,7 +894,7 @@ for fn in tqdm(files_to_zip):
894
894
  zip_single_file(fn)
895
895
 
896
896
 
897
- #%% Super-sanity-check that S11 info isn't leaking
897
+ #%% Validate that S11 info isn't leaking
898
898
 
899
899
  files_to_check = glob.glob(os.path.join(output_base,'*.json'))
900
900
 
@@ -992,7 +992,7 @@ viz_options.num_to_visualize = 500
992
992
  viz_options.trim_to_images_with_bboxes = True
993
993
  viz_options.add_search_links = True
994
994
  viz_options.sort_by_filename = False
995
- html_output_file,bbox_db = visualize_db.process_images(bbox_json_fn,os.path.join(output_base,'preview2'),image_base,viz_options)
995
+ html_output_file,bbox_db = visualize_db.visualize_db(bbox_json_fn,os.path.join(output_base,'preview2'),image_base,viz_options)
996
996
  os.startfile(html_output_file)
997
997
 
998
998
 
@@ -24,7 +24,7 @@ import numpy as np
24
24
  from tqdm import tqdm
25
25
 
26
26
  from md_visualization import visualize_db
27
- from data_management.databases import sanity_check_json_db
27
+ from data_management.databases import integrity_check_json_db
28
28
  from md_utils import path_utils
29
29
 
30
30
  # Text file with relative paths to all files (images and .csv files)
@@ -84,7 +84,6 @@ for fn in image_files:
84
84
  print('Found {} image files and {} .csv files ({} non-matching files)'.format(
85
85
  len(image_files),len(csv_files),len(non_matching_files)))
86
86
 
87
-
88
87
 
89
88
  #%% Verify column consistency, create a giant array with all rows from all .csv files
90
89
 
@@ -473,10 +472,10 @@ print('Finished writing .json file with {} images, {} annotations, and {} catego
473
472
  len(images),len(annotations),len(categories)))
474
473
 
475
474
 
476
- #%% Sanity-check the database's integrity
475
+ #%% Validate the database's integrity
477
476
 
478
- options = sanity_check_json_db.SanityCheckOptions()
479
- sortedCategories,data = sanity_check_json_db.sanity_check_json_db(output_file, options)
477
+ options = integrity_check_json_db.IntegrityCheckOptions()
478
+ sortedCategories,data = integrity_check_json_db.integrity_check_json_db(output_file, options)
480
479
 
481
480
 
482
481
  #%% Render a bunch of images to make sure the labels got carried along correctly
@@ -487,6 +486,5 @@ options.parallelize_rendering = True
487
486
  options.sort_by_filename = False
488
487
  options.classes_to_exclude = ['unlabeled','empty','ambiguous']
489
488
 
490
- html_output_file,data = visualize_db.process_images(output_file,preview_base,file_base,options)
489
+ html_output_file,data = visualize_db.visualize_db(output_file,preview_base,file_base,options)
491
490
  os.startfile(html_output_file)
492
-
@@ -25,7 +25,7 @@ from tqdm import tqdm
25
25
  from PIL import Image
26
26
 
27
27
  from md_visualization import visualize_db
28
- from data_management.databases import sanity_check_json_db
28
+ from data_management.databases import integrity_check_json_db
29
29
  from md_utils.path_utils import find_images
30
30
 
31
31
  input_base = r'e:\ubc'
@@ -373,13 +373,13 @@ print('Finished writing .json file with {} images, {} annotations, and {} catego
373
373
 
374
374
  #%% Validate output
375
375
 
376
- options = sanity_check_json_db.SanityCheckOptions()
376
+ options = integrity_check_json_db.IntegrityCheckOptions()
377
377
  options.baseDir = output_base
378
378
  options.bCheckImageSizes = False
379
379
  options.bCheckImageExistence = False
380
380
  options.bFindUnusedImages = True
381
381
 
382
- sortedCategories, data, errors = sanity_check_json_db.sanity_check_json_db(
382
+ sortedCategories, data, errors = integrity_check_json_db.integrity_check_json_db(
383
383
  output_json_file, options)
384
384
 
385
385
 
@@ -391,7 +391,7 @@ viz_options.trim_to_images_with_bboxes = False
391
391
  viz_options.add_search_links = True
392
392
  viz_options.sort_by_filename = False
393
393
  viz_options.parallelize_rendering = True
394
- html_output_file, image_db = visualize_db.process_images(db_path=output_json_file,
394
+ html_output_file, image_db = visualize_db.visualize_db(db_path=output_json_file,
395
395
  output_dir=os.path.join(
396
396
  output_base, 'preview'),
397
397
  image_base_dir=output_base,
@@ -292,7 +292,7 @@ import uuid
292
292
  import datetime
293
293
  from tqdm import tqdm
294
294
 
295
- from data_management.databases import sanity_check_json_db
295
+ from data_management.databases import integrity_check_json_db
296
296
 
297
297
  output_base = 'f:\orinoquia_camera_traps'
298
298
  output_image_base = os.path.join(output_base,'images')
@@ -431,13 +431,13 @@ print('Finished writing json to {}'.format(output_json_filename))
431
431
 
432
432
  #%% Validate .json file
433
433
 
434
- options = sanity_check_json_db.SanityCheckOptions()
434
+ options = integrity_check_json_db.IntegrityCheckOptions()
435
435
  options.baseDir = output_base
436
436
  options.bCheckImageSizes = False
437
437
  options.bCheckImageExistence = False
438
438
  options.bFindUnusedImages = False
439
439
 
440
- _, _, _ = sanity_check_json_db.sanity_check_json_db(output_json_filename, options)
440
+ _, _, _ = integrity_check_json_db.integrity_check_json_db(output_json_filename, options)
441
441
 
442
442
 
443
443
  #%% Map relative paths to annotation categories
@@ -497,7 +497,7 @@ viz_options.parallelize_rendering = True
497
497
  viz_options.include_filename_links = True
498
498
 
499
499
  # viz_options.classes_to_exclude = ['test']
500
- html_output_file, _ = visualize_db.process_images(db_path=output_json_filename,
500
+ html_output_file, _ = visualize_db.visualize_db(db_path=output_json_filename,
501
501
  output_dir=os.path.join(
502
502
  output_base,'preview'),
503
503
  image_base_dir=os.path.join(output_image_base,'public'),
@@ -253,7 +253,7 @@ viz_options.add_search_links = False
253
253
  viz_options.sort_by_filename = False
254
254
  viz_options.parallelize_rendering = True
255
255
  viz_options.classes_to_exclude = ['test']
256
- html_output_file, image_db = visualize_db.process_images(db_path=output_file,
256
+ html_output_file, image_db = visualize_db.visualize_db(db_path=output_file,
257
257
  output_dir=os.path.join(
258
258
  preview_dir),
259
259
  image_base_dir=image_directory,
@@ -351,7 +351,7 @@ viz_options.sort_by_filename = False
351
351
  viz_options.parallelize_rendering = True
352
352
  viz_options.include_filename_links = True
353
353
 
354
- html_output_file, _ = visualize_db.process_images(db_path=output_json_filename,
354
+ html_output_file, _ = visualize_db.visualize_db(db_path=output_json_filename,
355
355
  output_dir=preview_base,
356
356
  image_base_dir=image_base,
357
357
  options=viz_options)
@@ -426,7 +426,7 @@ if create_ordered_dataset:
426
426
  viz_options.parallelize_rendering = True
427
427
  viz_options.include_filename_links = True
428
428
 
429
- html_output_file, _ = visualize_db.process_images(db_path=ordered_json_filename,
429
+ html_output_file, _ = visualize_db.visualize_db(db_path=ordered_json_filename,
430
430
  output_dir=ordered_preview_base,
431
431
  image_base_dir=ordered_image_base,
432
432
  options=viz_options)
@@ -0,0 +1,181 @@
1
+ ########
2
+ #
3
+ # zamba_results_to_md_results.py
4
+ #
5
+ # Convert a labels.csv file produced by Zamba Cloud to a MD results file suitable
6
+ # for import into Timelapse.
7
+ #
8
+ # Columns are expected to be:
9
+ #
10
+ # video_uuid (not used)
11
+ # original_filename (assumed to be a relative path name)
12
+ # top_k_label,top_k_probability, for k = 1..N
13
+ # [category name 1],[category name 2],...
14
+ # corrected_label
15
+ #
16
+ # Because the MD results file fundamentally stores detections, what we'll
17
+ # actually do is created bogus detections that fill the entire image. Detection
18
+ # coordinates are not currently used in Timelapse video video anyway.
19
+ #
20
+ # There is no special handling of empty/blank categories; because these results are
21
+ # based on a classifier, rather than a detector (where "blank" would be the absence of
22
+ # all other categories), "blank" can be queried in Timelapse just like any other class.
23
+ #
24
+ ########
25
+
26
+ #%% Imports and constants
27
+
28
+ import pandas as pd
29
+ import json
30
+
31
+
32
+ #%% Main function
33
+
34
+ def zamba_results_to_md_results(input_file,output_file=None):
35
+ """
36
+ Converts the .csv file [input_file] to the MD-formatted .json file [output_file].
37
+
38
+ If [output_file] is None, '.json' will be appended to the input file.
39
+ """
40
+
41
+ if output_file is None:
42
+ output_file = input_file + '.json'
43
+
44
+ df = pd.read_csv(input_file)
45
+
46
+ expected_columns = ('video_uuid','corrected_label','original_filename')
47
+ for s in expected_columns:
48
+ assert s in df.columns,\
49
+ 'Expected column {} not found, are you sure this is a Zamba results .csv file?'.format(
50
+ s)
51
+
52
+ # How many results are included per file?
53
+ assert 'top_1_probability' in df.columns and 'top_1_label' in df.columns
54
+ top_k = 2
55
+ while(True):
56
+ p_string = 'top_' + str(top_k) + '_probability'
57
+ label_string = 'top_' + str(top_k) + '_label'
58
+
59
+ if p_string in df.columns:
60
+ assert label_string in df.columns,\
61
+ 'Oops, {} is a column but {} is not'.format(
62
+ p_string,label_string)
63
+ top_k += 1
64
+ continue
65
+ else:
66
+ assert label_string not in df.columns,\
67
+ 'Oops, {} is a column but {} is not'.format(
68
+ label_string,p_string)
69
+ top_k -= 1
70
+ break
71
+
72
+ print('Found {} probability column pairs'.format(top_k))
73
+
74
+ # Category names start after the fixed columns and the probability columns
75
+ category_names = []
76
+ column_names = list(df.columns)
77
+ first_category_name_index = 0
78
+ while('top_' in column_names[first_category_name_index] or \
79
+ column_names[first_category_name_index] in expected_columns):
80
+ first_category_name_index += 1
81
+
82
+ i_column = first_category_name_index
83
+ while( (i_column < len(column_names)) and (column_names[i_column] != 'corrected_label') ):
84
+ category_names.append(column_names[i_column])
85
+ i_column += 1
86
+
87
+ print('Found {} categories:\n'.format(len(category_names)))
88
+
89
+ for s in category_names:
90
+ print(s)
91
+
92
+ info = {}
93
+ info['format_version'] = '1.3'
94
+ info['detector'] = 'Zamba Cloud'
95
+ info['classifier'] = 'Zamba Cloud'
96
+
97
+ detection_category_id_to_name = {}
98
+ for category_id,category_name in enumerate(category_names):
99
+ detection_category_id_to_name[str(category_id)] = category_name
100
+ detection_category_name_to_id = {v: k for k, v in detection_category_id_to_name.items()}
101
+
102
+ images = []
103
+
104
+ # i_row = 0; row = df.iloc[i_row]
105
+ for i_row,row in df.iterrows():
106
+
107
+ im = {}
108
+ images.append(im)
109
+ im['file'] = row['original_filename']
110
+
111
+ detections = []
112
+
113
+ # k = 1
114
+ for k in range(1,top_k+1):
115
+ label = row['top_{}_label'.format(k)]
116
+ confidence = row['top_{}_probability'.format(k)]
117
+ det = {}
118
+ det['category'] = detection_category_name_to_id[label]
119
+ det['conf'] = confidence
120
+ det['bbox'] = [0,0,1.0,1.0]
121
+ detections.append(det)
122
+
123
+ im['detections'] = detections
124
+
125
+ # ...for each row
126
+
127
+ results = {}
128
+ results['info'] = info
129
+ results['detection_categories'] = detection_category_id_to_name
130
+ results['images'] = images
131
+
132
+ with open(output_file,'w') as f:
133
+ json.dump(results,f,indent=1)
134
+
135
+ # ...zamba_results_to_md_results(...)
136
+
137
+
138
+ #%% Interactive driver
139
+
140
+ if False:
141
+
142
+ pass
143
+
144
+ #%%
145
+
146
+ input_file = r"G:\temp\labels-job-b95a4b76-e332-4e17-ab40-03469392d36a-2023-11-04_16-28-50.060130.csv"
147
+ output_file = None
148
+ zamba_results_to_md_results(input_file,output_file)
149
+
150
+
151
+ #%% Command-line driver
152
+
153
+ import sys,argparse
154
+
155
+ def main():
156
+
157
+ parser = argparse.ArgumentParser(
158
+ description='Convert a Zamba-formatted .csv results file to a MD-formatted .json results file')
159
+
160
+ parser.add_argument(
161
+ 'input_file',
162
+ type=str,
163
+ help='input .csv file')
164
+
165
+ parser.add_argument(
166
+ '--output_file',
167
+ type=str,
168
+ default=None,
169
+ help='output .json file (defaults to input file appended with ".json")')
170
+
171
+ if len(sys.argv[1:]) == 0:
172
+ parser.print_help()
173
+ parser.exit()
174
+
175
+ args = parser.parse_args()
176
+
177
+ zamba_results_to_md_results(args.input_file,args.output_file)
178
+
179
+ if __name__ == '__main__':
180
+ main()
181
+
@@ -20,11 +20,19 @@ from tqdm import tqdm
20
20
 
21
21
  #%% Functions
22
22
 
23
- def labelme_to_coco(input_folder,output_file=None,category_id_to_category_name=None,
24
- empty_category_name='empty',empty_category_id=None,info_struct=None,
25
- relative_paths_to_include=None,relative_paths_to_exclude=None,
26
- use_folders_as_labels=False,recursive=True,no_json_handling='skip',
27
- validate_image_sizes=True):
23
+ def labelme_to_coco(input_folder,
24
+ output_file=None,
25
+ category_id_to_category_name=None,
26
+ empty_category_name='empty',
27
+ empty_category_id=None,
28
+ info_struct=None,
29
+ relative_paths_to_include=None,
30
+ relative_paths_to_exclude=None,
31
+ use_folders_as_labels=False,
32
+ recursive=True,
33
+ no_json_handling='skip',
34
+ validate_image_sizes=True,
35
+ right_edge_quantization_threshold=None):
28
36
  """
29
37
  Find all images in [input_folder] that have corresponding .json files, and convert
30
38
  to a COCO .json file.
@@ -48,7 +56,13 @@ def labelme_to_coco(input_folder,output_file=None,category_id_to_category_name=N
48
56
 
49
57
  * 'skip': ignore image files with no corresponding .json files
50
58
  * 'empty': treat image files with no corresponding .json files as empty
51
- * 'error': throw an error when an image file has no corresponding .json file
59
+ * 'error': throw an error when an image file has no corresponding .json file
60
+
61
+ right_edge_quantization_threshold is an off-by-default hack to handle cases where
62
+ boxes that really should be running off the right side of the image only extend like 99%
63
+ of the way there, due to what appears to be a slight bias inherent to MD. If a box extends
64
+ within [right_edge_quantization_threshold] (a small number, from 0 to 1, but probably around
65
+ 0.02) of the right edge of the image, it will be extended to the far right edge.
52
66
  """
53
67
 
54
68
  if category_id_to_category_name is None:
@@ -86,6 +100,8 @@ def labelme_to_coco(input_folder,output_file=None,category_id_to_category_name=N
86
100
  images = []
87
101
  annotations = []
88
102
 
103
+ n_edges_quantized = 0
104
+
89
105
  # image_fn_relative = image_filenames_relative[0]
90
106
  for image_fn_relative in tqdm(image_filenames_relative):
91
107
 
@@ -182,6 +198,14 @@ def labelme_to_coco(input_folder,output_file=None,category_id_to_category_name=N
182
198
  x1 = max(p0[0],p1[0])
183
199
  y0 = min(p0[1],p1[1])
184
200
  y1 = max(p0[1],p1[1])
201
+
202
+ if right_edge_quantization_threshold is not None:
203
+ x1_rel = x1 / (im['width'] - 1)
204
+ right_edge_distance = 1.0 - x1_rel
205
+ if right_edge_distance < right_edge_quantization_threshold:
206
+ n_edges_quantized += 1
207
+ x1 = im['width'] - 1
208
+
185
209
  bbox = [x0,y0,abs(x1-x0),abs(y1-y0)]
186
210
  ann = {}
187
211
  ann['id'] = str(uuid.uuid1())
@@ -197,6 +221,10 @@ def labelme_to_coco(input_folder,output_file=None,category_id_to_category_name=N
197
221
 
198
222
  # ..for each image
199
223
 
224
+ if n_edges_quantized > 0:
225
+ print('Quantized the right edge in {} of {} images'.format(
226
+ n_edges_quantized,len(image_filenames_relative)))
227
+
200
228
  output_dict = {}
201
229
  output_dict['images'] = images
202
230
  output_dict['annotations'] = annotations
@@ -324,7 +352,7 @@ if False:
324
352
  options.viz_size = (900, -1)
325
353
  options.num_to_visualize = 5000
326
354
 
327
- html_file,_ = visualize_db.process_images(output_file,os.path.expanduser('~/tmp/labelme_to_coco_preview'),
355
+ html_file,_ = visualize_db.visualize_db(output_file,os.path.expanduser('~/tmp/labelme_to_coco_preview'),
328
356
  input_folder,options)
329
357
 
330
358