QVideo 3.4.0__tar.gz → 3.4.2__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 (132) hide show
  1. {qvideo-3.4.0 → qvideo-3.4.2}/PKG-INFO +24 -9
  2. {qvideo-3.4.0 → qvideo-3.4.2}/QVideo.egg-info/PKG-INFO +24 -9
  3. {qvideo-3.4.0 → qvideo-3.4.2}/QVideo.egg-info/SOURCES.txt +3 -2
  4. {qvideo-3.4.0 → qvideo-3.4.2}/QVideo.egg-info/requires.txt +21 -2
  5. {qvideo-3.4.0 → qvideo-3.4.2}/README.md +5 -5
  6. {qvideo-3.4.0 → qvideo-3.4.2}/demos/__init__.py +7 -0
  7. {qvideo-3.4.0 → qvideo-3.4.2}/demos/trackpydemo.py +2 -0
  8. qvideo-3.4.2/demos/yolodemo.py +61 -0
  9. {qvideo-3.4.0 → qvideo-3.4.2}/filters/QYOLOFilter.py +12 -1
  10. {qvideo-3.4.0 → qvideo-3.4.2}/lib/QVideoScreen.py +33 -0
  11. {qvideo-3.4.0 → qvideo-3.4.2}/overlays/__init__.py +2 -1
  12. {qvideo-3.4.0 → qvideo-3.4.2}/overlays/trackpy.py +26 -9
  13. qvideo-3.4.2/overlays/yolo.py +269 -0
  14. {qvideo-3.4.0 → qvideo-3.4.2}/pyproject.toml +11 -8
  15. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qvideoscreen.py +82 -0
  16. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_trackpy_overlay.py +9 -1
  17. qvideo-3.4.2/tests/test_yolo_overlay.py +323 -0
  18. qvideo-3.4.0/dvr/icons_rc_qt6.py +0 -1106
  19. qvideo-3.4.0/overlays/yolo.py +0 -21
  20. {qvideo-3.4.0 → qvideo-3.4.2}/LICENSE.md +0 -0
  21. {qvideo-3.4.0 → qvideo-3.4.2}/QCamcorder.py +0 -0
  22. {qvideo-3.4.0 → qvideo-3.4.2}/QVideo.egg-info/dependency_links.txt +0 -0
  23. {qvideo-3.4.0 → qvideo-3.4.2}/QVideo.egg-info/top_level.txt +0 -0
  24. {qvideo-3.4.0 → qvideo-3.4.2}/__init__.py +0 -0
  25. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Basler/__init__.py +0 -0
  26. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Basler/_camera.py +0 -0
  27. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Basler/_tree.py +0 -0
  28. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Flir/QListFlirCameras.py +0 -0
  29. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Flir/__init__.py +0 -0
  30. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Flir/_camera.py +0 -0
  31. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Flir/_tree.py +0 -0
  32. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Genicam/__init__.py +0 -0
  33. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Genicam/_camera.py +0 -0
  34. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Genicam/_tree.py +0 -0
  35. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/IDS/__init__.py +0 -0
  36. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/IDS/_camera.py +0 -0
  37. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/IDS/_tree.py +0 -0
  38. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/MV/__init__.py +0 -0
  39. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/MV/_camera.py +0 -0
  40. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/MV/_tree.py +0 -0
  41. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Noise/__init__.py +0 -0
  42. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Noise/_camera.py +0 -0
  43. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Noise/_tree.py +0 -0
  44. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/OpenCV/QListCVCameras.py +0 -0
  45. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/OpenCV/__init__.py +0 -0
  46. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/OpenCV/_camera.py +0 -0
  47. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/OpenCV/_resolution_tree.py +0 -0
  48. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/OpenCV/_tree.py +0 -0
  49. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Picamera/__init__.py +0 -0
  50. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Picamera/_camera.py +0 -0
  51. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Picamera/_tree.py +0 -0
  52. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Vimbax/__init__.py +0 -0
  53. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Vimbax/_camera.py +0 -0
  54. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Vimbax/_tree.py +0 -0
  55. {qvideo-3.4.0 → qvideo-3.4.2}/cameras/__init__.py +0 -0
  56. {qvideo-3.4.0 → qvideo-3.4.2}/demos/ROIdemo.py +0 -0
  57. {qvideo-3.4.0 → qvideo-3.4.2}/demos/demo.py +0 -0
  58. {qvideo-3.4.0 → qvideo-3.4.2}/demos/filterdemo.py +0 -0
  59. {qvideo-3.4.0 → qvideo-3.4.2}/dvr/QDVRWidget.py +0 -0
  60. {qvideo-3.4.0 → qvideo-3.4.2}/dvr/QHDF5Reader.py +0 -0
  61. {qvideo-3.4.0 → qvideo-3.4.2}/dvr/QHDF5Writer.py +0 -0
  62. {qvideo-3.4.0 → qvideo-3.4.2}/dvr/QOpenCVReader.py +0 -0
  63. {qvideo-3.4.0 → qvideo-3.4.2}/dvr/QOpenCVWriter.py +0 -0
  64. {qvideo-3.4.0 → qvideo-3.4.2}/dvr/__init__.py +0 -0
  65. {qvideo-3.4.0 → qvideo-3.4.2}/dvr/icons_rc.py +0 -0
  66. {qvideo-3.4.0 → qvideo-3.4.2}/filters/Median.py +0 -0
  67. {qvideo-3.4.0 → qvideo-3.4.2}/filters/MoMedian.py +0 -0
  68. {qvideo-3.4.0 → qvideo-3.4.2}/filters/Normalize.py +0 -0
  69. {qvideo-3.4.0 → qvideo-3.4.2}/filters/QBlurFilter.py +0 -0
  70. {qvideo-3.4.0 → qvideo-3.4.2}/filters/QEdgeFilter.py +0 -0
  71. {qvideo-3.4.0 → qvideo-3.4.2}/filters/QRGBFilter.py +0 -0
  72. {qvideo-3.4.0 → qvideo-3.4.2}/filters/QSampleHold.py +0 -0
  73. {qvideo-3.4.0 → qvideo-3.4.2}/filters/_MedianBase.py +0 -0
  74. {qvideo-3.4.0 → qvideo-3.4.2}/filters/__init__.py +0 -0
  75. {qvideo-3.4.0 → qvideo-3.4.2}/lib/QCamera.py +0 -0
  76. {qvideo-3.4.0 → qvideo-3.4.2}/lib/QCameraTree.py +0 -0
  77. {qvideo-3.4.0 → qvideo-3.4.2}/lib/QFPSMeter.py +0 -0
  78. {qvideo-3.4.0 → qvideo-3.4.2}/lib/QFilterBank.py +0 -0
  79. {qvideo-3.4.0 → qvideo-3.4.2}/lib/QListCameras.py +0 -0
  80. {qvideo-3.4.0 → qvideo-3.4.2}/lib/QVideoFilter.py +0 -0
  81. {qvideo-3.4.0 → qvideo-3.4.2}/lib/QVideoReader.py +0 -0
  82. {qvideo-3.4.0 → qvideo-3.4.2}/lib/QVideoSource.py +0 -0
  83. {qvideo-3.4.0 → qvideo-3.4.2}/lib/QVideoWriter.py +0 -0
  84. {qvideo-3.4.0 → qvideo-3.4.2}/lib/__init__.py +0 -0
  85. {qvideo-3.4.0 → qvideo-3.4.2}/lib/chooser.py +0 -0
  86. {qvideo-3.4.0 → qvideo-3.4.2}/lib/clickable.py +0 -0
  87. {qvideo-3.4.0 → qvideo-3.4.2}/lib/resolutions.py +0 -0
  88. {qvideo-3.4.0 → qvideo-3.4.2}/lib/types.py +0 -0
  89. {qvideo-3.4.0 → qvideo-3.4.2}/setup.cfg +0 -0
  90. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_chooser.py +0 -0
  91. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_clickable.py +0 -0
  92. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_demo.py +0 -0
  93. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_filterdemo.py +0 -0
  94. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_icons_rc.py +0 -0
  95. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_median.py +0 -0
  96. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_momedian.py +0 -0
  97. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_normalize.py +0 -0
  98. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qbaslercamera.py +0 -0
  99. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qblurfilter.py +0 -0
  100. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qcamcorder.py +0 -0
  101. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qcamera.py +0 -0
  102. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qcameratree.py +0 -0
  103. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qdvrwidget.py +0 -0
  104. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qedgefilter.py +0 -0
  105. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qfilterbank.py +0 -0
  106. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qflircamera.py +0 -0
  107. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qfpsmeter.py +0 -0
  108. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qgenicamcamera.py +0 -0
  109. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qgenicamtree.py +0 -0
  110. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qhdf5reader.py +0 -0
  111. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qhdf5writer.py +0 -0
  112. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qidscamera.py +0 -0
  113. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qlistcameras.py +0 -0
  114. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qlistcvcameras.py +0 -0
  115. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qmvcamera.py +0 -0
  116. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qnoisecamera.py +0 -0
  117. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qnoisetree.py +0 -0
  118. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qopencvcamera.py +0 -0
  119. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qopencvreader.py +0 -0
  120. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qopencvresolutiontree.py +0 -0
  121. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qopencvtree.py +0 -0
  122. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qopencvwriter.py +0 -0
  123. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qpicamera.py +0 -0
  124. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qrgbfilter.py +0 -0
  125. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qsamplehold.py +0 -0
  126. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qvideoreader.py +0 -0
  127. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qvideosource.py +0 -0
  128. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qvideowriter.py +0 -0
  129. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qvimbaxcamera.py +0 -0
  130. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_resolutions.py +0 -0
  131. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_roidemo.py +0 -0
  132. {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_videofilter.py +0 -0
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: QVideo
3
- Version: 3.4.0
3
+ Version: 3.4.2
4
4
  Summary: PyQt-based framework for integrating video cameras into research applications
5
5
  Author-email: "David G. Grier" <david.grier@nyu.edu>
6
6
  License: GPL-3.0-or-later
7
7
  Project-URL: Homepage, https://github.com/davidgrier/QVideo
8
8
  Project-URL: Repository, https://github.com/davidgrier/QVideo
9
9
  Project-URL: Bug Tracker, https://github.com/davidgrier/QVideo/issues
10
- Keywords: camera,video,imaging,PyQt5,scientific,GenICam,GigE Vision,raspberry pi
10
+ Keywords: camera,video,imaging,PyQt5,PyQt6,scientific,GenICam,GigE Vision,raspberry pi
11
11
  Classifier: Development Status :: 5 - Production/Stable
12
12
  Classifier: Intended Audience :: Science/Research
13
13
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
@@ -24,15 +24,30 @@ License-File: LICENSE.md
24
24
  Requires-Dist: h5py
25
25
  Requires-Dist: numpy
26
26
  Requires-Dist: opencv-python
27
- Requires-Dist: PyQt5
28
- Requires-Dist: PyQt5-sip
27
+ Requires-Dist: pandas
29
28
  Requires-Dist: pyqtgraph
29
+ Provides-Extra: pyqt5
30
+ Requires-Dist: PyQt5; extra == "pyqt5"
31
+ Requires-Dist: PyQt5-sip; extra == "pyqt5"
32
+ Provides-Extra: pyqt6
33
+ Requires-Dist: PyQt6; extra == "pyqt6"
30
34
  Provides-Extra: genicam
31
35
  Requires-Dist: harvesters; extra == "genicam"
32
36
  Requires-Dist: genicam; extra == "genicam"
33
37
  Provides-Extra: picamera
34
38
  Requires-Dist: picamera2; extra == "picamera"
39
+ Provides-Extra: dev-pyqt5
40
+ Requires-Dist: PyQt5; extra == "dev-pyqt5"
41
+ Requires-Dist: PyQt5-sip; extra == "dev-pyqt5"
42
+ Requires-Dist: pytest; extra == "dev-pyqt5"
43
+ Requires-Dist: pytest-cov; extra == "dev-pyqt5"
44
+ Provides-Extra: dev-pyqt6
45
+ Requires-Dist: PyQt6; extra == "dev-pyqt6"
46
+ Requires-Dist: pytest; extra == "dev-pyqt6"
47
+ Requires-Dist: pytest-cov; extra == "dev-pyqt6"
35
48
  Provides-Extra: dev
49
+ Requires-Dist: PyQt5; extra == "dev"
50
+ Requires-Dist: PyQt5-sip; extra == "dev"
36
51
  Requires-Dist: pytest; extra == "dev"
37
52
  Requires-Dist: pytest-cov; extra == "dev"
38
53
  Provides-Extra: docs
@@ -48,8 +63,9 @@ Dynamic: license-file
48
63
  [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](LICENSE.md)
49
64
  [![Tests](https://github.com/davidgrier/QVideo/actions/workflows/test.yml/badge.svg)](https://github.com/davidgrier/QVideo/actions/workflows/test.yml)
50
65
  [![Documentation](https://readthedocs.org/projects/qvideo/badge/?version=latest)](https://qvideo.readthedocs.io/en/latest/)
66
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.19239402.svg)](https://doi.org/10.5281/zenodo.19239402)
51
67
 
52
- **QVideo** is a framework for integrating video cameras into PyQt5 projects
68
+ **QVideo** is a framework for integrating video cameras into PyQt projects
53
69
  for scientific research. It provides a unified, registration-based property
54
70
  system so that every camera backend — USB webcams, GenICam devices, FLIR
55
71
  cameras, Raspberry Pi cameras — is controlled through the same API. Property
@@ -87,16 +103,15 @@ pip install QVideo
87
103
  |---------|-------|-------|
88
104
  | GenICam cameras (Vimba, etc.) | `pip install QVideo[genicam]` | Requires a vendor-supplied `.cti` producer file |
89
105
  | Raspberry Pi camera | `pip install QVideo[picamera]` | Requires `picamera2` |
90
- | FLIR / Spinnaker cameras | — | Requires the proprietary PySpin SDK; install that separately |
91
106
 
92
107
  ## Quick start
93
108
 
94
109
  ```python
95
- from pyqtgraph.Qt import QtWidgets
110
+ import pyqtgraph as pg
96
111
  from QVideo.cameras.Noise import QNoiseSource
97
112
  from QVideo.lib import QVideoScreen
98
113
 
99
- app = QtWidgets.QApplication([])
114
+ pg.mkApp()
100
115
 
101
116
  source = QNoiseSource() # synthetic noise — no hardware needed
102
117
  screen = QVideoScreen()
@@ -104,7 +119,7 @@ source.newFrame.connect(screen.setImage)
104
119
 
105
120
  screen.show()
106
121
  source.start()
107
- app.exec()
122
+ pg.exec()
108
123
  ```
109
124
 
110
125
  Replace `QNoiseSource` with `QOpenCVSource`, `QGenicamSource`, etc. to switch
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: QVideo
3
- Version: 3.4.0
3
+ Version: 3.4.2
4
4
  Summary: PyQt-based framework for integrating video cameras into research applications
5
5
  Author-email: "David G. Grier" <david.grier@nyu.edu>
6
6
  License: GPL-3.0-or-later
7
7
  Project-URL: Homepage, https://github.com/davidgrier/QVideo
8
8
  Project-URL: Repository, https://github.com/davidgrier/QVideo
9
9
  Project-URL: Bug Tracker, https://github.com/davidgrier/QVideo/issues
10
- Keywords: camera,video,imaging,PyQt5,scientific,GenICam,GigE Vision,raspberry pi
10
+ Keywords: camera,video,imaging,PyQt5,PyQt6,scientific,GenICam,GigE Vision,raspberry pi
11
11
  Classifier: Development Status :: 5 - Production/Stable
12
12
  Classifier: Intended Audience :: Science/Research
13
13
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
@@ -24,15 +24,30 @@ License-File: LICENSE.md
24
24
  Requires-Dist: h5py
25
25
  Requires-Dist: numpy
26
26
  Requires-Dist: opencv-python
27
- Requires-Dist: PyQt5
28
- Requires-Dist: PyQt5-sip
27
+ Requires-Dist: pandas
29
28
  Requires-Dist: pyqtgraph
29
+ Provides-Extra: pyqt5
30
+ Requires-Dist: PyQt5; extra == "pyqt5"
31
+ Requires-Dist: PyQt5-sip; extra == "pyqt5"
32
+ Provides-Extra: pyqt6
33
+ Requires-Dist: PyQt6; extra == "pyqt6"
30
34
  Provides-Extra: genicam
31
35
  Requires-Dist: harvesters; extra == "genicam"
32
36
  Requires-Dist: genicam; extra == "genicam"
33
37
  Provides-Extra: picamera
34
38
  Requires-Dist: picamera2; extra == "picamera"
39
+ Provides-Extra: dev-pyqt5
40
+ Requires-Dist: PyQt5; extra == "dev-pyqt5"
41
+ Requires-Dist: PyQt5-sip; extra == "dev-pyqt5"
42
+ Requires-Dist: pytest; extra == "dev-pyqt5"
43
+ Requires-Dist: pytest-cov; extra == "dev-pyqt5"
44
+ Provides-Extra: dev-pyqt6
45
+ Requires-Dist: PyQt6; extra == "dev-pyqt6"
46
+ Requires-Dist: pytest; extra == "dev-pyqt6"
47
+ Requires-Dist: pytest-cov; extra == "dev-pyqt6"
35
48
  Provides-Extra: dev
49
+ Requires-Dist: PyQt5; extra == "dev"
50
+ Requires-Dist: PyQt5-sip; extra == "dev"
36
51
  Requires-Dist: pytest; extra == "dev"
37
52
  Requires-Dist: pytest-cov; extra == "dev"
38
53
  Provides-Extra: docs
@@ -48,8 +63,9 @@ Dynamic: license-file
48
63
  [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](LICENSE.md)
49
64
  [![Tests](https://github.com/davidgrier/QVideo/actions/workflows/test.yml/badge.svg)](https://github.com/davidgrier/QVideo/actions/workflows/test.yml)
50
65
  [![Documentation](https://readthedocs.org/projects/qvideo/badge/?version=latest)](https://qvideo.readthedocs.io/en/latest/)
66
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.19239402.svg)](https://doi.org/10.5281/zenodo.19239402)
51
67
 
52
- **QVideo** is a framework for integrating video cameras into PyQt5 projects
68
+ **QVideo** is a framework for integrating video cameras into PyQt projects
53
69
  for scientific research. It provides a unified, registration-based property
54
70
  system so that every camera backend — USB webcams, GenICam devices, FLIR
55
71
  cameras, Raspberry Pi cameras — is controlled through the same API. Property
@@ -87,16 +103,15 @@ pip install QVideo
87
103
  |---------|-------|-------|
88
104
  | GenICam cameras (Vimba, etc.) | `pip install QVideo[genicam]` | Requires a vendor-supplied `.cti` producer file |
89
105
  | Raspberry Pi camera | `pip install QVideo[picamera]` | Requires `picamera2` |
90
- | FLIR / Spinnaker cameras | — | Requires the proprietary PySpin SDK; install that separately |
91
106
 
92
107
  ## Quick start
93
108
 
94
109
  ```python
95
- from pyqtgraph.Qt import QtWidgets
110
+ import pyqtgraph as pg
96
111
  from QVideo.cameras.Noise import QNoiseSource
97
112
  from QVideo.lib import QVideoScreen
98
113
 
99
- app = QtWidgets.QApplication([])
114
+ pg.mkApp()
100
115
 
101
116
  source = QNoiseSource() # synthetic noise — no hardware needed
102
117
  screen = QVideoScreen()
@@ -104,7 +119,7 @@ source.newFrame.connect(screen.setImage)
104
119
 
105
120
  screen.show()
106
121
  source.start()
107
- app.exec()
122
+ pg.exec()
108
123
  ```
109
124
 
110
125
  Replace `QNoiseSource` with `QOpenCVSource`, `QGenicamSource`, etc. to switch
@@ -46,6 +46,7 @@ demos/__init__.py
46
46
  demos/demo.py
47
47
  demos/filterdemo.py
48
48
  demos/trackpydemo.py
49
+ demos/yolodemo.py
49
50
  dvr/QDVRWidget.py
50
51
  dvr/QHDF5Reader.py
51
52
  dvr/QHDF5Writer.py
@@ -53,7 +54,6 @@ dvr/QOpenCVReader.py
53
54
  dvr/QOpenCVWriter.py
54
55
  dvr/__init__.py
55
56
  dvr/icons_rc.py
56
- dvr/icons_rc_qt6.py
57
57
  filters/Median.py
58
58
  filters/MoMedian.py
59
59
  filters/Normalize.py
@@ -126,4 +126,5 @@ tests/test_qvimbaxcamera.py
126
126
  tests/test_resolutions.py
127
127
  tests/test_roidemo.py
128
128
  tests/test_trackpy_overlay.py
129
- tests/test_videofilter.py
129
+ tests/test_videofilter.py
130
+ tests/test_yolo_overlay.py
@@ -1,11 +1,23 @@
1
1
  h5py
2
2
  numpy
3
3
  opencv-python
4
- PyQt5
5
- PyQt5-sip
4
+ pandas
6
5
  pyqtgraph
7
6
 
8
7
  [dev]
8
+ PyQt5
9
+ PyQt5-sip
10
+ pytest
11
+ pytest-cov
12
+
13
+ [dev-pyqt5]
14
+ PyQt5
15
+ PyQt5-sip
16
+ pytest
17
+ pytest-cov
18
+
19
+ [dev-pyqt6]
20
+ PyQt6
9
21
  pytest
10
22
  pytest-cov
11
23
 
@@ -20,3 +32,10 @@ genicam
20
32
 
21
33
  [picamera]
22
34
  picamera2
35
+
36
+ [pyqt5]
37
+ PyQt5
38
+ PyQt5-sip
39
+
40
+ [pyqt6]
41
+ PyQt6
@@ -5,8 +5,9 @@
5
5
  [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](LICENSE.md)
6
6
  [![Tests](https://github.com/davidgrier/QVideo/actions/workflows/test.yml/badge.svg)](https://github.com/davidgrier/QVideo/actions/workflows/test.yml)
7
7
  [![Documentation](https://readthedocs.org/projects/qvideo/badge/?version=latest)](https://qvideo.readthedocs.io/en/latest/)
8
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.19239402.svg)](https://doi.org/10.5281/zenodo.19239402)
8
9
 
9
- **QVideo** is a framework for integrating video cameras into PyQt5 projects
10
+ **QVideo** is a framework for integrating video cameras into PyQt projects
10
11
  for scientific research. It provides a unified, registration-based property
11
12
  system so that every camera backend — USB webcams, GenICam devices, FLIR
12
13
  cameras, Raspberry Pi cameras — is controlled through the same API. Property
@@ -44,16 +45,15 @@ pip install QVideo
44
45
  |---------|-------|-------|
45
46
  | GenICam cameras (Vimba, etc.) | `pip install QVideo[genicam]` | Requires a vendor-supplied `.cti` producer file |
46
47
  | Raspberry Pi camera | `pip install QVideo[picamera]` | Requires `picamera2` |
47
- | FLIR / Spinnaker cameras | — | Requires the proprietary PySpin SDK; install that separately |
48
48
 
49
49
  ## Quick start
50
50
 
51
51
  ```python
52
- from pyqtgraph.Qt import QtWidgets
52
+ import pyqtgraph as pg
53
53
  from QVideo.cameras.Noise import QNoiseSource
54
54
  from QVideo.lib import QVideoScreen
55
55
 
56
- app = QtWidgets.QApplication([])
56
+ pg.mkApp()
57
57
 
58
58
  source = QNoiseSource() # synthetic noise — no hardware needed
59
59
  screen = QVideoScreen()
@@ -61,7 +61,7 @@ source.newFrame.connect(screen.setImage)
61
61
 
62
62
  screen.show()
63
63
  source.start()
64
- app.exec()
64
+ pg.exec()
65
65
  ```
66
66
 
67
67
  Replace `QNoiseSource` with `QOpenCVSource`, `QGenicamSource`, etc. to switch
@@ -26,6 +26,11 @@ trackpydemo
26
26
  panel so that trackpy particle positions are overlaid on the live feed
27
27
  in real time and locate results are available via a signal.
28
28
 
29
+ yolodemo
30
+ Extends :mod:`demo` with a :class:`~QVideo.overlays.yolo.QYoloWidget`
31
+ panel so that YOLO object-detection bounding boxes are overlaid on the
32
+ live feed in real time and detection results are available via a signal.
33
+
29
34
  Running
30
35
  -------
31
36
  Each demo can be launched directly::
@@ -34,6 +39,7 @@ Each demo can be launched directly::
34
39
  python -m QVideo.demos.filterdemo
35
40
  python -m QVideo.demos.ROIdemo
36
41
  python -m QVideo.demos.trackpydemo
42
+ python -m QVideo.demos.yolodemo
37
43
 
38
44
  Camera selection
39
45
  ----------------
@@ -66,4 +72,5 @@ from .demo import Demo
66
72
  from .filterdemo import FilterDemo
67
73
  from .ROIdemo import ROIFilter, ROIDemo
68
74
  from .trackpydemo import TrackpyDemo
75
+ from .yolodemo import YoloDemo
69
76
 
@@ -4,6 +4,8 @@
4
4
  Run directly::
5
5
 
6
6
  python -m QVideo.demos.trackpydemo
7
+
8
+ See :mod:`QVideo.overlays.trackpy` for literature references.
7
9
  '''
8
10
 
9
11
  from QVideo.demos.demo import Demo
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env python3
2
+ '''Demo combining a live video feed, camera controls, and a YOLO overlay.
3
+
4
+ Run directly::
5
+
6
+ python -m QVideo.demos.yolodemo
7
+
8
+ See :mod:`QVideo.overlays.yolo` for literature references.
9
+ '''
10
+
11
+ from QVideo.demos.demo import Demo
12
+ from QVideo.lib import QCameraTree
13
+ from QVideo.overlays import QYoloWidget
14
+
15
+
16
+ __all__ = ['YoloDemo']
17
+
18
+
19
+ class YoloDemo(Demo):
20
+ '''Extends :class:`~QVideo.demos.demo.Demo` with a YOLO overlay.
21
+
22
+ Adds a :class:`~QVideo.overlays.yolo.QYoloWidget` control panel
23
+ below the camera control tree. Detected object bounding boxes are
24
+ rendered in real time as a rectangle overlay on the video screen.
25
+
26
+ Parameters
27
+ ----------
28
+ cameraTree : QCameraTree
29
+ The camera control tree widget to display alongside the video feed.
30
+ model_name : str
31
+ YOLO model weights file passed to :class:`~QVideo.overlays.yolo.QYoloWidget`.
32
+ Default: ``'yolo11n.pt'``.
33
+ **kwargs :
34
+ Additional keyword arguments forwarded to :class:`~QVideo.demos.demo.Demo`.
35
+ '''
36
+
37
+ def __init__(self,
38
+ cameraTree: QCameraTree,
39
+ model_name: str = 'yolo11n.pt',
40
+ **kwargs) -> None:
41
+ super().__init__(cameraTree, **kwargs)
42
+ self.yolo = QYoloWidget(self, model_name=model_name)
43
+ self.yolo.source = self.screen.source
44
+ self.yolo.attachTo(self.screen)
45
+ self._controls.addWidget(self.yolo)
46
+
47
+
48
+ def main() -> None: # pragma: no cover
49
+ '''Launch the YOLO demo with an interactively chosen camera.'''
50
+ import pyqtgraph as pg
51
+ from QVideo.lib import choose_camera
52
+
53
+ pg.mkQApp()
54
+ camera = choose_camera().start()
55
+ widget = YoloDemo(camera)
56
+ widget.show()
57
+ pg.exec()
58
+
59
+
60
+ if __name__ == '__main__': # pragma: no cover
61
+ main()
@@ -1,4 +1,15 @@
1
- '''Real-time object detection with YOLO.'''
1
+ '''Real-time object detection with YOLO.
2
+
3
+ References
4
+ ----------
5
+ .. [1] Jocher, G., Chaurasia, A., & Qiu, J. (2023). Ultralytics YOLO.
6
+ https://github.com/ultralytics/ultralytics
7
+
8
+ .. [2] Redmon, J., Divvala, S., Girshick, R., & Farhadi, A. (2016).
9
+ You only look once: Unified, real-time object detection.
10
+ Proceedings of the IEEE Conference on Computer Vision and Pattern
11
+ Recognition, 779-788. https://doi.org/10.1109/CVPR.2016.91
12
+ '''
2
13
 
3
14
  from pyqtgraph.Qt import QtCore, QtWidgets
4
15
  from QVideo.lib.QVideoFilter import VideoFilter, QVideoFilter
@@ -53,6 +53,7 @@ class QVideoScreen(GraphicsLayoutWidget):
53
53
  self.framerate = framerate
54
54
  self._ready = True
55
55
  self._pending = None
56
+ self._overlays = []
56
57
  self._setupUi()
57
58
  self._timer = QtCore.QTimer()
58
59
  self._source = None
@@ -70,6 +71,38 @@ class QVideoScreen(GraphicsLayoutWidget):
70
71
  self.image = ImageItem(axisOrder='row-major')
71
72
  self.view.addItem(self.image)
72
73
 
74
+ def addOverlay(self, item) -> None:
75
+ '''Add a graphics item to the view and register it for visibility control.
76
+
77
+ Parameters
78
+ ----------
79
+ item : pyqtgraph.GraphicsObject
80
+ The overlay item to add.
81
+ '''
82
+ self.view.addItem(item)
83
+ self._overlays.append(item)
84
+
85
+ def removeOverlay(self, item) -> None:
86
+ '''Remove a previously added graphics item from the view.
87
+
88
+ Parameters
89
+ ----------
90
+ item : pyqtgraph.GraphicsObject
91
+ The overlay item to remove.
92
+ '''
93
+ self.view.removeItem(item)
94
+ self._overlays.remove(item)
95
+
96
+ @property
97
+ def overlaysVisible(self) -> bool:
98
+ '''Whether any registered overlay is currently visible.'''
99
+ return any(item.isVisible() for item in self._overlays)
100
+
101
+ @overlaysVisible.setter
102
+ def overlaysVisible(self, visible: bool) -> None:
103
+ for item in self._overlays:
104
+ item.setVisible(visible)
105
+
73
106
  @property
74
107
  def framerate(self) -> int | None:
75
108
  '''Maximum display frame rate [fps].
@@ -1,5 +1,6 @@
1
1
  '''Graphical overlays for :class:`~QVideo.lib.QVideoScreen.QVideoScreen`.'''
2
2
 
3
3
  from .trackpy import QTrackpyOverlay, QTrackpyWidget
4
+ from .yolo import QYoloOverlay, QYoloWidget
4
5
 
5
- __all__ = ['QTrackpyOverlay', 'QTrackpyWidget']
6
+ __all__ = ['QTrackpyOverlay', 'QTrackpyWidget', 'QYoloOverlay', 'QYoloWidget']
@@ -1,4 +1,15 @@
1
- '''Real-time particle tracking overlay using trackpy.'''
1
+ '''Real-time particle tracking overlay using trackpy.
2
+
3
+ References
4
+ ----------
5
+ Allan, D. B., Caswell, T., Keim, N. C., van der Wel, C. M., &
6
+ Verweij, R. W. trackpy: Fast, Friendly Particle Tracking in Python.
7
+ Zenodo. https://doi.org/10.5281/zenodo.9971
8
+
9
+ Crocker, J. C., & Grier, D. G. (1996). Methods of digital video
10
+ microscopy for colloidal studies. Journal of Colloid and Interface
11
+ Science, 179(1), 298-310. https://doi.org/10.1006/jcis.1996.0217
12
+ '''
2
13
 
3
14
  from pyqtgraph.Qt import QtCore, QtGui, QtWidgets
4
15
  import pyqtgraph as pg
@@ -133,14 +144,10 @@ class QTrackpyWidget(QtWidgets.QGroupBox):
133
144
  minmass : float
134
145
  Initial minimum integrated brightness. Default: ``100``.
135
146
 
136
- Signals
137
- -------
138
- newData(object)
139
- Emitted for each processed frame with the
140
- :func:`trackpy.locate` :class:`~pandas.DataFrame`
141
- (or ``None`` on error).
142
147
  '''
143
148
 
149
+ #: Emitted for each processed frame with the :func:`trackpy.locate`
150
+ #: :class:`~pandas.DataFrame`, or ``None`` on error.
144
151
  newData = QtCore.pyqtSignal(object)
145
152
  _locate = QtCore.pyqtSignal(np.ndarray)
146
153
 
@@ -203,9 +210,19 @@ class QTrackpyWidget(QtWidgets.QGroupBox):
203
210
  Parameters
204
211
  ----------
205
212
  screen : QVideoScreen
206
- The screen whose :attr:`view` will host the overlay.
213
+ The screen that will host the overlay.
214
+ '''
215
+ screen.addOverlay(self._overlay)
216
+
217
+ def detachFrom(self, screen) -> None:
218
+ '''Remove the overlay graphics item from *screen*.
219
+
220
+ Parameters
221
+ ----------
222
+ screen : QVideoScreen
223
+ The screen currently hosting the overlay.
207
224
  '''
208
- screen.view.addItem(self._overlay)
225
+ screen.removeOverlay(self._overlay)
209
226
 
210
227
  @QtCore.pyqtSlot(np.ndarray)
211
228
  def _onNewFrame(self, image: Image) -> None: