diff --git a/pyproject.toml b/pyproject.toml index 1dbdfbc..cca9caa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,11 +12,11 @@ package-url = 'https://github.com/PyMoDAQ/pymodaq_plugins_opencv' name = "pymodaq_plugins_opencv" description = 'plugin to use camera instrumented using the opencv library' dependencies = [ - "pymodaq>=5.3.2", + "pymodaq>=5.3.9", "pymodaq_utils>=5.3.1", - "pymodaq_gui>=5.3.0", + "pymodaq_gui>=5.3.9", "pymodaq_data>=5.3.0", - "pymodaq_plugins_utils>=5.3.1", + "pymodaq_plugins_utils>=5.3.2", 'opencv-python', ] diff --git a/src/pymodaq_plugins_opencv/daq_viewer_plugins/plugins_2D/daq_2Dviewer_OpenCV.py b/src/pymodaq_plugins_opencv/daq_viewer_plugins/plugins_2D/daq_2Dviewer_OpenCV.py index 14877ae..851f424 100644 --- a/src/pymodaq_plugins_opencv/daq_viewer_plugins/plugins_2D/daq_2Dviewer_OpenCV.py +++ b/src/pymodaq_plugins_opencv/daq_viewer_plugins/plugins_2D/daq_2Dviewer_OpenCV.py @@ -1,5 +1,3 @@ -from copy import deepcopy - from pymodaq_utils.logger import set_logger, get_module_name from pymodaq_gui.parameter import Parameter @@ -12,22 +10,6 @@ logger = set_logger(get_module_name(__file__)) -def webcam_params() -> list: - """The settings of ``CameraBase`` that suit a webcam: colour image converted to gray by default, no exposure - time nor buffer (OpenCV sets neither, see ``Cam. Settings``)""" - params = deepcopy(cam_params) - for param in params: - if param['name'] == 'color_conversion': - param['value'] = 'RGB2GRAY' - elif param['name'] == 'buffer': - param['visible'] = False - elif param['name'] == 'timing_opts': - for child in param['children']: - if child['name'] == 'exposure_time': - child['visible'] = False - return params - - class DAQ_2DViewer_OpenCV(CameraBase): """Cameras read with OpenCV (webcams, any device handled by ``cv2.VideoCapture``) @@ -42,7 +24,14 @@ class DAQ_2DViewer_OpenCV(CameraBase): [{'title': 'Camera index:', 'name': 'camera_index', 'type': 'int', 'value': 0, 'default': 0, 'min': 0}, {'title': 'Open Settings:', 'name': 'open_settings', 'type': 'bool', 'value': False}, {'title': 'Cam. Settings:', 'name': 'cam_settings', 'type': 'group', 'children': []}, - ] + webcam_params() + ] + cam_params + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # OpenCV sets neither the exposure time nor the buffer of CameraBase, and a colour image is shown in gray + self.settings.child('timing_opts', 'exposure_time').show(False) + self.settings.child('buffer').show(False) + self.settings.child('color_conversion').setOpts(value='RGB2GRAY', default='RGB2GRAY') def ini_detector_custom(self, controller=None): """Open the camera (master) or take the one of the master (slave)""" diff --git a/src/pymodaq_plugins_opencv/hardware/opencv_camera.py b/src/pymodaq_plugins_opencv/hardware/opencv_camera.py index 9a97c59..dd7f73b 100644 --- a/src/pymodaq_plugins_opencv/hardware/opencv_camera.py +++ b/src/pymodaq_plugins_opencv/hardware/opencv_camera.py @@ -12,6 +12,7 @@ Frames are given as RGB, the order of OpenCV being BGR. """ +import os import sys import threading import time @@ -27,6 +28,18 @@ from pymodaq_plugins_opencv.hardware.opencv import OpenCVProp +def _keep_qt_of_the_binding(): + """The opencv-python package (not the headless one) points Qt to the platform plugins it ships, which makes the + creation of a QApplication abort with the Qt of PyQt/PySide: restore the plugins of the Qt binding""" + cv2_dir = os.path.dirname(os.path.abspath(cv2.__file__)) + for name in ('QT_QPA_PLATFORM_PLUGIN_PATH', 'QT_QPA_FONTDIR'): + if os.environ.get(name, '').startswith(cv2_dir): + del os.environ[name] + + +_keep_qt_of_the_binding() + + class OpenCVCamera(CameraDriverBase): """A camera read with ``cv2.VideoCapture`` diff --git a/tests/test_opencv_camera.py b/tests/test_opencv_camera.py index 931a62c..6b70491 100644 --- a/tests/test_opencv_camera.py +++ b/tests/test_opencv_camera.py @@ -1,6 +1,7 @@ """The OpenCV camera driver and its plugin, without a webcam: a video file read by the real OpenCV, and a fake of ``cv2.VideoCapture`` for what a file cannot do (properties, failing reads, change of the frame size)""" import importlib.util +import os import time import cv2 @@ -24,7 +25,7 @@ from pymodaq_plugins_utils.hardware.camera_driver import CameraDriverBase -from pymodaq_plugins_opencv.hardware.opencv_camera import OpenCVCamera +from pymodaq_plugins_opencv.hardware.opencv_camera import OpenCVCamera, _keep_qt_of_the_binding from pymodaq_plugins_opencv.daq_viewer_plugins.plugins_2D.daq_2Dviewer_OpenCV import DAQ_2DViewer_OpenCV WIDTH, HEIGHT = 64, 48 @@ -116,12 +117,27 @@ def acquire(driver: OpenCVCamera, nframes=1) -> np.ndarray: return driver.read_multiple_images() +def click_led(plugin, name: str): + """What the user does: press the (checkable) button of the parameter, which the DAQ_Viewer sends to the plugin""" + param = plugin.settings.child('roi', name) + param.opts['checked'] = True + param.activate() + + def apply_roi(plugin, rows: slice, columns: slice): - plugin.settings.child('roi', 'update_roi').setValue(True) plugin.roi_select(RoiInfo.from_slices([rows, columns])) - param = plugin.settings.child('roi', 'apply_roi') - param.setValue(True) - plugin.commit_settings(param) + click_led(plugin, 'update_roi') + click_led(plugin, 'apply_roi') + + +def test_the_qt_plugins_of_opencv_python_are_forgotten(monkeypatch): + cv2_qt = os.path.join(os.path.dirname(os.path.abspath(cv2.__file__)), 'qt', 'plugins') + monkeypatch.setenv('QT_QPA_PLATFORM_PLUGIN_PATH', cv2_qt) + _keep_qt_of_the_binding() + assert 'QT_QPA_PLATFORM_PLUGIN_PATH' not in os.environ + monkeypatch.setenv('QT_QPA_PLATFORM_PLUGIN_PATH', '/my/own/plugins') # not the one of OpenCV: left alone + _keep_qt_of_the_binding() + assert os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] == '/my/own/plugins' class TestVideoFile: