QVideo 3.2.2__tar.gz → 3.4.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.
- {qvideo-3.2.2 → qvideo-3.4.0}/PKG-INFO +4 -3
- {qvideo-3.2.2 → qvideo-3.4.0}/QCamcorder.py +5 -1
- {qvideo-3.2.2 → qvideo-3.4.0}/QVideo.egg-info/PKG-INFO +4 -3
- {qvideo-3.2.2 → qvideo-3.4.0}/QVideo.egg-info/SOURCES.txt +11 -1
- {qvideo-3.2.2 → qvideo-3.4.0}/QVideo.egg-info/requires.txt +1 -1
- {qvideo-3.2.2 → qvideo-3.4.0}/README.md +2 -1
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/Basler/_tree.py +1 -1
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/Flir/_camera.py +8 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/Flir/_tree.py +3 -2
- qvideo-3.4.0/cameras/Genicam/__init__.py +11 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/Genicam/_camera.py +42 -5
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/Genicam/_tree.py +68 -1
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/IDS/_tree.py +1 -1
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/MV/_tree.py +1 -1
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/OpenCV/_resolution_tree.py +4 -0
- qvideo-3.4.0/demos/ROIdemo.py +146 -0
- qvideo-3.4.0/demos/__init__.py +69 -0
- qvideo-3.4.0/demos/demo.py +63 -0
- qvideo-3.4.0/demos/filterdemo.py +68 -0
- qvideo-3.4.0/demos/trackpydemo.py +53 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/dvr/QDVRWidget.py +6 -2
- {qvideo-3.2.2 → qvideo-3.4.0}/filters/Median.py +4 -4
- {qvideo-3.2.2 → qvideo-3.4.0}/filters/MoMedian.py +10 -8
- {qvideo-3.2.2 → qvideo-3.4.0}/filters/QBlurFilter.py +2 -2
- {qvideo-3.2.2 → qvideo-3.4.0}/filters/QEdgeFilter.py +6 -6
- {qvideo-3.2.2 → qvideo-3.4.0}/filters/QRGBFilter.py +2 -2
- {qvideo-3.2.2 → qvideo-3.4.0}/filters/QSampleHold.py +7 -5
- qvideo-3.4.0/filters/QYOLOFilter.py +89 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/filters/_MedianBase.py +1 -1
- {qvideo-3.2.2 → qvideo-3.4.0}/filters/__init__.py +2 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/lib/QCamera.py +2 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/lib/QCameraTree.py +6 -6
- {qvideo-3.2.2 → qvideo-3.4.0}/lib/QFilterBank.py +10 -3
- {qvideo-3.2.2 → qvideo-3.4.0}/lib/QListCameras.py +1 -0
- qvideo-3.2.2/lib/VideoFilter.py → qvideo-3.4.0/lib/QVideoFilter.py +14 -14
- {qvideo-3.2.2 → qvideo-3.4.0}/lib/QVideoReader.py +1 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/lib/QVideoScreen.py +34 -4
- {qvideo-3.2.2 → qvideo-3.4.0}/lib/QVideoSource.py +1 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/lib/__init__.py +3 -3
- {qvideo-3.2.2 → qvideo-3.4.0}/lib/chooser.py +3 -1
- {qvideo-3.2.2 → qvideo-3.4.0}/lib/clickable.py +18 -12
- {qvideo-3.2.2 → qvideo-3.4.0}/lib/resolutions.py +3 -1
- qvideo-3.4.0/overlays/__init__.py +5 -0
- qvideo-3.4.0/overlays/trackpy.py +244 -0
- qvideo-3.4.0/overlays/yolo.py +21 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/pyproject.toml +6 -2
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_demo.py +8 -3
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_filterdemo.py +10 -5
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qblurfilter.py +1 -1
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qdvrwidget.py +2 -3
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qedgefilter.py +1 -1
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qfilterbank.py +3 -3
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qgenicamcamera.py +3 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qgenicamtree.py +8 -1
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qopencvresolutiontree.py +15 -1
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qrgbfilter.py +1 -1
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qsamplehold.py +1 -1
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_resolutions.py +20 -4
- qvideo-3.4.0/tests/test_trackpy_overlay.py +346 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_videofilter.py +6 -6
- qvideo-3.2.2/cameras/Genicam/__init__.py +0 -5
- {qvideo-3.2.2 → qvideo-3.4.0}/LICENSE.md +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/QVideo.egg-info/dependency_links.txt +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/QVideo.egg-info/top_level.txt +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/__init__.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/Basler/__init__.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/Basler/_camera.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/Flir/QListFlirCameras.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/Flir/__init__.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/IDS/__init__.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/IDS/_camera.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/MV/__init__.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/MV/_camera.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/Noise/__init__.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/Noise/_camera.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/Noise/_tree.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/OpenCV/QListCVCameras.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/OpenCV/__init__.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/OpenCV/_camera.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/OpenCV/_tree.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/Picamera/__init__.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/Picamera/_camera.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/Picamera/_tree.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/Vimbax/__init__.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/Vimbax/_camera.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/Vimbax/_tree.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/cameras/__init__.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/dvr/QHDF5Reader.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/dvr/QHDF5Writer.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/dvr/QOpenCVReader.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/dvr/QOpenCVWriter.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/dvr/__init__.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/dvr/icons_rc.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/dvr/icons_rc_qt6.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/filters/Normalize.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/lib/QFPSMeter.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/lib/QVideoWriter.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/lib/types.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/setup.cfg +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_chooser.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_clickable.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_icons_rc.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_median.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_momedian.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_normalize.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qbaslercamera.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qcamcorder.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qcamera.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qcameratree.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qflircamera.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qfpsmeter.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qhdf5reader.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qhdf5writer.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qidscamera.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qlistcameras.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qlistcvcameras.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qmvcamera.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qnoisecamera.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qnoisetree.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qopencvcamera.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qopencvreader.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qopencvtree.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qopencvwriter.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qpicamera.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qvideoreader.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qvideoscreen.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qvideosource.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qvideowriter.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_qvimbaxcamera.py +0 -0
- {qvideo-3.2.2 → qvideo-3.4.0}/tests/test_roidemo.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: QVideo
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.4.0
|
|
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
|
|
@@ -36,7 +36,7 @@ Provides-Extra: dev
|
|
|
36
36
|
Requires-Dist: pytest; extra == "dev"
|
|
37
37
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
38
38
|
Provides-Extra: docs
|
|
39
|
-
Requires-Dist:
|
|
39
|
+
Requires-Dist: pydata-sphinx-theme; extra == "docs"
|
|
40
40
|
Requires-Dist: sphinx; extra == "docs"
|
|
41
41
|
Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
|
|
42
42
|
Dynamic: license-file
|
|
@@ -47,6 +47,7 @@ Dynamic: license-file
|
|
|
47
47
|
[](https://pypi.org/project/QVideo/)
|
|
48
48
|
[](LICENSE.md)
|
|
49
49
|
[](https://github.com/davidgrier/QVideo/actions/workflows/test.yml)
|
|
50
|
+
[](https://qvideo.readthedocs.io/en/latest/)
|
|
50
51
|
|
|
51
52
|
**QVideo** is a framework for integrating video cameras into PyQt5 projects
|
|
52
53
|
for scientific research. It provides a unified, registration-based property
|
|
@@ -156,5 +157,5 @@ additional code needed.
|
|
|
156
157
|
## Acknowledgements
|
|
157
158
|
|
|
158
159
|
Work on this project at New York University is supported by the National
|
|
159
|
-
Science Foundation of the United States under award number DMR-
|
|
160
|
+
Science Foundation of the United States under award number DMR-2428983 and
|
|
160
161
|
by an award from the TAC Program of New York University.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
Run directly to launch a full camcorder application with camera selection::
|
|
5
5
|
|
|
6
|
-
python -m QVideo.QCamcorder [-c|-f|-
|
|
6
|
+
python -m QVideo.QCamcorder [-b|-c|-f|-i|-m|-p|-r|-v] [cameraID]
|
|
7
7
|
|
|
8
8
|
Camera flags (mutually exclusive):
|
|
9
9
|
|
|
@@ -15,7 +15,9 @@ Camera flags (mutually exclusive):
|
|
|
15
15
|
-i [cameraID] IDS Imaging camera (requires IDS peak SDK)
|
|
16
16
|
-m [cameraID] MATRIX VISION mvGenTLProducer (universal GenICam, not FLIR)
|
|
17
17
|
-p [cameraID] Raspberry Pi camera module (requires picamera2)
|
|
18
|
+
-r [cameraID] OpenCV camera with resolution drop-down selector
|
|
18
19
|
-v [cameraID] Allied Vision VimbaX camera
|
|
20
|
+
-h Show help and exit
|
|
19
21
|
|
|
20
22
|
If no flag is given, a noise camera is used as a fallback.
|
|
21
23
|
'''
|
|
@@ -67,6 +69,8 @@ class QCamcorder(QWidget):
|
|
|
67
69
|
def _setupUi(self) -> None:
|
|
68
70
|
uic.loadUi(str(self.UIFILE), self)
|
|
69
71
|
self.controls.layout().addWidget(self.cameraWidget)
|
|
72
|
+
self.layout().setStretch(0, 1) # screen takes all surplus horizontal space
|
|
73
|
+
self.layout().setStretch(1, 0) # controls stay at their natural width
|
|
70
74
|
|
|
71
75
|
def _connectSignals(self) -> None:
|
|
72
76
|
self.dvr.playing.connect(self.dvrPlayback)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: QVideo
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.4.0
|
|
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
|
|
@@ -36,7 +36,7 @@ Provides-Extra: dev
|
|
|
36
36
|
Requires-Dist: pytest; extra == "dev"
|
|
37
37
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
38
38
|
Provides-Extra: docs
|
|
39
|
-
Requires-Dist:
|
|
39
|
+
Requires-Dist: pydata-sphinx-theme; extra == "docs"
|
|
40
40
|
Requires-Dist: sphinx; extra == "docs"
|
|
41
41
|
Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
|
|
42
42
|
Dynamic: license-file
|
|
@@ -47,6 +47,7 @@ Dynamic: license-file
|
|
|
47
47
|
[](https://pypi.org/project/QVideo/)
|
|
48
48
|
[](LICENSE.md)
|
|
49
49
|
[](https://github.com/davidgrier/QVideo/actions/workflows/test.yml)
|
|
50
|
+
[](https://qvideo.readthedocs.io/en/latest/)
|
|
50
51
|
|
|
51
52
|
**QVideo** is a framework for integrating video cameras into PyQt5 projects
|
|
52
53
|
for scientific research. It provides a unified, registration-based property
|
|
@@ -156,5 +157,5 @@ additional code needed.
|
|
|
156
157
|
## Acknowledgements
|
|
157
158
|
|
|
158
159
|
Work on this project at New York University is supported by the National
|
|
159
|
-
Science Foundation of the United States under award number DMR-
|
|
160
|
+
Science Foundation of the United States under award number DMR-2428983 and
|
|
160
161
|
by an award from the TAC Program of New York University.
|
|
@@ -41,6 +41,11 @@ cameras/Picamera/_tree.py
|
|
|
41
41
|
cameras/Vimbax/__init__.py
|
|
42
42
|
cameras/Vimbax/_camera.py
|
|
43
43
|
cameras/Vimbax/_tree.py
|
|
44
|
+
demos/ROIdemo.py
|
|
45
|
+
demos/__init__.py
|
|
46
|
+
demos/demo.py
|
|
47
|
+
demos/filterdemo.py
|
|
48
|
+
demos/trackpydemo.py
|
|
44
49
|
dvr/QDVRWidget.py
|
|
45
50
|
dvr/QHDF5Reader.py
|
|
46
51
|
dvr/QHDF5Writer.py
|
|
@@ -56,6 +61,7 @@ filters/QBlurFilter.py
|
|
|
56
61
|
filters/QEdgeFilter.py
|
|
57
62
|
filters/QRGBFilter.py
|
|
58
63
|
filters/QSampleHold.py
|
|
64
|
+
filters/QYOLOFilter.py
|
|
59
65
|
filters/_MedianBase.py
|
|
60
66
|
filters/__init__.py
|
|
61
67
|
lib/QCamera.py
|
|
@@ -63,16 +69,19 @@ lib/QCameraTree.py
|
|
|
63
69
|
lib/QFPSMeter.py
|
|
64
70
|
lib/QFilterBank.py
|
|
65
71
|
lib/QListCameras.py
|
|
72
|
+
lib/QVideoFilter.py
|
|
66
73
|
lib/QVideoReader.py
|
|
67
74
|
lib/QVideoScreen.py
|
|
68
75
|
lib/QVideoSource.py
|
|
69
76
|
lib/QVideoWriter.py
|
|
70
|
-
lib/VideoFilter.py
|
|
71
77
|
lib/__init__.py
|
|
72
78
|
lib/chooser.py
|
|
73
79
|
lib/clickable.py
|
|
74
80
|
lib/resolutions.py
|
|
75
81
|
lib/types.py
|
|
82
|
+
overlays/__init__.py
|
|
83
|
+
overlays/trackpy.py
|
|
84
|
+
overlays/yolo.py
|
|
76
85
|
tests/test_chooser.py
|
|
77
86
|
tests/test_clickable.py
|
|
78
87
|
tests/test_demo.py
|
|
@@ -116,4 +125,5 @@ tests/test_qvideowriter.py
|
|
|
116
125
|
tests/test_qvimbaxcamera.py
|
|
117
126
|
tests/test_resolutions.py
|
|
118
127
|
tests/test_roidemo.py
|
|
128
|
+
tests/test_trackpy_overlay.py
|
|
119
129
|
tests/test_videofilter.py
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
[](https://pypi.org/project/QVideo/)
|
|
5
5
|
[](LICENSE.md)
|
|
6
6
|
[](https://github.com/davidgrier/QVideo/actions/workflows/test.yml)
|
|
7
|
+
[](https://qvideo.readthedocs.io/en/latest/)
|
|
7
8
|
|
|
8
9
|
**QVideo** is a framework for integrating video cameras into PyQt5 projects
|
|
9
10
|
for scientific research. It provides a unified, registration-based property
|
|
@@ -113,5 +114,5 @@ additional code needed.
|
|
|
113
114
|
## Acknowledgements
|
|
114
115
|
|
|
115
116
|
Work on this project at New York University is supported by the National
|
|
116
|
-
Science Foundation of the United States under award number DMR-
|
|
117
|
+
Science Foundation of the United States under award number DMR-2428983 and
|
|
117
118
|
by an award from the TAC Program of New York University.
|
|
@@ -56,7 +56,7 @@ class QBaslerTree(QGenicamTree):
|
|
|
56
56
|
controls: list[str] | None = None,
|
|
57
57
|
**kwargs) -> None:
|
|
58
58
|
camera = camera or QBaslerCamera(cameraID=cameraID)
|
|
59
|
-
camera.
|
|
59
|
+
camera.settings = self._DEFAULT_SETTINGS
|
|
60
60
|
super().__init__(*args,
|
|
61
61
|
camera=camera,
|
|
62
62
|
controls=controls or self._DEFAULT_CONTROLS,
|
|
@@ -15,6 +15,14 @@ class QFlirCamera(QGenicamCamera):
|
|
|
15
15
|
|
|
16
16
|
If Spinnaker is not installed, instantiation raises :exc:`TypeError`.
|
|
17
17
|
|
|
18
|
+
.. warning::
|
|
19
|
+
|
|
20
|
+
Spinnaker GenTL producer **4.3.0.189** contains a bug in which
|
|
21
|
+
``DevClose()`` hangs indefinitely when the camera is released.
|
|
22
|
+
This causes the application to hang on exit. FLIR customer
|
|
23
|
+
support has confirmed the bug. If you experience this issue,
|
|
24
|
+
downgrade to Spinnaker **4.1.0.172** or earlier.
|
|
25
|
+
|
|
18
26
|
Parameters
|
|
19
27
|
----------
|
|
20
28
|
cameraID : int
|
|
@@ -10,7 +10,7 @@ class QFlirTree(QGenicamTree):
|
|
|
10
10
|
|
|
11
11
|
'''Camera property tree for :class:`~QVideo.cameras.Flir.QFlirCamera`.
|
|
12
12
|
|
|
13
|
-
Builds a :class:`~QVideo.lib.
|
|
13
|
+
Builds a :class:`~QVideo.lib.QcameraTree.QCameraTree` with a curated
|
|
14
14
|
set of controls and sensible default settings for FLIR cameras.
|
|
15
15
|
|
|
16
16
|
Parameters
|
|
@@ -59,7 +59,8 @@ class QFlirTree(QGenicamTree):
|
|
|
59
59
|
controls: list[str] | None = None,
|
|
60
60
|
**kwargs) -> None:
|
|
61
61
|
camera = camera or QFlirCamera(cameraID=cameraID)
|
|
62
|
-
camera.
|
|
62
|
+
camera.settings = {k: v for k, v in self._DEFAULT_SETTINGS.items()
|
|
63
|
+
if k in camera.properties}
|
|
63
64
|
super().__init__(*args,
|
|
64
65
|
camera=camera,
|
|
65
66
|
controls=controls or self._DEFAULT_CONTROLS,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from ._camera import QGenicamCamera, QGenicamSource
|
|
2
|
+
from ._tree import QGenicamTree
|
|
3
|
+
|
|
4
|
+
# Tell Sphinx that these classes belong to the public package namespace,
|
|
5
|
+
# not the private _camera / _tree submodules, to avoid duplicate
|
|
6
|
+
# object descriptions in the generated docs.
|
|
7
|
+
QGenicamCamera.__module__ = __name__
|
|
8
|
+
QGenicamSource.__module__ = __name__
|
|
9
|
+
QGenicamTree.__module__ = __name__
|
|
10
|
+
|
|
11
|
+
__all__ = 'QGenicamCamera QGenicamSource QGenicamTree'.split()
|
|
@@ -103,10 +103,25 @@ class QGenicamCamera(QCamera):
|
|
|
103
103
|
|
|
104
104
|
@staticmethod
|
|
105
105
|
def _make_getter(feature: IValue):
|
|
106
|
-
'''Return a zero-argument callable that reads the feature value.
|
|
106
|
+
'''Return a zero-argument callable that reads the feature value.
|
|
107
|
+
|
|
108
|
+
The returned callable checks the current access mode before reading,
|
|
109
|
+
returning ``None`` for features that are not readable at call time
|
|
110
|
+
(e.g. enumeration nodes whose access mode changes after acquisition
|
|
111
|
+
starts).
|
|
112
|
+
'''
|
|
107
113
|
if isinstance(feature, IEnumeration):
|
|
108
|
-
|
|
109
|
-
|
|
114
|
+
def getter():
|
|
115
|
+
if feature.node.get_access_mode() in (EAccessMode.RO, EAccessMode.RW):
|
|
116
|
+
return feature.to_string()
|
|
117
|
+
return None
|
|
118
|
+
return getter
|
|
119
|
+
|
|
120
|
+
def getter():
|
|
121
|
+
if feature.node.get_access_mode() in (EAccessMode.RO, EAccessMode.RW):
|
|
122
|
+
return feature.value
|
|
123
|
+
return None
|
|
124
|
+
return getter
|
|
110
125
|
|
|
111
126
|
@staticmethod
|
|
112
127
|
def _feature_ptype(feature: IValue) -> type:
|
|
@@ -179,8 +194,7 @@ class QGenicamCamera(QCamera):
|
|
|
179
194
|
return
|
|
180
195
|
name = feature.node.name
|
|
181
196
|
getter = self._make_getter(feature)
|
|
182
|
-
|
|
183
|
-
setter = self._make_setter(feature, name) if writable else None
|
|
197
|
+
setter = self._make_setter(feature, name)
|
|
184
198
|
self.registerProperty(name,
|
|
185
199
|
getter=getter,
|
|
186
200
|
setter=setter,
|
|
@@ -271,6 +285,7 @@ class QGenicamCamera(QCamera):
|
|
|
271
285
|
self.harvester.reset()
|
|
272
286
|
except Exception:
|
|
273
287
|
pass
|
|
288
|
+
self.nodeMap = None
|
|
274
289
|
|
|
275
290
|
def _deinitialize(self) -> None:
|
|
276
291
|
'''Stop acquisition and release the GenICam device.'''
|
|
@@ -343,6 +358,28 @@ class QGenicamCamera(QCamera):
|
|
|
343
358
|
logger.warning(f'node {name} is unknown')
|
|
344
359
|
return None
|
|
345
360
|
|
|
361
|
+
_SHAPE_ALIASES = frozenset(('width', 'height'))
|
|
362
|
+
|
|
363
|
+
@property
|
|
364
|
+
def settings(self) -> QCamera.Settings:
|
|
365
|
+
'''All registered property values, excluding lowercase shape aliases.
|
|
366
|
+
|
|
367
|
+
GenICam cameras register ``width``/``height`` as lowercase aliases for
|
|
368
|
+
``Width``/``Height`` so that :attr:`~QVideo.lib.QCamera.QCamera.shape`
|
|
369
|
+
and attribute access (``camera.width``) work the same as on other
|
|
370
|
+
backends. Those aliases are excluded here so that
|
|
371
|
+
:class:`~QVideo.cameras.Genicam._tree.QGenicamTree` does not try to
|
|
372
|
+
sync them to tree parameters (which use the canonical GenICam names).
|
|
373
|
+
'''
|
|
374
|
+
return {name: spec['getter']()
|
|
375
|
+
for name, spec in self._properties.items()
|
|
376
|
+
if name not in self._SHAPE_ALIASES}
|
|
377
|
+
|
|
378
|
+
@settings.setter
|
|
379
|
+
def settings(self, settings: QCamera.Settings) -> None:
|
|
380
|
+
for key, value in settings.items():
|
|
381
|
+
self.set(key, value)
|
|
382
|
+
|
|
346
383
|
def is_readwrite(self, feature: str) -> bool:
|
|
347
384
|
'''Return ``True`` if the named feature is currently writable.
|
|
348
385
|
|
|
@@ -4,6 +4,7 @@ from QVideo.cameras.Genicam import QGenicamCamera
|
|
|
4
4
|
from genicam.genapi import (IValue, EAccessMode, EVisibility,
|
|
5
5
|
ICategory, ICommand, IEnumeration,
|
|
6
6
|
IBoolean, IInteger, IFloat, IString)
|
|
7
|
+
from pyqtgraph.Qt import QtCore
|
|
7
8
|
import logging
|
|
8
9
|
|
|
9
10
|
|
|
@@ -21,6 +22,12 @@ class QGenicamTree(QCameraTree):
|
|
|
21
22
|
GenICam node map and exposes visibility and per-feature enable/disable
|
|
22
23
|
controls.
|
|
23
24
|
|
|
25
|
+
A timer polls the camera periodically so that autonomous camera-side
|
|
26
|
+
changes (e.g. ``Gain`` being adjusted by auto-exposure, ``GainAuto``
|
|
27
|
+
reverting from ``"Once"`` to ``"Off"``) are reflected in the UI.
|
|
28
|
+
``PyNodeCallback`` is not used because it only fires when the **host**
|
|
29
|
+
writes a node, not when the camera changes a value autonomously.
|
|
30
|
+
|
|
24
31
|
Parameters
|
|
25
32
|
----------
|
|
26
33
|
camera : QGenicamCamera
|
|
@@ -48,12 +55,23 @@ class QGenicamTree(QCameraTree):
|
|
|
48
55
|
self.controls = controls
|
|
49
56
|
self.visibility = visibility
|
|
50
57
|
self._updateEnabled()
|
|
58
|
+
self._pollTimer = QtCore.QTimer(self)
|
|
59
|
+
self._pollTimer.setInterval(500)
|
|
60
|
+
self._pollTimer.timeout.connect(self._pollCamera)
|
|
61
|
+
self._pollTimer.start()
|
|
62
|
+
QtCore.QCoreApplication.instance().aboutToQuit.connect(self._pollTimer.stop)
|
|
63
|
+
|
|
64
|
+
def closeEvent(self, event) -> None:
|
|
65
|
+
self._pollTimer.stop()
|
|
66
|
+
super().closeEvent(event)
|
|
51
67
|
|
|
52
68
|
def description(self, camera: QGenicamCamera) -> dict:
|
|
53
69
|
'''Return a dictionary describing the node map of the camera'''
|
|
54
70
|
root = camera.node('Root')
|
|
71
|
+
if root is None:
|
|
72
|
+
return []
|
|
55
73
|
description = self.describe(root)
|
|
56
|
-
return description
|
|
74
|
+
return description.get('children', [])
|
|
57
75
|
|
|
58
76
|
def describe(self, feature: IValue) -> dict[str, object]:
|
|
59
77
|
'''Return a dictionary describing the specified feature'''
|
|
@@ -110,6 +128,8 @@ class QGenicamTree(QCameraTree):
|
|
|
110
128
|
p.sigValueChanged.connect(self._handleItemChanges)
|
|
111
129
|
|
|
112
130
|
def _handleItemChanges(self) -> None:
|
|
131
|
+
if self._ignoreSync:
|
|
132
|
+
return
|
|
113
133
|
logger.debug('Handling item changes')
|
|
114
134
|
self._updateVisible()
|
|
115
135
|
self._updateEnabled()
|
|
@@ -168,6 +188,53 @@ class QGenicamTree(QCameraTree):
|
|
|
168
188
|
finally:
|
|
169
189
|
p.blockSignals(False)
|
|
170
190
|
|
|
191
|
+
def _pollCamera(self) -> None:
|
|
192
|
+
'''Refresh all readable Parameter values and enabled states.
|
|
193
|
+
|
|
194
|
+
Called by the poll timer to pick up autonomous camera-side changes
|
|
195
|
+
that do not generate host-side notifications — e.g. ``Gain`` being
|
|
196
|
+
adjusted during auto-exposure, or ``GainAuto`` reverting from
|
|
197
|
+
``"Once"`` to ``"Off"`` after the sweep completes.
|
|
198
|
+
|
|
199
|
+
Returns immediately if the camera is no longer open (e.g. during
|
|
200
|
+
application shutdown) to prevent accessing freed C++ genapi objects.
|
|
201
|
+
|
|
202
|
+
Signals are not blocked so that the visual widgets update and
|
|
203
|
+
``_handleItemChanges`` fires when a value changes.
|
|
204
|
+
:attr:`_ignoreSync` is set for the duration so that the resulting
|
|
205
|
+
``sigTreeStateChanged`` emissions do not send values back to the
|
|
206
|
+
camera. :meth:`_updateEnabled` is called unconditionally so that
|
|
207
|
+
access-mode changes (e.g. ``ExposureTime`` becoming writable again
|
|
208
|
+
after the sweep) are reflected even when the controlling node value
|
|
209
|
+
has not changed.
|
|
210
|
+
'''
|
|
211
|
+
if not self.camera.isOpen():
|
|
212
|
+
return
|
|
213
|
+
self._ignoreSync = True
|
|
214
|
+
try:
|
|
215
|
+
self._updateLimits()
|
|
216
|
+
for item in self.listAllItems()[1:]:
|
|
217
|
+
p = item.param
|
|
218
|
+
if not p.opts.get('visible', False):
|
|
219
|
+
continue
|
|
220
|
+
name = p.opts.get('name')
|
|
221
|
+
if not self.camera.has_node(name):
|
|
222
|
+
continue
|
|
223
|
+
node = self.camera.node(name)
|
|
224
|
+
mode = node.node.get_access_mode()
|
|
225
|
+
if mode not in (EAccessMode.RO, EAccessMode.RW):
|
|
226
|
+
continue
|
|
227
|
+
if isinstance(node, IEnumeration):
|
|
228
|
+
value = node.to_string()
|
|
229
|
+
elif isinstance(node, (IBoolean, IInteger, IFloat, IString)):
|
|
230
|
+
value = node.value
|
|
231
|
+
else:
|
|
232
|
+
continue
|
|
233
|
+
p.setValue(value)
|
|
234
|
+
self._updateEnabled()
|
|
235
|
+
finally:
|
|
236
|
+
self._ignoreSync = False
|
|
237
|
+
|
|
171
238
|
def _updateLimits(self) -> None:
|
|
172
239
|
'''Refresh Parameter constraints from the live GenICam node values.
|
|
173
240
|
|
|
@@ -54,7 +54,7 @@ class QIDSTree(QGenicamTree):
|
|
|
54
54
|
controls: list[str] | None = None,
|
|
55
55
|
**kwargs) -> None:
|
|
56
56
|
camera = camera or QIDSCamera(cameraID=cameraID)
|
|
57
|
-
camera.
|
|
57
|
+
camera.settings = self._DEFAULT_SETTINGS
|
|
58
58
|
super().__init__(*args,
|
|
59
59
|
camera=camera,
|
|
60
60
|
controls=controls or self._DEFAULT_CONTROLS,
|
|
@@ -54,7 +54,7 @@ class QMVTree(QGenicamTree):
|
|
|
54
54
|
controls: list[str] | None = None,
|
|
55
55
|
**kwargs) -> None:
|
|
56
56
|
camera = camera or QMVCamera(cameraID=cameraID)
|
|
57
|
-
camera.
|
|
57
|
+
camera.settings = self._DEFAULT_SETTINGS
|
|
58
58
|
super().__init__(*args,
|
|
59
59
|
camera=camera,
|
|
60
60
|
controls=controls or self._DEFAULT_CONTROLS,
|
|
@@ -117,8 +117,12 @@ class QOpenCVResolutionTree(QCameraTree):
|
|
|
117
117
|
if change == 'value' and param.name() == 'resolution':
|
|
118
118
|
if value in self._resolutionMap:
|
|
119
119
|
w, h = self._resolutionMap[value]
|
|
120
|
+
fps = (self.camera.fps
|
|
121
|
+
if 'fps' in self.camera._properties else None)
|
|
120
122
|
self.camera.set('width', w)
|
|
121
123
|
self.camera.set('height', h)
|
|
124
|
+
if fps is not None:
|
|
125
|
+
self.camera.set('fps', fps)
|
|
122
126
|
return
|
|
123
127
|
super()._sync(root, changes)
|
|
124
128
|
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
'''Camcorder demo with a draggable ROI for recording a cropped video region.
|
|
3
|
+
|
|
4
|
+
Run directly::
|
|
5
|
+
|
|
6
|
+
python -m QVideo.demos.ROIdemo
|
|
7
|
+
'''
|
|
8
|
+
|
|
9
|
+
from QVideo.QCamcorder import QCamcorder
|
|
10
|
+
from pyqtgraph.Qt.QtCore import pyqtSignal, pyqtSlot
|
|
11
|
+
import pyqtgraph as pg
|
|
12
|
+
import numpy as np
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
__all__ = ['ROIFilter', 'ROIDemo']
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ROIFilter(pg.RectROI):
|
|
20
|
+
'''Draggable rectangular ROI that crops video frames to its bounds.
|
|
21
|
+
|
|
22
|
+
Subclasses :class:`pyqtgraph.RectROI` and adds a :attr:`newFrame`
|
|
23
|
+
signal and :meth:`crop` slot, making it compatible with
|
|
24
|
+
:class:`~QVideo.lib.QVideoWriter` as a frame source.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
fps : float
|
|
29
|
+
Frame rate of the video source [frames per second].
|
|
30
|
+
Stored as an attribute for :class:`~QVideo.lib.QVideoWriter`
|
|
31
|
+
compatibility.
|
|
32
|
+
pos : list[float]
|
|
33
|
+
Initial [x, y] position of the ROI.
|
|
34
|
+
size : list[float]
|
|
35
|
+
Initial [width, height] of the ROI.
|
|
36
|
+
**kwargs :
|
|
37
|
+
Additional keyword arguments forwarded to
|
|
38
|
+
:class:`~pyqtgraph.RectROI`.
|
|
39
|
+
|
|
40
|
+
Signals
|
|
41
|
+
-------
|
|
42
|
+
newFrame : np.ndarray
|
|
43
|
+
Emitted with the cropped frame each time :meth:`crop` is called.
|
|
44
|
+
'''
|
|
45
|
+
|
|
46
|
+
#: Emitted with the cropped frame each time :meth:`crop` is called.
|
|
47
|
+
newFrame = pyqtSignal(np.ndarray)
|
|
48
|
+
|
|
49
|
+
def __init__(self, fps: float, *args, **kwargs) -> None:
|
|
50
|
+
super().__init__(*args, **kwargs)
|
|
51
|
+
self.fps = fps
|
|
52
|
+
|
|
53
|
+
@pyqtSlot(np.ndarray)
|
|
54
|
+
def crop(self, frame: np.ndarray) -> None:
|
|
55
|
+
'''Crop *frame* to the current ROI bounds and emit :attr:`newFrame`.
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
frame : np.ndarray
|
|
60
|
+
Input video frame to crop.
|
|
61
|
+
'''
|
|
62
|
+
x, y = self.pos()
|
|
63
|
+
w, h = self.size()
|
|
64
|
+
crop = frame[int(y):int(y + h), int(x):int(x + w)]
|
|
65
|
+
self.newFrame.emit(crop)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class ROIDemo(QCamcorder):
|
|
69
|
+
'''Camcorder demo with a draggable ROI for recording cropped video.
|
|
70
|
+
|
|
71
|
+
Subclasses :class:`~QVideo.QCamcorder.QCamcorder` and overlays a
|
|
72
|
+
resizable :class:`ROIFilter` on the video screen. While recording,
|
|
73
|
+
camera frames are routed through the ROI cropper before being saved
|
|
74
|
+
by the DVR.
|
|
75
|
+
|
|
76
|
+
Parameters
|
|
77
|
+
----------
|
|
78
|
+
cameraTree : QCameraTree
|
|
79
|
+
Camera control tree providing the video source.
|
|
80
|
+
**kwargs :
|
|
81
|
+
Additional keyword arguments forwarded to
|
|
82
|
+
:class:`~QVideo.QCamcorder.QCamcorder`.
|
|
83
|
+
|
|
84
|
+
Attributes
|
|
85
|
+
----------
|
|
86
|
+
ROI_POS : list[int]
|
|
87
|
+
Default [x, y] position of the ROI overlay. Default: ``[100, 100]``.
|
|
88
|
+
ROI_SIZE : list[int]
|
|
89
|
+
Default [width, height] of the ROI overlay. Default: ``[400, 400]``.
|
|
90
|
+
'''
|
|
91
|
+
|
|
92
|
+
ROI_POS: list[int] = [100, 100]
|
|
93
|
+
ROI_SIZE: list[int] = [400, 400]
|
|
94
|
+
|
|
95
|
+
def _setupUi(self) -> None:
|
|
96
|
+
super()._setupUi()
|
|
97
|
+
self.roi = ROIFilter(self.source.fps,
|
|
98
|
+
self.ROI_POS, self.ROI_SIZE,
|
|
99
|
+
snapSize=8,
|
|
100
|
+
scaleSnap=True,
|
|
101
|
+
sideScalers=True,
|
|
102
|
+
movable=True,
|
|
103
|
+
invertible=False,
|
|
104
|
+
rotatable=False,
|
|
105
|
+
removable=False)
|
|
106
|
+
self.screen.view.addItem(self.roi)
|
|
107
|
+
self.dvr.filename = str(Path.home() / 'roidemo.avi')
|
|
108
|
+
|
|
109
|
+
def _connectSignals(self) -> None:
|
|
110
|
+
super()._connectSignals()
|
|
111
|
+
self.dvr.source = self.roi
|
|
112
|
+
self.dvr.recording.connect(self.recording)
|
|
113
|
+
|
|
114
|
+
@pyqtSlot(bool)
|
|
115
|
+
def recording(self, is_recording: bool) -> None:
|
|
116
|
+
'''Respond to DVR recording state changes.
|
|
117
|
+
|
|
118
|
+
Locks the ROI and connects the camera source to the ROI cropper
|
|
119
|
+
when recording starts; unlocks and disconnects when stopped.
|
|
120
|
+
|
|
121
|
+
Parameters
|
|
122
|
+
----------
|
|
123
|
+
is_recording : bool
|
|
124
|
+
``True`` when the DVR starts recording, ``False`` when stopped.
|
|
125
|
+
'''
|
|
126
|
+
if is_recording:
|
|
127
|
+
self.roi.movable = False
|
|
128
|
+
self.source.newFrame.connect(self.roi.crop)
|
|
129
|
+
else:
|
|
130
|
+
self.roi.movable = True
|
|
131
|
+
self.source.newFrame.disconnect(self.roi.crop)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def main() -> None: # pragma: no cover
|
|
135
|
+
'''Launch the ROI demo with an interactively chosen camera.'''
|
|
136
|
+
from QVideo.lib import choose_camera
|
|
137
|
+
|
|
138
|
+
pg.mkQApp()
|
|
139
|
+
camera = choose_camera().start()
|
|
140
|
+
widget = ROIDemo(camera)
|
|
141
|
+
widget.show()
|
|
142
|
+
pg.exec()
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
if __name__ == '__main__': # pragma: no cover
|
|
146
|
+
main()
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'''Runnable demo applications built on the QVideo framework.
|
|
2
|
+
|
|
3
|
+
Each demo composes a :class:`~QVideo.lib.QCameraTree.QCameraTree` with one
|
|
4
|
+
or more QVideo widgets into a standalone window. All demos use
|
|
5
|
+
:func:`~QVideo.lib.chooser.choose_camera` to present a camera-selection
|
|
6
|
+
dialog at startup, so no camera-specific code is needed in the demo itself.
|
|
7
|
+
|
|
8
|
+
Demos
|
|
9
|
+
-----
|
|
10
|
+
demo
|
|
11
|
+
Minimal layout: live video screen alongside a camera control tree.
|
|
12
|
+
The starting point for building a custom camera application.
|
|
13
|
+
|
|
14
|
+
filterdemo
|
|
15
|
+
Extends :mod:`demo` with a :class:`~QVideo.lib.QFilterBank.QFilterBank`
|
|
16
|
+
panel so that image-processing filters can be toggled and adjusted
|
|
17
|
+
alongside the live feed.
|
|
18
|
+
|
|
19
|
+
ROIdemo
|
|
20
|
+
Extends :class:`~QVideo.QCamcorder.QCamcorder` with a draggable
|
|
21
|
+
rectangular ROI overlay. Only the cropped region is saved when
|
|
22
|
+
the DVR records, making it easy to capture a sub-region of interest.
|
|
23
|
+
|
|
24
|
+
trackpydemo
|
|
25
|
+
Extends :mod:`demo` with a :class:`~QVideo.overlays.trackpy.QTrackpyWidget`
|
|
26
|
+
panel so that trackpy particle positions are overlaid on the live feed
|
|
27
|
+
in real time and locate results are available via a signal.
|
|
28
|
+
|
|
29
|
+
Running
|
|
30
|
+
-------
|
|
31
|
+
Each demo can be launched directly::
|
|
32
|
+
|
|
33
|
+
python -m QVideo.demos.demo
|
|
34
|
+
python -m QVideo.demos.filterdemo
|
|
35
|
+
python -m QVideo.demos.ROIdemo
|
|
36
|
+
python -m QVideo.demos.trackpydemo
|
|
37
|
+
|
|
38
|
+
Camera selection
|
|
39
|
+
----------------
|
|
40
|
+
All demos accept the same command-line flags to select a camera backend.
|
|
41
|
+
If no flag is given, a noise camera is used as a fallback.
|
|
42
|
+
|
|
43
|
+
.. code-block:: text
|
|
44
|
+
|
|
45
|
+
-b [cameraID] Basler camera (requires pylon SDK)
|
|
46
|
+
-c [cameraID] OpenCV camera
|
|
47
|
+
-f [cameraID] FLIR camera (requires Spinnaker SDK)
|
|
48
|
+
-i [cameraID] IDS Imaging camera (requires IDS peak SDK)
|
|
49
|
+
-m [cameraID] MATRIX VISION mvGenTLProducer (universal GenICam, not FLIR)
|
|
50
|
+
-p [cameraID] Raspberry Pi camera module (requires picamera2)
|
|
51
|
+
-r [cameraID] OpenCV camera with resolution drop-down selector
|
|
52
|
+
-v [cameraID] Allied Vision VimbaX camera
|
|
53
|
+
-h Show help and exit
|
|
54
|
+
|
|
55
|
+
``cameraID`` is an optional integer index (default ``0``) used when
|
|
56
|
+
multiple cameras of the same type are connected. The flags are mutually
|
|
57
|
+
exclusive — only one backend can be selected at a time.
|
|
58
|
+
|
|
59
|
+
Example::
|
|
60
|
+
|
|
61
|
+
python -m QVideo.demos.demo -f # first FLIR camera
|
|
62
|
+
python -m QVideo.demos.filterdemo -c 1 # second OpenCV camera
|
|
63
|
+
'''
|
|
64
|
+
|
|
65
|
+
from .demo import Demo
|
|
66
|
+
from .filterdemo import FilterDemo
|
|
67
|
+
from .ROIdemo import ROIFilter, ROIDemo
|
|
68
|
+
from .trackpydemo import TrackpyDemo
|
|
69
|
+
|