OTVision 0.6.5__tar.gz → 0.6.6__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 (319) hide show
  1. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/detect/detected_frame_factory.py +1 -0
  2. {otvision-0.6.5 → otvision-0.6.6}/OTVision/detect/otdet_file_writer.py +1 -1
  3. {otvision-0.6.5 → otvision-0.6.6}/OTVision/detect/rtsp_input_source.py +36 -28
  4. {otvision-0.6.5 → otvision-0.6.6}/OTVision/detect/timestamper.py +1 -0
  5. {otvision-0.6.5 → otvision-0.6.6}/OTVision/detect/video_input_source.py +7 -4
  6. {otvision-0.6.5 → otvision-0.6.6}/OTVision/domain/frame.py +6 -0
  7. {otvision-0.6.5 → otvision-0.6.6}/OTVision/track/parser/chunk_parser_plugins.py +1 -0
  8. {otvision-0.6.5 → otvision-0.6.6}/OTVision/track/tracker/tracker_plugin_iou.py +1 -0
  9. {otvision-0.6.5 → otvision-0.6.6}/OTVision/version.py +1 -1
  10. {otvision-0.6.5 → otvision-0.6.6}/PKG-INFO +1 -1
  11. {otvision-0.6.5 → otvision-0.6.6}/tests/application/detect/test_detected_frame_factory.py +2 -0
  12. {otvision-0.6.5 → otvision-0.6.6}/tests/application/detect/test_timestamper.py +2 -0
  13. {otvision-0.6.5 → otvision-0.6.6}/tests/detect/test_detected_frame_buffer.py +3 -0
  14. otvision-0.6.5/tests/detect/test_odet.py → otvision-0.6.6/tests/detect/test_otdet.py +2 -0
  15. {otvision-0.6.5 → otvision-0.6.6}/tests/detect/test_rtsp_input_source.py +87 -19
  16. {otvision-0.6.5 → otvision-0.6.6}/tests/detect/test_video_input_source.py +5 -2
  17. {otvision-0.6.5 → otvision-0.6.6}/tests/detect/yolo_test.py +3 -1
  18. {otvision-0.6.5 → otvision-0.6.6}/tests/track/helper/data_builder.py +3 -0
  19. {otvision-0.6.5 → otvision-0.6.6}/tests/track/test_frame_chunk.py +1 -0
  20. {otvision-0.6.5 → otvision-0.6.6}/tests/track/test_tracking_data_structures.py +2 -0
  21. {otvision-0.6.5 → otvision-0.6.6}/.editorconfig +0 -0
  22. {otvision-0.6.5 → otvision-0.6.6}/.flake8 +0 -0
  23. {otvision-0.6.5 → otvision-0.6.6}/.github/dependabot.yml +0 -0
  24. {otvision-0.6.5 → otvision-0.6.6}/.github/workflows/build-nightly.yml +0 -0
  25. {otvision-0.6.5 → otvision-0.6.6}/.github/workflows/build-release.yml +0 -0
  26. {otvision-0.6.5 → otvision-0.6.6}/.github/workflows/linter.yml +0 -0
  27. {otvision-0.6.5 → otvision-0.6.6}/.github/workflows/release-pypi.yml +0 -0
  28. {otvision-0.6.5 → otvision-0.6.6}/.github/workflows/release-testpypi.yml +0 -0
  29. {otvision-0.6.5 → otvision-0.6.6}/.github/workflows/test.yml +0 -0
  30. {otvision-0.6.5 → otvision-0.6.6}/.gitignore +0 -0
  31. {otvision-0.6.5 → otvision-0.6.6}/.pre-commit-config.yaml +0 -0
  32. {otvision-0.6.5 → otvision-0.6.6}/.vscode/launch.json +0 -0
  33. {otvision-0.6.5 → otvision-0.6.6}/.vscode/scripts/build_debug_env.cmd +0 -0
  34. {otvision-0.6.5 → otvision-0.6.6}/.vscode/scripts/build_debug_env.sh +0 -0
  35. {otvision-0.6.5 → otvision-0.6.6}/.vscode/scripts/teardown_debug_env.cmd +0 -0
  36. {otvision-0.6.5 → otvision-0.6.6}/.vscode/scripts/teardown_debug_env.sh +0 -0
  37. {otvision-0.6.5 → otvision-0.6.6}/.vscode/settings.json +0 -0
  38. {otvision-0.6.5 → otvision-0.6.6}/.vscode/tasks.json +0 -0
  39. {otvision-0.6.5 → otvision-0.6.6}/.yamllint.yaml +0 -0
  40. {otvision-0.6.5 → otvision-0.6.6}/LICENSE +0 -0
  41. {otvision-0.6.5 → otvision-0.6.6}/OTVision/__init__.py +0 -0
  42. {otvision-0.6.5 → otvision-0.6.6}/OTVision/abstraction/__init__.py +0 -0
  43. {otvision-0.6.5 → otvision-0.6.6}/OTVision/abstraction/defaults.py +0 -0
  44. {otvision-0.6.5 → otvision-0.6.6}/OTVision/abstraction/observer.py +0 -0
  45. {otvision-0.6.5 → otvision-0.6.6}/OTVision/abstraction/pipes_and_filter.py +0 -0
  46. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/__init__.py +0 -0
  47. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/buffer.py +0 -0
  48. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/config.py +0 -0
  49. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/config_parser.py +0 -0
  50. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/configure_logger.py +0 -0
  51. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/detect/__init__.py +0 -0
  52. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/detect/current_object_detector.py +0 -0
  53. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/detect/current_object_detector_metadata.py +0 -0
  54. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/detect/detected_frame_producer.py +0 -0
  55. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/detect/detection_file_save_path_provider.py +0 -0
  56. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/detect/factory.py +0 -0
  57. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/detect/get_detect_cli_args.py +0 -0
  58. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/detect/timestamper.py +0 -0
  59. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/detect/update_detect_config_with_cli_args.py +0 -0
  60. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/frame_count_provider.py +0 -0
  61. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/get_config.py +0 -0
  62. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/get_current_config.py +0 -0
  63. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/track/__init__.py +0 -0
  64. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/track/get_track_cli_args.py +0 -0
  65. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/track/update_current_track_config.py +0 -0
  66. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/track/update_track_config_with_cli_args.py +0 -0
  67. {otvision-0.6.5 → otvision-0.6.6}/OTVision/application/update_current_config.py +0 -0
  68. {otvision-0.6.5 → otvision-0.6.6}/OTVision/config.py +0 -0
  69. {otvision-0.6.5 → otvision-0.6.6}/OTVision/convert/__init__.py +0 -0
  70. {otvision-0.6.5 → otvision-0.6.6}/OTVision/convert/convert.py +0 -0
  71. {otvision-0.6.5 → otvision-0.6.6}/OTVision/dataformat.py +0 -0
  72. {otvision-0.6.5 → otvision-0.6.6}/OTVision/detect/__init__.py +0 -0
  73. {otvision-0.6.5 → otvision-0.6.6}/OTVision/detect/builder.py +0 -0
  74. {otvision-0.6.5 → otvision-0.6.6}/OTVision/detect/cli.py +0 -0
  75. {otvision-0.6.5 → otvision-0.6.6}/OTVision/detect/detect.py +0 -0
  76. {otvision-0.6.5 → otvision-0.6.6}/OTVision/detect/detected_frame_buffer.py +0 -0
  77. {otvision-0.6.5 → otvision-0.6.6}/OTVision/detect/file_based_detect_builder.py +0 -0
  78. {otvision-0.6.5 → otvision-0.6.6}/OTVision/detect/otdet.py +0 -0
  79. {otvision-0.6.5 → otvision-0.6.6}/OTVision/detect/plugin_av/__init__.py +0 -0
  80. {otvision-0.6.5 → otvision-0.6.6}/OTVision/detect/plugin_av/rotate_frame.py +0 -0
  81. {otvision-0.6.5 → otvision-0.6.6}/OTVision/detect/pyav_frame_count_provider.py +0 -0
  82. {otvision-0.6.5 → otvision-0.6.6}/OTVision/detect/rtsp_based_detect_builder.py +0 -0
  83. {otvision-0.6.5 → otvision-0.6.6}/OTVision/detect/yolo.py +0 -0
  84. {otvision-0.6.5 → otvision-0.6.6}/OTVision/domain/__init__.py +0 -0
  85. {otvision-0.6.5 → otvision-0.6.6}/OTVision/domain/cli.py +0 -0
  86. {otvision-0.6.5 → otvision-0.6.6}/OTVision/domain/current_config.py +0 -0
  87. {otvision-0.6.5 → otvision-0.6.6}/OTVision/domain/detect_producer_consumer.py +0 -0
  88. {otvision-0.6.5 → otvision-0.6.6}/OTVision/domain/detection.py +0 -0
  89. {otvision-0.6.5 → otvision-0.6.6}/OTVision/domain/input_source_detect.py +0 -0
  90. {otvision-0.6.5 → otvision-0.6.6}/OTVision/domain/object_detection.py +0 -0
  91. {otvision-0.6.5 → otvision-0.6.6}/OTVision/domain/serialization.py +0 -0
  92. {otvision-0.6.5 → otvision-0.6.6}/OTVision/domain/time.py +0 -0
  93. {otvision-0.6.5 → otvision-0.6.6}/OTVision/helpers/__init__.py +0 -0
  94. {otvision-0.6.5 → otvision-0.6.6}/OTVision/helpers/date.py +0 -0
  95. {otvision-0.6.5 → otvision-0.6.6}/OTVision/helpers/files.py +0 -0
  96. {otvision-0.6.5 → otvision-0.6.6}/OTVision/helpers/formats.py +0 -0
  97. {otvision-0.6.5 → otvision-0.6.6}/OTVision/helpers/input_types.py +0 -0
  98. {otvision-0.6.5 → otvision-0.6.6}/OTVision/helpers/log.py +0 -0
  99. {otvision-0.6.5 → otvision-0.6.6}/OTVision/helpers/machine.py +0 -0
  100. {otvision-0.6.5 → otvision-0.6.6}/OTVision/helpers/video.py +0 -0
  101. {otvision-0.6.5 → otvision-0.6.6}/OTVision/plugin/__init__.py +0 -0
  102. {otvision-0.6.5 → otvision-0.6.6}/OTVision/plugin/yaml_serialization.py +0 -0
  103. {otvision-0.6.5 → otvision-0.6.6}/OTVision/track/__init__.py +0 -0
  104. {otvision-0.6.5 → otvision-0.6.6}/OTVision/track/builder.py +0 -0
  105. {otvision-0.6.5 → otvision-0.6.6}/OTVision/track/cli.py +0 -0
  106. {otvision-0.6.5 → otvision-0.6.6}/OTVision/track/exporter/__init__.py +0 -0
  107. {otvision-0.6.5 → otvision-0.6.6}/OTVision/track/exporter/filebased_exporter.py +0 -0
  108. {otvision-0.6.5 → otvision-0.6.6}/OTVision/track/id_generator.py +0 -0
  109. {otvision-0.6.5 → otvision-0.6.6}/OTVision/track/model/__init__.py +0 -0
  110. {otvision-0.6.5 → otvision-0.6.6}/OTVision/track/model/filebased/__init__.py +0 -0
  111. {otvision-0.6.5 → otvision-0.6.6}/OTVision/track/model/filebased/frame_chunk.py +0 -0
  112. {otvision-0.6.5 → otvision-0.6.6}/OTVision/track/model/filebased/frame_group.py +0 -0
  113. {otvision-0.6.5 → otvision-0.6.6}/OTVision/track/model/track_exporter.py +0 -0
  114. {otvision-0.6.5 → otvision-0.6.6}/OTVision/track/model/tracking_interfaces.py +0 -0
  115. {otvision-0.6.5 → otvision-0.6.6}/OTVision/track/parser/__init__.py +0 -0
  116. {otvision-0.6.5 → otvision-0.6.6}/OTVision/track/parser/frame_group_parser_plugins.py +0 -0
  117. {otvision-0.6.5 → otvision-0.6.6}/OTVision/track/track.py +0 -0
  118. {otvision-0.6.5 → otvision-0.6.6}/OTVision/track/tracker/__init__.py +0 -0
  119. {otvision-0.6.5 → otvision-0.6.6}/OTVision/track/tracker/filebased_tracking.py +0 -0
  120. {otvision-0.6.5 → otvision-0.6.6}/OTVision/transform/__init__.py +0 -0
  121. {otvision-0.6.5 → otvision-0.6.6}/OTVision/transform/get_homography.py +0 -0
  122. {otvision-0.6.5 → otvision-0.6.6}/OTVision/transform/reference_points_picker.py +0 -0
  123. {otvision-0.6.5 → otvision-0.6.6}/OTVision/transform/transform.py +0 -0
  124. {otvision-0.6.5 → otvision-0.6.6}/OTVision/view/__init__.py +0 -0
  125. {otvision-0.6.5 → otvision-0.6.6}/OTVision/view/helpers/OTC.ico +0 -0
  126. {otvision-0.6.5 → otvision-0.6.6}/OTVision/view/view.py +0 -0
  127. {otvision-0.6.5 → otvision-0.6.6}/OTVision/view/view_convert.py +0 -0
  128. {otvision-0.6.5 → otvision-0.6.6}/OTVision/view/view_detect.py +0 -0
  129. {otvision-0.6.5 → otvision-0.6.6}/OTVision/view/view_helpers.py +0 -0
  130. {otvision-0.6.5 → otvision-0.6.6}/OTVision/view/view_track.py +0 -0
  131. {otvision-0.6.5 → otvision-0.6.6}/OTVision/view/view_transform.py +0 -0
  132. {otvision-0.6.5 → otvision-0.6.6}/OTVision.bat +0 -0
  133. {otvision-0.6.5 → otvision-0.6.6}/README.md +0 -0
  134. {otvision-0.6.5 → otvision-0.6.6}/clean-up-repository.sh +0 -0
  135. {otvision-0.6.5 → otvision-0.6.6}/config.yml +0 -0
  136. {otvision-0.6.5 → otvision-0.6.6}/convert.py +0 -0
  137. {otvision-0.6.5 → otvision-0.6.6}/detect.py +0 -0
  138. {otvision-0.6.5 → otvision-0.6.6}/export_models.py +0 -0
  139. {otvision-0.6.5 → otvision-0.6.6}/install.cmd +0 -0
  140. {otvision-0.6.5 → otvision-0.6.6}/install.sh +0 -0
  141. {otvision-0.6.5 → otvision-0.6.6}/install_dev.cmd +0 -0
  142. {otvision-0.6.5 → otvision-0.6.6}/install_dev.sh +0 -0
  143. {otvision-0.6.5 → otvision-0.6.6}/pyproject.toml +0 -0
  144. {otvision-0.6.5 → otvision-0.6.6}/reference_points_picker.py +0 -0
  145. {otvision-0.6.5 → otvision-0.6.6}/requirements-dev.txt +0 -0
  146. {otvision-0.6.5 → otvision-0.6.6}/requirements.txt +0 -0
  147. {otvision-0.6.5 → otvision-0.6.6}/tests/__init__.py +0 -0
  148. {otvision-0.6.5 → otvision-0.6.6}/tests/abstraction/__init__.py +0 -0
  149. {otvision-0.6.5 → otvision-0.6.6}/tests/abstraction/test_defaults.py +0 -0
  150. {otvision-0.6.5 → otvision-0.6.6}/tests/abstraction/test_observer.py +0 -0
  151. {otvision-0.6.5 → otvision-0.6.6}/tests/application/__init__.py +0 -0
  152. {otvision-0.6.5 → otvision-0.6.6}/tests/application/detect/__init__.py +0 -0
  153. {otvision-0.6.5 → otvision-0.6.6}/tests/application/detect/test_current_object_detector.py +0 -0
  154. {otvision-0.6.5 → otvision-0.6.6}/tests/application/detect/test_detected_frame_producer.py +0 -0
  155. {otvision-0.6.5 → otvision-0.6.6}/tests/application/detect/test_detection_file_save_path_provider.py +0 -0
  156. {otvision-0.6.5 → otvision-0.6.6}/tests/application/detect/test_get_detect_cli_args.py +0 -0
  157. {otvision-0.6.5 → otvision-0.6.6}/tests/application/detect/test_update_detect_config_with_cli_args.py +0 -0
  158. {otvision-0.6.5 → otvision-0.6.6}/tests/application/test_buffer.py +0 -0
  159. {otvision-0.6.5 → otvision-0.6.6}/tests/application/test_get_config.py +0 -0
  160. {otvision-0.6.5 → otvision-0.6.6}/tests/application/track/__init__.py +0 -0
  161. {otvision-0.6.5 → otvision-0.6.6}/tests/application/track/test_get_track_cli_args.py +0 -0
  162. {otvision-0.6.5 → otvision-0.6.6}/tests/application/track/test_update_current_track_config.py +0 -0
  163. {otvision-0.6.5 → otvision-0.6.6}/tests/application/track/test_update_track_config_with_cli_args.py +0 -0
  164. {otvision-0.6.5 → otvision-0.6.6}/tests/cli/custom_cli_test_config.yaml +0 -0
  165. {otvision-0.6.5 → otvision-0.6.6}/tests/cli/test_convert_cli.py +0 -0
  166. {otvision-0.6.5 → otvision-0.6.6}/tests/cli/test_detect_cli.py +0 -0
  167. {otvision-0.6.5 → otvision-0.6.6}/tests/cli/test_track_cli.py +0 -0
  168. {otvision-0.6.5 → otvision-0.6.6}/tests/conftest.py +0 -0
  169. {otvision-0.6.5 → otvision-0.6.6}/tests/convert/__init__.py +0 -0
  170. {otvision-0.6.5 → otvision-0.6.6}/tests/convert/test_convert.py +0 -0
  171. {otvision-0.6.5 → otvision-0.6.6}/tests/data/Testvideo_CamView.png +0 -0
  172. {otvision-0.6.5 → otvision-0.6.6}/tests/data/Testvideo_CamView_Cars-Cyclist.png +0 -0
  173. {otvision-0.6.5 → otvision-0.6.6}/tests/data/Testvideo_CamView_Cars-Truck.png +0 -0
  174. {otvision-0.6.5 → otvision-0.6.6}/tests/data/Testvideo_CamView_refpts.png +0 -0
  175. {otvision-0.6.5 → otvision-0.6.6}/tests/data/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.gpkg +0 -0
  176. {otvision-0.6.5 → otvision-0.6.6}/tests/data/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.h264 +0 -0
  177. {otvision-0.6.5 → otvision-0.6.6}/tests/data/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mp4 +0 -0
  178. {otvision-0.6.5 → otvision-0.6.6}/tests/data/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  179. {otvision-0.6.5 → otvision-0.6.6}/tests/data/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otrfpts +0 -0
  180. {otvision-0.6.5 → otvision-0.6.6}/tests/data/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  181. {otvision-0.6.5 → otvision-0.6.6}/tests/data/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.gpkg +0 -0
  182. {otvision-0.6.5 → otvision-0.6.6}/tests/data/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.h264 +0 -0
  183. {otvision-0.6.5 → otvision-0.6.6}/tests/data/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.mp4 +0 -0
  184. {otvision-0.6.5 → otvision-0.6.6}/tests/data/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  185. {otvision-0.6.5 → otvision-0.6.6}/tests/data/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otrfpts +0 -0
  186. {otvision-0.6.5 → otvision-0.6.6}/tests/data/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  187. {otvision-0.6.5 → otvision-0.6.6}/tests/data/Testvideo_FR20.otrfpts +0 -0
  188. {otvision-0.6.5 → otvision-0.6.6}/tests/data/Testvideo_Satellite.jpg +0 -0
  189. {otvision-0.6.5 → otvision-0.6.6}/tests/data/Testvideo_Satellite_far.jpg +0 -0
  190. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/default/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.h264 +0 -0
  191. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/default/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mp4 +0 -0
  192. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/default/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.h264 +0 -0
  193. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/default/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.mp4 +0 -0
  194. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/fail_fps_from_filename/Testvideo_Cars-Cyclist_F20_2020-01-01_00-00-00.h264 +0 -0
  195. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/fail_fps_from_filename/Testvideo_Cars-Truck_2020-01-01_00-00-00.h264 +0 -0
  196. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/fps_from_filename/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.h264 +0 -0
  197. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/fps_from_filename/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mp4 +0 -0
  198. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/fps_from_filename/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.h264 +0 -0
  199. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/fps_from_filename/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.mp4 +0 -0
  200. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/input_fps_20/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.h264 +0 -0
  201. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/input_fps_20/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mp4 +0 -0
  202. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/input_fps_20/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.h264 +0 -0
  203. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/input_fps_20/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.mp4 +0 -0
  204. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/input_fps_40/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.h264 +0 -0
  205. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/input_fps_40/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mp4 +0 -0
  206. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/input_fps_40/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.h264 +0 -0
  207. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/input_fps_40/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.mp4 +0 -0
  208. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/output_filetype_avi/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.avi +0 -0
  209. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/output_filetype_avi/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.h264 +0 -0
  210. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/output_filetype_avi/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.avi +0 -0
  211. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/output_filetype_avi/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.h264 +0 -0
  212. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/output_filetype_mkv/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.h264 +0 -0
  213. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/output_filetype_mkv/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mkv +0 -0
  214. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/output_filetype_mkv/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.h264 +0 -0
  215. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/output_filetype_mkv/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.mkv +0 -0
  216. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/output_filetype_mov/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.h264 +0 -0
  217. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/output_filetype_mov/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mov +0 -0
  218. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/output_filetype_mov/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.h264 +0 -0
  219. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/output_filetype_mov/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.mov +0 -0
  220. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/output_filetype_mp4/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.h264 +0 -0
  221. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/output_filetype_mp4/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mp4 +0 -0
  222. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/output_filetype_mp4/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.h264 +0 -0
  223. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/output_filetype_mp4/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.mp4 +0 -0
  224. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/rotation/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00_rotate.h264 +0 -0
  225. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/rotation/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00_rotate.mov +0 -0
  226. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/rotation/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00_rotate.mp4 +0 -0
  227. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/rotation/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00_rotate.h264 +0 -0
  228. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/rotation/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00_rotate.mov +0 -0
  229. {otvision-0.6.5 → otvision-0.6.6}/tests/data/convert/rotation/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00_rotate.mp4 +0 -0
  230. {otvision-0.6.5 → otvision-0.6.6}/tests/data/detect/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mp4 +0 -0
  231. {otvision-0.6.5 → otvision-0.6.6}/tests/data/detect/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.mp4 +0 -0
  232. {otvision-0.6.5 → otvision-0.6.6}/tests/data/detect/default/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  233. {otvision-0.6.5 → otvision-0.6.6}/tests/data/detect/default/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  234. {otvision-0.6.5 → otvision-0.6.6}/tests/data/detect/rotated-Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.mp4 +0 -0
  235. {otvision-0.6.5 → otvision-0.6.6}/tests/data/log/_otvision_logs/test.log +0 -0
  236. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/default/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  237. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/default/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  238. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/default/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  239. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/default/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  240. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_h_0_2/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  241. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_h_0_2/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  242. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_h_0_2/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  243. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_h_0_2/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  244. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_h_0_6/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  245. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_h_0_6/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  246. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_h_0_6/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  247. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_h_0_6/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  248. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_iou_0_2/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  249. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_iou_0_2/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  250. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_iou_0_2/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  251. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_iou_0_2/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  252. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_iou_0_6/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  253. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_iou_0_6/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  254. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_iou_0_6/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  255. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_iou_0_6/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  256. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_l_0_1/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  257. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_l_0_1/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  258. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_l_0_1/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  259. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_l_0_1/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  260. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_l_0_5/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  261. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_l_0_5/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  262. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_l_0_5/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  263. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/sigma_l_0_5/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  264. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/t_min_10/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  265. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/t_min_10/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  266. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/t_min_10/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  267. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/t_min_10/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  268. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/t_min_3/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  269. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/t_min_3/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  270. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/t_min_3/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  271. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/t_min_3/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  272. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/t_miss_max_25/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  273. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/t_miss_max_25/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  274. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/t_miss_max_25/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  275. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/t_miss_max_25/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  276. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/t_miss_max_75/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otdet +0 -0
  277. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/t_miss_max_75/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  278. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/t_miss_max_75/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otdet +0 -0
  279. {otvision-0.6.5 → otvision-0.6.6}/tests/data/track/t_miss_max_75/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  280. {otvision-0.6.5 → otvision-0.6.6}/tests/data/transform/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.gpkg +0 -0
  281. {otvision-0.6.5 → otvision-0.6.6}/tests/data/transform/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.otrfpts +0 -0
  282. {otvision-0.6.5 → otvision-0.6.6}/tests/data/transform/Testvideo_Cars-Cyclist_FR20_2020-01-01_00-00-00.ottrk +0 -0
  283. {otvision-0.6.5 → otvision-0.6.6}/tests/data/transform/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.gpkg +0 -0
  284. {otvision-0.6.5 → otvision-0.6.6}/tests/data/transform/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.otrfpts +0 -0
  285. {otvision-0.6.5 → otvision-0.6.6}/tests/data/transform/Testvideo_Cars-Truck_FR20_2020-01-01_00-00-00.ottrk +0 -0
  286. {otvision-0.6.5 → otvision-0.6.6}/tests/data/transform/Testvideo_FR20.otrfpts +0 -0
  287. {otvision-0.6.5 → otvision-0.6.6}/tests/data/yolov8m.mlpackage/Data/com.apple.CoreML/model.mlmodel +0 -0
  288. {otvision-0.6.5 → otvision-0.6.6}/tests/data/yolov8m.mlpackage/Data/com.apple.CoreML/weights/weight.bin +0 -0
  289. {otvision-0.6.5 → otvision-0.6.6}/tests/data/yolov8m.mlpackage/Manifest.json +0 -0
  290. {otvision-0.6.5 → otvision-0.6.6}/tests/detect/__init__.py +0 -0
  291. {otvision-0.6.5 → otvision-0.6.6}/tests/detect/detect_test.py +0 -0
  292. {otvision-0.6.5 → otvision-0.6.6}/tests/detect/plugin_av/__init__.py +0 -0
  293. {otvision-0.6.5 → otvision-0.6.6}/tests/detect/plugin_av/test_rotate_frame.py +0 -0
  294. {otvision-0.6.5 → otvision-0.6.6}/tests/detect/test_otdet_file_writer.py +0 -0
  295. {otvision-0.6.5 → otvision-0.6.6}/tests/detect/test_pyav_frame_count_provider.py +0 -0
  296. {otvision-0.6.5 → otvision-0.6.6}/tests/helpers/__init__.py +0 -0
  297. {otvision-0.6.5 → otvision-0.6.6}/tests/helpers/files_test.py +0 -0
  298. {otvision-0.6.5 → otvision-0.6.6}/tests/helpers/formats_test.py +0 -0
  299. {otvision-0.6.5 → otvision-0.6.6}/tests/helpers/test_log.py +0 -0
  300. {otvision-0.6.5 → otvision-0.6.6}/tests/log/__init__.py +0 -0
  301. {otvision-0.6.5 → otvision-0.6.6}/tests/log/log_maker.py +0 -0
  302. {otvision-0.6.5 → otvision-0.6.6}/tests/log/test_log.py +0 -0
  303. {otvision-0.6.5 → otvision-0.6.6}/tests/test_config.py +0 -0
  304. {otvision-0.6.5 → otvision-0.6.6}/tests/track/__init__.py +0 -0
  305. {otvision-0.6.5 → otvision-0.6.6}/tests/track/helper/__init__.py +0 -0
  306. {otvision-0.6.5 → otvision-0.6.6}/tests/track/parser/__init__.py +0 -0
  307. {otvision-0.6.5 → otvision-0.6.6}/tests/track/parser/test_chunk_parser_plugins.py +0 -0
  308. {otvision-0.6.5 → otvision-0.6.6}/tests/track/test_frame_group.py +0 -0
  309. {otvision-0.6.5 → otvision-0.6.6}/tests/track/test_frame_group_parser_plugins.py +0 -0
  310. {otvision-0.6.5 → otvision-0.6.6}/tests/track/test_track.py +0 -0
  311. {otvision-0.6.5 → otvision-0.6.6}/tests/transform/__init__.py +0 -0
  312. {otvision-0.6.5 → otvision-0.6.6}/tests/transform/test_transform.py +0 -0
  313. {otvision-0.6.5 → otvision-0.6.6}/tests/utils/__init__.py +0 -0
  314. {otvision-0.6.5 → otvision-0.6.6}/tests/utils/generator.py +0 -0
  315. {otvision-0.6.5 → otvision-0.6.6}/tests/utils/mocking.py +0 -0
  316. {otvision-0.6.5 → otvision-0.6.6}/track.py +0 -0
  317. {otvision-0.6.5 → otvision-0.6.6}/transform.py +0 -0
  318. {otvision-0.6.5 → otvision-0.6.6}/update_precommit.py +0 -0
  319. {otvision-0.6.5 → otvision-0.6.6}/view.py +0 -0
@@ -20,6 +20,7 @@ class DetectedFrameFactory:
20
20
 
21
21
  return DetectedFrame(
22
22
  source=frame[FrameKeys.source],
23
+ output=frame[FrameKeys.output],
23
24
  no=frame[FrameKeys.frame],
24
25
  occurrence=frame[FrameKeys.occurrence],
25
26
  detections=detections,
@@ -62,7 +62,7 @@ class OtdetFileWriter:
62
62
  detect_config = config.detect
63
63
 
64
64
  actual_frames = len(event.frames)
65
- if (expected_duration := detect_config.expected_duration) is not None:
65
+ if expected_duration := detect_config.expected_duration:
66
66
  actual_fps = actual_frames / expected_duration.total_seconds()
67
67
  else:
68
68
  actual_fps = actual_frames / source_metadata.duration.total_seconds()
@@ -31,6 +31,7 @@ RETRY_SECONDS = 1
31
31
 
32
32
  class Counter:
33
33
  def __init__(self, start_value: int = 0) -> None:
34
+ self._start_value = start_value
34
35
  self.__counter = start_value
35
36
 
36
37
  def increment(self) -> None:
@@ -39,6 +40,9 @@ class Counter:
39
40
  def get(self) -> int:
40
41
  return self.__counter
41
42
 
43
+ def reset(self) -> None:
44
+ self.__counter = self._start_value
45
+
42
46
 
43
47
  class RtspInputSource(InputSourceDetect):
44
48
 
@@ -68,6 +72,10 @@ class RtspInputSource(InputSourceDetect):
68
72
  def flush_buffer_size(self) -> int:
69
73
  return self.stream_config.flush_buffer_size
70
74
 
75
+ @property
76
+ def fps(self) -> float:
77
+ return self.config.convert.output_fps
78
+
71
79
  def __init__(
72
80
  self,
73
81
  subject: Subject[FlushEvent],
@@ -82,6 +90,9 @@ class RtspInputSource(InputSourceDetect):
82
90
  self._get_current_config = get_current_config
83
91
  self._current_stream: str | None = None
84
92
  self._current_video_capture: VideoCapture | None = None
93
+ self._stream_start_time: datetime = self._datetime_provider.provide()
94
+ self._current_video_start_time = self._stream_start_time
95
+ self._outdated = True
85
96
 
86
97
  @property
87
98
  def _video_capture(self) -> VideoCapture:
@@ -106,20 +117,30 @@ class RtspInputSource(InputSourceDetect):
106
117
  return self._current_video_capture
107
118
 
108
119
  def produce(self) -> Generator[Frame, None, None]:
109
- start_time = self._datetime_provider.provide()
120
+ self._stream_start_time = self._datetime_provider.provide()
121
+ self._current_video_start_time = self._stream_start_time
110
122
  while not self.should_stop():
111
123
  if (frame := self._read_next_frame()) is not None:
112
124
  self._frame_counter.increment()
125
+ occurrence = self._datetime_provider.provide()
126
+
127
+ if self._outdated:
128
+ self._current_video_start_time = occurrence
129
+ self._outdated = False
113
130
 
114
131
  yield Frame(
115
132
  data=convert_frame_to_rgb(frame), # YOLO expects RGB
116
133
  frame=self.current_frame_number,
117
134
  source=self.rtsp_url,
118
- occurrence=self._datetime_provider.provide(),
135
+ output=self.create_output(),
136
+ occurrence=occurrence,
119
137
  )
120
138
  if self.flush_condition_met():
121
- self._notify(start_time)
122
- self._notify(start_time)
139
+ self._notify()
140
+ self._outdated = True
141
+ self._frame_counter.reset()
142
+
143
+ self._notify()
123
144
 
124
145
  def _init_video_capture(self, source: str) -> VideoCapture:
125
146
  cap = VideoCapture(source)
@@ -152,24 +173,16 @@ class RtspInputSource(InputSourceDetect):
152
173
  def flush_condition_met(self) -> bool:
153
174
  return self.current_frame_number % self.flush_buffer_size == 0
154
175
 
155
- def _notify(self, start_time: datetime) -> None:
176
+ def _notify(self) -> None:
156
177
  frame_width = int(self._video_capture.get(CAP_PROP_FRAME_WIDTH))
157
178
  frame_height = int(self._video_capture.get(CAP_PROP_FRAME_HEIGHT))
158
- fps = self.config.convert.output_fps
159
- _start_time = calculate_start_time(
160
- start_time, self.current_frame_number, fps, self.flush_buffer_size
161
- )
162
179
  frames = (
163
180
  self.flush_buffer_size
164
181
  if self.current_frame_number % self.flush_buffer_size == 0
165
182
  else self.current_frame_number % self.flush_buffer_size
166
183
  )
167
- duration = timedelta(seconds=round(frames / fps))
168
- output_filename = (
169
- f"{self.stream_config.name}_FR{round(fps)}"
170
- f"_{_start_time.strftime(DATETIME_FORMAT)}.mp4"
171
- )
172
- output = str(self.stream_config.save_dir / output_filename)
184
+ duration = timedelta(seconds=round(frames / self.fps))
185
+ output = self.create_output()
173
186
  self._subject.notify(
174
187
  FlushEvent.create(
175
188
  source=self.rtsp_url,
@@ -177,22 +190,17 @@ class RtspInputSource(InputSourceDetect):
177
190
  duration=duration,
178
191
  source_width=frame_width,
179
192
  source_height=frame_height,
180
- source_fps=fps,
181
- start_time=_start_time,
193
+ source_fps=self.fps,
194
+ start_time=self._current_video_start_time,
182
195
  )
183
196
  )
184
197
 
185
-
186
- def calculate_start_time(
187
- start: datetime, current_frame_number: int, fps: float, flush_buffer_size: int
188
- ) -> datetime:
189
- offset_in_frames = (
190
- current_frame_number // flush_buffer_size - 1
191
- ) * flush_buffer_size
192
- if offset_in_frames == 0:
193
- return start
194
- offset_in_seconds = offset_in_frames / fps
195
- return start + timedelta(seconds=offset_in_seconds)
198
+ def create_output(self) -> str:
199
+ output_filename = (
200
+ f"{self.stream_config.name}_FR{round(self.fps)}"
201
+ f"_{self._current_video_start_time.strftime(DATETIME_FORMAT)}.mp4"
202
+ )
203
+ return str(self.stream_config.save_dir / output_filename)
196
204
 
197
205
 
198
206
  def convert_frame_to_rgb(frame: ndarray) -> ndarray:
@@ -61,6 +61,7 @@ class VideoTimestamper(Timestamper):
61
61
  data=frame[FrameKeys.data],
62
62
  frame=frame[FrameKeys.frame],
63
63
  source=frame[FrameKeys.source],
64
+ output=frame[FrameKeys.output],
64
65
  occurrence=occurrence,
65
66
  )
66
67
 
@@ -116,6 +116,7 @@ class VideoSource(InputSourceDetect):
116
116
  FrameKeys.data: rotated_image,
117
117
  FrameKeys.frame: frame_number,
118
118
  FrameKeys.source: str(video_file),
119
+ FrameKeys.output: str(video_file),
119
120
  }
120
121
  )
121
122
  else:
@@ -124,6 +125,7 @@ class VideoSource(InputSourceDetect):
124
125
  FrameKeys.data: None,
125
126
  FrameKeys.frame: frame_number,
126
127
  FrameKeys.source: str(video_file),
128
+ FrameKeys.output: str(video_file),
127
129
  }
128
130
  )
129
131
  counter += 1
@@ -206,8 +208,9 @@ class VideoSource(InputSourceDetect):
206
208
  def __add_occurrence(self, timestamper: Timestamper, frame: dict) -> Frame:
207
209
  updated = timestamper.stamp(frame)
208
210
  return Frame(
209
- data=updated["data"],
210
- frame=updated["frame"],
211
- source=updated["source"],
212
- occurrence=updated["occurrence"],
211
+ data=updated[FrameKeys.data],
212
+ frame=updated[FrameKeys.frame],
213
+ source=updated[FrameKeys.source],
214
+ output=updated[FrameKeys.output],
215
+ occurrence=updated[FrameKeys.occurrence],
213
216
  )
@@ -20,6 +20,7 @@ class FrameKeys:
20
20
  frame: Literal["frame"] = "frame"
21
21
  source: Literal["source"] = "source"
22
22
  occurrence: Literal["occurrence"] = "occurrence"
23
+ output: Literal["output"] = "output"
23
24
 
24
25
 
25
26
  class Frame(TypedDict):
@@ -35,6 +36,7 @@ class Frame(TypedDict):
35
36
  data: Optional[ndarray]
36
37
  frame: int
37
38
  source: str
39
+ output: str
38
40
  occurrence: datetime
39
41
 
40
42
 
@@ -49,6 +51,7 @@ class DetectedFrame:
49
51
  no (FrameNo): Frame number.
50
52
  occurrence (datetime): Time stamp, at which frame was recorded.
51
53
  source (str): Source from where frame was obtained, e.g. video file path.
54
+ output (str): Output file name, e.g. video file name.
52
55
  detections (Sequence[Detection]): A sequence of Detections occurring in frame.
53
56
  image (Optional[ndarray]): Optional image data of frame.
54
57
  """
@@ -56,6 +59,7 @@ class DetectedFrame:
56
59
  no: FrameNo
57
60
  occurrence: datetime
58
61
  source: str
62
+ output: str
59
63
  detections: Sequence[Detection]
60
64
  image: Optional[ndarray] = None
61
65
 
@@ -64,6 +68,7 @@ class DetectedFrame:
64
68
  no=self.no,
65
69
  occurrence=self.occurrence,
66
70
  source=self.source,
71
+ output=self.output,
67
72
  detections=self.detections,
68
73
  image=None,
69
74
  )
@@ -153,6 +158,7 @@ class TrackedFrame(DetectedFrame):
153
158
  no=self.no,
154
159
  occurrence=self.occurrence,
155
160
  source=self.source,
161
+ output=self.output,
156
162
  finished_tracks=self.finished_tracks,
157
163
  detections=detections,
158
164
  image=self.image,
@@ -62,6 +62,7 @@ class JsonChunkParser(ChunkParser):
62
62
  no=int(key) + frame_offset,
63
63
  occurrence=occurrence,
64
64
  source=str(file),
65
+ output=str(file),
65
66
  detections=detections,
66
67
  image=None,
67
68
  )
@@ -222,6 +222,7 @@ class IouTracker(Tracker):
222
222
  no=frame.no,
223
223
  occurrence=frame.occurrence,
224
224
  source=frame.source,
225
+ output=frame.output,
225
226
  detections=tracked_detections,
226
227
  image=frame.image,
227
228
  finished_tracks=set(finished_track_ids),
@@ -1,4 +1,4 @@
1
- __version__ = "v0.6.5"
1
+ __version__ = "v0.6.6"
2
2
 
3
3
 
4
4
  def otdet_version() -> str:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: OTVision
3
- Version: 0.6.5
3
+ Version: 0.6.6
4
4
  Summary: OTVision is a core module of the OpenTrafficCam framework to perform object detection and tracking.
5
5
  Project-URL: Homepage, https://opentrafficcam.org/
6
6
  Project-URL: Documentation, https://opentrafficcam.org/overview/
@@ -16,6 +16,7 @@ class TestDetectedFrameFactory:
16
16
 
17
17
  assert actual == DetectedFrame(
18
18
  source=given_frame[FrameKeys.source],
19
+ output=given_frame[FrameKeys.output],
19
20
  no=given_frame[FrameKeys.frame],
20
21
  occurrence=given_frame[FrameKeys.occurrence],
21
22
  detections=given_detections,
@@ -28,6 +29,7 @@ class TestDetectedFrameFactory:
28
29
  frame=1,
29
30
  occurrence=datetime(2020, 1, 1, 12, 1, 1),
30
31
  source="path/to/source.mp4",
32
+ output="path/to/output.mp4",
31
33
  )
32
34
 
33
35
  def create_detections(self) -> list[Detection]:
@@ -98,6 +98,7 @@ def create_frame_without_occurrence(frame_number: int) -> dict:
98
98
  FrameKeys.data: Mock(),
99
99
  FrameKeys.frame: frame_number,
100
100
  FrameKeys.source: SOURCE,
101
+ FrameKeys.output: SOURCE,
101
102
  }
102
103
 
103
104
 
@@ -112,5 +113,6 @@ def create_expected_frame(raw_data: dict, occurrence: datetime) -> Frame:
112
113
  data=raw_data[FrameKeys.data],
113
114
  frame=raw_data[FrameKeys.frame],
114
115
  source=raw_data[FrameKeys.source],
116
+ output=raw_data[FrameKeys.output],
115
117
  occurrence=occurrence,
116
118
  )
@@ -47,6 +47,7 @@ class TestDetectedFrameBuffer:
47
47
  frame_number = 1
48
48
  occurrence = datetime(2020, 1, 1, 12, 0, 0)
49
49
  source = "my_source"
50
+ output = "path/to/output.mp4"
50
51
  detections: list[Detection] = create_mocks(3)
51
52
  image = Mock()
52
53
 
@@ -54,6 +55,7 @@ class TestDetectedFrameBuffer:
54
55
  no=frame_number,
55
56
  occurrence=occurrence,
56
57
  source=source,
58
+ output=output,
57
59
  detections=detections,
58
60
  image=image,
59
61
  )
@@ -64,6 +66,7 @@ class TestDetectedFrameBuffer:
64
66
  no=frame_number,
65
67
  occurrence=occurrence,
66
68
  source=source,
69
+ output=output,
67
70
  detections=detections,
68
71
  image=None,
69
72
  )
@@ -19,6 +19,7 @@ GIVEN_ACTUAL_DURATION = timedelta(
19
19
  hours=36, seconds=33, milliseconds=12, microseconds=15
20
20
  )
21
21
  EXPECTED_VIDEO_LENGTH = "36:00:33"
22
+ DETECTED_FRAME_OUTPUT = "path/to/output.mp4"
22
23
 
23
24
 
24
25
  def create_expected_video_metadata(
@@ -109,6 +110,7 @@ def create_detected_frame(source: str, frame_number: int) -> DetectedFrame:
109
110
  )
110
111
  return DetectedFrame(
111
112
  source=source,
113
+ output=DETECTED_FRAME_OUTPUT,
112
114
  no=frame_number,
113
115
  detections=[detection],
114
116
  occurrence=datetime(2020, 1, 1, 12, 0, 10),
@@ -1,6 +1,7 @@
1
1
  from dataclasses import dataclass
2
2
  from datetime import datetime, timedelta
3
3
  from pathlib import Path
4
+ from typing import Any
4
5
  from unittest.mock import Mock, call, patch
5
6
 
6
7
  import pytest
@@ -12,8 +13,11 @@ from OTVision.detect.rtsp_input_source import Counter, RtspInputSource
12
13
  from OTVision.domain.frame import Frame
13
14
 
14
15
  START_TIME = datetime(2020, 1, 1, 12, 0, 0)
16
+ INIT_TIME = START_TIME - timedelta(seconds=1)
15
17
  FIRST_OCCURRENCE = START_TIME + timedelta(seconds=1)
16
18
  SECOND_OCCURRENCE = FIRST_OCCURRENCE + timedelta(seconds=2)
19
+ THIRD_OCCURRENCE = SECOND_OCCURRENCE + timedelta(seconds=1)
20
+ FOURTH_OCCURRENCE = THIRD_OCCURRENCE + timedelta(seconds=1)
17
21
 
18
22
  WIDTH = 800
19
23
  HEIGHT = 600
@@ -22,9 +26,13 @@ OUTPUT_FPS = 1.0
22
26
  FIRST_FRAME_DATA = Mock()
23
27
  SECOND_FRAME_DATA = Mock()
24
28
  THIRD_FRAME_DATA = Mock()
29
+ FOURTH_FRAME_DATA = Mock()
30
+ FIFTH_FRAME_DATA = Mock()
25
31
 
26
32
  FIRST_FRAME_RGB_DATA = Mock()
27
33
  THIRD_FRAME_RGB_DATA = Mock()
34
+ FOURTH_FRAME_RGB_DATA = Mock()
35
+ FIFTH_FRAME_RGB_DATA = Mock()
28
36
  RTSP_URL = "rtsp://192.168.1.100:554/1/h264preview"
29
37
  STREAM_NAME = "OTCamera15"
30
38
  STREAM_SAVE_DIR = Path("path/to/save/dir")
@@ -35,6 +43,22 @@ STREAM_CONFIG = StreamConfig(
35
43
  save_dir=STREAM_SAVE_DIR,
36
44
  flush_buffer_size=FLUSH_BUFFER_SIZE,
37
45
  )
46
+ FIRST_OUTPUT = str(
47
+ STREAM_CONFIG.save_dir / f"{STREAM_NAME}_FR{round(OUTPUT_FPS)}"
48
+ f"_{FIRST_OCCURRENCE.strftime(DATETIME_FORMAT)}.mp4"
49
+ )
50
+ THIRD_OUTPUT = str(
51
+ STREAM_CONFIG.save_dir / f"{STREAM_NAME}_FR{round(OUTPUT_FPS)}"
52
+ f"_{FIRST_OCCURRENCE.strftime(DATETIME_FORMAT)}.mp4"
53
+ )
54
+ FOURTH_OUTPUT = str(
55
+ STREAM_CONFIG.save_dir / f"{STREAM_NAME}_FR{round(OUTPUT_FPS)}"
56
+ f"_{THIRD_OCCURRENCE.strftime(DATETIME_FORMAT)}.mp4"
57
+ )
58
+ FIFTH_OUTPUT = str(
59
+ STREAM_CONFIG.save_dir / f"{STREAM_NAME}_FR{round(OUTPUT_FPS)}"
60
+ f"_{THIRD_OCCURRENCE.strftime(DATETIME_FORMAT)}.mp4"
61
+ )
38
62
 
39
63
 
40
64
  @dataclass
@@ -62,6 +86,8 @@ class TestRtspInputSource:
62
86
  actual = list()
63
87
  actual.append(next(generator))
64
88
  actual.append(next(generator))
89
+ actual.append(next(generator))
90
+ actual.append(next(generator))
65
91
  target.stop()
66
92
  with pytest.raises(StopIteration):
67
93
  next(generator)
@@ -71,43 +97,48 @@ class TestRtspInputSource:
71
97
  data=FIRST_FRAME_RGB_DATA,
72
98
  frame=1,
73
99
  source=RTSP_URL,
100
+ output=FIRST_OUTPUT,
74
101
  occurrence=FIRST_OCCURRENCE,
75
102
  ),
76
103
  Frame(
77
104
  data=THIRD_FRAME_RGB_DATA,
78
105
  frame=2,
79
106
  source=RTSP_URL,
107
+ output=THIRD_OUTPUT,
80
108
  occurrence=SECOND_OCCURRENCE,
81
109
  ),
110
+ Frame(
111
+ data=FOURTH_FRAME_RGB_DATA,
112
+ frame=1,
113
+ source=RTSP_URL,
114
+ output=FOURTH_OUTPUT,
115
+ occurrence=THIRD_OCCURRENCE,
116
+ ),
117
+ Frame(
118
+ data=FIFTH_FRAME_RGB_DATA,
119
+ frame=2,
120
+ source=RTSP_URL,
121
+ output=FIFTH_OUTPUT,
122
+ occurrence=FOURTH_OCCURRENCE,
123
+ ),
82
124
  ]
83
- assert given.datetime_provider.provide.call_count == 3
84
- assert given.video_capture_instance.read.call_count == 3
125
+ assert given.datetime_provider.provide.call_count == 6
126
+ assert given.video_capture_instance.read.call_count == 5
85
127
  assert given.convert_frame_to_rgb.call_args_list == [
86
128
  call(FIRST_FRAME_DATA),
87
129
  call(THIRD_FRAME_DATA),
130
+ call(FOURTH_FRAME_DATA),
131
+ call(FIFTH_FRAME_DATA),
88
132
  ]
89
133
  assert given.video_capture_instance.get.call_args_list == [
90
134
  call(CAP_PROP_FRAME_WIDTH),
91
135
  call(CAP_PROP_FRAME_HEIGHT),
92
136
  call(CAP_PROP_FRAME_WIDTH),
93
137
  call(CAP_PROP_FRAME_HEIGHT),
138
+ call(CAP_PROP_FRAME_WIDTH),
139
+ call(CAP_PROP_FRAME_HEIGHT),
94
140
  ]
95
- expected_flush_event = FlushEvent.create(
96
- source=RTSP_URL,
97
- output=str(
98
- STREAM_SAVE_DIR / f"{STREAM_NAME}_FR{round(OUTPUT_FPS)}"
99
- f"_{START_TIME.strftime(DATETIME_FORMAT)}.mp4"
100
- ),
101
- duration=timedelta(seconds=2),
102
- source_width=WIDTH,
103
- source_height=HEIGHT,
104
- source_fps=OUTPUT_FPS,
105
- start_time=START_TIME,
106
- )
107
- assert given.subject.notify.call_args_list == [
108
- call(expected_flush_event),
109
- call(expected_flush_event),
110
- ]
141
+ assert given.subject.notify.call_args_list == create_expected_flush_events()
111
142
 
112
143
 
113
144
  def create_given(video_capture: Mock, convert_frame_to_rgb: Mock) -> Given:
@@ -131,22 +162,36 @@ def create_target_with(
131
162
  (True, FIRST_FRAME_DATA),
132
163
  (False, SECOND_FRAME_DATA),
133
164
  (True, THIRD_FRAME_DATA),
165
+ (True, FOURTH_FRAME_DATA),
166
+ (True, FIFTH_FRAME_DATA),
134
167
  ]
135
168
 
136
169
  given.video_capture_instance.isOpened.return_value = video_capture_is_opened
137
170
  given.video_capture_instance.read.side_effect = frames
138
- given.video_capture_instance.get.side_effect = [WIDTH, HEIGHT, WIDTH, HEIGHT]
171
+ given.video_capture_instance.get.side_effect = [
172
+ WIDTH,
173
+ HEIGHT,
174
+ WIDTH,
175
+ HEIGHT,
176
+ WIDTH,
177
+ HEIGHT,
178
+ ]
139
179
 
140
180
  given.datetime_provider.provide.side_effect = [
181
+ INIT_TIME,
141
182
  START_TIME,
142
183
  FIRST_OCCURRENCE,
143
184
  SECOND_OCCURRENCE,
185
+ THIRD_OCCURRENCE,
186
+ FOURTH_OCCURRENCE,
144
187
  ]
145
188
  given.video_capture.return_value = given.video_capture_instance
146
189
 
147
190
  given.convert_frame_to_rgb.side_effect = [
148
191
  FIRST_FRAME_RGB_DATA,
149
192
  THIRD_FRAME_RGB_DATA,
193
+ FOURTH_FRAME_RGB_DATA,
194
+ FIFTH_FRAME_RGB_DATA,
150
195
  ]
151
196
  given.config.stream = STREAM_CONFIG
152
197
  given.config.convert.output_fps = OUTPUT_FPS
@@ -158,3 +203,26 @@ def create_target_with(
158
203
  frame_counter=given.frame_counter,
159
204
  get_current_config=given.get_current_config,
160
205
  )
206
+
207
+
208
+ def create_expected_flush_events() -> list[Any]:
209
+ return [
210
+ call(create_expected_flush_event(FIRST_OCCURRENCE)),
211
+ call(create_expected_flush_event(THIRD_OCCURRENCE)),
212
+ call(create_expected_flush_event(THIRD_OCCURRENCE)),
213
+ ]
214
+
215
+
216
+ def create_expected_flush_event(start_time: datetime) -> FlushEvent:
217
+ return FlushEvent.create(
218
+ source=RTSP_URL,
219
+ output=str(
220
+ STREAM_SAVE_DIR / f"{STREAM_NAME}_FR{round(OUTPUT_FPS)}"
221
+ f"_{start_time.strftime(DATETIME_FORMAT)}.mp4"
222
+ ),
223
+ duration=timedelta(seconds=2),
224
+ source_width=WIDTH,
225
+ source_height=HEIGHT,
226
+ source_fps=OUTPUT_FPS,
227
+ start_time=start_time,
228
+ )
@@ -1,7 +1,8 @@
1
1
  from dataclasses import dataclass
2
2
  from itertools import chain
3
3
  from pathlib import Path
4
- from unittest.mock import MagicMock, Mock, _Call, call, patch
4
+ from typing import Any
5
+ from unittest.mock import MagicMock, Mock, call, patch
5
6
 
6
7
  import pytest
7
8
  from av import VideoFrame
@@ -91,6 +92,7 @@ class TestVideoSource:
91
92
  FrameKeys.data: rotated_frame,
92
93
  FrameKeys.frame: frame_number,
93
94
  FrameKeys.source: str(cyclist_mp4),
95
+ FrameKeys.output: str(cyclist_mp4),
94
96
  }
95
97
  )
96
98
  for frame_number, rotated_frame in enumerate(
@@ -137,6 +139,7 @@ class TestVideoSource:
137
139
  FrameKeys.data: rotated_frame,
138
140
  FrameKeys.frame: frame_number,
139
141
  FrameKeys.source: str(input_file),
142
+ FrameKeys.output: str(input_file),
140
143
  }
141
144
  )
142
145
  for frame_number, rotated_frame in enumerate(
@@ -291,7 +294,7 @@ class TestVideoSource:
291
294
 
292
295
  def create_expected_frame_call(
293
296
  data: Mock | None, frame_number: int, source: Path
294
- ) -> _Call:
297
+ ) -> Any:
295
298
  return call(
296
299
  {
297
300
  FrameKeys.data: data,
@@ -178,4 +178,6 @@ class TestYoloDetector:
178
178
  if has_data:
179
179
  data = Mock()
180
180
 
181
- return Frame(data=data, frame=frame_no, source=source, occurrence=Mock())
181
+ return Frame(
182
+ data=data, frame=frame_no, source=source, output=source, occurrence=Mock()
183
+ )
@@ -83,6 +83,7 @@ class DataBuilder:
83
83
  no=frame_number,
84
84
  occurrence=occurrence_date,
85
85
  source=str(self.input_file_path),
86
+ output=str(self.input_file_path),
86
87
  detections=[],
87
88
  image=None,
88
89
  )
@@ -170,6 +171,7 @@ class DataBuilder:
170
171
  no=frame_number,
171
172
  occurrence=occurrence_date,
172
173
  source=str(self.input_file_path),
174
+ output=str(self.input_file_path),
173
175
  detections=[
174
176
  self.create_classification_object(label, confidence, x, y, w, h)
175
177
  for i in range(0, number_of_classifications)
@@ -253,6 +255,7 @@ def create_frame(
253
255
  no=frame_number,
254
256
  occurrence=occurrence,
255
257
  source=str(input_file_path),
258
+ output=str(input_file_path),
256
259
  detections=detections,
257
260
  image=None,
258
261
  )
@@ -72,6 +72,7 @@ class TestTrackedChunk(unittest.TestCase):
72
72
  no=no,
73
73
  occurrence=self._mock_occurrence(no),
74
74
  source=str(self.mock_file),
75
+ output=str(self.mock_file),
75
76
  detections=[self._mock_detection(track_id=i) for i in observed],
76
77
  image=None,
77
78
  finished_tracks=finished,
@@ -194,6 +194,7 @@ class TestTrackedFrame:
194
194
  no=frame.no,
195
195
  occurrence=frame.occurrence,
196
196
  source=frame.source,
197
+ output=frame.output,
197
198
  detections=tuple(tracked_dets),
198
199
  image=None,
199
200
  finished_tracks=finished_ids,
@@ -273,6 +274,7 @@ class TestFinishedFrame(unittest.TestCase):
273
274
  no=no,
274
275
  occurrence=self._mock_occurrence(no),
275
276
  source=self.mock_file,
277
+ output=self.mock_file,
276
278
  detections=[self._mock_detection(track_id=i) for i in observed],
277
279
  image=None,
278
280
  finished_tracks=finished,
File without changes
File without changes
File without changes
File without changes