Source code for QVideo.cameras.OpenCV._tree

from qtpy import QtCore
from QVideo.lib import QCameraTree
from QVideo.cameras.OpenCV import QOpenCVCamera


__all__ = ['QOpenCVTree']


[docs] class QOpenCVTree(QCameraTree): '''Camera control tree for :class:`~QVideo.cameras.OpenCV.QOpenCVCamera`. Extends :class:`~QVideo.lib.QCameraTree.QCameraTree` with a ``resolution`` dropdown populated from the formats reported by :class:`~QVideo.cameras.OpenCV._devices.QOpenCVDevices`. Selecting an entry atomically updates width, height, and frame rate on the live device without stopping the video source. Width, height, and fps are displayed as read-only fields. All format changes go through the ``resolution`` dropdown. When no format information is available (e.g. when :class:`~QtMultimedia.QMediaDevices` is absent and probing fails), the dropdown is omitted and the tree falls back to the standard read-only width/height display. Parameters ---------- camera : QOpenCVCamera or None Camera instance to use. If ``None``, a new :class:`~QVideo.cameras.OpenCV.QOpenCVCamera` is created from the keyword arguments below. cameraID : int Index of the camera device to open. Used only when *camera* is ``None``. Default: ``0``. mirrored : bool Flip the image horizontally. Used only when *camera* is ``None``. Default: ``False``. flipped : bool Flip the image vertically. Used only when *camera* is ``None``. Default: ``False``. gray : bool Open in grayscale mode. Used only when *camera* is ``None``. Default: ``False``. *args : Positional arguments forwarded to :class:`~QVideo.lib.QCameraTree.QCameraTree`. **kwargs : Keyword arguments forwarded to :class:`~QVideo.lib.QCameraTree.QCameraTree`. ''' def __init__(self, *args, camera: QOpenCVCamera | None = None, cameraID: int = 0, mirrored: bool = False, flipped: bool = False, gray: bool = False, **kwargs) -> None: if camera is None: camera = QOpenCVCamera(cameraID=cameraID, mirrored=mirrored, flipped=flipped, gray=gray) super().__init__(camera, *args, **kwargs) for key in ('width', 'height'): if key in self._parameters: self._parameters[key].setOpts(enabled=False) # fps is controlled by the resolution dropdown when formats are known if self._hasFormats and 'fps' in self._parameters: self._parameters['fps'].setOpts(enabled=False) def _createTree(self, description=None) -> None: '''Build the parameter tree, prepending a resolution enum when formats are available.''' if description is None: description = self._defaultDescription(self.camera) formats = getattr(self.camera, '_formats', []) self._hasFormats = bool(formats) if formats: description = [self._formatEntry(formats)] + [ d for d in description if d.get('name') != 'resolution' ] super()._createTree(description) def _formatEntry(self, formats: list) -> dict: '''Build the ``resolution`` list-parameter description dict.''' current_w = self.camera.width current_h = self.camera.height values: dict[str, tuple] = {} current_value = None for w, h, _min_fps, max_fps in formats: label = f'{w}\u00d7{h} @ {max_fps:.0f} Hz' val = (w, h, float(max_fps)) values[label] = val if w == current_w and h == current_h and current_value is None: current_value = val if current_value is None: current_value = next(iter(values.values())) return {'name': 'resolution', 'type': 'list', 'limits': values, 'value': current_value, 'default': current_value} @QtCore.Slot(object, object) def _sync(self, root, changes) -> None: '''Handle parameter changes, routing ``resolution`` entries here. A ``resolution`` change is applied directly to the camera (width, height, fps) without going through the base-class ``camera.set`` dispatch, since ``resolution`` is not a registered camera property. All other changes are forwarded to the base class. ''' if self._ignoreSync: return fmt_value = None other = [] for param, change, value in changes: if change == 'value' and param.name() == 'resolution': fmt_value = value else: other.append((param, change, value)) if fmt_value is not None: w, h, fps = fmt_value self.camera.set('width', w) self.camera.set('height', h) self.camera.set('fps', fps) self._ignoreSync = True for key, val in self.camera.settings.items(): if key != 'resolution': self.set(key, val) self._ignoreSync = False if other: super()._sync(root, other)
if __name__ == '__main__': # pragma: no cover QOpenCVTree.example()