megadetector 5.0.29__py3-none-any.whl → 10.0.1__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/classification/efficientnet/model.py +8 -8
- megadetector/classification/efficientnet/utils.py +6 -5
- megadetector/classification/prepare_classification_script_mc.py +3 -3
- megadetector/data_management/annotations/annotation_constants.py +0 -1
- megadetector/data_management/camtrap_dp_to_coco.py +34 -1
- megadetector/data_management/cct_json_utils.py +2 -2
- megadetector/data_management/coco_to_yolo.py +22 -5
- megadetector/data_management/databases/add_width_and_height_to_db.py +85 -12
- megadetector/data_management/databases/combine_coco_camera_traps_files.py +2 -2
- megadetector/data_management/databases/integrity_check_json_db.py +29 -15
- megadetector/data_management/generate_crops_from_cct.py +50 -1
- megadetector/data_management/labelme_to_coco.py +4 -2
- megadetector/data_management/labelme_to_yolo.py +82 -2
- megadetector/data_management/lila/generate_lila_per_image_labels.py +276 -18
- megadetector/data_management/lila/get_lila_annotation_counts.py +5 -3
- megadetector/data_management/lila/lila_common.py +3 -0
- megadetector/data_management/lila/test_lila_metadata_urls.py +15 -5
- megadetector/data_management/mewc_to_md.py +5 -0
- megadetector/data_management/ocr_tools.py +4 -3
- megadetector/data_management/read_exif.py +20 -5
- megadetector/data_management/remap_coco_categories.py +66 -4
- megadetector/data_management/remove_exif.py +50 -1
- megadetector/data_management/rename_images.py +3 -3
- megadetector/data_management/resize_coco_dataset.py +563 -95
- megadetector/data_management/yolo_output_to_md_output.py +131 -2
- megadetector/data_management/yolo_to_coco.py +140 -5
- megadetector/detection/change_detection.py +4 -3
- megadetector/detection/pytorch_detector.py +60 -22
- megadetector/detection/run_detector.py +225 -25
- megadetector/detection/run_detector_batch.py +42 -16
- megadetector/detection/run_inference_with_yolov5_val.py +12 -2
- megadetector/detection/run_tiled_inference.py +1 -0
- megadetector/detection/video_utils.py +53 -24
- megadetector/postprocessing/add_max_conf.py +4 -0
- megadetector/postprocessing/categorize_detections_by_size.py +1 -1
- megadetector/postprocessing/classification_postprocessing.py +55 -20
- megadetector/postprocessing/combine_batch_outputs.py +3 -2
- megadetector/postprocessing/compare_batch_results.py +64 -10
- megadetector/postprocessing/convert_output_format.py +12 -8
- megadetector/postprocessing/create_crop_folder.py +137 -10
- megadetector/postprocessing/load_api_results.py +26 -8
- megadetector/postprocessing/md_to_coco.py +4 -4
- megadetector/postprocessing/md_to_labelme.py +18 -7
- megadetector/postprocessing/merge_detections.py +5 -0
- megadetector/postprocessing/postprocess_batch_results.py +6 -3
- megadetector/postprocessing/remap_detection_categories.py +55 -2
- megadetector/postprocessing/render_detection_confusion_matrix.py +9 -6
- megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +2 -2
- megadetector/taxonomy_mapping/map_new_lila_datasets.py +3 -4
- megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +40 -19
- megadetector/taxonomy_mapping/preview_lila_taxonomy.py +1 -1
- megadetector/taxonomy_mapping/species_lookup.py +123 -41
- megadetector/utils/ct_utils.py +133 -113
- megadetector/utils/md_tests.py +93 -13
- megadetector/utils/path_utils.py +137 -107
- megadetector/utils/split_locations_into_train_val.py +2 -2
- megadetector/utils/string_utils.py +7 -7
- megadetector/utils/url_utils.py +81 -58
- megadetector/utils/wi_utils.py +46 -17
- megadetector/visualization/plot_utils.py +13 -9
- megadetector/visualization/render_images_with_thumbnails.py +2 -1
- megadetector/visualization/visualization_utils.py +94 -46
- megadetector/visualization/visualize_db.py +36 -9
- megadetector/visualization/visualize_detector_output.py +4 -4
- {megadetector-5.0.29.dist-info → megadetector-10.0.1.dist-info}/METADATA +135 -135
- megadetector-10.0.1.dist-info/RECORD +139 -0
- {megadetector-5.0.29.dist-info → megadetector-10.0.1.dist-info}/licenses/LICENSE +0 -0
- {megadetector-5.0.29.dist-info → megadetector-10.0.1.dist-info}/top_level.txt +0 -0
- megadetector/api/batch_processing/api_core/__init__.py +0 -0
- megadetector/api/batch_processing/api_core/batch_service/__init__.py +0 -0
- megadetector/api/batch_processing/api_core/batch_service/score.py +0 -438
- megadetector/api/batch_processing/api_core/server.py +0 -294
- megadetector/api/batch_processing/api_core/server_api_config.py +0 -97
- megadetector/api/batch_processing/api_core/server_app_config.py +0 -55
- megadetector/api/batch_processing/api_core/server_batch_job_manager.py +0 -220
- megadetector/api/batch_processing/api_core/server_job_status_table.py +0 -149
- megadetector/api/batch_processing/api_core/server_orchestration.py +0 -360
- megadetector/api/batch_processing/api_core/server_utils.py +0 -88
- megadetector/api/batch_processing/api_core_support/__init__.py +0 -0
- megadetector/api/batch_processing/api_core_support/aggregate_results_manually.py +0 -46
- megadetector/api/batch_processing/api_support/__init__.py +0 -0
- megadetector/api/batch_processing/api_support/summarize_daily_activity.py +0 -152
- megadetector/api/batch_processing/data_preparation/__init__.py +0 -0
- megadetector/api/synchronous/__init__.py +0 -0
- megadetector/api/synchronous/api_core/animal_detection_api/__init__.py +0 -0
- megadetector/api/synchronous/api_core/animal_detection_api/api_backend.py +0 -151
- megadetector/api/synchronous/api_core/animal_detection_api/api_frontend.py +0 -263
- megadetector/api/synchronous/api_core/animal_detection_api/config.py +0 -35
- megadetector/api/synchronous/api_core/tests/__init__.py +0 -0
- megadetector/api/synchronous/api_core/tests/load_test.py +0 -109
- megadetector/utils/azure_utils.py +0 -178
- megadetector/utils/sas_blob_utils.py +0 -513
- megadetector-5.0.29.dist-info/RECORD +0 -163
- /megadetector/{api/batch_processing/__init__.py → __init__.py} +0 -0
- {megadetector-5.0.29.dist-info → megadetector-10.0.1.dist-info}/WHEEL +0 -0
megadetector/utils/md_tests.py
CHANGED
|
@@ -65,6 +65,9 @@ class MDTestOptions:
|
|
|
65
65
|
#: Skip download tests
|
|
66
66
|
self.skip_download_tests = False
|
|
67
67
|
|
|
68
|
+
#: Skip download tests for local URLs
|
|
69
|
+
self.skip_localhost_downloads = False
|
|
70
|
+
|
|
68
71
|
#: Skip force-CPU tests
|
|
69
72
|
self.skip_cpu_tests = False
|
|
70
73
|
|
|
@@ -163,6 +166,10 @@ def get_expected_results_filename(gpu_is_available,
|
|
|
163
166
|
|
|
164
167
|
Args:
|
|
165
168
|
gpu_is_available (bool): whether a GPU is available
|
|
169
|
+
model_string (str, optional): the model for which we're retrieving expected results
|
|
170
|
+
test_type (str, optional): the test type we're running ("image" or "video")
|
|
171
|
+
augment (bool, optional): whether we're running this test with image augmentation
|
|
172
|
+
options (MDTestOptiosn, optional): additional control flow options
|
|
166
173
|
|
|
167
174
|
Returns:
|
|
168
175
|
str: relative filename of the results file we should use (within the test
|
|
@@ -361,6 +368,7 @@ def output_files_are_identical(fn1,fn2,verbose=False):
|
|
|
361
368
|
Args:
|
|
362
369
|
fn1 (str): the first filename to compare
|
|
363
370
|
fn2 (str): the second filename to compare
|
|
371
|
+
verbose (bool, optional): enable additional debug output
|
|
364
372
|
|
|
365
373
|
Returns:
|
|
366
374
|
bool: whether [fn1] and [fn2] are identical other than file sorting.
|
|
@@ -692,6 +700,9 @@ def execute_and_print(cmd,print_output=True,catch_exceptions=False,echo_command=
|
|
|
692
700
|
Args:
|
|
693
701
|
cmd (str): command to run
|
|
694
702
|
print_output (bool, optional): whether to print output from [cmd]
|
|
703
|
+
catch_exceptions (bool, optional): whether to catch exceptions, rather than raising
|
|
704
|
+
them
|
|
705
|
+
echo_command (bool, optional): whether to print [cmd] to stdout prior to execution
|
|
695
706
|
|
|
696
707
|
Returns:
|
|
697
708
|
dict: a dictionary with fields "status" (the process return code) and "output"
|
|
@@ -762,7 +773,7 @@ def test_package_imports(package_name,exceptions=None,verbose=True):
|
|
|
762
773
|
print(f"Failed to import module {modname}: {e}")
|
|
763
774
|
raise
|
|
764
775
|
|
|
765
|
-
|
|
776
|
+
|
|
766
777
|
def run_python_tests(options):
|
|
767
778
|
"""
|
|
768
779
|
Runs Python-based (as opposed to CLI-based) package tests.
|
|
@@ -785,7 +796,7 @@ def run_python_tests(options):
|
|
|
785
796
|
test_package_imports('megadetector.visualization')
|
|
786
797
|
test_package_imports('megadetector.postprocessing')
|
|
787
798
|
test_package_imports('megadetector.postprocessing.repeat_detection_elimination')
|
|
788
|
-
test_package_imports('megadetector.utils',exceptions=['
|
|
799
|
+
test_package_imports('megadetector.utils',exceptions=['md_tests'])
|
|
789
800
|
test_package_imports('megadetector.data_management',exceptions=['lila','ocr_tools'])
|
|
790
801
|
|
|
791
802
|
|
|
@@ -1523,6 +1534,8 @@ def run_cli_tests(options):
|
|
|
1523
1534
|
|
|
1524
1535
|
def run_download_tests(options):
|
|
1525
1536
|
"""
|
|
1537
|
+
Test automatic model downloads.
|
|
1538
|
+
|
|
1526
1539
|
Args:
|
|
1527
1540
|
options (MDTestOptions): see MDTestOptions for details
|
|
1528
1541
|
"""
|
|
@@ -1539,14 +1552,15 @@ def run_download_tests(options):
|
|
|
1539
1552
|
# e.g. "v5a.0.0"
|
|
1540
1553
|
for model_name in known_models:
|
|
1541
1554
|
url = known_models[model_name]['url']
|
|
1542
|
-
if 'localhost' in url:
|
|
1555
|
+
if ('localhost' in url) and options.skip_localhost_downloads:
|
|
1543
1556
|
continue
|
|
1544
1557
|
print('Testing download for known model {}'.format(model_name))
|
|
1545
1558
|
fn = try_download_known_detector(model_name,
|
|
1546
1559
|
force_download=False,
|
|
1547
1560
|
verbose=False)
|
|
1548
1561
|
version_string = get_detector_version_from_model_file(fn, verbose=False)
|
|
1549
|
-
|
|
1562
|
+
# Make sure this is the same version we asked for, modulo the MDv5 re-releases
|
|
1563
|
+
assert (version_string.replace('.0.1','.0.0') == model_name.replace('.0.1','.0.0'))
|
|
1550
1564
|
|
|
1551
1565
|
# Make sure we can download models based on short names, e.g. "MDV5A"
|
|
1552
1566
|
for model_name in model_string_to_model_version:
|
|
@@ -1561,6 +1575,53 @@ def run_download_tests(options):
|
|
|
1561
1575
|
verbose=False)
|
|
1562
1576
|
assert fn != model_name
|
|
1563
1577
|
|
|
1578
|
+
# Test corruption handling for .pt files
|
|
1579
|
+
print('Testing corruption handling for MDV5B')
|
|
1580
|
+
|
|
1581
|
+
# First ensure MDV5B is downloaded
|
|
1582
|
+
mdv5b_file = try_download_known_detector('MDV5B',
|
|
1583
|
+
force_download=False,
|
|
1584
|
+
verbose=False)
|
|
1585
|
+
assert mdv5b_file is not None
|
|
1586
|
+
assert os.path.exists(mdv5b_file)
|
|
1587
|
+
assert mdv5b_file.endswith('.pt')
|
|
1588
|
+
|
|
1589
|
+
# Get the original file size and MD5 hash for comparison
|
|
1590
|
+
original_size = os.path.getsize(mdv5b_file)
|
|
1591
|
+
from megadetector.utils.path_utils import compute_file_hash
|
|
1592
|
+
original_hash = compute_file_hash(mdv5b_file, algorithm='md5')
|
|
1593
|
+
|
|
1594
|
+
# Deliberately corrupt the file by overwriting the first few bytes
|
|
1595
|
+
print('Corrupting model file: {}'.format(mdv5b_file))
|
|
1596
|
+
with open(mdv5b_file, 'r+b') as f:
|
|
1597
|
+
f.write(b'CORRUPTED_FILE_DATA_XXXXXX')
|
|
1598
|
+
|
|
1599
|
+
# Verify the file is now corrupted (different hash)
|
|
1600
|
+
corrupted_hash = compute_file_hash(mdv5b_file, algorithm='md5')
|
|
1601
|
+
assert corrupted_hash != original_hash, 'File corruption verification failed'
|
|
1602
|
+
|
|
1603
|
+
# Try to download again; this should detect corruption and re-download
|
|
1604
|
+
print('Testing corruption detection and re-download')
|
|
1605
|
+
mdv5b_file_redownloaded = try_download_known_detector('MDV5B',
|
|
1606
|
+
force_download=False,
|
|
1607
|
+
verbose=True)
|
|
1608
|
+
|
|
1609
|
+
# Verify that the file was re-downloaded and is now valid
|
|
1610
|
+
assert mdv5b_file_redownloaded is not None
|
|
1611
|
+
assert os.path.exists(mdv5b_file_redownloaded)
|
|
1612
|
+
assert mdv5b_file_redownloaded == mdv5b_file
|
|
1613
|
+
|
|
1614
|
+
# Verify that the file is back to its original state
|
|
1615
|
+
new_size = os.path.getsize(mdv5b_file_redownloaded)
|
|
1616
|
+
new_hash = compute_file_hash(mdv5b_file_redownloaded, algorithm='md5')
|
|
1617
|
+
|
|
1618
|
+
assert new_size == original_size, \
|
|
1619
|
+
'Re-downloaded file size ({}) does not match original ({})'.format(new_size, original_size)
|
|
1620
|
+
assert new_hash == original_hash, \
|
|
1621
|
+
'Re-downloaded file hash ({}) does not match original ({})'.format(new_hash, original_hash)
|
|
1622
|
+
|
|
1623
|
+
print('Corruption handling test passed')
|
|
1624
|
+
|
|
1564
1625
|
# ...def run_download_tests()
|
|
1565
1626
|
|
|
1566
1627
|
|
|
@@ -1630,6 +1691,9 @@ def run_tests(options):
|
|
|
1630
1691
|
#%% Automated test entry point
|
|
1631
1692
|
|
|
1632
1693
|
def test_suite_entry_point():
|
|
1694
|
+
"""
|
|
1695
|
+
Main entry point for the numerical test suite.
|
|
1696
|
+
"""
|
|
1633
1697
|
|
|
1634
1698
|
options = MDTestOptions()
|
|
1635
1699
|
options.disable_gpu = False
|
|
@@ -1647,10 +1711,11 @@ def test_suite_entry_point():
|
|
|
1647
1711
|
options.skip_video_rendering_tests = True
|
|
1648
1712
|
options.cli_working_dir = None
|
|
1649
1713
|
options.cli_test_pythonpath = None
|
|
1650
|
-
|
|
1651
1714
|
options.skip_download_tests = True
|
|
1652
|
-
|
|
1715
|
+
options.skip_localhost_downloads = True
|
|
1716
|
+
|
|
1653
1717
|
options = download_test_data(options)
|
|
1718
|
+
|
|
1654
1719
|
run_tests(options)
|
|
1655
1720
|
|
|
1656
1721
|
|
|
@@ -1660,7 +1725,7 @@ if False:
|
|
|
1660
1725
|
|
|
1661
1726
|
pass
|
|
1662
1727
|
|
|
1663
|
-
#%%
|
|
1728
|
+
#%% Test Prep
|
|
1664
1729
|
|
|
1665
1730
|
options = MDTestOptions()
|
|
1666
1731
|
|
|
@@ -1677,6 +1742,9 @@ if False:
|
|
|
1677
1742
|
options.max_coord_error = 0.01 # 0.001
|
|
1678
1743
|
options.max_conf_error = 0.01 # 0.005
|
|
1679
1744
|
options.skip_video_rendering_tests = True
|
|
1745
|
+
options.skip_download_tests = False
|
|
1746
|
+
options.skip_localhost_downloads = False
|
|
1747
|
+
|
|
1680
1748
|
# options.iou_threshold_for_file_comparison = 0.7
|
|
1681
1749
|
|
|
1682
1750
|
options.cli_working_dir = r'c:\git\MegaDetector'
|
|
@@ -1691,18 +1759,30 @@ if False:
|
|
|
1691
1759
|
# options.yolo_working_dir = '/mnt/c/git/yolov5-md'
|
|
1692
1760
|
options = download_test_data(options)
|
|
1693
1761
|
|
|
1694
|
-
#%%
|
|
1695
1762
|
|
|
1763
|
+
#%% Environment prep
|
|
1764
|
+
|
|
1765
|
+
# Add the YOLO working dir to the PYTHONPATH if necessary
|
|
1696
1766
|
import os
|
|
1697
|
-
if (
|
|
1698
|
-
|
|
1699
|
-
|
|
1767
|
+
if (options.yolo_working_dir is not None) and \
|
|
1768
|
+
(('PYTHONPATH' not in os.environ) or (options.yolo_working_dir not in os.environ['PYTHONPATH'])):
|
|
1769
|
+
if ('PYTHONPATH' not in os.environ):
|
|
1770
|
+
os.environ['PYTHONPATH'] = options.yolo_working_dir
|
|
1771
|
+
else:
|
|
1772
|
+
os.environ['PYTHONPATH'] = os.environ['PYTHONPATH'] + ';' + options.yolo_working_dir
|
|
1700
1773
|
|
|
1701
|
-
|
|
1774
|
+
|
|
1775
|
+
#%% Run download tests
|
|
1776
|
+
|
|
1777
|
+
run_download_tests(options=options)
|
|
1778
|
+
|
|
1779
|
+
|
|
1780
|
+
#%% Run all tests
|
|
1702
1781
|
|
|
1703
1782
|
run_tests(options)
|
|
1704
1783
|
|
|
1705
|
-
|
|
1784
|
+
|
|
1785
|
+
#%% Run YOLO inference tests
|
|
1706
1786
|
|
|
1707
1787
|
yolo_inference_options_dict = {'input_folder': '/tmp/md-tests/md-test-images',
|
|
1708
1788
|
'image_filename_list': None,
|