|
|
|
|
@@ -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()
|
|
|
|
|
|