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.

Files changed (95) hide show
  1. megadetector/classification/efficientnet/model.py +8 -8
  2. megadetector/classification/efficientnet/utils.py +6 -5
  3. megadetector/classification/prepare_classification_script_mc.py +3 -3
  4. megadetector/data_management/annotations/annotation_constants.py +0 -1
  5. megadetector/data_management/camtrap_dp_to_coco.py +34 -1
  6. megadetector/data_management/cct_json_utils.py +2 -2
  7. megadetector/data_management/coco_to_yolo.py +22 -5
  8. megadetector/data_management/databases/add_width_and_height_to_db.py +85 -12
  9. megadetector/data_management/databases/combine_coco_camera_traps_files.py +2 -2
  10. megadetector/data_management/databases/integrity_check_json_db.py +29 -15
  11. megadetector/data_management/generate_crops_from_cct.py +50 -1
  12. megadetector/data_management/labelme_to_coco.py +4 -2
  13. megadetector/data_management/labelme_to_yolo.py +82 -2
  14. megadetector/data_management/lila/generate_lila_per_image_labels.py +276 -18
  15. megadetector/data_management/lila/get_lila_annotation_counts.py +5 -3
  16. megadetector/data_management/lila/lila_common.py +3 -0
  17. megadetector/data_management/lila/test_lila_metadata_urls.py +15 -5
  18. megadetector/data_management/mewc_to_md.py +5 -0
  19. megadetector/data_management/ocr_tools.py +4 -3
  20. megadetector/data_management/read_exif.py +20 -5
  21. megadetector/data_management/remap_coco_categories.py +66 -4
  22. megadetector/data_management/remove_exif.py +50 -1
  23. megadetector/data_management/rename_images.py +3 -3
  24. megadetector/data_management/resize_coco_dataset.py +563 -95
  25. megadetector/data_management/yolo_output_to_md_output.py +131 -2
  26. megadetector/data_management/yolo_to_coco.py +140 -5
  27. megadetector/detection/change_detection.py +4 -3
  28. megadetector/detection/pytorch_detector.py +60 -22
  29. megadetector/detection/run_detector.py +225 -25
  30. megadetector/detection/run_detector_batch.py +42 -16
  31. megadetector/detection/run_inference_with_yolov5_val.py +12 -2
  32. megadetector/detection/run_tiled_inference.py +1 -0
  33. megadetector/detection/video_utils.py +53 -24
  34. megadetector/postprocessing/add_max_conf.py +4 -0
  35. megadetector/postprocessing/categorize_detections_by_size.py +1 -1
  36. megadetector/postprocessing/classification_postprocessing.py +55 -20
  37. megadetector/postprocessing/combine_batch_outputs.py +3 -2
  38. megadetector/postprocessing/compare_batch_results.py +64 -10
  39. megadetector/postprocessing/convert_output_format.py +12 -8
  40. megadetector/postprocessing/create_crop_folder.py +137 -10
  41. megadetector/postprocessing/load_api_results.py +26 -8
  42. megadetector/postprocessing/md_to_coco.py +4 -4
  43. megadetector/postprocessing/md_to_labelme.py +18 -7
  44. megadetector/postprocessing/merge_detections.py +5 -0
  45. megadetector/postprocessing/postprocess_batch_results.py +6 -3
  46. megadetector/postprocessing/remap_detection_categories.py +55 -2
  47. megadetector/postprocessing/render_detection_confusion_matrix.py +9 -6
  48. megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +2 -2
  49. megadetector/taxonomy_mapping/map_new_lila_datasets.py +3 -4
  50. megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +40 -19
  51. megadetector/taxonomy_mapping/preview_lila_taxonomy.py +1 -1
  52. megadetector/taxonomy_mapping/species_lookup.py +123 -41
  53. megadetector/utils/ct_utils.py +133 -113
  54. megadetector/utils/md_tests.py +93 -13
  55. megadetector/utils/path_utils.py +137 -107
  56. megadetector/utils/split_locations_into_train_val.py +2 -2
  57. megadetector/utils/string_utils.py +7 -7
  58. megadetector/utils/url_utils.py +81 -58
  59. megadetector/utils/wi_utils.py +46 -17
  60. megadetector/visualization/plot_utils.py +13 -9
  61. megadetector/visualization/render_images_with_thumbnails.py +2 -1
  62. megadetector/visualization/visualization_utils.py +94 -46
  63. megadetector/visualization/visualize_db.py +36 -9
  64. megadetector/visualization/visualize_detector_output.py +4 -4
  65. {megadetector-5.0.29.dist-info → megadetector-10.0.1.dist-info}/METADATA +135 -135
  66. megadetector-10.0.1.dist-info/RECORD +139 -0
  67. {megadetector-5.0.29.dist-info → megadetector-10.0.1.dist-info}/licenses/LICENSE +0 -0
  68. {megadetector-5.0.29.dist-info → megadetector-10.0.1.dist-info}/top_level.txt +0 -0
  69. megadetector/api/batch_processing/api_core/__init__.py +0 -0
  70. megadetector/api/batch_processing/api_core/batch_service/__init__.py +0 -0
  71. megadetector/api/batch_processing/api_core/batch_service/score.py +0 -438
  72. megadetector/api/batch_processing/api_core/server.py +0 -294
  73. megadetector/api/batch_processing/api_core/server_api_config.py +0 -97
  74. megadetector/api/batch_processing/api_core/server_app_config.py +0 -55
  75. megadetector/api/batch_processing/api_core/server_batch_job_manager.py +0 -220
  76. megadetector/api/batch_processing/api_core/server_job_status_table.py +0 -149
  77. megadetector/api/batch_processing/api_core/server_orchestration.py +0 -360
  78. megadetector/api/batch_processing/api_core/server_utils.py +0 -88
  79. megadetector/api/batch_processing/api_core_support/__init__.py +0 -0
  80. megadetector/api/batch_processing/api_core_support/aggregate_results_manually.py +0 -46
  81. megadetector/api/batch_processing/api_support/__init__.py +0 -0
  82. megadetector/api/batch_processing/api_support/summarize_daily_activity.py +0 -152
  83. megadetector/api/batch_processing/data_preparation/__init__.py +0 -0
  84. megadetector/api/synchronous/__init__.py +0 -0
  85. megadetector/api/synchronous/api_core/animal_detection_api/__init__.py +0 -0
  86. megadetector/api/synchronous/api_core/animal_detection_api/api_backend.py +0 -151
  87. megadetector/api/synchronous/api_core/animal_detection_api/api_frontend.py +0 -263
  88. megadetector/api/synchronous/api_core/animal_detection_api/config.py +0 -35
  89. megadetector/api/synchronous/api_core/tests/__init__.py +0 -0
  90. megadetector/api/synchronous/api_core/tests/load_test.py +0 -109
  91. megadetector/utils/azure_utils.py +0 -178
  92. megadetector/utils/sas_blob_utils.py +0 -513
  93. megadetector-5.0.29.dist-info/RECORD +0 -163
  94. /megadetector/{api/batch_processing/__init__.py → __init__.py} +0 -0
  95. {megadetector-5.0.29.dist-info → megadetector-10.0.1.dist-info}/WHEEL +0 -0
@@ -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=['azure_utils','sas_blob_utils','md_tests'])
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
- assert version_string == model_name
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 ('PYTHONPATH' not in os.environ) or \
1698
- (options.yolo_working_dir is not None and options.yolo_working_dir not in os.environ['PYTHONPATH']):
1699
- os.environ['PYTHONPATH'] += ';' + options.yolo_working_dir
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,