OTVision 0.5.5__tar.gz → 0.6.1__tar.gz

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.
Files changed (281) hide show
  1. {otvision-0.5.5 → otvision-0.6.1}/.github/workflows/test.yml +1 -1
  2. {otvision-0.5.5 → otvision-0.6.1}/.pre-commit-config.yaml +2 -2
  3. otvision-0.6.1/OTVision/abstraction/observer.py +43 -0
  4. otvision-0.6.1/OTVision/abstraction/pipes_and_filter.py +28 -0
  5. otvision-0.6.1/OTVision/application/buffer.py +34 -0
  6. otvision-0.6.1/OTVision/application/detect/current_object_detector.py +40 -0
  7. otvision-0.6.1/OTVision/application/detect/current_object_detector_metadata.py +27 -0
  8. otvision-0.6.1/OTVision/application/detect/detected_frame_factory.py +26 -0
  9. otvision-0.6.1/OTVision/application/detect/detected_frame_producer.py +25 -0
  10. otvision-0.6.1/OTVision/application/detect/detection_file_save_path_provider.py +59 -0
  11. otvision-0.6.1/OTVision/application/detect/factory.py +25 -0
  12. otvision-0.6.1/OTVision/application/detect/timestamper.py +25 -0
  13. {otvision-0.5.5 → otvision-0.6.1}/OTVision/application/detect/update_detect_config_with_cli_args.py +5 -0
  14. otvision-0.6.1/OTVision/application/frame_count_provider.py +23 -0
  15. otvision-0.6.1/OTVision/application/get_current_config.py +10 -0
  16. otvision-0.6.1/OTVision/application/update_current_config.py +10 -0
  17. {otvision-0.5.5 → otvision-0.6.1}/OTVision/config.py +70 -1
  18. otvision-0.6.1/OTVision/detect/builder.py +180 -0
  19. {otvision-0.5.5 → otvision-0.6.1}/OTVision/detect/cli.py +16 -1
  20. otvision-0.6.1/OTVision/detect/detect.py +39 -0
  21. otvision-0.6.1/OTVision/detect/detected_frame_buffer.py +57 -0
  22. {otvision-0.5.5 → otvision-0.6.1}/OTVision/detect/otdet.py +36 -15
  23. otvision-0.6.1/OTVision/detect/otdet_file_writer.py +106 -0
  24. otvision-0.6.1/OTVision/detect/pyav_frame_count_provider.py +15 -0
  25. otvision-0.6.1/OTVision/detect/timestamper.py +152 -0
  26. otvision-0.6.1/OTVision/detect/video_input_source.py +213 -0
  27. otvision-0.6.1/OTVision/detect/yolo.py +270 -0
  28. {otvision-0.5.5 → otvision-0.6.1}/OTVision/domain/cli.py +2 -1
  29. otvision-0.6.1/OTVision/domain/current_config.py +12 -0
  30. otvision-0.6.1/OTVision/domain/detect_producer_consumer.py +30 -0
  31. otvision-0.6.1/OTVision/domain/detection.py +20 -0
  32. otvision-0.6.1/OTVision/domain/frame.py +29 -0
  33. otvision-0.6.1/OTVision/domain/input_source_detect.py +31 -0
  34. otvision-0.6.1/OTVision/domain/object_detection.py +47 -0
  35. {otvision-0.5.5 → otvision-0.6.1}/OTVision/helpers/files.py +1 -1
  36. {otvision-0.5.5 → otvision-0.6.1}/OTVision/helpers/video.py +6 -0
  37. {otvision-0.5.5 → otvision-0.6.1}/OTVision/track/preprocess.py +4 -2
  38. {otvision-0.5.5 → otvision-0.6.1}/OTVision/version.py +1 -1
  39. {otvision-0.5.5 → otvision-0.6.1}/PKG-INFO +1 -1
  40. {otvision-0.5.5 → otvision-0.6.1}/config.yml +8 -1
  41. {otvision-0.5.5 → otvision-0.6.1}/detect.py +2 -3
  42. {otvision-0.5.5 → otvision-0.6.1}/install.cmd +1 -1
  43. {otvision-0.5.5 → otvision-0.6.1}/install.sh +1 -1
  44. {otvision-0.5.5 → otvision-0.6.1}/install_dev.cmd +1 -1
  45. {otvision-0.5.5 → otvision-0.6.1}/install_dev.sh +1 -1
  46. {otvision-0.5.5 → otvision-0.6.1}/requirements-dev.txt +1 -1
  47. otvision-0.6.1/tests/abstraction/test_observer.py +44 -0
  48. otvision-0.6.1/tests/application/detect/test_current_object_detector.py +48 -0
  49. otvision-0.6.1/tests/application/detect/test_detected_frame_factory.py +33 -0
  50. otvision-0.6.1/tests/application/detect/test_detected_frame_producer.py +50 -0
  51. otvision-0.6.1/tests/application/detect/test_detection_file_save_path_provider.py +69 -0
  52. otvision-0.6.1/tests/application/detect/test_timestamper.py +116 -0
  53. otvision-0.6.1/tests/application/test_buffer.py +83 -0
  54. {otvision-0.5.5 → otvision-0.6.1}/tests/cli/test_detect_cli.py +35 -27
  55. {otvision-0.5.5 → otvision-0.6.1}/tests/detect/detect_test.py +127 -211
  56. otvision-0.6.1/tests/detect/test_detected_frame_buffer.py +37 -0
  57. {otvision-0.5.5 → otvision-0.6.1}/tests/detect/test_odet.py +69 -34
  58. otvision-0.6.1/tests/detect/test_otdet_file_writer.py +146 -0
  59. otvision-0.6.1/tests/detect/test_pyav_frame_count_provider.py +19 -0
  60. otvision-0.6.1/tests/detect/test_video_input_source.py +447 -0
  61. otvision-0.6.1/tests/detect/yolo_test.py +181 -0
  62. otvision-0.6.1/tests/track/__init__.py +0 -0
  63. {otvision-0.5.5 → otvision-0.6.1}/tests/track/test_preprocess.py +4 -1
  64. otvision-0.6.1/tests/transform/__init__.py +0 -0
  65. otvision-0.6.1/tests/utils/__init__.py +0 -0
  66. otvision-0.6.1/tests/utils/generator.py +5 -0
  67. otvision-0.6.1/tests/utils/mocking.py +5 -0
  68. otvision-0.5.5/OTVision/detect/builder.py +0 -48
  69. otvision-0.5.5/OTVision/detect/detect.py +0 -308
  70. otvision-0.5.5/OTVision/detect/yolo.py +0 -277
  71. otvision-0.5.5/tests/detect/yolo_test.py +0 -135
  72. {otvision-0.5.5 → otvision-0.6.1}/.editorconfig +0 -0
  73. {otvision-0.5.5 → otvision-0.6.1}/.flake8 +0 -0
  74. {otvision-0.5.5 → otvision-0.6.1}/.github/dependabot.yml +0 -0
  75. {otvision-0.5.5 → otvision-0.6.1}/.github/workflows/build-nightly.yml +0 -0
  76. {otvision-0.5.5 → otvision-0.6.1}/.github/workflows/build-release.yml +0 -0
  77. {otvision-0.5.5 → otvision-0.6.1}/.github/workflows/linter.yml +0 -0
  78. {otvision-0.5.5 → otvision-0.6.1}/.github/workflows/release-pypi.yml +0 -0
  79. {otvision-0.5.5 → otvision-0.6.1}/.github/workflows/release-testpypi.yml +0 -0
  80. {otvision-0.5.5 → otvision-0.6.1}/.gitignore +0 -0
  81. {otvision-0.5.5 → otvision-0.6.1}/.vscode/launch.json +0 -0
  82. {otvision-0.5.5 → otvision-0.6.1}/.vscode/scripts/build_debug_env.cmd +0 -0
  83. {otvision-0.5.5 → otvision-0.6.1}/.vscode/scripts/build_debug_env.sh +0 -0
  84. {otvision-0.5.5 → otvision-0.6.1}/.vscode/scripts/teardown_debug_env.cmd +0 -0
  85. {otvision-0.5.5 → otvision-0.6.1}/.vscode/scripts/teardown_debug_env.sh +0 -0
  86. {otvision-0.5.5 → otvision-0.6.1}/.vscode/settings.json +0 -0
  87. {otvision-0.5.5 → otvision-0.6.1}/.vscode/tasks.json +0 -0
  88. {otvision-0.5.5 → otvision-0.6.1}/.yamllint.yaml +0 -0
  89. {otvision-0.5.5 → otvision-0.6.1}/LICENSE +0 -0
  90. {otvision-0.5.5 → otvision-0.6.1}/OTVision/__init__.py +0 -0
  91. {otvision-0.5.5/OTVision/application → otvision-0.6.1/OTVision/abstraction}/__init__.py +0 -0
  92. {otvision-0.5.5/OTVision/application/detect → otvision-0.6.1/OTVision/application}/__init__.py +0 -0
  93. {otvision-0.5.5 → otvision-0.6.1}/OTVision/application/configure_logger.py +0 -0
  94. {otvision-0.5.5/OTVision/convert → otvision-0.6.1/OTVision/application/detect}/__init__.py +0 -0
  95. {otvision-0.5.5 → otvision-0.6.1}/OTVision/application/detect/get_detect_cli_args.py +0 -0
  96. {otvision-0.5.5 → otvision-0.6.1}/OTVision/application/get_config.py +0 -0
  97. {otvision-0.5.5/OTVision/detect → otvision-0.6.1/OTVision/convert}/__init__.py +0 -0
  98. {otvision-0.5.5 → otvision-0.6.1}/OTVision/convert/convert.py +0 -0
  99. {otvision-0.5.5 → otvision-0.6.1}/OTVision/dataformat.py +0 -0
  100. {otvision-0.5.5/OTVision/detect/plugin_av → otvision-0.6.1/OTVision/detect}/__init__.py +0 -0
  101. {otvision-0.5.5/OTVision/domain → otvision-0.6.1/OTVision/detect/plugin_av}/__init__.py +0 -0
  102. {otvision-0.5.5 → otvision-0.6.1}/OTVision/detect/plugin_av/rotate_frame.py +0 -0
  103. {otvision-0.5.5/OTVision/helpers → otvision-0.6.1/OTVision/domain}/__init__.py +0 -0
  104. {otvision-0.5.5/OTVision/track → otvision-0.6.1/OTVision/helpers}/__init__.py +0 -0
  105. {otvision-0.5.5 → otvision-0.6.1}/OTVision/helpers/date.py +0 -0
  106. {otvision-0.5.5 → otvision-0.6.1}/OTVision/helpers/formats.py +0 -0
  107. {otvision-0.5.5 → otvision-0.6.1}/OTVision/helpers/log.py +0 -0
  108. {otvision-0.5.5 → otvision-0.6.1}/OTVision/helpers/machine.py +0 -0
  109. {otvision-0.5.5/OTVision/transform → otvision-0.6.1/OTVision/track}/__init__.py +0 -0
  110. {otvision-0.5.5 → otvision-0.6.1}/OTVision/track/iou.py +0 -0
  111. {otvision-0.5.5 → otvision-0.6.1}/OTVision/track/iou_util.py +0 -0
  112. {otvision-0.5.5 → otvision-0.6.1}/OTVision/track/track.py +0 -0
  113. {otvision-0.5.5/OTVision/view → otvision-0.6.1/OTVision/transform}/__init__.py +0 -0
  114. {otvision-0.5.5 → otvision-0.6.1}/OTVision/transform/get_homography.py +0 -0
  115. {otvision-0.5.5 → otvision-0.6.1}/OTVision/transform/reference_points_picker.py +0 -0
  116. {otvision-0.5.5 → otvision-0.6.1}/OTVision/transform/transform.py +0 -0
  117. {otvision-0.5.5/tests → otvision-0.6.1/OTVision/view}/__init__.py +0 -0
  118. {otvision-0.5.5 → otvision-0.6.1}/OTVision/view/helpers/OTC.ico +0 -0
  119. {otvision-0.5.5 → otvision-0.6.1}/OTVision/view/view.py +0 -0
  120. {otvision-0.5.5 → otvision-0.6.1}/OTVision/view/view_convert.py +0 -0
  121. {otvision-0.5.5 → otvision-0.6.1}/OTVision/view/view_detect.py +0 -0
  122. {otvision-0.5.5 → otvision-0.6.1}/OTVision/view/view_helpers.py +0 -0
  123. {otvision-0.5.5 → otvision-0.6.1}/OTVision/view/view_track.py +0 -0
  124. {otvision-0.5.5 → otvision-0.6.1}/OTVision/view/view_transform.py +0 -0
  125. {otvision-0.5.5 → otvision-0.6.1}/OTVision.bat +0 -0
  126. {otvision-0.5.5 → otvision-0.6.1}/README.md +0 -0
  127. {otvision-0.5.5 → otvision-0.6.1}/clean-up-repository.sh +0 -0
  128. {otvision-0.5.5 → otvision-0.6.1}/convert.py +0 -0
  129. {otvision-0.5.5 → otvision-0.6.1}/export_models.py +0 -0
  130. {otvision-0.5.5 → otvision-0.6.1}/pyproject.toml +0 -0
  131. {otvision-0.5.5 → otvision-0.6.1}/reference_points_picker.py +0 -0
  132. {otvision-0.5.5 → otvision-0.6.1}/requirements.txt +0 -0
  133. {otvision-0.5.5/tests/application → otvision-0.6.1/tests}/__init__.py +0 -0
  134. {otvision-0.5.5/tests/application/detect → otvision-0.6.1/tests/abstraction}/__init__.py +0 -0
  135. {otvision-0.5.5/tests/convert → otvision-0.6.1/tests/application}/__init__.py +0 -0
  136. {otvision-0.5.5/tests → otvision-0.6.1/tests/application}/detect/__init__.py +0 -0
  137. {otvision-0.5.5 → otvision-0.6.1}/tests/application/detect/test_get_detect_cli_args.py +0 -0
  138. {otvision-0.5.5 → otvision-0.6.1}/tests/application/detect/test_update_detect_config_with_cli_args.py +0 -0
  139. {otvision-0.5.5 → otvision-0.6.1}/tests/application/test_get_config.py +0 -0
  140. {otvision-0.5.5 → otvision-0.6.1}/tests/cli/custom_cli_test_config.yaml +0 -0
  141. {otvision-0.5.5 → otvision-0.6.1}/tests/cli/test_convert_cli.py +0 -0
  142. {otvision-0.5.5 → otvision-0.6.1}/tests/cli/test_track_cli.py +0 -0
  143. {otvision-0.5.5 → otvision-0.6.1}/tests/conftest.py +0 -0
  144. {otvision-0.5.5/tests/detect/plugin_av → otvision-0.6.1/tests/convert}/__init__.py +0 -0
  145. {otvision-0.5.5 → otvision-0.6.1}/tests/convert/test_convert.py +0 -0
  146. {otvision-0.5.5 → otvision-0.6.1}/tests/data/Testvideo_CamView.png +0 -0
  147. {otvision-0.5.5 → otvision-0.6.1}/tests/data/Testvideo_CamView_Cars-Cyclist.png +0 -0
  148. {otvision-0.5.5 → otvision-0.6.1}/tests/data/Testvideo_CamView_Cars-Truck.png +0 -0
  149. {otvision-0.5.5 → otvision-0.6.1}/tests/data/Testvideo_CamView_refpts.png +0 -0
  150. {otvision-0.5.5 → otvision-0.6.1}/tests/data/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.gpkg +0 -0
  151. {otvision-0.5.5 → otvision-0.6.1}/tests/data/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.h264 +0 -0
  152. {otvision-0.5.5 → otvision-0.6.1}/tests/data/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mp4 +0 -0
  153. {otvision-0.5.5 → otvision-0.6.1}/tests/data/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  154. {otvision-0.5.5 → otvision-0.6.1}/tests/data/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otrfpts +0 -0
  155. {otvision-0.5.5 → otvision-0.6.1}/tests/data/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  156. {otvision-0.5.5 → otvision-0.6.1}/tests/data/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.gpkg +0 -0
  157. {otvision-0.5.5 → otvision-0.6.1}/tests/data/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.h264 +0 -0
  158. {otvision-0.5.5 → otvision-0.6.1}/tests/data/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.mp4 +0 -0
  159. {otvision-0.5.5 → otvision-0.6.1}/tests/data/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  160. {otvision-0.5.5 → otvision-0.6.1}/tests/data/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otrfpts +0 -0
  161. {otvision-0.5.5 → otvision-0.6.1}/tests/data/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  162. {otvision-0.5.5 → otvision-0.6.1}/tests/data/Testvideo_FR20.otrfpts +0 -0
  163. {otvision-0.5.5 → otvision-0.6.1}/tests/data/Testvideo_Satellite.jpg +0 -0
  164. {otvision-0.5.5 → otvision-0.6.1}/tests/data/Testvideo_Satellite_far.jpg +0 -0
  165. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/default/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.h264 +0 -0
  166. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/default/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mp4 +0 -0
  167. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/default/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.h264 +0 -0
  168. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/default/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.mp4 +0 -0
  169. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/fail_fps_from_filename/Testvideo_Cars-Cyclist_F20_2020-01-01_00-00-00.h264 +0 -0
  170. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/fail_fps_from_filename/Testvideo_Cars-Truck_2020-01-01_00-00-00.h264 +0 -0
  171. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/fps_from_filename/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.h264 +0 -0
  172. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/fps_from_filename/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mp4 +0 -0
  173. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/fps_from_filename/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.h264 +0 -0
  174. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/fps_from_filename/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.mp4 +0 -0
  175. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/input_fps_20/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.h264 +0 -0
  176. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/input_fps_20/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mp4 +0 -0
  177. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/input_fps_20/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.h264 +0 -0
  178. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/input_fps_20/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.mp4 +0 -0
  179. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/input_fps_40/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.h264 +0 -0
  180. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/input_fps_40/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mp4 +0 -0
  181. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/input_fps_40/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.h264 +0 -0
  182. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/input_fps_40/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.mp4 +0 -0
  183. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/output_filetype_avi/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.avi +0 -0
  184. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/output_filetype_avi/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.h264 +0 -0
  185. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/output_filetype_avi/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.avi +0 -0
  186. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/output_filetype_avi/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.h264 +0 -0
  187. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/output_filetype_mkv/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.h264 +0 -0
  188. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/output_filetype_mkv/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mkv +0 -0
  189. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/output_filetype_mkv/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.h264 +0 -0
  190. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/output_filetype_mkv/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.mkv +0 -0
  191. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/output_filetype_mov/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.h264 +0 -0
  192. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/output_filetype_mov/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mov +0 -0
  193. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/output_filetype_mov/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.h264 +0 -0
  194. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/output_filetype_mov/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.mov +0 -0
  195. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/output_filetype_mp4/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.h264 +0 -0
  196. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/output_filetype_mp4/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mp4 +0 -0
  197. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/output_filetype_mp4/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.h264 +0 -0
  198. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/output_filetype_mp4/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.mp4 +0 -0
  199. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/rotation/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00_rotate.h264 +0 -0
  200. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/rotation/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00_rotate.mov +0 -0
  201. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/rotation/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00_rotate.mp4 +0 -0
  202. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/rotation/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00_rotate.h264 +0 -0
  203. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/rotation/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00_rotate.mov +0 -0
  204. {otvision-0.5.5 → otvision-0.6.1}/tests/data/convert/rotation/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00_rotate.mp4 +0 -0
  205. {otvision-0.5.5 → otvision-0.6.1}/tests/data/detect/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mp4 +0 -0
  206. {otvision-0.5.5 → otvision-0.6.1}/tests/data/detect/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.mp4 +0 -0
  207. {otvision-0.5.5 → otvision-0.6.1}/tests/data/detect/default/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  208. {otvision-0.5.5 → otvision-0.6.1}/tests/data/detect/default/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  209. {otvision-0.5.5 → otvision-0.6.1}/tests/data/detect/rotated-Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mp4 +0 -0
  210. {otvision-0.5.5 → otvision-0.6.1}/tests/data/log/_otvision_logs/test.log +0 -0
  211. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/default/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  212. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/default/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  213. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/default/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  214. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/default/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  215. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_h_0_2/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  216. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_h_0_2/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  217. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_h_0_2/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  218. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_h_0_2/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  219. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_h_0_6/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  220. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_h_0_6/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  221. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_h_0_6/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  222. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_h_0_6/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  223. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_iou_0_2/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  224. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_iou_0_2/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  225. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_iou_0_2/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  226. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_iou_0_2/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  227. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_iou_0_6/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  228. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_iou_0_6/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  229. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_iou_0_6/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  230. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_iou_0_6/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  231. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_l_0_1/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  232. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_l_0_1/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  233. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_l_0_1/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  234. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_l_0_1/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  235. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_l_0_5/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  236. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_l_0_5/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  237. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_l_0_5/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  238. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/sigma_l_0_5/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  239. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/t_min_10/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  240. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/t_min_10/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  241. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/t_min_10/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  242. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/t_min_10/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  243. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/t_min_3/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  244. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/t_min_3/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  245. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/t_min_3/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  246. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/t_min_3/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  247. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/t_miss_max_25/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  248. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/t_miss_max_25/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  249. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/t_miss_max_25/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  250. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/t_miss_max_25/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  251. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/t_miss_max_75/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  252. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/t_miss_max_75/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  253. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/t_miss_max_75/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  254. {otvision-0.5.5 → otvision-0.6.1}/tests/data/track/t_miss_max_75/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  255. {otvision-0.5.5 → otvision-0.6.1}/tests/data/transform/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.gpkg +0 -0
  256. {otvision-0.5.5 → otvision-0.6.1}/tests/data/transform/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otrfpts +0 -0
  257. {otvision-0.5.5 → otvision-0.6.1}/tests/data/transform/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  258. {otvision-0.5.5 → otvision-0.6.1}/tests/data/transform/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.gpkg +0 -0
  259. {otvision-0.5.5 → otvision-0.6.1}/tests/data/transform/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otrfpts +0 -0
  260. {otvision-0.5.5 → otvision-0.6.1}/tests/data/transform/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  261. {otvision-0.5.5 → otvision-0.6.1}/tests/data/transform/Testvideo_FR20.otrfpts +0 -0
  262. {otvision-0.5.5 → otvision-0.6.1}/tests/data/yolov8m.mlpackage/Data/com.apple.CoreML/model.mlmodel +0 -0
  263. {otvision-0.5.5 → otvision-0.6.1}/tests/data/yolov8m.mlpackage/Data/com.apple.CoreML/weights/weight.bin +0 -0
  264. {otvision-0.5.5 → otvision-0.6.1}/tests/data/yolov8m.mlpackage/Manifest.json +0 -0
  265. {otvision-0.5.5/tests/helpers → otvision-0.6.1/tests/detect}/__init__.py +0 -0
  266. {otvision-0.5.5/tests/log → otvision-0.6.1/tests/detect/plugin_av}/__init__.py +0 -0
  267. {otvision-0.5.5 → otvision-0.6.1}/tests/detect/plugin_av/test_rotate_frame.py +0 -0
  268. {otvision-0.5.5/tests/track → otvision-0.6.1/tests/helpers}/__init__.py +0 -0
  269. {otvision-0.5.5 → otvision-0.6.1}/tests/helpers/files_test.py +0 -0
  270. {otvision-0.5.5 → otvision-0.6.1}/tests/helpers/formats_test.py +0 -0
  271. {otvision-0.5.5 → otvision-0.6.1}/tests/helpers/test_log.py +0 -0
  272. {otvision-0.5.5/tests/transform → otvision-0.6.1/tests/log}/__init__.py +0 -0
  273. {otvision-0.5.5 → otvision-0.6.1}/tests/log/log_maker.py +0 -0
  274. {otvision-0.5.5 → otvision-0.6.1}/tests/log/test_log.py +0 -0
  275. {otvision-0.5.5 → otvision-0.6.1}/tests/test_config.py +0 -0
  276. {otvision-0.5.5 → otvision-0.6.1}/tests/track/test_track.py +0 -0
  277. {otvision-0.5.5 → otvision-0.6.1}/tests/transform/test_transform.py +0 -0
  278. {otvision-0.5.5 → otvision-0.6.1}/track.py +0 -0
  279. {otvision-0.5.5 → otvision-0.6.1}/transform.py +0 -0
  280. {otvision-0.5.5 → otvision-0.6.1}/update_precommit.py +0 -0
  281. {otvision-0.5.5 → otvision-0.6.1}/view.py +0 -0
@@ -16,7 +16,7 @@ jobs:
16
16
  fail-fast: True
17
17
  matrix:
18
18
  os: [ubuntu-latest, windows-latest]
19
- py: ["3.11"]
19
+ py: ["3.12"]
20
20
  uses: "platomo/GitHub-workflows/.github/workflows/reusable-python-tests.yml@main"
21
21
  with:
22
22
  os: ${{ matrix.os }}
@@ -39,7 +39,7 @@ repos:
39
39
  hooks:
40
40
  - id: black
41
41
  - repo: https://github.com/pre-commit/mirrors-mypy
42
- rev: v1.11.1
42
+ rev: v1.15.0
43
43
  hooks:
44
44
  - id: mypy
45
45
  entry: mypy .
@@ -53,7 +53,7 @@ repos:
53
53
  - interrogate==1.5.0
54
54
  - isort==5.13.2
55
55
  - moviepy==1.0.3
56
- - mypy==1.11.1
56
+ - mypy==1.15.0
57
57
  - numpy==1.26.4
58
58
  - opencv-python==4.9.0.80
59
59
  - pandas-stubs==2.2.2.240807
@@ -0,0 +1,43 @@
1
+ from typing import Callable, TypeVar
2
+
3
+ VALUE = TypeVar("VALUE")
4
+ type Observer[T] = Callable[[T], None]
5
+
6
+
7
+ class Subject[T]:
8
+ """Generic subject class to handle and notify observers.
9
+
10
+ This class ensures that no duplicate observers can be registered.
11
+ The order that registered observers are notified is dictated by the order they have
12
+ been registered. Meaning, first to be registered is first to be notified.
13
+ """
14
+
15
+ def __init__(self) -> None:
16
+ self._observers: list[Observer[T]] = []
17
+
18
+ def register(self, observer: Observer[T]) -> None:
19
+ """Listen to changes of subject.
20
+
21
+ Args:
22
+ observer (OBSERVER): the observer to be registered. This must be a
23
+ `Callable`.
24
+ """
25
+ new_observers = self._observers.copy()
26
+ new_observers.append(observer)
27
+ self._observers = list(dict.fromkeys(new_observers))
28
+
29
+ def notify(self, value: T) -> None:
30
+ """Notifies observers about the list of tracks.
31
+
32
+ Args:
33
+ value (VALUE): value to notify the observer with.
34
+ """
35
+ [notify_observer(value) for notify_observer in self._observers]
36
+
37
+
38
+ class Observable[T]:
39
+ def __init__(self, subject: Subject[T]) -> None:
40
+ self._subject = subject
41
+
42
+ def register(self, observer: Observer[T]) -> None:
43
+ self._subject.register(observer)
@@ -0,0 +1,28 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Generator
3
+
4
+
5
+ class Filter[IN, OUT](ABC):
6
+ """Abstract base class for implementing pipe-and-filter pattern filters.
7
+
8
+ A filter processes a stream of input elements and produces a stream of output
9
+ elements. This class defines the interface for all concrete filter implementations.
10
+
11
+ Type Parameters:
12
+ IN: The type of elements that the filter receives as input.
13
+ OUT: The type of elements that the filter produces as output.
14
+ """
15
+
16
+ @abstractmethod
17
+ def filter(self, pipe: Generator[IN, None, None]) -> Generator[OUT, None, None]:
18
+ """Process elements from the input pipe and produce output elements.
19
+
20
+ Args:
21
+ pipe (Generator[IN, None, None]): Input stream of elements to be processed.
22
+
23
+ Returns:
24
+ Generator[OUT, None, None]: Output stream of processed elements.
25
+
26
+ """
27
+
28
+ raise NotImplementedError
@@ -0,0 +1,34 @@
1
+ from abc import abstractmethod
2
+ from typing import Generator
3
+
4
+ from OTVision.abstraction.observer import Observable, Subject
5
+ from OTVision.abstraction.pipes_and_filter import Filter
6
+
7
+
8
+ class Buffer[T, SUBJECT_TYPE, OBSERVING_TYPE](Observable[SUBJECT_TYPE], Filter[T, T]):
9
+ def __init__(self, subject: Subject[SUBJECT_TYPE]) -> None:
10
+ super().__init__(subject)
11
+ self._buffer: list[T] = []
12
+
13
+ def filter(self, pipe: Generator[T, None, None]) -> Generator[T, None, None]:
14
+ for element in pipe:
15
+ self.buffer(element)
16
+ yield element
17
+
18
+ def buffer(self, to_buffer: T) -> None:
19
+ self._buffer.append(to_buffer)
20
+
21
+ def _get_buffered_elements(self) -> list[T]:
22
+ return self._buffer
23
+
24
+ def _reset_buffer(self) -> None:
25
+ self._buffer = []
26
+
27
+ def on_flush(self, event: OBSERVING_TYPE) -> None:
28
+ buffered_elements = self._get_buffered_elements()
29
+ self._notify_observers(buffered_elements, event)
30
+ self._reset_buffer()
31
+
32
+ @abstractmethod
33
+ def _notify_observers(self, elements: list[T], event: OBSERVING_TYPE) -> None:
34
+ raise NotImplementedError
@@ -0,0 +1,40 @@
1
+ from typing import Generator
2
+
3
+ from OTVision.abstraction.pipes_and_filter import Filter
4
+ from OTVision.application.get_current_config import GetCurrentConfig
5
+ from OTVision.domain.detection import DetectedFrame
6
+ from OTVision.domain.frame import Frame
7
+ from OTVision.domain.object_detection import ObjectDetector, ObjectDetectorFactory
8
+
9
+
10
+ class CurrentObjectDetector(Filter[Frame, DetectedFrame]):
11
+ """Use case to retrieve the currently used object detector.
12
+
13
+ Filter implementation for detecting objects in frames using current
14
+ configuration.
15
+
16
+ Args:
17
+ get_current_config (GetCurrentConfig): Provider of current configuration.
18
+ factory (ObjectDetectorFactory): Factory for creating object detector instances.
19
+ """
20
+
21
+ def __init__(
22
+ self, get_current_config: GetCurrentConfig, factory: ObjectDetectorFactory
23
+ ) -> None:
24
+ self._get_current_config = get_current_config
25
+ self._factory = factory
26
+
27
+ def get(self) -> ObjectDetector:
28
+ """Retrieve the currently used object detector.
29
+
30
+ Returns:
31
+ ObjectDetector: The object detector.
32
+
33
+ """
34
+ detect_config = self._get_current_config.get().detect
35
+ return self._factory.create(detect_config)
36
+
37
+ def filter(
38
+ self, pipe: Generator[Frame, None, None]
39
+ ) -> Generator[DetectedFrame, None, None]:
40
+ return self.get().detect(pipe)
@@ -0,0 +1,27 @@
1
+ from OTVision.application.detect.current_object_detector import CurrentObjectDetector
2
+ from OTVision.domain.object_detection import ObjectDetectorMetadata
3
+
4
+
5
+ class CurrentObjectDetectorMetadata:
6
+ """Provider for metadata about the currently configured object detector.
7
+
8
+ This class serves as a wrapper to access metadata information about the
9
+ currently configured object detector.
10
+
11
+ Args:
12
+ current_object_detector (CurrentObjectDetector): The current object detector
13
+ instance from which to retrieve metadata.
14
+ """
15
+
16
+ def __init__(self, current_object_detector: CurrentObjectDetector) -> None:
17
+ self.current_object_detector = current_object_detector
18
+
19
+ def get(self) -> ObjectDetectorMetadata:
20
+ """Retrieve metadata about the currently configured object detector.
21
+
22
+ Returns:
23
+ ObjectDetectorMetadata: Metadata information about the current object
24
+ detector configuration.
25
+ """
26
+
27
+ return self.current_object_detector.get()
@@ -0,0 +1,26 @@
1
+ from OTVision.domain.detection import DetectedFrame, Detection
2
+ from OTVision.domain.frame import Frame, FrameKeys
3
+
4
+
5
+ class DetectedFrameFactory:
6
+ """Factory for creating DetectedFrame objects from Frame and Detection data."""
7
+
8
+ def create(self, frame: Frame, detections: list[Detection]) -> DetectedFrame:
9
+ """Creates a DetectedFrame object from a Frame and its detections.
10
+
11
+ Args:
12
+ frame (Frame): the frame object.
13
+ detections (list[Detection]): The detections to be associated with
14
+ the frame.
15
+
16
+ Returns:
17
+ DetectedFrame: A new DetectedFrame instance containing the combined frame
18
+ and detection information.
19
+ """
20
+
21
+ return DetectedFrame(
22
+ source=frame[FrameKeys.source],
23
+ frame_number=frame[FrameKeys.frame],
24
+ occurrence=frame[FrameKeys.occurrence],
25
+ detections=detections,
26
+ )
@@ -0,0 +1,25 @@
1
+ from typing import Generator
2
+
3
+ from OTVision.abstraction.pipes_and_filter import Filter
4
+ from OTVision.domain.detect_producer_consumer import DetectedFrameProducer
5
+ from OTVision.domain.detection import DetectedFrame
6
+ from OTVision.domain.frame import Frame
7
+ from OTVision.domain.input_source_detect import InputSourceDetect
8
+
9
+
10
+ class SimpleDetectedFrameProducer(DetectedFrameProducer):
11
+
12
+ def __init__(
13
+ self,
14
+ input_source: InputSourceDetect,
15
+ detection_filter: Filter[Frame, DetectedFrame],
16
+ detected_frame_buffer: Filter[DetectedFrame, DetectedFrame],
17
+ ) -> None:
18
+ self._input_source = input_source
19
+ self._detection_filter = detection_filter
20
+ self._detected_frame_buffer = detected_frame_buffer
21
+
22
+ def produce(self) -> Generator[DetectedFrame, None, None]:
23
+ return self._detected_frame_buffer.filter(
24
+ self._detection_filter.filter(self._input_source.produce())
25
+ )
@@ -0,0 +1,59 @@
1
+ from pathlib import Path
2
+
3
+ from OTVision.application.get_current_config import GetCurrentConfig
4
+
5
+
6
+ class DetectionFileSavePathProvider:
7
+ """Provides a mechanism to generate file save paths for detections.
8
+
9
+ This class is responsible for deriving the appropriate filenames for
10
+ detection files based on the source and current configuration
11
+ settings. It utilizes a configuration provider to dynamically fetch
12
+ the required configuration values.
13
+
14
+ Args:
15
+ get_current_config (GetCurrentConfig): Retrieve the current application
16
+ configuration.
17
+ """
18
+
19
+ def __init__(self, get_current_config: GetCurrentConfig) -> None:
20
+ self._get_current_config = get_current_config
21
+
22
+ def provide(self, source: str) -> Path:
23
+ config = self._get_current_config.get()
24
+ return derive_filename(
25
+ video_file=Path(source),
26
+ detect_suffix=config.filetypes.detect,
27
+ detect_start=config.detect.detect_start,
28
+ detect_end=config.detect.detect_end,
29
+ )
30
+
31
+
32
+ def derive_filename(
33
+ video_file: Path,
34
+ detect_suffix: str,
35
+ detect_start: int | None = None,
36
+ detect_end: int | None = None,
37
+ ) -> Path:
38
+ """
39
+ Generates a filename for detection files by appending specified start and end
40
+ markers and a suffix to the stem of the input video file.
41
+
42
+ Args:
43
+ video_file (Path): The input video file whose filename is to be modified.
44
+ detect_start (int | None): The starting marker to append to the filename.
45
+ If None, no starting marker will be appended.
46
+ detect_end (int | None): The ending marker to append to the filename. If None,
47
+ no ending marker will be appended.
48
+ detect_suffix (str): The file suffix to apply to the derived filename.
49
+
50
+ Returns:
51
+ Path: The modified video file path with the updated stem and suffix applied.
52
+ """
53
+ cutout = ""
54
+ if detect_start is not None:
55
+ cutout += f"_start_{detect_start}"
56
+ if detect_end is not None:
57
+ cutout += f"_end_{detect_end}"
58
+ new_stem = f"{video_file.stem}{cutout}"
59
+ return video_file.with_stem(new_stem).with_suffix(detect_suffix)
@@ -0,0 +1,25 @@
1
+ from OTVision.config import DetectConfig
2
+ from OTVision.domain.object_detection import ObjectDetector, ObjectDetectorFactory
3
+
4
+
5
+ class ObjectDetectorCachedFactory(ObjectDetectorFactory):
6
+
7
+ def __init__(self, other: ObjectDetectorFactory) -> None:
8
+ self._other = other
9
+ self.__cache: dict[str, ObjectDetector] = {}
10
+
11
+ def create(self, config: DetectConfig) -> ObjectDetector:
12
+ if cached_model := self.__cache.get(config.yolo_config.weights):
13
+ return cached_model
14
+ model = self._other.create(config)
15
+ self.__add_to_cache(model)
16
+ return model
17
+
18
+ def __add_to_cache(self, model: ObjectDetector) -> None:
19
+ weights = model.config.yolo_config.weights
20
+ if not self.__cache.get(weights):
21
+ self.__cache[weights] = model
22
+
23
+ def __remove_from_cache(self, weights: str) -> None:
24
+ if self.__cache.get(weights):
25
+ del self.__cache[weights]
@@ -0,0 +1,25 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from OTVision.domain.frame import Frame
4
+
5
+
6
+ class Timestamper(ABC):
7
+ """Interface for adding timestamps to frame data.
8
+
9
+ This class defines the interface for timestamp processors that convert raw frame
10
+ dictionaries into Frame objects with proper timestamp information.
11
+ """
12
+
13
+ @abstractmethod
14
+ def stamp(self, frame: dict) -> Frame:
15
+ """Add timestamp information to a frame.
16
+
17
+ Args:
18
+ frame (dict): Raw frame data dictionary to be processed.
19
+
20
+ Returns:
21
+ Frame: A Frame object with added timestamp information.
22
+
23
+ """
24
+
25
+ raise NotImplementedError
@@ -68,6 +68,11 @@ class UpdateDetectConfigWithCliArgs:
68
68
  if cli_args.half is not None
69
69
  else detect_config.half_precision
70
70
  ),
71
+ start_time=(
72
+ cli_args.start_time
73
+ if cli_args.start_time is not None
74
+ else detect_config.start_time
75
+ ),
71
76
  detect_start=(
72
77
  cli_args.detect_start
73
78
  if cli_args.detect_start is not None
@@ -0,0 +1,23 @@
1
+ from abc import ABC
2
+ from pathlib import Path
3
+
4
+
5
+ class FrameCountProvider(ABC):
6
+ """Abstract base class for retrieving the total number of frames in a video file.
7
+
8
+ This interface defines the contract for components that can determine the frame
9
+ count of video files. Implementations might use different methods or libraries
10
+ to calculate the total number of frames.
11
+ """
12
+
13
+ def provide(self, video_file: Path) -> int:
14
+ """Get the total number of frames in a video file.
15
+
16
+ Args:
17
+ video_file (Path): Path to the video file to analyze.
18
+
19
+ Returns:
20
+ int: Total number of frames in the video.
21
+
22
+ """
23
+ raise NotImplementedError
@@ -0,0 +1,10 @@
1
+ from OTVision.config import Config
2
+ from OTVision.domain.current_config import CurrentConfig
3
+
4
+
5
+ class GetCurrentConfig:
6
+ def __init__(self, current_config: CurrentConfig) -> None:
7
+ self._current_config = current_config
8
+
9
+ def get(self) -> Config:
10
+ return self._current_config.get()
@@ -0,0 +1,10 @@
1
+ from OTVision.config import Config
2
+ from OTVision.domain.current_config import CurrentConfig
3
+
4
+
5
+ class UpdateCurrentConfig:
6
+ def __init__(self, current_config: CurrentConfig) -> None:
7
+ self._current_config = current_config
8
+
9
+ def update(self, config: Config) -> None:
10
+ self._current_config.update(config)
@@ -22,7 +22,7 @@ OTVision config module for setting default values
22
22
 
23
23
  import logging
24
24
  from dataclasses import dataclass, field
25
- from datetime import timedelta
25
+ from datetime import datetime, timedelta
26
26
  from pathlib import Path
27
27
 
28
28
  import yaml
@@ -85,9 +85,12 @@ LOG = "LOG"
85
85
  LOG_LEVEL_CONSOLE = "LOG_LEVEL_CONSOLE"
86
86
  LOG_LEVEL_FILE = "LOG_LEVEL_FILE"
87
87
  LOG_DIR = "LOG_DIR"
88
+ START_TIME = "START_TIME"
88
89
  DETECT_END = "DETECT_END"
89
90
  DETECT_START = "DETECT_START"
90
91
 
92
+ DATETIME_FORMAT = "%Y-%m-%d_%H-%M-%S"
93
+
91
94
  """Default length of a video is 15 minutes."""
92
95
  DEFAULT_EXPECTED_DURATION: timedelta = timedelta(minutes=15)
93
96
 
@@ -260,6 +263,18 @@ class _YoloWeights:
260
263
 
261
264
  @dataclass(frozen=True)
262
265
  class YoloConfig:
266
+ """Represents the configuration for the YOLO model.
267
+
268
+ Attributes:
269
+ weights (str): Path to YOLO model weights.
270
+ available_weights (_YoloWeights): List of available default YOLO model weights.
271
+ conf (float): Confidence threshold.
272
+ iou (float): Intersection over union threshold.
273
+ img_size (int): Size of the input image.
274
+ chunk_size (int): Chunk size for processing.
275
+ normalized (bool): Whether to normalize the bounding boxes.
276
+ """
277
+
263
278
  weights: str = _YoloWeights.yolov8s
264
279
  available_weights: _YoloWeights = _YoloWeights()
265
280
  conf: float = 0.25
@@ -291,12 +306,55 @@ class YoloConfig:
291
306
 
292
307
  @dataclass(frozen=True)
293
308
  class DetectConfig:
309
+ """Represents the configuration for the `detect` command.
310
+
311
+ Attributes:
312
+ paths (list[Path]): List of files to be processed.
313
+ run_chained (bool): Whether to run chained commands.
314
+ yolo_config (YoloConfig): Configuration for the YOLO model.
315
+ expected_duration (timedelta | None): Expected duration of the video.
316
+ `None` if unknown.
317
+ overwrite (bool): Whether to overwrite existing files.
318
+ half_precision (bool): Whether to use half precision.
319
+ detect_start (int | None): Start frame for detection expressed in seconds.
320
+ Value `None` marks the start of the video.
321
+ detect_end (int | None): End frame for detection expressed in seconds.
322
+ Value `None` marks the end of the video.
323
+
324
+ """
325
+
326
+ @property
327
+ def confidence(self) -> float:
328
+ """Gets the confidence level set in the YOLO configuration.
329
+
330
+ Returns:
331
+ float: The intersection over union threshold value.
332
+ """
333
+ return self.yolo_config.conf
334
+
335
+ @property
336
+ def weights(self) -> str:
337
+ return self.yolo_config.weights
338
+
339
+ @property
340
+ def iou(self) -> float:
341
+ return self.yolo_config.iou
342
+
343
+ @property
344
+ def img_size(self) -> int:
345
+ return self.yolo_config.img_size
346
+
347
+ @property
348
+ def normalized(self) -> bool:
349
+ return self.yolo_config.normalized
350
+
294
351
  paths: list[Path] = field(default_factory=list)
295
352
  run_chained: bool = True
296
353
  yolo_config: YoloConfig = YoloConfig()
297
354
  expected_duration: timedelta | None = None
298
355
  overwrite: bool = True
299
356
  half_precision: bool = False
357
+ start_time: datetime | None = None
300
358
  detect_start: int | None = None
301
359
  detect_end: int | None = None
302
360
 
@@ -314,6 +372,7 @@ class DetectConfig:
314
372
  if expected_duration is not None:
315
373
  expected_duration = timedelta(seconds=int(expected_duration))
316
374
 
375
+ start_time = DetectConfig._parse_start_time(d)
317
376
  return DetectConfig(
318
377
  files,
319
378
  d.get(RUN_CHAINED, DetectConfig.run_chained),
@@ -321,10 +380,17 @@ class DetectConfig:
321
380
  expected_duration,
322
381
  d.get(OVERWRITE, DetectConfig.overwrite),
323
382
  d.get(HALF_PRECISION, DetectConfig.half_precision),
383
+ start_time,
324
384
  d.get(DETECT_START, DetectConfig.detect_start),
325
385
  d.get(DETECT_END, DetectConfig.detect_end),
326
386
  )
327
387
 
388
+ @staticmethod
389
+ def _parse_start_time(d: dict) -> datetime | None:
390
+ if start_time := d.get(START_TIME, DetectConfig.start_time):
391
+ return datetime.strptime(start_time, DATETIME_FORMAT)
392
+ return start_time
393
+
328
394
  def to_dict(self) -> dict:
329
395
  expected_duration = (
330
396
  int(self.expected_duration.total_seconds())
@@ -338,6 +404,9 @@ class DetectConfig:
338
404
  EXPECTED_DURATION: expected_duration,
339
405
  OVERWRITE: self.overwrite,
340
406
  HALF_PRECISION: self.half_precision,
407
+ START_TIME: self.start_time,
408
+ DETECT_START: self.detect_start,
409
+ DETECT_END: self.detect_end,
341
410
  }
342
411
 
343
412