QVideo 3.0.0__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 (114) hide show
  1. qvideo-3.0.0/LICENSE.md +17 -0
  2. qvideo-3.0.0/PKG-INFO +161 -0
  3. qvideo-3.0.0/QCamcorder.py +125 -0
  4. qvideo-3.0.0/QVideo.egg-info/PKG-INFO +161 -0
  5. qvideo-3.0.0/QVideo.egg-info/SOURCES.txt +115 -0
  6. qvideo-3.0.0/QVideo.egg-info/dependency_links.txt +1 -0
  7. qvideo-3.0.0/QVideo.egg-info/requires.txt +23 -0
  8. qvideo-3.0.0/QVideo.egg-info/top_level.txt +1 -0
  9. qvideo-3.0.0/README.md +117 -0
  10. qvideo-3.0.0/__init__.py +5 -0
  11. qvideo-3.0.0/cameras/Basler/QBaslerCamera.py +50 -0
  12. qvideo-3.0.0/cameras/Basler/QBaslerTree.py +67 -0
  13. qvideo-3.0.0/cameras/Basler/__init__.py +5 -0
  14. qvideo-3.0.0/cameras/Flir/QFlirCamera.py +48 -0
  15. qvideo-3.0.0/cameras/Flir/QFlirTree.py +70 -0
  16. qvideo-3.0.0/cameras/Flir/QListFlirCameras.py +31 -0
  17. qvideo-3.0.0/cameras/Flir/__init__.py +5 -0
  18. qvideo-3.0.0/cameras/Genicam/QGenicamCamera.py +382 -0
  19. qvideo-3.0.0/cameras/Genicam/QGenicamTree.py +224 -0
  20. qvideo-3.0.0/cameras/Genicam/__init__.py +5 -0
  21. qvideo-3.0.0/cameras/IDS/QIDSCamera.py +49 -0
  22. qvideo-3.0.0/cameras/IDS/QIDSTree.py +65 -0
  23. qvideo-3.0.0/cameras/IDS/__init__.py +5 -0
  24. qvideo-3.0.0/cameras/MV/QMVCamera.py +55 -0
  25. qvideo-3.0.0/cameras/MV/QMVTree.py +65 -0
  26. qvideo-3.0.0/cameras/MV/__init__.py +5 -0
  27. qvideo-3.0.0/cameras/Noise/QNoiseCamera.py +144 -0
  28. qvideo-3.0.0/cameras/Noise/QNoiseTree.py +35 -0
  29. qvideo-3.0.0/cameras/Noise/__init__.py +5 -0
  30. qvideo-3.0.0/cameras/OpenCV/QListCVCameras.py +73 -0
  31. qvideo-3.0.0/cameras/OpenCV/QOpenCVCamera.py +224 -0
  32. qvideo-3.0.0/cameras/OpenCV/QOpenCVTree.py +59 -0
  33. qvideo-3.0.0/cameras/OpenCV/__init__.py +5 -0
  34. qvideo-3.0.0/cameras/Picamera/QPicamera.py +229 -0
  35. qvideo-3.0.0/cameras/Picamera/QPicameraTree.py +47 -0
  36. qvideo-3.0.0/cameras/Picamera/__init__.py +5 -0
  37. qvideo-3.0.0/cameras/Vimbax/QVimbaXCamera.py +51 -0
  38. qvideo-3.0.0/cameras/Vimbax/QVimbaXTree.py +37 -0
  39. qvideo-3.0.0/cameras/Vimbax/__init__.py +5 -0
  40. qvideo-3.0.0/cameras/__init__.py +0 -0
  41. qvideo-3.0.0/dvr/QDVRWidget.py +354 -0
  42. qvideo-3.0.0/dvr/QHDF5Reader.py +93 -0
  43. qvideo-3.0.0/dvr/QHDF5Writer.py +89 -0
  44. qvideo-3.0.0/dvr/QOpenCVReader.py +98 -0
  45. qvideo-3.0.0/dvr/QOpenCVWriter.py +144 -0
  46. qvideo-3.0.0/dvr/__init__.py +14 -0
  47. qvideo-3.0.0/dvr/icons_rc.py +1082 -0
  48. qvideo-3.0.0/dvr/icons_rc_qt6.py +1106 -0
  49. qvideo-3.0.0/filters/Median.py +89 -0
  50. qvideo-3.0.0/filters/MoMedian.py +63 -0
  51. qvideo-3.0.0/filters/Normalize.py +142 -0
  52. qvideo-3.0.0/filters/QBlurFilter.py +101 -0
  53. qvideo-3.0.0/filters/QEdgeFilter.py +162 -0
  54. qvideo-3.0.0/filters/QRGBFilter.py +97 -0
  55. qvideo-3.0.0/filters/QSampleHold.py +141 -0
  56. qvideo-3.0.0/filters/_MedianBase.py +104 -0
  57. qvideo-3.0.0/filters/__init__.py +17 -0
  58. qvideo-3.0.0/lib/QCamera.py +387 -0
  59. qvideo-3.0.0/lib/QCameraTree.py +212 -0
  60. qvideo-3.0.0/lib/QFPSMeter.py +90 -0
  61. qvideo-3.0.0/lib/QFilterBank.py +118 -0
  62. qvideo-3.0.0/lib/QListCameras.py +87 -0
  63. qvideo-3.0.0/lib/QVideoReader.py +227 -0
  64. qvideo-3.0.0/lib/QVideoScreen.py +173 -0
  65. qvideo-3.0.0/lib/QVideoSource.py +196 -0
  66. qvideo-3.0.0/lib/QVideoWriter.py +123 -0
  67. qvideo-3.0.0/lib/VideoFilter.py +149 -0
  68. qvideo-3.0.0/lib/__init__.py +17 -0
  69. qvideo-3.0.0/lib/chooser.py +118 -0
  70. qvideo-3.0.0/lib/clickable.py +43 -0
  71. qvideo-3.0.0/lib/resolutions.py +46 -0
  72. qvideo-3.0.0/lib/types.py +6 -0
  73. qvideo-3.0.0/pyproject.toml +105 -0
  74. qvideo-3.0.0/setup.cfg +4 -0
  75. qvideo-3.0.0/tests/test_chooser.py +311 -0
  76. qvideo-3.0.0/tests/test_clickable.py +108 -0
  77. qvideo-3.0.0/tests/test_demo.py +46 -0
  78. qvideo-3.0.0/tests/test_filterdemo.py +60 -0
  79. qvideo-3.0.0/tests/test_icons_rc.py +24 -0
  80. qvideo-3.0.0/tests/test_median.py +205 -0
  81. qvideo-3.0.0/tests/test_momedian.py +142 -0
  82. qvideo-3.0.0/tests/test_normalize.py +134 -0
  83. qvideo-3.0.0/tests/test_qblurfilter.py +155 -0
  84. qvideo-3.0.0/tests/test_qcamcorder.py +104 -0
  85. qvideo-3.0.0/tests/test_qcamera.py +381 -0
  86. qvideo-3.0.0/tests/test_qcameratree.py +213 -0
  87. qvideo-3.0.0/tests/test_qdvrwidget.py +543 -0
  88. qvideo-3.0.0/tests/test_qedgefilter.py +192 -0
  89. qvideo-3.0.0/tests/test_qfilterbank.py +143 -0
  90. qvideo-3.0.0/tests/test_qfpsmeter.py +217 -0
  91. qvideo-3.0.0/tests/test_qgenicamcamera.py +816 -0
  92. qvideo-3.0.0/tests/test_qgenicamtree.py +637 -0
  93. qvideo-3.0.0/tests/test_qhdf5reader.py +224 -0
  94. qvideo-3.0.0/tests/test_qhdf5writer.py +165 -0
  95. qvideo-3.0.0/tests/test_qlistcameras.py +138 -0
  96. qvideo-3.0.0/tests/test_qlistcvcameras.py +253 -0
  97. qvideo-3.0.0/tests/test_qnoisecamera.py +266 -0
  98. qvideo-3.0.0/tests/test_qnoisetree.py +30 -0
  99. qvideo-3.0.0/tests/test_qopencvcamera.py +331 -0
  100. qvideo-3.0.0/tests/test_qopencvreader.py +192 -0
  101. qvideo-3.0.0/tests/test_qopencvtree.py +80 -0
  102. qvideo-3.0.0/tests/test_qopencvwriter.py +269 -0
  103. qvideo-3.0.0/tests/test_qpicamera.py +379 -0
  104. qvideo-3.0.0/tests/test_qrgbfilter.py +145 -0
  105. qvideo-3.0.0/tests/test_qsamplehold.py +168 -0
  106. qvideo-3.0.0/tests/test_qvideoreader.py +267 -0
  107. qvideo-3.0.0/tests/test_qvideoscreen.py +301 -0
  108. qvideo-3.0.0/tests/test_qvideosource.py +229 -0
  109. qvideo-3.0.0/tests/test_qvideowriter.py +223 -0
  110. qvideo-3.0.0/tests/test_qvimbaxcamera.py +259 -0
  111. qvideo-3.0.0/tests/test_resolutions.py +102 -0
  112. qvideo-3.0.0/tests/test_roidemo.py +97 -0
  113. qvideo-3.0.0/tests/test_videofilter.py +167 -0
  114. qvideo-3.0.0/version.py +4 -0
@@ -0,0 +1,17 @@
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 3, 29 June 2007
3
+
4
+ Copyright (c) 2022 David G. Grier
5
+
6
+ This program is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
qvideo-3.0.0/PKG-INFO ADDED
@@ -0,0 +1,161 @@
1
+ Metadata-Version: 2.4
2
+ Name: QVideo
3
+ Version: 3.0.0
4
+ Summary: PyQt-based framework for integrating video cameras into research applications
5
+ Author-email: "David G. Grier" <david.grier@nyu.edu>
6
+ License: GPL-3.0-or-later
7
+ Project-URL: Homepage, https://github.com/davidgrier/QVideo
8
+ Project-URL: Repository, https://github.com/davidgrier/QVideo
9
+ Project-URL: Bug Tracker, https://github.com/davidgrier/QVideo/issues
10
+ Keywords: camera,video,imaging,PyQt5,scientific,GenICam,GigE Vision,raspberry pi
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Scientific/Engineering
19
+ Classifier: Topic :: Multimedia :: Video :: Capture
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE.md
24
+ Requires-Dist: h5py
25
+ Requires-Dist: numba
26
+ Requires-Dist: numpy
27
+ Requires-Dist: opencv-python
28
+ Requires-Dist: PyQt5
29
+ Requires-Dist: PyQt5-sip
30
+ Requires-Dist: pyqtgraph
31
+ Provides-Extra: genicam
32
+ Requires-Dist: harvesters; extra == "genicam"
33
+ Requires-Dist: genicam; extra == "genicam"
34
+ Provides-Extra: picamera
35
+ Requires-Dist: picamera2; extra == "picamera"
36
+ Provides-Extra: dev
37
+ Requires-Dist: pytest; extra == "dev"
38
+ Requires-Dist: pytest-cov; extra == "dev"
39
+ Provides-Extra: docs
40
+ Requires-Dist: furo; extra == "docs"
41
+ Requires-Dist: sphinx; extra == "docs"
42
+ Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
43
+ Dynamic: license-file
44
+
45
+ # QVideo: PyQt support for video cameras
46
+
47
+ [![PyPI version](https://img.shields.io/pypi/v/QVideo)](https://pypi.org/project/QVideo/)
48
+ [![Python](https://img.shields.io/pypi/pyversions/QVideo)](https://pypi.org/project/QVideo/)
49
+ [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](LICENSE.md)
50
+ [![Tests](https://github.com/davidgrier/QVideo/actions/workflows/test.yml/badge.svg)](https://github.com/davidgrier/QVideo/actions/workflows/test.yml)
51
+
52
+ **QVideo** is a framework for integrating video cameras into PyQt5 projects
53
+ for scientific research. It provides a unified, registration-based property
54
+ system so that every camera backend — USB webcams, GenICam devices, FLIR
55
+ cameras, Raspberry Pi cameras — is controlled through the same API. Property
56
+ trees, display widgets, and a digital video recorder are built on top of that
57
+ abstraction and require no camera-specific code.
58
+
59
+ <img src="docs/dvrdemo.png" width="75%" alt="QVideo interface demo">
60
+
61
+ ## Features
62
+
63
+ - **Unified camera API** — `QCamera` subclasses expose adjustable parameters
64
+ via `registerProperty` / `registerMethod`; UI and recording layers consume
65
+ them without knowing the underlying hardware.
66
+ - **Auto-built property trees** — `QCameraTree` reads the registered property
67
+ map and builds a `pyqtgraph` parameter tree widget automatically.
68
+ - **Threaded video source** — `QVideoSource` wraps any camera in a `QThread`
69
+ and emits `newFrame(ndarray)` at acquisition rate.
70
+ - **Composable filter pipeline** — `VideoFilter` / `QFilterBank` sit between
71
+ source and display; filters include blur, edge detection, RGB channel
72
+ selection, sample-and-hold, and statistical median variants.
73
+ - **Digital video recorder** — lossless HDF5 (with timestamps) and OpenCV
74
+ video formats; `QDVRWidget` is the composite UI widget.
75
+ - **Live display** — `QVideoScreen` supports mouse-aware graphical overlays
76
+ for annotations, regions of interest, and user interaction.
77
+
78
+ ## Installation
79
+
80
+ ```bash
81
+ pip install QVideo
82
+ ```
83
+
84
+ ### Optional hardware backends
85
+
86
+ | Backend | Extra | Notes |
87
+ |---------|-------|-------|
88
+ | GenICam cameras (Vimba, etc.) | `pip install QVideo[genicam]` | Requires a vendor-supplied `.cti` producer file |
89
+ | Raspberry Pi camera | `pip install QVideo[picamera]` | Requires `picamera2` |
90
+ | FLIR / Spinnaker cameras | — | Requires the proprietary PySpin SDK; install that separately |
91
+
92
+ ## Quick start
93
+
94
+ ```python
95
+ from pyqtgraph.Qt import QtWidgets
96
+ from QVideo.cameras.Noise import QNoiseSource
97
+ from QVideo.lib import QVideoScreen
98
+
99
+ app = QtWidgets.QApplication([])
100
+
101
+ source = QNoiseSource() # synthetic noise — no hardware needed
102
+ screen = QVideoScreen()
103
+ source.newFrame.connect(screen.setImage)
104
+
105
+ screen.show()
106
+ source.start()
107
+ app.exec()
108
+ ```
109
+
110
+ Replace `QNoiseSource` with `QOpenCVSource`, `QGenicamSource`, etc. to switch
111
+ hardware — the rest of the code is identical.
112
+
113
+ ## Camera backends
114
+
115
+ | Backend | Class | Hardware |
116
+ |---------|-------|----------|
117
+ | `cameras/Noise` | `QNoiseCamera` | Synthetic — no hardware required |
118
+ | `cameras/OpenCV` | `QOpenCVCamera` | USB webcams via OpenCV |
119
+ | `cameras/Genicam` | `QGenicamCamera` | Abstract base for all GenICam/GigE Vision cameras |
120
+ | `cameras/Flir` | `QFlirCamera` | FLIR cameras via GenICam (Spinnaker GenTL producer) |
121
+ | `cameras/Basler` | `QBaslerCamera` | Basler cameras via GenICam (pylon GenTL producer) |
122
+ | `cameras/IDS` | `QIDSCamera` | IDS Imaging cameras via GenICam |
123
+ | `cameras/MV` | `QMVCamera` | Any GenICam camera via MATRIX VISION mvGenTLProducer |
124
+ | `cameras/Vimbax` | `QVimbaXCamera` | Allied Vision cameras via VimbaX GenTL producer |
125
+ | `cameras/Picamera` | `QPicamera` | Raspberry Pi camera module |
126
+
127
+ ## Writing a new camera backend
128
+
129
+ Subclass `QCamera` and implement three methods:
130
+
131
+ ```python
132
+ from QVideo.lib import QCamera
133
+
134
+ class MyCamera(QCamera):
135
+
136
+ def _initialize(self) -> bool:
137
+ self.device = open_my_hardware()
138
+ if not self.device:
139
+ return False
140
+ self.registerProperty('exposure',
141
+ getter=lambda: self.device.get_exposure(),
142
+ setter=lambda v: self.device.set_exposure(v),
143
+ ptype=float)
144
+ return True
145
+
146
+ def _deinitialize(self) -> None:
147
+ self.device.close()
148
+
149
+ def read(self):
150
+ ok, frame = self.device.read_frame()
151
+ return ok, frame
152
+ ```
153
+
154
+ `QCameraTree` and `QVideoSource` work with `MyCamera` immediately — no
155
+ additional code needed.
156
+
157
+ ## Acknowledgements
158
+
159
+ Work on this project at New York University is supported by the National
160
+ Science Foundation of the United States under award number DMR-2104837 and
161
+ by an award from the TAC Program of New York University.
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env python3
2
+ '''Composite camcorder widget combining a video screen, camera controls, and DVR.
3
+
4
+ Run directly to launch a full camcorder application with camera selection::
5
+
6
+ python -m QVideo.QCamcorder [-c|-f|-s|-v] [cameraID]
7
+
8
+ Camera flags (mutually exclusive):
9
+
10
+ .. code-block:: text
11
+
12
+ -b [cameraID] Basler camera (requires pylon SDK)
13
+ -c [cameraID] OpenCV camera
14
+ -f [cameraID] FLIR camera (requires Spinnaker SDK)
15
+ -i [cameraID] IDS Imaging camera (requires IDS peak SDK)
16
+ -m [cameraID] MATRIX VISION mvGenTLProducer (universal GenICam, not FLIR)
17
+ -p [cameraID] Raspberry Pi camera module (requires picamera2)
18
+ -v [cameraID] Allied Vision VimbaX camera
19
+
20
+ If no flag is given, a noise camera is used as a fallback.
21
+ '''
22
+
23
+ from pyqtgraph.Qt.QtWidgets import QWidget
24
+ from pyqtgraph.Qt.QtCore import pyqtSlot
25
+ from pyqtgraph.Qt import QtGui, uic
26
+ from QVideo.lib import QCameraTree, QVideoSource
27
+ from pathlib import Path
28
+
29
+
30
+ __all__ = ['QCamcorder']
31
+
32
+
33
+ class QCamcorder(QWidget):
34
+ '''A widget combining a video screen, camera controls, and DVR.
35
+
36
+ Lays out a :class:`~QVideo.lib.QVideoScreen.QVideoScreen` alongside
37
+ a :class:`~QVideo.dvr.QDVRWidget.QDVRWidget` and an arbitrary
38
+ :class:`~QVideo.lib.QCameraTree.QCameraTree` control panel. Live
39
+ frames from the camera source are routed to the screen; when the DVR
40
+ starts playback the screen is switched to the playback stream and the
41
+ camera controls are disabled until playback ends.
42
+
43
+ Parameters
44
+ ----------
45
+ cameraWidget : QCameraTree
46
+ Camera control tree to embed in the controls panel.
47
+ *args :
48
+ Additional positional arguments forwarded to
49
+ :class:`~pyqtgraph.Qt.QtWidgets.QWidget`.
50
+ **kwargs :
51
+ Additional keyword arguments forwarded to
52
+ :class:`~pyqtgraph.Qt.QtWidgets.QWidget`.
53
+ '''
54
+
55
+ UIFILE = Path(__file__).parent / 'QCamcorder.ui'
56
+
57
+ def __init__(self,
58
+ cameraWidget: QCameraTree,
59
+ *args, **kwargs) -> None:
60
+ super().__init__(*args, **kwargs)
61
+ self.cameraWidget = cameraWidget
62
+ self._setupUi()
63
+ self._connectSignals()
64
+ self.screen.source = self.source
65
+ self.dvr.source = self.source
66
+
67
+ def _setupUi(self) -> None:
68
+ uic.loadUi(str(self.UIFILE), self)
69
+ self.controls.layout().addWidget(self.cameraWidget)
70
+
71
+ def _connectSignals(self) -> None:
72
+ self.dvr.playing.connect(self.dvrPlayback)
73
+
74
+ def closeEvent(self, event: QtGui.QCloseEvent) -> None:
75
+ '''Stop the camera source when the widget is closed.'''
76
+ self.cameraWidget.stop()
77
+ super().closeEvent(event)
78
+
79
+ @pyqtSlot(bool)
80
+ def dvrPlayback(self, playback: bool) -> None:
81
+ '''Switch the screen source between live camera and DVR playback.
82
+
83
+ Connected to :attr:`~QVideo.dvr.QDVRWidget.QDVRWidget.playing`.
84
+ When playback starts the camera source is disconnected from the
85
+ screen and the DVR's :attr:`~QVideo.dvr.QDVRWidget.QDVRWidget.newFrame`
86
+ signal is connected instead; the camera controls are disabled.
87
+ When playback ends the connections are reversed and the controls
88
+ are re-enabled.
89
+
90
+ Parameters
91
+ ----------
92
+ playback : bool
93
+ ``True`` when DVR playback begins, ``False`` when it ends.
94
+ '''
95
+ try:
96
+ if playback:
97
+ self.source.newFrame.disconnect(self.screen.setImage)
98
+ self.dvr.newFrame.connect(self.screen.setImage)
99
+ else:
100
+ self.dvr.newFrame.disconnect(self.screen.setImage)
101
+ self.source.newFrame.connect(self.screen.setImage)
102
+ except (RuntimeError, TypeError):
103
+ pass
104
+ self.cameraWidget.setDisabled(playback)
105
+
106
+ @property
107
+ def source(self) -> QVideoSource:
108
+ '''The :class:`~QVideo.lib.QVideoSource.QVideoSource` from the camera widget.'''
109
+ return self.cameraWidget.source
110
+
111
+
112
+ def main() -> None: # pragma: no cover
113
+ '''Launch the camcorder with an interactively chosen camera.'''
114
+ import pyqtgraph as pg
115
+ from QVideo.lib import choose_camera
116
+
117
+ pg.mkQApp()
118
+ camera = choose_camera()
119
+ widget = QCamcorder(camera.start())
120
+ widget.show()
121
+ pg.exec()
122
+
123
+
124
+ if __name__ == '__main__':
125
+ main()
@@ -0,0 +1,161 @@
1
+ Metadata-Version: 2.4
2
+ Name: QVideo
3
+ Version: 3.0.0
4
+ Summary: PyQt-based framework for integrating video cameras into research applications
5
+ Author-email: "David G. Grier" <david.grier@nyu.edu>
6
+ License: GPL-3.0-or-later
7
+ Project-URL: Homepage, https://github.com/davidgrier/QVideo
8
+ Project-URL: Repository, https://github.com/davidgrier/QVideo
9
+ Project-URL: Bug Tracker, https://github.com/davidgrier/QVideo/issues
10
+ Keywords: camera,video,imaging,PyQt5,scientific,GenICam,GigE Vision,raspberry pi
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Scientific/Engineering
19
+ Classifier: Topic :: Multimedia :: Video :: Capture
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE.md
24
+ Requires-Dist: h5py
25
+ Requires-Dist: numba
26
+ Requires-Dist: numpy
27
+ Requires-Dist: opencv-python
28
+ Requires-Dist: PyQt5
29
+ Requires-Dist: PyQt5-sip
30
+ Requires-Dist: pyqtgraph
31
+ Provides-Extra: genicam
32
+ Requires-Dist: harvesters; extra == "genicam"
33
+ Requires-Dist: genicam; extra == "genicam"
34
+ Provides-Extra: picamera
35
+ Requires-Dist: picamera2; extra == "picamera"
36
+ Provides-Extra: dev
37
+ Requires-Dist: pytest; extra == "dev"
38
+ Requires-Dist: pytest-cov; extra == "dev"
39
+ Provides-Extra: docs
40
+ Requires-Dist: furo; extra == "docs"
41
+ Requires-Dist: sphinx; extra == "docs"
42
+ Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
43
+ Dynamic: license-file
44
+
45
+ # QVideo: PyQt support for video cameras
46
+
47
+ [![PyPI version](https://img.shields.io/pypi/v/QVideo)](https://pypi.org/project/QVideo/)
48
+ [![Python](https://img.shields.io/pypi/pyversions/QVideo)](https://pypi.org/project/QVideo/)
49
+ [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](LICENSE.md)
50
+ [![Tests](https://github.com/davidgrier/QVideo/actions/workflows/test.yml/badge.svg)](https://github.com/davidgrier/QVideo/actions/workflows/test.yml)
51
+
52
+ **QVideo** is a framework for integrating video cameras into PyQt5 projects
53
+ for scientific research. It provides a unified, registration-based property
54
+ system so that every camera backend — USB webcams, GenICam devices, FLIR
55
+ cameras, Raspberry Pi cameras — is controlled through the same API. Property
56
+ trees, display widgets, and a digital video recorder are built on top of that
57
+ abstraction and require no camera-specific code.
58
+
59
+ <img src="docs/dvrdemo.png" width="75%" alt="QVideo interface demo">
60
+
61
+ ## Features
62
+
63
+ - **Unified camera API** — `QCamera` subclasses expose adjustable parameters
64
+ via `registerProperty` / `registerMethod`; UI and recording layers consume
65
+ them without knowing the underlying hardware.
66
+ - **Auto-built property trees** — `QCameraTree` reads the registered property
67
+ map and builds a `pyqtgraph` parameter tree widget automatically.
68
+ - **Threaded video source** — `QVideoSource` wraps any camera in a `QThread`
69
+ and emits `newFrame(ndarray)` at acquisition rate.
70
+ - **Composable filter pipeline** — `VideoFilter` / `QFilterBank` sit between
71
+ source and display; filters include blur, edge detection, RGB channel
72
+ selection, sample-and-hold, and statistical median variants.
73
+ - **Digital video recorder** — lossless HDF5 (with timestamps) and OpenCV
74
+ video formats; `QDVRWidget` is the composite UI widget.
75
+ - **Live display** — `QVideoScreen` supports mouse-aware graphical overlays
76
+ for annotations, regions of interest, and user interaction.
77
+
78
+ ## Installation
79
+
80
+ ```bash
81
+ pip install QVideo
82
+ ```
83
+
84
+ ### Optional hardware backends
85
+
86
+ | Backend | Extra | Notes |
87
+ |---------|-------|-------|
88
+ | GenICam cameras (Vimba, etc.) | `pip install QVideo[genicam]` | Requires a vendor-supplied `.cti` producer file |
89
+ | Raspberry Pi camera | `pip install QVideo[picamera]` | Requires `picamera2` |
90
+ | FLIR / Spinnaker cameras | — | Requires the proprietary PySpin SDK; install that separately |
91
+
92
+ ## Quick start
93
+
94
+ ```python
95
+ from pyqtgraph.Qt import QtWidgets
96
+ from QVideo.cameras.Noise import QNoiseSource
97
+ from QVideo.lib import QVideoScreen
98
+
99
+ app = QtWidgets.QApplication([])
100
+
101
+ source = QNoiseSource() # synthetic noise — no hardware needed
102
+ screen = QVideoScreen()
103
+ source.newFrame.connect(screen.setImage)
104
+
105
+ screen.show()
106
+ source.start()
107
+ app.exec()
108
+ ```
109
+
110
+ Replace `QNoiseSource` with `QOpenCVSource`, `QGenicamSource`, etc. to switch
111
+ hardware — the rest of the code is identical.
112
+
113
+ ## Camera backends
114
+
115
+ | Backend | Class | Hardware |
116
+ |---------|-------|----------|
117
+ | `cameras/Noise` | `QNoiseCamera` | Synthetic — no hardware required |
118
+ | `cameras/OpenCV` | `QOpenCVCamera` | USB webcams via OpenCV |
119
+ | `cameras/Genicam` | `QGenicamCamera` | Abstract base for all GenICam/GigE Vision cameras |
120
+ | `cameras/Flir` | `QFlirCamera` | FLIR cameras via GenICam (Spinnaker GenTL producer) |
121
+ | `cameras/Basler` | `QBaslerCamera` | Basler cameras via GenICam (pylon GenTL producer) |
122
+ | `cameras/IDS` | `QIDSCamera` | IDS Imaging cameras via GenICam |
123
+ | `cameras/MV` | `QMVCamera` | Any GenICam camera via MATRIX VISION mvGenTLProducer |
124
+ | `cameras/Vimbax` | `QVimbaXCamera` | Allied Vision cameras via VimbaX GenTL producer |
125
+ | `cameras/Picamera` | `QPicamera` | Raspberry Pi camera module |
126
+
127
+ ## Writing a new camera backend
128
+
129
+ Subclass `QCamera` and implement three methods:
130
+
131
+ ```python
132
+ from QVideo.lib import QCamera
133
+
134
+ class MyCamera(QCamera):
135
+
136
+ def _initialize(self) -> bool:
137
+ self.device = open_my_hardware()
138
+ if not self.device:
139
+ return False
140
+ self.registerProperty('exposure',
141
+ getter=lambda: self.device.get_exposure(),
142
+ setter=lambda v: self.device.set_exposure(v),
143
+ ptype=float)
144
+ return True
145
+
146
+ def _deinitialize(self) -> None:
147
+ self.device.close()
148
+
149
+ def read(self):
150
+ ok, frame = self.device.read_frame()
151
+ return ok, frame
152
+ ```
153
+
154
+ `QCameraTree` and `QVideoSource` work with `MyCamera` immediately — no
155
+ additional code needed.
156
+
157
+ ## Acknowledgements
158
+
159
+ Work on this project at New York University is supported by the National
160
+ Science Foundation of the United States under award number DMR-2104837 and
161
+ by an award from the TAC Program of New York University.
@@ -0,0 +1,115 @@
1
+ LICENSE.md
2
+ QCamcorder.py
3
+ README.md
4
+ __init__.py
5
+ pyproject.toml
6
+ version.py
7
+ ./QCamcorder.py
8
+ ./__init__.py
9
+ ./version.py
10
+ QVideo.egg-info/PKG-INFO
11
+ QVideo.egg-info/SOURCES.txt
12
+ QVideo.egg-info/dependency_links.txt
13
+ QVideo.egg-info/requires.txt
14
+ QVideo.egg-info/top_level.txt
15
+ cameras/__init__.py
16
+ cameras/Basler/QBaslerCamera.py
17
+ cameras/Basler/QBaslerTree.py
18
+ cameras/Basler/__init__.py
19
+ cameras/Flir/QFlirCamera.py
20
+ cameras/Flir/QFlirTree.py
21
+ cameras/Flir/QListFlirCameras.py
22
+ cameras/Flir/__init__.py
23
+ cameras/Genicam/QGenicamCamera.py
24
+ cameras/Genicam/QGenicamTree.py
25
+ cameras/Genicam/__init__.py
26
+ cameras/IDS/QIDSCamera.py
27
+ cameras/IDS/QIDSTree.py
28
+ cameras/IDS/__init__.py
29
+ cameras/MV/QMVCamera.py
30
+ cameras/MV/QMVTree.py
31
+ cameras/MV/__init__.py
32
+ cameras/Noise/QNoiseCamera.py
33
+ cameras/Noise/QNoiseTree.py
34
+ cameras/Noise/__init__.py
35
+ cameras/OpenCV/QListCVCameras.py
36
+ cameras/OpenCV/QOpenCVCamera.py
37
+ cameras/OpenCV/QOpenCVTree.py
38
+ cameras/OpenCV/__init__.py
39
+ cameras/Picamera/QPicamera.py
40
+ cameras/Picamera/QPicameraTree.py
41
+ cameras/Picamera/__init__.py
42
+ cameras/Vimbax/QVimbaXCamera.py
43
+ cameras/Vimbax/QVimbaXTree.py
44
+ cameras/Vimbax/__init__.py
45
+ dvr/QDVRWidget.py
46
+ dvr/QHDF5Reader.py
47
+ dvr/QHDF5Writer.py
48
+ dvr/QOpenCVReader.py
49
+ dvr/QOpenCVWriter.py
50
+ dvr/__init__.py
51
+ dvr/icons_rc.py
52
+ dvr/icons_rc_qt6.py
53
+ filters/Median.py
54
+ filters/MoMedian.py
55
+ filters/Normalize.py
56
+ filters/QBlurFilter.py
57
+ filters/QEdgeFilter.py
58
+ filters/QRGBFilter.py
59
+ filters/QSampleHold.py
60
+ filters/_MedianBase.py
61
+ filters/__init__.py
62
+ lib/QCamera.py
63
+ lib/QCameraTree.py
64
+ lib/QFPSMeter.py
65
+ lib/QFilterBank.py
66
+ lib/QListCameras.py
67
+ lib/QVideoReader.py
68
+ lib/QVideoScreen.py
69
+ lib/QVideoSource.py
70
+ lib/QVideoWriter.py
71
+ lib/VideoFilter.py
72
+ lib/__init__.py
73
+ lib/chooser.py
74
+ lib/clickable.py
75
+ lib/resolutions.py
76
+ lib/types.py
77
+ tests/test_chooser.py
78
+ tests/test_clickable.py
79
+ tests/test_demo.py
80
+ tests/test_filterdemo.py
81
+ tests/test_icons_rc.py
82
+ tests/test_median.py
83
+ tests/test_momedian.py
84
+ tests/test_normalize.py
85
+ tests/test_qblurfilter.py
86
+ tests/test_qcamcorder.py
87
+ tests/test_qcamera.py
88
+ tests/test_qcameratree.py
89
+ tests/test_qdvrwidget.py
90
+ tests/test_qedgefilter.py
91
+ tests/test_qfilterbank.py
92
+ tests/test_qfpsmeter.py
93
+ tests/test_qgenicamcamera.py
94
+ tests/test_qgenicamtree.py
95
+ tests/test_qhdf5reader.py
96
+ tests/test_qhdf5writer.py
97
+ tests/test_qlistcameras.py
98
+ tests/test_qlistcvcameras.py
99
+ tests/test_qnoisecamera.py
100
+ tests/test_qnoisetree.py
101
+ tests/test_qopencvcamera.py
102
+ tests/test_qopencvreader.py
103
+ tests/test_qopencvtree.py
104
+ tests/test_qopencvwriter.py
105
+ tests/test_qpicamera.py
106
+ tests/test_qrgbfilter.py
107
+ tests/test_qsamplehold.py
108
+ tests/test_qvideoreader.py
109
+ tests/test_qvideoscreen.py
110
+ tests/test_qvideosource.py
111
+ tests/test_qvideowriter.py
112
+ tests/test_qvimbaxcamera.py
113
+ tests/test_resolutions.py
114
+ tests/test_roidemo.py
115
+ tests/test_videofilter.py
@@ -0,0 +1,23 @@
1
+ h5py
2
+ numba
3
+ numpy
4
+ opencv-python
5
+ PyQt5
6
+ PyQt5-sip
7
+ pyqtgraph
8
+
9
+ [dev]
10
+ pytest
11
+ pytest-cov
12
+
13
+ [docs]
14
+ furo
15
+ sphinx
16
+ sphinx-autodoc-typehints
17
+
18
+ [genicam]
19
+ harvesters
20
+ genicam
21
+
22
+ [picamera]
23
+ picamera2
@@ -0,0 +1 @@
1
+ QVideo