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.
- {qvideo-3.4.0 → qvideo-3.4.2}/PKG-INFO +24 -9
- {qvideo-3.4.0 → qvideo-3.4.2}/QVideo.egg-info/PKG-INFO +24 -9
- {qvideo-3.4.0 → qvideo-3.4.2}/QVideo.egg-info/SOURCES.txt +3 -2
- {qvideo-3.4.0 → qvideo-3.4.2}/QVideo.egg-info/requires.txt +21 -2
- {qvideo-3.4.0 → qvideo-3.4.2}/README.md +5 -5
- {qvideo-3.4.0 → qvideo-3.4.2}/demos/__init__.py +7 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/demos/trackpydemo.py +2 -0
- qvideo-3.4.2/demos/yolodemo.py +61 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/filters/QYOLOFilter.py +12 -1
- {qvideo-3.4.0 → qvideo-3.4.2}/lib/QVideoScreen.py +33 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/overlays/__init__.py +2 -1
- {qvideo-3.4.0 → qvideo-3.4.2}/overlays/trackpy.py +26 -9
- qvideo-3.4.2/overlays/yolo.py +269 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/pyproject.toml +11 -8
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qvideoscreen.py +82 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_trackpy_overlay.py +9 -1
- qvideo-3.4.2/tests/test_yolo_overlay.py +323 -0
- qvideo-3.4.0/dvr/icons_rc_qt6.py +0 -1106
- qvideo-3.4.0/overlays/yolo.py +0 -21
- {qvideo-3.4.0 → qvideo-3.4.2}/LICENSE.md +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/QCamcorder.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/QVideo.egg-info/dependency_links.txt +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/QVideo.egg-info/top_level.txt +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/__init__.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Basler/__init__.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Basler/_camera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Basler/_tree.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Flir/QListFlirCameras.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Flir/__init__.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Flir/_camera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Flir/_tree.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Genicam/__init__.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Genicam/_camera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Genicam/_tree.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/IDS/__init__.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/IDS/_camera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/IDS/_tree.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/MV/__init__.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/MV/_camera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/MV/_tree.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Noise/__init__.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Noise/_camera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Noise/_tree.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/OpenCV/QListCVCameras.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/OpenCV/__init__.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/OpenCV/_camera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/OpenCV/_resolution_tree.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/OpenCV/_tree.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Picamera/__init__.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Picamera/_camera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Picamera/_tree.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Vimbax/__init__.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Vimbax/_camera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/Vimbax/_tree.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/cameras/__init__.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/demos/ROIdemo.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/demos/demo.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/demos/filterdemo.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/dvr/QDVRWidget.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/dvr/QHDF5Reader.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/dvr/QHDF5Writer.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/dvr/QOpenCVReader.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/dvr/QOpenCVWriter.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/dvr/__init__.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/dvr/icons_rc.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/filters/Median.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/filters/MoMedian.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/filters/Normalize.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/filters/QBlurFilter.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/filters/QEdgeFilter.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/filters/QRGBFilter.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/filters/QSampleHold.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/filters/_MedianBase.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/filters/__init__.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/lib/QCamera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/lib/QCameraTree.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/lib/QFPSMeter.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/lib/QFilterBank.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/lib/QListCameras.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/lib/QVideoFilter.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/lib/QVideoReader.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/lib/QVideoSource.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/lib/QVideoWriter.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/lib/__init__.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/lib/chooser.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/lib/clickable.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/lib/resolutions.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/lib/types.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/setup.cfg +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_chooser.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_clickable.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_demo.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_filterdemo.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_icons_rc.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_median.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_momedian.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_normalize.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qbaslercamera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qblurfilter.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qcamcorder.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qcamera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qcameratree.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qdvrwidget.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qedgefilter.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qfilterbank.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qflircamera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qfpsmeter.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qgenicamcamera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qgenicamtree.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qhdf5reader.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qhdf5writer.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qidscamera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qlistcameras.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qlistcvcameras.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qmvcamera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qnoisecamera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qnoisetree.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qopencvcamera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qopencvreader.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qopencvresolutiontree.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qopencvtree.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qopencvwriter.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qpicamera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qrgbfilter.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qsamplehold.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qvideoreader.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qvideosource.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qvideowriter.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_qvimbaxcamera.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_resolutions.py +0 -0
- {qvideo-3.4.0 → qvideo-3.4.2}/tests/test_roidemo.py +0 -0
- {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.
|
|
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:
|
|
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.md)
|
|
49
64
|
[](https://github.com/davidgrier/QVideo/actions/workflows/test.yml)
|
|
50
65
|
[](https://qvideo.readthedocs.io/en/latest/)
|
|
66
|
+
[](https://doi.org/10.5281/zenodo.19239402)
|
|
51
67
|
|
|
52
|
-
**QVideo** is a framework for integrating video cameras into
|
|
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
|
-
|
|
110
|
+
import pyqtgraph as pg
|
|
96
111
|
from QVideo.cameras.Noise import QNoiseSource
|
|
97
112
|
from QVideo.lib import QVideoScreen
|
|
98
113
|
|
|
99
|
-
|
|
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
|
-
|
|
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.
|
|
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:
|
|
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.md)
|
|
49
64
|
[](https://github.com/davidgrier/QVideo/actions/workflows/test.yml)
|
|
50
65
|
[](https://qvideo.readthedocs.io/en/latest/)
|
|
66
|
+
[](https://doi.org/10.5281/zenodo.19239402)
|
|
51
67
|
|
|
52
|
-
**QVideo** is a framework for integrating video cameras into
|
|
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
|
-
|
|
110
|
+
import pyqtgraph as pg
|
|
96
111
|
from QVideo.cameras.Noise import QNoiseSource
|
|
97
112
|
from QVideo.lib import QVideoScreen
|
|
98
113
|
|
|
99
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.md)
|
|
6
6
|
[](https://github.com/davidgrier/QVideo/actions/workflows/test.yml)
|
|
7
7
|
[](https://qvideo.readthedocs.io/en/latest/)
|
|
8
|
+
[](https://doi.org/10.5281/zenodo.19239402)
|
|
8
9
|
|
|
9
|
-
**QVideo** is a framework for integrating video cameras into
|
|
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
|
-
|
|
52
|
+
import pyqtgraph as pg
|
|
53
53
|
from QVideo.cameras.Noise import QNoiseSource
|
|
54
54
|
from QVideo.lib import QVideoScreen
|
|
55
55
|
|
|
56
|
-
|
|
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
|
-
|
|
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
|
|
|
@@ -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
|
|
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.
|
|
225
|
+
screen.removeOverlay(self._overlay)
|
|
209
226
|
|
|
210
227
|
@QtCore.pyqtSlot(np.ndarray)
|
|
211
228
|
def _onNewFrame(self, image: Image) -> None:
|