megadetector 5.0.13__py3-none-any.whl → 5.0.14__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.
- megadetector/data_management/read_exif.py +11 -5
- megadetector/detection/process_video.py +228 -68
- megadetector/detection/pytorch_detector.py +16 -11
- megadetector/detection/run_detector.py +17 -5
- megadetector/detection/run_detector_batch.py +179 -65
- megadetector/detection/tf_detector.py +11 -3
- megadetector/detection/video_utils.py +174 -43
- megadetector/postprocessing/convert_output_format.py +12 -5
- megadetector/utils/md_tests.py +80 -24
- megadetector/utils/path_utils.py +38 -6
- megadetector/utils/process_utils.py +8 -2
- megadetector/visualization/visualization_utils.py +7 -2
- megadetector/visualization/visualize_detector_output.py +0 -1
- {megadetector-5.0.13.dist-info → megadetector-5.0.14.dist-info}/METADATA +1 -1
- {megadetector-5.0.13.dist-info → megadetector-5.0.14.dist-info}/RECORD +18 -18
- {megadetector-5.0.13.dist-info → megadetector-5.0.14.dist-info}/LICENSE +0 -0
- {megadetector-5.0.13.dist-info → megadetector-5.0.14.dist-info}/WHEEL +0 -0
- {megadetector-5.0.13.dist-info → megadetector-5.0.14.dist-info}/top_level.txt +0 -0
megadetector/utils/md_tests.py
CHANGED
|
@@ -75,10 +75,12 @@ class MDTestOptions:
|
|
|
75
75
|
self.max_coord_error = 0.001
|
|
76
76
|
|
|
77
77
|
#: How much deviation from the expected confidence values should we allow before
|
|
78
|
-
#: a disrepancy becomes an error?
|
|
78
|
+
#: a disrepancy becomes an error?
|
|
79
79
|
self.max_conf_error = 0.005
|
|
80
80
|
|
|
81
81
|
#: Current working directory when running CLI tests
|
|
82
|
+
#:
|
|
83
|
+
#: If this is None, we won't mess with the inherited working directory.
|
|
82
84
|
self.cli_working_dir = None
|
|
83
85
|
|
|
84
86
|
#: YOLOv5 installation, only relevant if we're testing run_inference_with_yolov5_val.
|
|
@@ -92,7 +94,7 @@ class MDTestOptions:
|
|
|
92
94
|
#: Default model to use for testing (filename, URL, or well-known model string)
|
|
93
95
|
self.default_model = 'MDV5A'
|
|
94
96
|
|
|
95
|
-
#: For comparison tests, use a model that produces slightly different output
|
|
97
|
+
#: For comparison tests, use a model that produces slightly different output
|
|
96
98
|
self.alt_model = 'MDV5B'
|
|
97
99
|
|
|
98
100
|
#: PYTHONPATH to set for CLI tests; if None, inherits from the parent process. Only
|
|
@@ -104,7 +106,9 @@ class MDTestOptions:
|
|
|
104
106
|
|
|
105
107
|
#%% Support functions
|
|
106
108
|
|
|
107
|
-
def get_expected_results_filename(gpu_is_available
|
|
109
|
+
def get_expected_results_filename(gpu_is_available,
|
|
110
|
+
model_string='mdv5a',
|
|
111
|
+
test_type='images'):
|
|
108
112
|
"""
|
|
109
113
|
Expected results vary just a little across inference environments, particularly
|
|
110
114
|
between PT 1.x and 2.x, so when making sure things are working acceptably, we
|
|
@@ -140,13 +144,13 @@ def get_expected_results_filename(gpu_is_available):
|
|
|
140
144
|
import torch
|
|
141
145
|
m1_inference = torch.backends.mps.is_built and torch.backends.mps.is_available()
|
|
142
146
|
if m1_inference:
|
|
143
|
-
print('I appear to be running on M1/M2 hardware')
|
|
147
|
+
print('I appear to be running on M1/M2 hardware, using pt1/cpu as the reference results')
|
|
144
148
|
hw_string = 'cpu'
|
|
145
149
|
pt_string = 'pt1.10.1'
|
|
146
150
|
except Exception:
|
|
147
151
|
pass
|
|
148
152
|
|
|
149
|
-
return '
|
|
153
|
+
return '{}-{}-results-{}-{}.json'.format(model_string,test_type,hw_string,pt_string)
|
|
150
154
|
|
|
151
155
|
|
|
152
156
|
def download_test_data(options=None):
|
|
@@ -312,18 +316,19 @@ def output_files_are_identical(fn1,fn2,verbose=False):
|
|
|
312
316
|
len(fn2_results['images']),fn2))
|
|
313
317
|
return False
|
|
314
318
|
|
|
319
|
+
# i_image = 0; fn1_image = fn1_results['images'][i_image]
|
|
315
320
|
for i_image,fn1_image in enumerate(fn1_results['images']):
|
|
316
321
|
|
|
317
322
|
fn2_image = fn2_results['images'][i_image]
|
|
318
323
|
|
|
319
324
|
if fn1_image['file'] != fn2_image['file']:
|
|
320
325
|
if verbose:
|
|
321
|
-
print('Filename difference: {} vs {} '.format(fn1_image['file'],fn1_image['file']))
|
|
326
|
+
print('Filename difference at {}: {} vs {} '.format(i_image,fn1_image['file'],fn1_image['file']))
|
|
322
327
|
return False
|
|
323
328
|
|
|
324
329
|
if fn1_image != fn2_image:
|
|
325
330
|
if verbose:
|
|
326
|
-
print('Image-level difference in image {}'.format(fn1_image['file']))
|
|
331
|
+
print('Image-level difference in image {}: {}'.format(i_image,fn1_image['file']))
|
|
327
332
|
return False
|
|
328
333
|
|
|
329
334
|
return True
|
|
@@ -382,7 +387,7 @@ def execute(cmd):
|
|
|
382
387
|
return return_code
|
|
383
388
|
|
|
384
389
|
|
|
385
|
-
def execute_and_print(cmd,print_output=True,catch_exceptions=False):
|
|
390
|
+
def execute_and_print(cmd,print_output=True,catch_exceptions=False,echo_command=True):
|
|
386
391
|
"""
|
|
387
392
|
Runs [cmd] (a single string) in a shell, capturing (and optionally printing) output.
|
|
388
393
|
|
|
@@ -395,8 +400,11 @@ def execute_and_print(cmd,print_output=True,catch_exceptions=False):
|
|
|
395
400
|
(the content of stdout)
|
|
396
401
|
"""
|
|
397
402
|
|
|
403
|
+
if echo_command:
|
|
404
|
+
print('Running command:\n{}\n'.format(cmd))
|
|
405
|
+
|
|
398
406
|
to_return = {'status':'unknown','output':''}
|
|
399
|
-
output=[]
|
|
407
|
+
output = []
|
|
400
408
|
try:
|
|
401
409
|
for s in execute(cmd):
|
|
402
410
|
output.append(s)
|
|
@@ -754,7 +762,6 @@ def run_cli_tests(options):
|
|
|
754
762
|
cmd = 'python megadetector/detection/run_detector.py'
|
|
755
763
|
cmd += ' "{}" --image_file "{}" --output_dir "{}"'.format(
|
|
756
764
|
options.default_model,image_fn,output_dir)
|
|
757
|
-
print('Running: {}'.format(cmd))
|
|
758
765
|
cmd_results = execute_and_print(cmd)
|
|
759
766
|
|
|
760
767
|
if options.cpu_execution_is_error:
|
|
@@ -769,6 +776,7 @@ def run_cli_tests(options):
|
|
|
769
776
|
|
|
770
777
|
## Run inference on a folder
|
|
771
778
|
|
|
779
|
+
|
|
772
780
|
image_folder = os.path.join(options.scratch_dir,'md-test-images')
|
|
773
781
|
assert os.path.isdir(image_folder), 'Test image folder {} is not available'.format(image_folder)
|
|
774
782
|
inference_output_file = os.path.join(options.scratch_dir,'folder_inference_output.json')
|
|
@@ -780,24 +788,75 @@ def run_cli_tests(options):
|
|
|
780
788
|
options.default_model,image_folder,inference_output_file)
|
|
781
789
|
cmd += ' --output_relative_filenames --quiet --include_image_size'
|
|
782
790
|
cmd += ' --include_image_timestamp --include_exif_data'
|
|
783
|
-
print('Running: {}'.format(cmd))
|
|
784
791
|
cmd_results = execute_and_print(cmd)
|
|
785
792
|
|
|
793
|
+
base_cmd = cmd
|
|
794
|
+
|
|
786
795
|
|
|
787
796
|
## Run again with checkpointing enabled, make sure the results are the same
|
|
788
797
|
|
|
789
|
-
cmd += ' --checkpoint_frequency 5'
|
|
790
798
|
from megadetector.utils.path_utils import insert_before_extension
|
|
799
|
+
|
|
800
|
+
checkpoint_string = ' --checkpoint_frequency 5'
|
|
801
|
+
cmd = base_cmd + checkpoint_string
|
|
791
802
|
inference_output_file_checkpoint = insert_before_extension(inference_output_file,'_checkpoint')
|
|
792
|
-
assert inference_output_file_checkpoint != inference_output_file
|
|
793
803
|
cmd = cmd.replace(inference_output_file,inference_output_file_checkpoint)
|
|
794
|
-
print('Running: {}'.format(cmd))
|
|
795
804
|
cmd_results = execute_and_print(cmd)
|
|
796
805
|
|
|
797
806
|
assert output_files_are_identical(fn1=inference_output_file,
|
|
798
807
|
fn2=inference_output_file_checkpoint,verbose=True)
|
|
799
808
|
|
|
800
809
|
|
|
810
|
+
## Run again with the image queue enabled, make sure the results are the same
|
|
811
|
+
|
|
812
|
+
cmd = base_cmd + ' --use_image_queue'
|
|
813
|
+
from megadetector.utils.path_utils import insert_before_extension
|
|
814
|
+
inference_output_file_queue = insert_before_extension(inference_output_file,'_queue')
|
|
815
|
+
cmd = cmd.replace(inference_output_file,inference_output_file_queue)
|
|
816
|
+
cmd_results = execute_and_print(cmd)
|
|
817
|
+
|
|
818
|
+
assert output_files_are_identical(fn1=inference_output_file,
|
|
819
|
+
fn2=inference_output_file_queue,verbose=True)
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
## Run again on multiple cores, make sure the results are the same
|
|
823
|
+
|
|
824
|
+
# First run again on the CPU on a single thread if necessary, so we get a file that
|
|
825
|
+
# *should* be identical to the multicore version.
|
|
826
|
+
|
|
827
|
+
gpu_available = is_gpu_available(verbose=False)
|
|
828
|
+
|
|
829
|
+
cuda_visible_devices = None
|
|
830
|
+
if 'CUDA_VISIBLE_DEVICES' in os.environ:
|
|
831
|
+
cuda_visible_devices = os.environ['CUDA_VISIBLE_DEVICES']
|
|
832
|
+
os.environ['CUDA_VISIBLE_DEVICES'] = '-1'
|
|
833
|
+
|
|
834
|
+
# If we already ran on the CPU, no need to run again
|
|
835
|
+
if not gpu_available:
|
|
836
|
+
inference_output_file_cpu = inference_output_file
|
|
837
|
+
else:
|
|
838
|
+
inference_output_file_cpu = insert_before_extension(inference_output_file,'cpu')
|
|
839
|
+
cmd = base_cmd
|
|
840
|
+
cmd = cmd.replace(inference_output_file,inference_output_file_cpu)
|
|
841
|
+
cmd_results = execute_and_print(cmd)
|
|
842
|
+
|
|
843
|
+
cpu_string = ' --ncores 4'
|
|
844
|
+
cmd = base_cmd + cpu_string
|
|
845
|
+
from megadetector.utils.path_utils import insert_before_extension
|
|
846
|
+
inference_output_file_cpu_multicore = insert_before_extension(inference_output_file,'multicore')
|
|
847
|
+
cmd = cmd.replace(inference_output_file,inference_output_file_cpu_multicore)
|
|
848
|
+
cmd_results = execute_and_print(cmd)
|
|
849
|
+
|
|
850
|
+
if cuda_visible_devices is not None:
|
|
851
|
+
print('Restoring CUDA_VISIBLE_DEVICES')
|
|
852
|
+
os.environ['CUDA_VISIBLE_DEVICES'] = cuda_visible_devices
|
|
853
|
+
else:
|
|
854
|
+
del os.environ['CUDA_VISIBLE_DEVICES']
|
|
855
|
+
|
|
856
|
+
assert output_files_are_identical(fn1=inference_output_file_cpu,
|
|
857
|
+
fn2=inference_output_file_cpu_multicore,verbose=True)
|
|
858
|
+
|
|
859
|
+
|
|
801
860
|
## Postprocessing
|
|
802
861
|
|
|
803
862
|
postprocessing_output_dir = os.path.join(options.scratch_dir,'postprocessing_output_cli')
|
|
@@ -809,7 +868,6 @@ def run_cli_tests(options):
|
|
|
809
868
|
cmd += ' "{}" "{}"'.format(
|
|
810
869
|
inference_output_file,postprocessing_output_dir)
|
|
811
870
|
cmd += ' --image_base_dir "{}"'.format(image_folder)
|
|
812
|
-
print('Running: {}'.format(cmd))
|
|
813
871
|
cmd_results = execute_and_print(cmd)
|
|
814
872
|
|
|
815
873
|
|
|
@@ -825,7 +883,6 @@ def run_cli_tests(options):
|
|
|
825
883
|
cmd += ' --imageBase "{}"'.format(image_folder)
|
|
826
884
|
cmd += ' --outputBase "{}"'.format(rde_output_dir)
|
|
827
885
|
cmd += ' --occurrenceThreshold 1' # Use an absurd number here to make sure we get some suspicious detections
|
|
828
|
-
print('Running: {}'.format(cmd))
|
|
829
886
|
cmd_results = execute_and_print(cmd)
|
|
830
887
|
|
|
831
888
|
# Find the latest filtering folder
|
|
@@ -844,7 +901,6 @@ def run_cli_tests(options):
|
|
|
844
901
|
else:
|
|
845
902
|
cmd = 'python megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py'
|
|
846
903
|
cmd += ' "{}" "{}" "{}"'.format(inference_output_file,filtered_output_file,filtering_output_dir)
|
|
847
|
-
print('Running: {}'.format(cmd))
|
|
848
904
|
cmd_results = execute_and_print(cmd)
|
|
849
905
|
|
|
850
906
|
assert os.path.isfile(filtered_output_file), \
|
|
@@ -863,7 +919,6 @@ def run_cli_tests(options):
|
|
|
863
919
|
cmd += ' "{}" "{}" "{}" "{}"'.format(
|
|
864
920
|
options.default_model,image_folder,tiling_folder,inference_output_file_tiled)
|
|
865
921
|
cmd += ' --overwrite_handling overwrite'
|
|
866
|
-
print('Running: {}'.format(cmd))
|
|
867
922
|
cmd_results = execute_and_print(cmd)
|
|
868
923
|
|
|
869
924
|
with open(inference_output_file_tiled,'r') as f:
|
|
@@ -894,7 +949,6 @@ def run_cli_tests(options):
|
|
|
894
949
|
cmd += ' --augment_enabled 1'
|
|
895
950
|
# cmd += ' --no_use_symlinks'
|
|
896
951
|
cmd += ' --overwrite_handling overwrite'
|
|
897
|
-
print('Running: {}'.format(cmd))
|
|
898
952
|
cmd_results = execute_and_print(cmd)
|
|
899
953
|
|
|
900
954
|
# Run again with checkpointing, make sure the output are identical
|
|
@@ -931,7 +985,6 @@ def run_cli_tests(options):
|
|
|
931
985
|
cmd += ' --render_output_video --fourcc {}'.format(options.video_fourcc)
|
|
932
986
|
cmd += ' --force_extracted_frame_folder_deletion --force_rendered_frame_folder_deletion --n_cores 5 --frame_sample 3'
|
|
933
987
|
cmd += ' --verbose'
|
|
934
|
-
print('Running: {}'.format(cmd))
|
|
935
988
|
cmd_results = execute_and_print(cmd)
|
|
936
989
|
|
|
937
990
|
# ...if we're not skipping video tests
|
|
@@ -949,7 +1002,6 @@ def run_cli_tests(options):
|
|
|
949
1002
|
options.alt_model,image_folder,inference_output_file_alt)
|
|
950
1003
|
cmd += ' --output_relative_filenames --quiet --include_image_size'
|
|
951
1004
|
cmd += ' --include_image_timestamp --include_exif_data'
|
|
952
|
-
print('Running: {}'.format(cmd))
|
|
953
1005
|
cmd_results = execute_and_print(cmd)
|
|
954
1006
|
|
|
955
1007
|
with open(inference_output_file_alt,'r') as f:
|
|
@@ -967,7 +1019,6 @@ def run_cli_tests(options):
|
|
|
967
1019
|
else:
|
|
968
1020
|
cmd = 'python megadetector/postprocessing/compare_batch_results.py'
|
|
969
1021
|
cmd += ' "{}" "{}" {}'.format(comparison_output_folder,image_folder,results_files_string)
|
|
970
|
-
print('Running: {}'.format(cmd))
|
|
971
1022
|
cmd_results = execute_and_print(cmd)
|
|
972
1023
|
|
|
973
1024
|
assert cmd_results['status'] == 0, 'Error generating comparison HTML'
|
|
@@ -1040,6 +1091,10 @@ if False:
|
|
|
1040
1091
|
options.cli_working_dir = r'c:\git\MegaDetector'
|
|
1041
1092
|
options.yolo_working_dir = r'c:\git\yolov5-md'
|
|
1042
1093
|
|
|
1094
|
+
import os
|
|
1095
|
+
|
|
1096
|
+
if 'PYTHONPATH' not in os.environ or options.yolo_working_dir not in os.environ['PYTHONPATH']:
|
|
1097
|
+
os.environ['PYTHONPATH'] += ';' + options.yolo_working_dir
|
|
1043
1098
|
|
|
1044
1099
|
#%%
|
|
1045
1100
|
|
|
@@ -1150,15 +1205,16 @@ if __name__ == '__main__':
|
|
|
1150
1205
|
|
|
1151
1206
|
#%% Sample invocations
|
|
1152
1207
|
|
|
1153
|
-
"""
|
|
1208
|
+
r"""
|
|
1154
1209
|
# Windows
|
|
1155
1210
|
set PYTHONPATH=c:\git\MegaDetector;c:\git\yolov5-md
|
|
1211
|
+
cd c:\git\MegaDetector\megadetector\utils
|
|
1156
1212
|
python md_tests.py --cli_working_dir "c:\git\MegaDetector" --yolo_working_dir "c:\git\yolov5-md" --cli_test_pythonpath "c:\git\MegaDetector;c:\git\yolov5-md"
|
|
1157
1213
|
|
|
1158
1214
|
# Linux
|
|
1159
1215
|
export PYTHONPATH=/mnt/c/git/MegaDetector:/mnt/c/git/yolov5-md
|
|
1216
|
+
cd /mnt/c/git/MegaDetector/megadetector/utils
|
|
1160
1217
|
python md_tests.py --cli_working_dir "/mnt/c/git/MegaDetector" --yolo_working_dir "/mnt/c/git/yolov5-md" --cli_test_pythonpath "/mnt/c/git/MegaDetector:/mnt/c/git/yolov5-md"
|
|
1161
1218
|
|
|
1162
1219
|
python -c "import md_tests; print(md_tests.get_expected_results_filename(True))"
|
|
1163
1220
|
"""
|
|
1164
|
-
|
megadetector/utils/path_utils.py
CHANGED
|
@@ -733,9 +733,13 @@ def _get_file_size(filename,verbose=False):
|
|
|
733
733
|
return (filename,size)
|
|
734
734
|
|
|
735
735
|
|
|
736
|
-
def parallel_get_file_sizes(filenames,
|
|
737
|
-
|
|
738
|
-
|
|
736
|
+
def parallel_get_file_sizes(filenames,
|
|
737
|
+
max_workers=16,
|
|
738
|
+
use_threads=True,
|
|
739
|
+
verbose=False,
|
|
740
|
+
recursive=True,
|
|
741
|
+
convert_slashes=True,
|
|
742
|
+
return_relative_paths=False):
|
|
739
743
|
"""
|
|
740
744
|
Returns a dictionary mapping every file in [filenames] to the corresponding file size,
|
|
741
745
|
or None for errors. If [filenames] is a folder, will enumerate the folder (optionally recursively).
|
|
@@ -748,6 +752,9 @@ def parallel_get_file_sizes(filenames, max_workers=16,
|
|
|
748
752
|
parallel copying; ignored if max_workers <= 1
|
|
749
753
|
verbose (bool, optional): enable additionald debug output
|
|
750
754
|
recursive (bool, optional): enumerate recursively, only relevant if [filenames] is a folder.
|
|
755
|
+
convert_slashes (bool, optional): convert backslashes to forward slashes
|
|
756
|
+
return_relative_paths (bool, optional): return relative paths; only relevant if [filenames]
|
|
757
|
+
is a folder.
|
|
751
758
|
|
|
752
759
|
Returns:
|
|
753
760
|
dict: dictionary mapping filenames to file sizes in bytes
|
|
@@ -755,20 +762,45 @@ def parallel_get_file_sizes(filenames, max_workers=16,
|
|
|
755
762
|
|
|
756
763
|
n_workers = min(max_workers,len(filenames))
|
|
757
764
|
|
|
765
|
+
folder_name = None
|
|
766
|
+
|
|
767
|
+
if verbose:
|
|
768
|
+
print('Enumerating files')
|
|
769
|
+
|
|
758
770
|
if isinstance(filenames,str) and os.path.isdir(filenames):
|
|
771
|
+
|
|
772
|
+
folder_name = filenames
|
|
773
|
+
|
|
774
|
+
# Enumerate absolute paths here, we'll convert to relative later if requested
|
|
759
775
|
filenames = recursive_file_list(filenames,recursive=recursive,return_relative_paths=False)
|
|
776
|
+
|
|
777
|
+
if verbose:
|
|
778
|
+
print('Creating worker pool')
|
|
760
779
|
|
|
761
780
|
if use_threads:
|
|
781
|
+
pool_string = 'thread'
|
|
762
782
|
pool = ThreadPool(n_workers)
|
|
763
783
|
else:
|
|
784
|
+
pool_string = 'process'
|
|
764
785
|
pool = Pool(n_workers)
|
|
765
786
|
|
|
766
|
-
|
|
787
|
+
if verbose:
|
|
788
|
+
print('Created a {} pool of {} workers'.format(
|
|
789
|
+
pool_string,n_workers))
|
|
790
|
+
|
|
791
|
+
# This returns (filename,size) tuples
|
|
792
|
+
get_size_results = list(tqdm(pool.imap(
|
|
767
793
|
partial(_get_file_size,verbose=verbose),filenames), total=len(filenames)))
|
|
768
794
|
|
|
769
795
|
to_return = {}
|
|
770
|
-
for r in
|
|
771
|
-
|
|
796
|
+
for r in get_size_results:
|
|
797
|
+
fn = r[0]
|
|
798
|
+
if return_relative_paths and (folder_name is not None):
|
|
799
|
+
fn = os.path.relpath(fn,folder_name)
|
|
800
|
+
if convert_slashes:
|
|
801
|
+
fn = fn.replace('\\','/')
|
|
802
|
+
size = r[1]
|
|
803
|
+
to_return[fn] = size
|
|
772
804
|
|
|
773
805
|
return to_return
|
|
774
806
|
|
|
@@ -60,7 +60,8 @@ def execute(cmd,encoding=None,errors=None,env=None,verbose=False):
|
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
def execute_and_print(cmd,print_output=True,encoding=None,errors=None,
|
|
63
|
-
env=None,verbose=False,catch_exceptions=True
|
|
63
|
+
env=None,verbose=False,catch_exceptions=True,
|
|
64
|
+
echo_command=False):
|
|
64
65
|
"""
|
|
65
66
|
Run [cmd] (a single string) in a shell, capturing and printing output. Returns
|
|
66
67
|
a dictionary with fields "status" and "output".
|
|
@@ -77,12 +78,17 @@ def execute_and_print(cmd,print_output=True,encoding=None,errors=None,
|
|
|
77
78
|
errors (str, optional): error handling, see Popen() documentation
|
|
78
79
|
env (dict, optional): environment variables, see Popen() documentation
|
|
79
80
|
verbose (bool, optional): enable additional debug console output
|
|
80
|
-
|
|
81
|
+
catch_exceptions (bool, optional): catch exceptions and include in the output, otherwise raise
|
|
82
|
+
echo_command (bool, optional): print the command before executing
|
|
83
|
+
|
|
81
84
|
Returns:
|
|
82
85
|
dict: a dictionary with fields "status" (the process return code) and "output"
|
|
83
86
|
(the content of stdout)
|
|
84
87
|
"""
|
|
85
88
|
|
|
89
|
+
if echo_command:
|
|
90
|
+
print('Running command:\n{}\n'.format(cmd))
|
|
91
|
+
|
|
86
92
|
to_return = {'status':'unknown','output':''}
|
|
87
93
|
output = []
|
|
88
94
|
try:
|
|
@@ -1457,7 +1457,8 @@ def parallel_check_image_integrity(filenames,
|
|
|
1457
1457
|
modes=None,
|
|
1458
1458
|
max_workers=16,
|
|
1459
1459
|
use_threads=True,
|
|
1460
|
-
recursive=True
|
|
1460
|
+
recursive=True,
|
|
1461
|
+
verbose=False):
|
|
1461
1462
|
"""
|
|
1462
1463
|
Check whether we can successfully load a list of images via OpenCV and/or PIL.
|
|
1463
1464
|
|
|
@@ -1470,6 +1471,7 @@ def parallel_check_image_integrity(filenames,
|
|
|
1470
1471
|
parallelization
|
|
1471
1472
|
recursive (bool, optional): if [filenames] is a folder, whether to search recursively for images.
|
|
1472
1473
|
Ignored if [filenames] is a list.
|
|
1474
|
+
verbose (bool, optional): enable additional debug output
|
|
1473
1475
|
|
|
1474
1476
|
Returns:
|
|
1475
1477
|
list: a list of dicts, each with a key called 'file' (the value of [filename]), one key for
|
|
@@ -1480,9 +1482,12 @@ def parallel_check_image_integrity(filenames,
|
|
|
1480
1482
|
n_workers = min(max_workers,len(filenames))
|
|
1481
1483
|
|
|
1482
1484
|
if isinstance(filenames,str) and os.path.isdir(filenames):
|
|
1485
|
+
if verbose:
|
|
1486
|
+
print('Enumerating images in {}'.format(filenames))
|
|
1483
1487
|
filenames = find_images(filenames,recursive=recursive,return_relative_paths=False)
|
|
1484
1488
|
|
|
1485
|
-
|
|
1489
|
+
if verbose:
|
|
1490
|
+
print('Checking image integrity for {} filenames'.format(len(filenames)))
|
|
1486
1491
|
|
|
1487
1492
|
if n_workers <= 1:
|
|
1488
1493
|
|
|
@@ -174,7 +174,6 @@ def visualize_detector_output(detector_output_path,
|
|
|
174
174
|
f'Confidence threshold {confidence_threshold} is invalid, must be in (0, 1).')
|
|
175
175
|
|
|
176
176
|
if 'detection_categories' in detector_output:
|
|
177
|
-
print('Using custom label mapping')
|
|
178
177
|
detector_label_map = detector_output['detection_categories']
|
|
179
178
|
else:
|
|
180
179
|
detector_label_map = DEFAULT_DETECTOR_LABEL_MAP
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: megadetector
|
|
3
|
-
Version: 5.0.
|
|
3
|
+
Version: 5.0.14
|
|
4
4
|
Summary: MegaDetector is an AI model that helps conservation folks spend less time doing boring things with camera trap images.
|
|
5
5
|
Author-email: Your friendly neighborhood MegaDetector team <cameratraps@lila.science>
|
|
6
6
|
Maintainer-email: Your friendly neighborhood MegaDetector team <cameratraps@lila.science>
|
|
@@ -63,7 +63,7 @@ megadetector/data_management/get_image_sizes.py,sha256=2b6arj4gvoN-9f61lC3t1zAFF
|
|
|
63
63
|
megadetector/data_management/labelme_to_coco.py,sha256=8RUXALXbLpmS7UYUet4BAe9JVSDW7ojwDDpxYs072ZI,21231
|
|
64
64
|
megadetector/data_management/labelme_to_yolo.py,sha256=dRePSOwU_jiCr0EakDQCz1Ct-ZHDxDglUk4HbM1LfWc,10034
|
|
65
65
|
megadetector/data_management/ocr_tools.py,sha256=T9ClY3B-blnK3-UF1vpVdageknYsykm_6FAfqn0kliU,32529
|
|
66
|
-
megadetector/data_management/read_exif.py,sha256
|
|
66
|
+
megadetector/data_management/read_exif.py,sha256=-q0NqJ3VZSBovD_d6de-s3UR2NuKF6gSw2etfvVuRO4,27866
|
|
67
67
|
megadetector/data_management/remap_coco_categories.py,sha256=xXWv0QhTjkUfc9RKtAZanK77HMSq_21mFg_34KFD6hw,2903
|
|
68
68
|
megadetector/data_management/remove_exif.py,sha256=9YwMUliszhVzkkUcotpRKA-a3h5WdQF1taQ594Bgm60,1666
|
|
69
69
|
megadetector/data_management/rename_images.py,sha256=AG3YIxXEYdGmK4G-rv0_XZIylPqOZpS6gfEkydF6oDg,6918
|
|
@@ -135,14 +135,14 @@ megadetector/data_management/lila/get_lila_image_counts.py,sha256=UxXS5RDnSA_Wbx
|
|
|
135
135
|
megadetector/data_management/lila/lila_common.py,sha256=IEnGoyRgcqbek1qJ1gFE83p1Pg_5kaMS-nQI25lRWIs,10132
|
|
136
136
|
megadetector/data_management/lila/test_lila_metadata_urls.py,sha256=2zKNjgqC3kxdFfyvQC3KTlpc9lf2iMzecHQBf--r_Tk,4438
|
|
137
137
|
megadetector/detection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
138
|
-
megadetector/detection/process_video.py,sha256=
|
|
139
|
-
megadetector/detection/pytorch_detector.py,sha256=
|
|
140
|
-
megadetector/detection/run_detector.py,sha256=
|
|
141
|
-
megadetector/detection/run_detector_batch.py,sha256=
|
|
138
|
+
megadetector/detection/process_video.py,sha256=wNjv2LciLSzIu_wkMQMrSf9gOyv0NC-Busq-yYORG_0,42686
|
|
139
|
+
megadetector/detection/pytorch_detector.py,sha256=p70kAX5pqU4SO4GjYJmzbTPV4tKUp5WRapOs7vgSKes,13885
|
|
140
|
+
megadetector/detection/run_detector.py,sha256=biXbeS8aNDlidilxjzhZ-p4_wr2ID-rpsRklbNEd7ME,30094
|
|
141
|
+
megadetector/detection/run_detector_batch.py,sha256=V8gfcWNHu7r0Nj7seQVeFpB5ylkkhZK1gFwHuoiB4L4,56894
|
|
142
142
|
megadetector/detection/run_inference_with_yolov5_val.py,sha256=u9i1ndwl_k0DsiAWYQcYrrrB9D9Wt56_k6iGTAetUaM,46786
|
|
143
143
|
megadetector/detection/run_tiled_inference.py,sha256=vw0713eNuMiEOjHfweQl58zPHNxPOMdFWZ8bTDLhlMY,37883
|
|
144
|
-
megadetector/detection/tf_detector.py,sha256=-
|
|
145
|
-
megadetector/detection/video_utils.py,sha256=
|
|
144
|
+
megadetector/detection/tf_detector.py,sha256=-vcBuYRRLKumUj6imcDYgCgClGji0a21uMjoUAtY3yw,8104
|
|
145
|
+
megadetector/detection/video_utils.py,sha256=e6XidwChyqkN5ga7yLbujMqKwXITvQGVWEw0qyAhSoA,32398
|
|
146
146
|
megadetector/detection/detector_training/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
147
147
|
megadetector/detection/detector_training/model_main_tf2.py,sha256=YwNsZ7hkIFaEuwKU0rHG_VyqiR_0E01BbdlD0Yx4Smo,4936
|
|
148
148
|
megadetector/postprocessing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -151,7 +151,7 @@ megadetector/postprocessing/categorize_detections_by_size.py,sha256=YdapcvjA6Dz2
|
|
|
151
151
|
megadetector/postprocessing/classification_postprocessing.py,sha256=8uvlA0Gc8nakM5IE5Pud7WZfmF5kEhcYvxgQXcI9kl0,30429
|
|
152
152
|
megadetector/postprocessing/combine_api_outputs.py,sha256=xCJHEKca8YW-mupEr0yNNwwSBeL9NvcV1w3VtEzN4lk,8535
|
|
153
153
|
megadetector/postprocessing/compare_batch_results.py,sha256=7O5c6-JsIDpuIGobks_R9j8MPuiZQRnEtNnJQsJqICM,38918
|
|
154
|
-
megadetector/postprocessing/convert_output_format.py,sha256=
|
|
154
|
+
megadetector/postprocessing/convert_output_format.py,sha256=HwThfK76UPEAGa3KQbJ_tMKIrUvJ3JhKoQVWJt9dPBk,15447
|
|
155
155
|
megadetector/postprocessing/load_api_results.py,sha256=FqcaiPMuqTojZOV3Jn14pJESpuwjWGbZtcvJuVXUaDM,6861
|
|
156
156
|
megadetector/postprocessing/md_to_coco.py,sha256=t8zHN3QmwxuvcQKxLd_yMSjwncxy7YEoq2EGr0kwBDs,11049
|
|
157
157
|
megadetector/postprocessing/md_to_labelme.py,sha256=hejMKVxaz_xdtsGDPTQkeWuis7gzT-VOrL2Qf8ym1x0,11703
|
|
@@ -180,9 +180,9 @@ megadetector/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
|
|
|
180
180
|
megadetector/utils/azure_utils.py,sha256=0BdnkG2hW-X0yFpsJqmBhOd2wysz_LvhuyImPJMVPJs,6271
|
|
181
181
|
megadetector/utils/ct_utils.py,sha256=RTMc0UszYuW9QpMo-qetaWder1mFWIzkMLL2UM6PYdY,17960
|
|
182
182
|
megadetector/utils/directory_listing.py,sha256=r4rg2xA4O9ZVxVtzPZzXIXa0DOEukAJMTTNcNSiQcuM,9668
|
|
183
|
-
megadetector/utils/md_tests.py,sha256=
|
|
184
|
-
megadetector/utils/path_utils.py,sha256=
|
|
185
|
-
megadetector/utils/process_utils.py,sha256=
|
|
183
|
+
megadetector/utils/md_tests.py,sha256=W8Ua4eh8Z1QHBUlhKoBTt-2a9XOEhVv2TgLu065_PlI,46842
|
|
184
|
+
megadetector/utils/path_utils.py,sha256=Uj_aNvA_P0buq-3ebQLZz-6to8mNO5JyBhD7n1-pUoU,37149
|
|
185
|
+
megadetector/utils/process_utils.py,sha256=2SdFVxqob-YUW2BTjUEavNuRH3jA4V05fbKMtrVSd3c,5635
|
|
186
186
|
megadetector/utils/sas_blob_utils.py,sha256=k76EcMmJc_otrEHcfV2fxAC6fNhxU88FxM3ddSYrsKU,16917
|
|
187
187
|
megadetector/utils/split_locations_into_train_val.py,sha256=jvaDu1xKB51L3Xq2nXQo0XtXRjNRf8RglBApl1g6gHo,10101
|
|
188
188
|
megadetector/utils/string_utils.py,sha256=ZQapJodzvTDyQhjZgMoMl3-9bqnKAUlORpws8Db9AkA,2050
|
|
@@ -191,11 +191,11 @@ megadetector/utils/write_html_image_list.py,sha256=apzoWkgZWG-ybCT4k92PlS4-guN_s
|
|
|
191
191
|
megadetector/visualization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
192
192
|
megadetector/visualization/plot_utils.py,sha256=lOfU3uPrcuHZagV_1SN8erT8PujIepocgw6KZ17Ej6c,10671
|
|
193
193
|
megadetector/visualization/render_images_with_thumbnails.py,sha256=kgJYW8BsqRO4C7T3sqItdBuSkZ64I1vOtIWAsVG4XBI,10589
|
|
194
|
-
megadetector/visualization/visualization_utils.py,sha256=
|
|
194
|
+
megadetector/visualization/visualization_utils.py,sha256=jWiXlLpmWh_CH2vApZURclOC7fdip1aKWQ66wuNabyA,62369
|
|
195
195
|
megadetector/visualization/visualize_db.py,sha256=3FhOtn3GHvNsomwSpsSEzYe58lF9B4Ob3MEi_xplrdo,21256
|
|
196
|
-
megadetector/visualization/visualize_detector_output.py,sha256=
|
|
197
|
-
megadetector-5.0.
|
|
198
|
-
megadetector-5.0.
|
|
199
|
-
megadetector-5.0.
|
|
200
|
-
megadetector-5.0.
|
|
201
|
-
megadetector-5.0.
|
|
196
|
+
megadetector/visualization/visualize_detector_output.py,sha256=LY8QgDWpWlXVLZJUskvT29CdkNvIlEsFTk4DC_lS6pk,17052
|
|
197
|
+
megadetector-5.0.14.dist-info/LICENSE,sha256=RMa3qq-7Cyk7DdtqRj_bP1oInGFgjyHn9-PZ3PcrqIs,1100
|
|
198
|
+
megadetector-5.0.14.dist-info/METADATA,sha256=yeX8szvUXU887ERsfi8lV8lSYEa4fBPM21KXbjNJOOI,7893
|
|
199
|
+
megadetector-5.0.14.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
200
|
+
megadetector-5.0.14.dist-info/top_level.txt,sha256=wf9DXa8EwiOSZ4G5IPjakSxBPxTDjhYYnqWRfR-zS4M,13
|
|
201
|
+
megadetector-5.0.14.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|