From 7d63be7e041bcff890a2f7ae308e4c2f1a819fc5 Mon Sep 17 00:00:00 2001 From: wakonig_k Date: Mon, 16 Jun 2025 16:40:47 +0200 Subject: [PATCH] refactor(ids): move to PSIDeviceBase and preview signal --- csaxs_bec/devices/ids_cameras/ids_camera.py | 671 +++++++----------- .../devices/ids_cameras/ids_ueye_signals.py | 83 --- 2 files changed, 252 insertions(+), 502 deletions(-) delete mode 100644 csaxs_bec/devices/ids_cameras/ids_ueye_signals.py diff --git a/csaxs_bec/devices/ids_cameras/ids_camera.py b/csaxs_bec/devices/ids_cameras/ids_camera.py index 37edadb..e9e9cbb 100644 --- a/csaxs_bec/devices/ids_cameras/ids_camera.py +++ b/csaxs_bec/devices/ids_cameras/ids_camera.py @@ -3,12 +3,9 @@ import time import numpy as np from ophyd import Component as Cpt -from ophyd import Device, Kind -from ophyd_devices.interfaces.base_classes.psi_detector_base import ( - CustomDetectorMixin, - PSIDetectorBase, -) -from ophyd_devices.sim.sim_signals import SetableSignal +from ophyd import DeviceStatus, Kind, StatusBase +from ophyd_devices import PSIDeviceBase +from ophyd_devices.utils.bec_signals import PreviewSignal try: from pyueye import ueye @@ -17,212 +14,10 @@ except ImportError: ueye = None -class IDSCustomPrepare(CustomDetectorMixin): - - USER_ACCESS = ["pyueye"] - pyueye = ueye - - def __init__(self, *_args, parent: Device = None, **_kwargs) -> None: - super().__init__(*_args, parent=parent, **_kwargs) - self.ueye = ueye - self.h_cam = None - self.s_info = None - self.data_thread = None - self.thread_event = None - - def on_connection_established(self): - self.hCam = self.ueye.HIDS( - self.parent.camera_ID - ) # 0: first available camera; 1-254: The camera with the specified camera ID - self.sInfo = self.ueye.SENSORINFO() - self.cInfo = self.ueye.CAMINFO() - self.pcImageMemory = self.ueye.c_mem_p() - self.MemID = self.ueye.int() - self.rectAOI = self.ueye.IS_RECT() - self.pitch = self.ueye.INT() - self.nBitsPerPixel = self.ueye.INT( - self.parent.bits_per_pixel - ) # 24: bits per pixel for color mode; take 8 bits per pixel for monochrome - self.channels = ( - self.parent.channels - ) # 3: channels for color mode(RGB); take 1 channel for monochrome - self.m_nColorMode = self.ueye.INT( - self.parent.m_n_colormode - ) # Y8/RGB16/RGB24/REG32 (1 for our color cameras) - self.bytes_per_pixel = int(self.nBitsPerPixel / 8) - - # Starts the driver and establishes the connection to the camera - nRet = self.ueye.is_InitCamera(self.hCam, None) - if nRet != self.ueye.IS_SUCCESS: - print("is_InitCamera ERROR") - - # Reads out the data hard-coded in the non-volatile camera memory and writes it to the data structure that cInfo points to - nRet = self.ueye.is_GetCameraInfo(self.hCam, self.cInfo) - if nRet != self.ueye.IS_SUCCESS: - print("is_GetCameraInfo ERROR") - - # You can query additional information about the sensor type used in the camera - nRet = self.ueye.is_GetSensorInfo(self.hCam, self.sInfo) - if nRet != self.ueye.IS_SUCCESS: - print("is_GetSensorInfo ERROR") - - nRet = self.ueye.is_ResetToDefault(self.hCam) - if nRet != self.ueye.IS_SUCCESS: - print("is_ResetToDefault ERROR") - - # Set display mode to DIB - nRet = self.ueye.is_SetDisplayMode(self.hCam, self.ueye.IS_SET_DM_DIB) - - # Set the right color mode - if ( - int.from_bytes(self.sInfo.nColorMode.value, byteorder="big") - == self.ueye.IS_COLORMODE_BAYER - ): - # setup the color depth to the current windows setting - self.ueye.is_GetColorDepth(self.hCam, self.nBitsPerPixel, self.m_nColorMode) - bytes_per_pixel = int(self.nBitsPerPixel / 8) - print("IS_COLORMODE_BAYER: ") - print("\tm_nColorMode: \t\t", self.m_nColorMode) - print("\tnBitsPerPixel: \t\t", self.nBitsPerPixel) - print("\tbytes_per_pixel: \t\t", bytes_per_pixel) - print() - - elif ( - int.from_bytes(self.sInfo.nColorMode.value, byteorder="big") - == self.ueye.IS_COLORMODE_CBYCRY - ): - # for color camera models use RGB32 mode - m_nColorMode = ueye.IS_CM_BGRA8_PACKED - nBitsPerPixel = ueye.INT(32) - bytes_per_pixel = int(self.nBitsPerPixel / 8) - print("IS_COLORMODE_CBYCRY: ") - print("\tm_nColorMode: \t\t", m_nColorMode) - print("\tnBitsPerPixel: \t\t", nBitsPerPixel) - print("\tbytes_per_pixel: \t\t", bytes_per_pixel) - print() - - elif ( - int.from_bytes(self.sInfo.nColorMode.value, byteorder="big") - == self.ueye.IS_COLORMODE_MONOCHROME - ): - # for color camera models use RGB32 mode - m_nColorMode = self.ueye.IS_CM_MONO8 - nBitsPerPixel = self.ueye.INT(8) - bytes_per_pixel = int(nBitsPerPixel / 8) - print("IS_COLORMODE_MONOCHROME: ") - print("\tm_nColorMode: \t\t", m_nColorMode) - print("\tnBitsPerPixel: \t\t", nBitsPerPixel) - print("\tbytes_per_pixel: \t\t", bytes_per_pixel) - print() - - else: - # for monochrome camera models use Y8 mode - m_nColorMode = self.ueye.IS_CM_MONO8 - nBitsPerPixel = self.ueye.INT(8) - bytes_per_pixel = int(nBitsPerPixel / 8) - print("else") - - # Can be used to set the size and position of an "area of interest"(AOI) within an image - nRet = self.ueye.is_AOI( - self.hCam, ueye.IS_AOI_IMAGE_GET_AOI, self.rectAOI, self.ueye.sizeof(self.rectAOI) - ) - if nRet != self.ueye.IS_SUCCESS: - print("is_AOI ERROR") - - self.width = self.rectAOI.s32Width - self.height = self.rectAOI.s32Height - - # Prints out some information about the camera and the sensor - print("Camera model:\t\t", self.sInfo.strSensorName.decode("utf-8")) - print("Camera serial no.:\t", self.cInfo.SerNo.decode("utf-8")) - print("Maximum image width:\t", self.width) - print("Maximum image height:\t", self.height) - print() - - # --------------------------------------------------------------------------------------------------------------------------------------- - - # Allocates an image memory for an image having its dimensions defined by width and height and its color depth defined by nBitsPerPixel - nRet = self.ueye.is_AllocImageMem( - self.hCam, self.width, self.height, self.nBitsPerPixel, self.pcImageMemory, self.MemID - ) - if nRet != self.ueye.IS_SUCCESS: - print("is_AllocImageMem ERROR") - else: - # Makes the specified image memory the active memory - nRet = self.ueye.is_SetImageMem(self.hCam, self.pcImageMemory, self.MemID) - if nRet != self.ueye.IS_SUCCESS: - print("is_SetImageMem ERROR") - else: - # Set the desired color mode - nRet = self.ueye.is_SetColorMode(self.hCam, self.m_nColorMode) - - # Activates the camera's live video mode (free run mode) - nRet = self.ueye.is_CaptureVideo(self.hCam, self.ueye.IS_DONT_WAIT) - if nRet != self.ueye.IS_SUCCESS: - print("is_CaptureVideo ERROR") - - # Enables the queue mode for existing image memory sequences - nRet = self.ueye.is_InquireImageMem( - self.hCam, - self.pcImageMemory, - self.MemID, - self.width, - self.height, - self.nBitsPerPixel, - self.pitch, - ) - if nRet != self.ueye.IS_SUCCESS: - print("is_InquireImageMem ERROR") - else: - print("Press q to leave the programm") - startmeasureframerate = True - Gain = False - - # Start live mode of camera immediately - self.parent.start_live_mode() - - def _start_data_thread(self): - self.thread_event = threading.Event() - self.data_thread = threading.Thread(target=self._receive_data_from_camera, daemon=True) - self.data_thread.start() - - def _receive_data_from_camera(self): - while not self.thread_event.is_set(): - - # In order to display the image in an OpenCV window we need to... - # ...extract the data of our image memory - array = ueye.get_data( - self.pcImageMemory, - self.width, - self.height, - self.nBitsPerPixel, - self.pitch, - copy=False, - ) - - # bytes_per_pixel = int(nBitsPerPixel / 8) - - # ...reshape it in an numpy array... - frame = np.reshape(array, (self.height.value, self.width.value, self.bytes_per_pixel)) - self.parent.image_data.put(frame) - self.parent._run_subs(sub_type=self.parent.SUB_MONITOR, value=frame) - - time.sleep(0.1) - - def on_trigger(self): - pass - # self.parent._run_subs(sub_type=self.parent.SUB_MONITOR, value=self.parent.image_data.get()) - - -class IDSCamera(PSIDetectorBase): +class IDSCamera(PSIDeviceBase): USER_ACCESS = ["start_live_mode", "stop_live_mode"] - custom_prepare_cls = IDSCustomPrepare - - image_data = Cpt(SetableSignal, value=np.empty((100, 100)), kind=Kind.omitted) - - SUB_MONITOR = "device_monitor_2d" - _default_sub = SUB_MONITOR + image_data = Cpt(PreviewSignal, value=np.empty((100, 100)), kind=Kind.omitted) def __init__( self, @@ -234,19 +29,219 @@ class IDSCamera(PSIDetectorBase): channels: int, m_n_colormode: int, kind=None, - parent=None, device_manager=None, **kwargs, ): + super().__init__( - prefix=prefix, name=name, kind=kind, parent=parent, device_manager=device_manager, **kwargs + prefix=prefix, name=name, kind=kind, device_manager=device_manager, **kwargs ) self.camera_ID = camera_ID self.bits_per_pixel = bits_per_pixel + self.bytes_per_pixel = None self.channels = channels - self.m_n_colormode = m_n_colormode - #TODO fix connected and wait_for_connection - self.custom_prepare.on_connection_established() + self._m_n_colormode_input = m_n_colormode + self.m_n_colormode = None + self.ueye = ueye + self.h_cam = None + self.s_info = None + self.data_thread = None + self.c_info = None + self.pc_image_memory = None + self.mem_id = None + self.rect_aoi = None + self.pitch = None + self.n_bits_per_pixel = None + self.width = None + self.height = None + self.thread_event = threading.Event() + self.data_thread = None + + def start_backend(self): + if self.ueye is None: + raise ImportError("The pyueye library is not installed.") + self.h_cam = self.ueye.HIDS( + self.camera_ID + ) # 0: first available camera; 1-254: The camera with the specified camera ID + self.s_info = self.ueye.SENSORINFO() + self.c_info = self.ueye.CAMINFO() + self.pc_image_memory = self.ueye.c_mem_p() + self.mem_id = self.ueye.int() + self.rect_aoi = self.ueye.IS_RECT() + self.pitch = self.ueye.INT() + self.n_bits_per_pixel = self.ueye.INT( + self.bits_per_pixel + ) # 24: bits per pixel for color mode; take 8 bits per pixel for monochrome + self.m_n_colormode = self.ueye.INT( + self._m_n_colormode_input + ) # Y8/RGB16/RGB24/REG32 (1 for our color cameras) + self.bytes_per_pixel = int(self.n_bits_per_pixel / 8) + + # Starts the driver and establishes the connection to the camera + ret = self.ueye.is_InitCamera(self.h_cam, None) + if ret != self.ueye.IS_SUCCESS: + print("is_InitCamera ERROR") + + # Reads out the data hard-coded in the non-volatile camera memory and writes it to the data structure that c_info points to + ret = self.ueye.is_GetCameraInfo(self.h_cam, self.c_info) + if ret != self.ueye.IS_SUCCESS: + print("is_GetCameraInfo ERROR") + + # You can query additional information about the sensor type used in the camera + ret = self.ueye.is_GetSensorInfo(self.h_cam, self.s_info) + if ret != self.ueye.IS_SUCCESS: + print("is_GetSensorInfo ERROR") + + ret = self.ueye.is_ResetToDefault(self.h_cam) + if ret != self.ueye.IS_SUCCESS: + print("is_ResetToDefault ERROR") + + # Set display mode to DIB + ret = self.ueye.is_SetDisplayMode(self.h_cam, self.ueye.IS_SET_DM_DIB) + + # Set the right color mode + if ( + int.from_bytes(self.s_info.nColorMode.value, byteorder="big") + == self.ueye.IS_COLORMODE_BAYER + ): + # setup the color depth to the current windows setting + self.ueye.is_GetColorDepth(self.h_cam, self.n_bits_per_pixel, self.m_n_colormode) + bytes_per_pixel = int(self.n_bits_per_pixel / 8) + print("IS_COLORMODE_BAYER: ") + print("\tm_n_colormode: \t\t", self.m_n_colormode) + print("\tn_bits_per_pixel: \t\t", self.n_bits_per_pixel) + print("\tbytes_per_pixel: \t\t", bytes_per_pixel) + print() + + elif ( + int.from_bytes(self.s_info.nColorMode.value, byteorder="big") + == self.ueye.IS_COLORMODE_CBYCRY + ): + # for color camera models use RGB32 mode + m_n_colormode = self.ueye.IS_CM_BGRA8_PACKED + n_bits_per_pixel = self.ueye.INT(32) + bytes_per_pixel = int(self.n_bits_per_pixel / 8) + print("IS_COLORMODE_CBYCRY: ") + print("\tm_n_colormode: \t\t", m_n_colormode) + print("\tn_bits_per_pixel: \t\t", n_bits_per_pixel) + print("\tbytes_per_pixel: \t\t", bytes_per_pixel) + print() + + elif ( + int.from_bytes(self.s_info.nColorMode.value, byteorder="big") + == self.ueye.IS_COLORMODE_MONOCHROME + ): + # for color camera models use RGB32 mode + m_n_colormode = self.ueye.IS_CM_MONO8 + n_bits_per_pixel = self.ueye.INT(8) + bytes_per_pixel = int(n_bits_per_pixel / 8) + print("IS_COLORMODE_MONOCHROME: ") + print("\tm_n_colormode: \t\t", m_n_colormode) + print("\tn_bits_per_pixel: \t\t", n_bits_per_pixel) + print("\tbytes_per_pixel: \t\t", bytes_per_pixel) + print() + + else: + # for monochrome camera models use Y8 mode + m_n_colormode = self.ueye.IS_CM_MONO8 + n_bits_per_pixel = self.ueye.INT(8) + bytes_per_pixel = int(n_bits_per_pixel / 8) + print("else") + + # Can be used to set the size and position of an "area of interest"(AOI) within an image + ret = self.ueye.is_AOI( + self.h_cam, + self.ueye.IS_AOI_IMAGE_GET_AOI, + self.rect_aoi, + self.ueye.sizeof(self.rect_aoi), + ) + if ret != self.ueye.IS_SUCCESS: + print("is_AOI ERROR") + + self.width = self.rect_aoi.s32Width + self.height = self.rect_aoi.s32Height + + # Prints out some information about the camera and the sensor + print("Camera model:\t\t", self.s_info.strSensorName.decode("utf-8")) + print("Camera serial no.:\t", self.c_info.SerNo.decode("utf-8")) + print("Maximum image width:\t", self.width) + print("Maximum image height:\t", self.height) + print() + + # --------------------------------------------------------------------------------------------------------------------------------------- + + # Allocates an image memory for an image having its dimensions defined by width and height and its color depth defined by n_bits_per_pixel + ret = self.ueye.is_AllocImageMem( + self.h_cam, + self.width, + self.height, + self.n_bits_per_pixel, + self.pc_image_memory, + self.mem_id, + ) + if ret != self.ueye.IS_SUCCESS: + print("is_AllocImageMem ERROR") + else: + # Makes the specified image memory the active memory + ret = self.ueye.is_SetImageMem(self.h_cam, self.pc_image_memory, self.mem_id) + if ret != self.ueye.IS_SUCCESS: + print("is_SetImageMem ERROR") + else: + # Set the desired color mode + ret = self.ueye.is_SetColorMode(self.h_cam, self.m_n_colormode) + + # Activates the camera's live video mode (free run mode) + ret = self.ueye.is_CaptureVideo(self.h_cam, self.ueye.IS_DONT_WAIT) + if ret != self.ueye.IS_SUCCESS: + print("is_CaptureVideo ERROR") + + # Enables the queue mode for existing image memory sequences + ret = self.ueye.is_InquireImageMem( + self.h_cam, + self.pc_image_memory, + self.mem_id, + self.width, + self.height, + self.n_bits_per_pixel, + self.pitch, + ) + if ret != self.ueye.IS_SUCCESS: + print("is_InquireImageMem ERROR") + else: + print("Press q to leave the programm") + # startmeasureframerate = True + # Gain = False + + # Start live mode of camera immediately + self.start_live_mode() + + def _start_data_thread(self): + self.data_thread = threading.Thread(target=self._receive_data_from_camera, daemon=True) + self.data_thread.start() + + def _receive_data_from_camera(self): + while not self.thread_event.is_set(): + if self.ueye is None: + print("pyueye library not available.") + return + # In order to display the image in an OpenCV window we need to... + # ...extract the data of our image memory + array = self.ueye.get_data( + self.pc_image_memory, + self.width, + self.height, + self.n_bits_per_pixel, + self.pitch, + copy=False, + ) + + # bytes_per_pixel = int(n_bits_per_pixel / 8) + + # ...reshape it in an numpy array... + frame = np.reshape(array, (self.height.value, self.width.value, self.bytes_per_pixel)) + self.image_data.put(frame) + + time.sleep(0.1) def wait_for_connection(self, all_signals=False, timeout=10): if ueye is None: @@ -254,226 +249,64 @@ class IDSCamera(PSIDetectorBase): "The pyueye library is not installed or doesn't provide the necessary c libs" ) super().wait_for_connection(all_signals, timeout) - #self.custom_prepare.on_connection_established() - - def destroy(self): - """Extend Ophyds destroy function to kill the data thread""" - self.stop_live_mode() - super().destroy() def start_live_mode(self): - if self.custom_prepare.data_thread is not None: + if self.data_thread is not None: self.stop_live_mode() - self.custom_prepare._start_data_thread() + self._start_data_thread() def stop_live_mode(self): """Stopping the camera live mode.""" - if self.custom_prepare.thread_event is not None: - self.custom_prepare.thread_event.set() - if self.custom_prepare.data_thread is not None: - self.custom_prepare.data_thread.join() - self.custom_prepare.thread_event = None - self.custom_prepare.data_thread = None + self.thread_event.set() + if self.data_thread is not None: + self.data_thread.join() + self.thread_event.clear() + self.data_thread = None + ######################################## + # Beamline Specific Implementations # + ######################################## -"""from pyueye import ueye -import numpy as np -import cv2 -import sys -import time + def on_init(self) -> None: + """ + Called when the device is initialized. -#--------------------------------------------------------------------------------------------------------------------------------------- + No signals are connected at this point. If you like to + set default values on signals, please use on_connected instead. + """ -#Variables -hCam = ueye.HIDS(202) #0: first available camera; 1-254: The camera with the specified camera ID -sInfo = ueye.SENSORINFO() -cInfo = ueye.CAMINFO() -pcImageMemory = ueye.c_mem_p() -MemID = ueye.int() -rectAOI = ueye.IS_RECT() -pitch = ueye.INT() -nBitsPerPixel = ueye.INT(24) #24: bits per pixel for color mode; take 8 bits per pixel for monochrome -channels = 3 #3: channels for color mode(RGB); take 1 channel for monochrome -m_nColorMode = ueye.INT(1) # Y8/RGB16/RGB24/REG32 (1 for our color cameras) -bytes_per_pixel = int(nBitsPerPixel / 8) + def on_connected(self) -> None: + """ + Called after the device is connected and its signals are connected. + Default values for signals should be set here. + """ + self.start_backend() -ids_cam - ... - deviceConfig: - camera_ID: 202 - bits_per_pixel: 24 - channels: 3 - m_n_colormode: 1 + def on_stage(self) -> DeviceStatus | StatusBase | None: + """ + Called while staging the device. -#--------------------------------------------------------------------------------------------------------------------------------------- -print("START") -print() + Information about the upcoming scan can be accessed from the scan_info (self.scan_info.msg) object. + """ -# Starts the driver and establishes the connection to the camera -nRet = ueye.is_InitCamera(hCam, None) -if nRet != ueye.IS_SUCCESS: - print("is_InitCamera ERROR") + def on_unstage(self) -> DeviceStatus | StatusBase | None: + """Called while unstaging the device.""" -# Reads out the data hard-coded in the non-volatile camera memory and writes it to the data structure that cInfo points to -nRet = ueye.is_GetCameraInfo(hCam, cInfo) -if nRet != ueye.IS_SUCCESS: - print("is_GetCameraInfo ERROR") + def on_pre_scan(self) -> DeviceStatus | StatusBase | None: + """Called right before the scan starts on all devices automatically.""" -# You can query additional information about the sensor type used in the camera -nRet = ueye.is_GetSensorInfo(hCam, sInfo) -if nRet != ueye.IS_SUCCESS: - print("is_GetSensorInfo ERROR") + def on_trigger(self) -> DeviceStatus | StatusBase | None: + """Called when the device is triggered.""" -nRet = ueye.is_ResetToDefault( hCam) -if nRet != ueye.IS_SUCCESS: - print("is_ResetToDefault ERROR") + def on_complete(self) -> DeviceStatus | StatusBase | None: + """Called to inquire if a device has completed a scans.""" -# Set display mode to DIB -nRet = ueye.is_SetDisplayMode(hCam, ueye.IS_SET_DM_DIB) + def on_kickoff(self) -> DeviceStatus | StatusBase | None: + """Called to kickoff a device for a fly scan. Has to be called explicitly.""" + def on_stop(self) -> None: + """Called when the device is stopped.""" - -# Set the right color mode -if int.from_bytes(sInfo.nColorMode.value, byteorder='big') == ueye.IS_COLORMODE_BAYER: - # setup the color depth to the current windows setting - ueye.is_GetColorDepth(hCam, nBitsPerPixel, m_nColorMode) - bytes_per_pixel = int(nBitsPerPixel / 8) - print("IS_COLORMODE_BAYER: ", ) - print("\tm_nColorMode: \t\t", m_nColorMode) - print("\tnBitsPerPixel: \t\t", nBitsPerPixel) - print("\tbytes_per_pixel: \t\t", bytes_per_pixel) - print() - -elif int.from_bytes(sInfo.nColorMode.value, byteorder='big') == ueye.IS_COLORMODE_CBYCRY: - # for color camera models use RGB32 mode - m_nColorMode = ueye.IS_CM_BGRA8_PACKED - nBitsPerPixel = ueye.INT(32) - bytes_per_pixel = int(nBitsPerPixel / 8) - print("IS_COLORMODE_CBYCRY: ", ) - print("\tm_nColorMode: \t\t", m_nColorMode) - print("\tnBitsPerPixel: \t\t", nBitsPerPixel) - print("\tbytes_per_pixel: \t\t", bytes_per_pixel) - print() - -elif int.from_bytes(sInfo.nColorMode.value, byteorder='big') == ueye.IS_COLORMODE_MONOCHROME: - # for color camera models use RGB32 mode - m_nColorMode = ueye.IS_CM_MONO8 - nBitsPerPixel = ueye.INT(8) - bytes_per_pixel = int(nBitsPerPixel / 8) - print("IS_COLORMODE_MONOCHROME: ", ) - print("\tm_nColorMode: \t\t", m_nColorMode) - print("\tnBitsPerPixel: \t\t", nBitsPerPixel) - print("\tbytes_per_pixel: \t\t", bytes_per_pixel) - print() - -else: - # for monochrome camera models use Y8 mode - m_nColorMode = ueye.IS_CM_MONO8 - nBitsPerPixel = ueye.INT(8) - bytes_per_pixel = int(nBitsPerPixel / 8) - print("else") - -# Can be used to set the size and position of an "area of interest"(AOI) within an image -nRet = ueye.is_AOI(hCam, ueye.IS_AOI_IMAGE_GET_AOI, rectAOI, ueye.sizeof(rectAOI)) -if nRet != ueye.IS_SUCCESS: - print("is_AOI ERROR") - -width = rectAOI.s32Width -height = rectAOI.s32Height - -# Prints out some information about the camera and the sensor -print("Camera model:\t\t", sInfo.strSensorName.decode('utf-8')) -print("Camera serial no.:\t", cInfo.SerNo.decode('utf-8')) -print("Maximum image width:\t", width) -print("Maximum image height:\t", height) -print() - -#--------------------------------------------------------------------------------------------------------------------------------------- - -# Allocates an image memory for an image having its dimensions defined by width and height and its color depth defined by nBitsPerPixel -nRet = ueye.is_AllocImageMem(hCam, width, height, nBitsPerPixel, pcImageMemory, MemID) -if nRet != ueye.IS_SUCCESS: - print("is_AllocImageMem ERROR") -else: - # Makes the specified image memory the active memory - nRet = ueye.is_SetImageMem(hCam, pcImageMemory, MemID) - if nRet != ueye.IS_SUCCESS: - print("is_SetImageMem ERROR") - else: - # Set the desired color mode - nRet = ueye.is_SetColorMode(hCam, m_nColorMode) - - - -# Activates the camera's live video mode (free run mode) -nRet = ueye.is_CaptureVideo(hCam, ueye.IS_DONT_WAIT) -if nRet != ueye.IS_SUCCESS: - print("is_CaptureVideo ERROR") - -# Enables the queue mode for existing image memory sequences -nRet = ueye.is_InquireImageMem(hCam, pcImageMemory, MemID, width, height, nBitsPerPixel, pitch) -if nRet != ueye.IS_SUCCESS: - print("is_InquireImageMem ERROR") -else: - print("Press q to leave the programm") -startmeasureframerate=True -Gain = False -#--------------------------------------------------------------------------------------------------------------------------------------- - -# Continuous image display -while(nRet == ueye.IS_SUCCESS): - - # In order to display the image in an OpenCV window we need to... - # ...extract the data of our image memory - array = ueye.get_data(pcImageMemory, width, height, nBitsPerPixel, pitch, copy=False) - - # bytes_per_pixel = int(nBitsPerPixel / 8) - - # ...reshape it in an numpy array... - frame = np.reshape(array,(height.value, width.value, bytes_per_pixel)) - - # ...resize the image by a half - frame = cv2.resize(frame,(0,0),fx=0.5, fy=0.5) - -#--------------------------------------------------------------------------------------------------------------------------------------- - #Include image data processing here - -#--------------------------------------------------------------------------------------------------------------------------------------- - - #...and finally display it - cv2.imshow("SimpleLive_Python_uEye_OpenCV", frame) - if startmeasureframerate: - starttime = time.time() - startmeasureframerate=False - framenumber=0 - if time.time() > starttime+5: - print(f"Caught {framenumber/5} frames per second") - startmeasureframerate=True - Gain = ~Gain - if Gain: - nRet = ueye.is_SetGainBoost(hCam, 1) - else: - nRet = ueye.is_SetGainBoost(hCam, 0) - print(f"Gain setting status {nRet}") - #...and finally display it - cv2.imshow("SimpleLive_Python_uEye_OpenCV", frame) - framenumber+=1 - time.sleep(0.1) - - # Press q if you want to end the loop - if (cv2.waitKey(1) & 0xFF) == ord('q'): - break -#--------------------------------------------------------------------------------------------------------------------------------------- - -# Releases an image memory that was allocated using is_AllocImageMem() and removes it from the driver management -ueye.is_FreeImageMem(hCam, pcImageMemory, MemID) - -# Disables the hCam camera handle and releases the data structures and memory areas taken up by the uEye camera -ueye.is_ExitCamera(hCam) - -# Destroys the OpenCv windows -cv2.destroyAllWindows() - -print() -print("END") -""" + def on_destroy(self) -> None: + """Called when the device is destroyed. Cleanup resources here.""" + self.stop_live_mode() diff --git a/csaxs_bec/devices/ids_cameras/ids_ueye_signals.py b/csaxs_bec/devices/ids_cameras/ids_ueye_signals.py deleted file mode 100644 index 9c1c215..0000000 --- a/csaxs_bec/devices/ids_cameras/ids_ueye_signals.py +++ /dev/null @@ -1,83 +0,0 @@ -import time - -import numpy as np -from bec_lib import bec_logger -from ophyd import Kind, Signal -from ophyd.utils import ReadOnlyError - -from ophyd_devices.utils.bec_device_base import BECDeviceBase - -logger = bec_logger.logger - -# Readout precision for Setable/ReadOnlySignal signals -PRECISION = 3 - - -class ReadOnlySignal(Signal): - """Setable signal for simulated devices. - - The signal will store the value in sim_state of the SimulatedData class of the parent device. - It will also return the value from sim_state when get is called. Compared to the ReadOnlySignal, - this signal can be written to. - The setable signal inherits from the Signal class of ophyd, thus the class attribute needs to be - initiated as a Component (class from ophyd). - - >>> signal = SetableSignal(name="signal", parent=parent, value=0) - - Parameters - ---------- - - name (string) : Name of the signal - parent (object) : Parent object of the signal, default none. - value (any) : Initial value of the signal, default 0. - kind (int) : Kind of the signal, default Kind.normal. - precision (float) : Precision of the signal, default PRECISION. - """ - - def __init__( - self, - name: str, - *args, - fcn: callable, - kind: int = Kind.normal, - precision: float = PRECISION, - **kwargs, - ): - super().__init__(*args, name=name, value=value, kind=kind, **kwargs) - self._metadata.update(connected=True, write_access=False) - self._value = None - self.precision = precision - self.fcn = fcn - - # pylint: disable=arguments-differ - def get(self): - """Get the current position of the simulated device. - - Core function for signal. - """ - self._value = self.fcn() - return self._value - - # pylint: disable=arguments-differ - def put(self, value): - """Put the value to the simulated device. - - Core function for signal. - """ - self._update_sim_state(value) - self._value = value - - def describe(self): - """Describe the readback signal. - - Core function for signal. - """ - res = super().describe() - if self.precision is not None: - res[self.name]["precision"] = self.precision - return res - - @property - def timestamp(self): - """Timestamp of the readback value""" - return self._get_timestamp()