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
@@ -350,26 +350,56 @@ def process_image(im_file, detector, confidence_threshold, image=None,
350
350
  # ...def process_image(...)
351
351
 
352
352
 
353
+ def load_custom_class_mapping(class_mapping_filename):
354
+ """
355
+ This is an experimental hack to allow the use of non-MD YOLOv5 models through
356
+ the same infrastructure; it disables the code that enforces MDv5-like class lists.
357
+
358
+ Should be a .json file that maps int-strings to strings, or a YOLOv5 dataset.yaml file.
359
+ """
360
+
361
+ if class_mapping_filename is None:
362
+ return
363
+
364
+ run_detector.USE_MODEL_NATIVE_CLASSES = True
365
+ if class_mapping_filename.endswith('.json'):
366
+ with open(class_mapping_filename,'r') as f:
367
+ class_mapping = json.load(f)
368
+ elif (class_mapping_filename.endswith('.yml') or class_mapping_filename.endswith('.yaml')):
369
+ from data_management.yolo_output_to_md_output import read_classes_from_yolo_dataset_file
370
+ class_mapping = read_classes_from_yolo_dataset_file(class_mapping_filename)
371
+ # convert from ints to int-strings
372
+ class_mapping = {str(k):v for k,v in class_mapping.items()}
373
+ else:
374
+ raise ValueError('Unrecognized class mapping file {}'.format(class_mapping_filename))
375
+
376
+ print('Loaded custom class mapping:')
377
+ print(class_mapping)
378
+ run_detector.DEFAULT_DETECTOR_LABEL_MAP = class_mapping
379
+ return class_mapping
380
+
381
+
353
382
  #%% Main function
354
383
 
355
384
  def load_and_run_detector_batch(model_file, image_file_names, checkpoint_path=None,
356
385
  confidence_threshold=run_detector.DEFAULT_OUTPUT_CONFIDENCE_THRESHOLD,
357
386
  checkpoint_frequency=-1, results=None, n_cores=1,
358
- use_image_queue=False, quiet=False, image_size=None, class_mapping_filename=None,
359
- include_image_size=False, include_image_timestamp=False,
360
- include_exif_data=False):
387
+ use_image_queue=False, quiet=False, image_size=None,
388
+ class_mapping_filename=None, include_image_size=False,
389
+ include_image_timestamp=False, include_exif_data=False):
361
390
  """
362
391
  Args
363
392
  - model_file: path to model file, or supported model string (e.g. "MDV5A")
364
393
  - image_file_names: list of strings (image filenames), a single image filename,
365
- a folder to recursively search for images in, or a .json file containing
366
- a list of images.
394
+ a folder to recursively search for images in, or a .json or .txt file
395
+ containing a list of images.
367
396
  - checkpoint_path: str, path to JSON checkpoint file
368
397
  - confidence_threshold: float, only detections above this threshold are returned
369
398
  - checkpoint_frequency: int, write results to JSON checkpoint file every N images
370
399
  - results: list of dict, existing results loaded from checkpoint
371
400
  - n_cores: int, # of CPU cores to use
372
401
  - class_mapping_filename: str, use a non-default class mapping supplied in a .json file
402
+ or YOLOv5 dataset.yaml file.
373
403
 
374
404
  Returns
375
405
  - results: list of dicts; each dict represents detections on one image
@@ -384,15 +414,8 @@ def load_and_run_detector_batch(model_file, image_file_names, checkpoint_path=No
384
414
  if checkpoint_frequency is None:
385
415
  checkpoint_frequency = -1
386
416
 
387
- # This is an experimental hack to allow the use of non-MD YOLOv5 models through
388
- # the same infrastructure; it disables the code that enforces MDv5-like class lists.
389
417
  if class_mapping_filename is not None:
390
- run_detector.USE_MODEL_NATIVE_CLASSES = True
391
- with open(class_mapping_filename,'r') as f:
392
- class_mapping = json.load(f)
393
- print('Loaded custom class mapping:')
394
- print(class_mapping)
395
- run_detector.DEFAULT_DETECTOR_LABEL_MAP = class_mapping
418
+ load_custom_class_mapping(class_mapping_filename)
396
419
 
397
420
  # Handle the case where image_file_names is not yet actually a list
398
421
  if isinstance(image_file_names,str):
@@ -403,22 +426,32 @@ def load_and_run_detector_batch(model_file, image_file_names, checkpoint_path=No
403
426
  image_file_names = path_utils.find_images(image_dir, True)
404
427
  print('{} image files found in folder {}'.format(len(image_file_names),image_dir))
405
428
 
406
- # A json list of image paths
407
- elif os.path.isfile(image_file_names) and image_file_names.endswith('.json'):
429
+ # A single file, or a list of image paths
430
+ elif os.path.isfile(image_file_names):
408
431
  list_file = image_file_names
409
- with open(list_file) as f:
410
- image_file_names = json.load(f)
411
- print('Loaded {} image filenames from list file {}'.format(len(image_file_names),list_file))
412
-
413
- # A single image file
414
- elif os.path.isfile(image_file_names) and path_utils.is_image_file(image_file_names):
415
- image_file_names = [image_file_names]
416
- print('Processing image {}'.format(image_file_names[0]))
432
+ if image_file_names.endswith('.json'):
433
+ with open(list_file,'r') as f:
434
+ image_file_names = json.load(f)
435
+ print('Loaded {} image filenames from .json list file {}'.format(
436
+ len(image_file_names),list_file))
437
+ elif image_file_names.endswith('.txt'):
438
+ with open(list_file,'r') as f:
439
+ image_file_names = f.readlines()
440
+ image_file_names = [s.strip() for s in image_file_names if len(s.strip()) > 0]
441
+ print('Loaded {} image filenames from .txt list file {}'.format(
442
+ len(image_file_names),list_file))
443
+ elif path_utils.is_image_file(image_file_names):
444
+ image_file_names = [image_file_names]
445
+ print('Processing image {}'.format(image_file_names[0]))
446
+ else:
447
+ raise ValueError(
448
+ 'File {} supplied as [image_file_names] argument, but extension is neither .json nor .txt'\
449
+ .format(
450
+ list_file))
451
+ else:
452
+ raise ValueError(
453
+ '{} supplied as [image_file_names] argument, but it does not appear to be a file or folder')
417
454
 
418
- else:
419
- raise ValueError('image_file_names is a string, but is not a directory, a json ' + \
420
- 'list (.json), or an image file')
421
-
422
455
  if results is None:
423
456
  results = []
424
457
 
@@ -718,17 +751,75 @@ if False:
718
751
 
719
752
  #%%
720
753
 
754
+ model_file = 'MDV5A'
755
+ image_dir = r'g:\camera_traps\camera_trap_images'
756
+ output_file = r'g:\temp\md-test.json'
757
+
758
+ recursive = True
759
+ output_relative_filenames = True
760
+ include_max_conf = False
761
+ quiet = True
762
+ image_size = None
763
+ use_image_queue = False
764
+ confidence_threshold = 0.0001
765
+ checkpoint_frequency = 5
721
766
  checkpoint_path = None
722
- model_file = r'G:\temp\models\md_v4.1.0.pb'
723
- confidence_threshold = 0.1
724
- checkpoint_frequency = -1
725
- results = None
767
+ resume_from_checkpoint = 'auto'
768
+ allow_checkpoint_overwrite = False
726
769
  ncores = 1
727
- use_image_queue = False
728
- quiet = False
729
- image_dir = r'G:\temp\demo_images\ssmini'
730
- image_size = None
770
+ class_mapping_filename = None
771
+ include_image_size = True
772
+ include_image_timestamp = True
773
+ include_exif_data = True
774
+ overwrite_handling = None
775
+
776
+ # Generate a command line
777
+ cmd = 'python run_detector_batch.py "{}" "{}" "{}"'.format(
778
+ model_file,image_dir,output_file)
779
+
780
+ if recursive:
781
+ cmd += ' --recursive'
782
+ if output_relative_filenames:
783
+ cmd += ' --output_relative_filenames'
784
+ if include_max_conf:
785
+ cmd += ' --include_max_conf'
786
+ if quiet:
787
+ cmd += ' --quiet'
788
+ if image_size is not None:
789
+ cmd += ' --image_size {}'.format(image_size)
790
+ if use_image_queue:
791
+ cmd += ' --use_image_queue'
792
+ if confidence_threshold is not None:
793
+ cmd += ' --threshold {}'.format(confidence_threshold)
794
+ if checkpoint_frequency is not None:
795
+ cmd += ' --checkpoint_frequency {}'.format(checkpoint_frequency)
796
+ if checkpoint_path is not None:
797
+ cmd += ' --checkpoint_path "{}"'.format(checkpoint_path)
798
+ if resume_from_checkpoint is not None:
799
+ cmd += ' --resume_from_checkpoint "{}"'.format(resume_from_checkpoint)
800
+ if allow_checkpoint_overwrite:
801
+ cmd += ' --allow_checkpoint_overwrite'
802
+ if ncores is not None:
803
+ cmd += ' --ncores {}'.format(ncores)
804
+ if class_mapping_filename is not None:
805
+ cmd += ' --class_mapping_filename "{}"'.format(class_mapping_filename)
806
+ if include_image_size:
807
+ cmd += ' --include_image_size'
808
+ if include_image_timestamp:
809
+ cmd += ' --include_image_timestamp'
810
+ if include_exif_data:
811
+ cmd += ' --include_exif_data'
812
+ if overwrite_handling is not None:
813
+ cmd += ' --overwrite_handling {}'.format(overwrite_handling)
814
+
815
+ print(cmd)
816
+ import clipboard; clipboard.copy(cmd)
817
+
818
+
819
+ #%% Run inference interactively
820
+
731
821
  image_file_names = path_utils.find_images(image_dir, recursive=False)
822
+ results = None
732
823
 
733
824
  start_time = time.time()
734
825
 
@@ -759,7 +850,8 @@ def main():
759
850
  help='Path to detector model file (.pb or .pt). Can also be the strings "MDV4", "MDV5A", or "MDV5B" to request automatic download.')
760
851
  parser.add_argument(
761
852
  'image_file',
762
- help='Path to a single image file, a JSON file containing a list of paths to images, or a directory')
853
+ help=\
854
+ 'Path to a single image file, a .json or .txt file containing a list of paths to images, or a directory')
763
855
  parser.add_argument(
764
856
  'output_file',
765
857
  help='Path to output JSON results file, should end with a .json extension')
@@ -806,12 +898,15 @@ def main():
806
898
  '--checkpoint_path',
807
899
  type=str,
808
900
  default=None,
809
- help='File name to which checkpoints will be written if checkpoint_frequency is > 0')
901
+ help='File name to which checkpoints will be written if checkpoint_frequency is > 0, ' + \
902
+ 'defaults to md_checkpoint_[date].json in the same folder as the output file')
810
903
  parser.add_argument(
811
904
  '--resume_from_checkpoint',
812
905
  type=str,
813
906
  default=None,
814
- help='Path to a JSON checkpoint file to resume from')
907
+ help='Path to a JSON checkpoint file to resume from, or "auto" to ' + \
908
+ 'find the most recent checkpoint in the same folder as the output file. "auto" uses' + \
909
+ 'checkpoint_path (rather than searching the output folder) if checkpoint_path is specified.')
815
910
  parser.add_argument(
816
911
  '--allow_checkpoint_overwrite',
817
912
  action='store_true',
@@ -828,7 +923,7 @@ def main():
828
923
  default=None,
829
924
  help='Use a non-default class mapping, supplied in a .json file with a dictionary mapping' + \
830
925
  'int-strings to strings. This will also disable the addition of "1" to all category ' + \
831
- 'IDs, so your class mapping should start at zero.')
926
+ 'IDs, so your class mapping should start at zero. Can also be a YOLOv5 dataset.yaml file.')
832
927
  parser.add_argument(
833
928
  '--include_image_size',
834
929
  action='store_true',
@@ -863,7 +958,7 @@ def main():
863
958
 
864
959
  assert os.path.exists(args.detector_file), \
865
960
  'detector file {} does not exist'.format(args.detector_file)
866
- assert 0.0 < args.threshold <= 1.0, 'Confidence threshold needs to be between 0 and 1'
961
+ assert 0.0 <= args.threshold <= 1.0, 'Confidence threshold needs to be between 0 and 1'
867
962
  assert args.output_file.endswith('.json'), 'output_file specified needs to end with .json'
868
963
  if args.checkpoint_frequency != -1:
869
964
  assert args.checkpoint_frequency > 0, 'Checkpoint_frequency needs to be > 0 or == -1'
@@ -885,26 +980,42 @@ def main():
885
980
  else:
886
981
  raise ValueError('Illegal overwrite handling string {}'.format(args.overwrite_handling))
887
982
 
888
- # This is an experimental hack to allow the use of non-MD YOLOv5 models through
889
- # the same infrastructure; it disables the code that enforces MDv5-like class lists.
890
- if args.class_mapping_filename is not None:
891
- run_detector.USE_MODEL_NATIVE_CLASSES = True
892
- with open(args.class_mapping_filename,'r') as f:
893
- class_mapping = json.load(f)
894
- print('Loaded custom class mapping:')
895
- print(class_mapping)
896
- run_detector.DEFAULT_DETECTOR_LABEL_MAP = class_mapping
983
+ output_dir = os.path.dirname(args.output_file)
984
+
985
+ if len(output_dir) > 0:
986
+ os.makedirs(output_dir,exist_ok=True)
897
987
 
988
+ assert not os.path.isdir(args.output_file), 'Specified output file is a directory'
989
+
990
+ if args.class_mapping_filename is not None:
991
+ load_custom_class_mapping(args.class_mapping_filename)
992
+
898
993
  # Load the checkpoint if available
899
994
  #
900
995
  # Relative file names are only output at the end; all file paths in the checkpoint are
901
- # still full paths.
996
+ # still absolute paths.
902
997
  if args.resume_from_checkpoint is not None:
903
- assert os.path.exists(args.resume_from_checkpoint), \
998
+ if args.resume_from_checkpoint == 'auto':
999
+ checkpoint_files = os.listdir(output_dir)
1000
+ checkpoint_files = [fn for fn in checkpoint_files if \
1001
+ (fn.startswith('md_checkpoint') and fn.endswith('.json'))]
1002
+ if len(checkpoint_files) == 0:
1003
+ raise ValueError('resume_from_checkpoint set to "auto", but no checkpoints found in {}'.format(
1004
+ output_dir))
1005
+ else:
1006
+ if len(checkpoint_files) > 1:
1007
+ print('Warning: found {} checkpoints in {}, using the latest'.format(
1008
+ len(checkpoint_files),output_dir))
1009
+ checkpoint_files = sorted(checkpoint_files)
1010
+ checkpoint_file_relative = checkpoint_files[-1]
1011
+ checkpoint_file = os.path.join(output_dir,checkpoint_file_relative)
1012
+ else:
1013
+ checkpoint_file = args.resume_from_checkpoint
1014
+ assert os.path.exists(checkpoint_file), \
904
1015
  'File at resume_from_checkpoint specified does not exist'
905
- with open(args.resume_from_checkpoint) as f:
1016
+ with open(checkpoint_file) as f:
906
1017
  print('Loading previous results from checkpoint file {}'.format(
907
- args.resume_from_checkpoint))
1018
+ checkpoint_file))
908
1019
  saved = json.load(f)
909
1020
  assert 'images' in saved, \
910
1021
  'The checkpoint file does not have the correct fields; cannot be restored'
@@ -931,7 +1042,15 @@ def main():
931
1042
  elif os.path.isfile(args.image_file) and args.image_file.endswith('.json'):
932
1043
  with open(args.image_file) as f:
933
1044
  image_file_names = json.load(f)
934
- print('Loaded {} image filenames from list file {}'.format(
1045
+ print('Loaded {} image filenames from .json list file {}'.format(
1046
+ len(image_file_names),args.image_file))
1047
+
1048
+ # A text list of image paths
1049
+ elif os.path.isfile(args.image_file) and args.image_file.endswith('.txt'):
1050
+ with open(args.image_file) as f:
1051
+ image_file_names = f.readlines()
1052
+ image_file_names = [fn.strip() for fn in image_file_names if len(fn.strip()) > 0]
1053
+ print('Loaded {} image filenames from .txt list file {}'.format(
935
1054
  len(image_file_names),args.image_file))
936
1055
 
937
1056
  # A single image file
@@ -945,14 +1064,7 @@ def main():
945
1064
 
946
1065
  assert len(image_file_names) > 0, 'Specified image_file does not point to valid image files'
947
1066
  assert os.path.exists(image_file_names[0]), \
948
- 'The first image to be scored does not exist at {}'.format(image_file_names[0])
949
-
950
- output_dir = os.path.dirname(args.output_file)
951
-
952
- if len(output_dir) > 0:
953
- os.makedirs(output_dir,exist_ok=True)
954
-
955
- assert not os.path.isdir(args.output_file), 'Specified output file is a directory'
1067
+ 'The first image to be processed does not exist at {}'.format(image_file_names[0])
956
1068
 
957
1069
  # Test that we can write to the output_file's dir if checkpointing requested
958
1070
  if args.checkpoint_frequency != -1:
@@ -961,7 +1073,7 @@ def main():
961
1073
  checkpoint_path = args.checkpoint_path
962
1074
  else:
963
1075
  checkpoint_path = os.path.join(output_dir,
964
- 'checkpoint_{}.json'.format(
1076
+ 'md_checkpoint_{}.json'.format(
965
1077
  datetime.utcnow().strftime("%Y%m%d%H%M%S")))
966
1078
 
967
1079
  # Don't overwrite existing checkpoint files, this is a sure-fire way to eventually
@@ -988,6 +1100,9 @@ def main():
988
1100
 
989
1101
  else:
990
1102
 
1103
+ if args.checkpoint_path is not None:
1104
+ print('Warning: checkpointing disabled because checkpoint_frequency is -1, ' + \
1105
+ 'but a checkpoint path was specified')
991
1106
  checkpoint_path = None
992
1107
 
993
1108
  start_time = time.time()