added force monochrome mode plus delay after disconnect #105

Merged
wyzula_j merged 1 commits from ids_monochrome into main 2025-11-12 13:37:20 +01:00
3 changed files with 23 additions and 5 deletions

View File

@@ -399,7 +399,9 @@ cam_xeye:
deviceConfig:
camera_id: 1
bits_per_pixel: 24
# channels: 3
num_rotation_90: 3
transpose: false
force_monochrome: true
m_n_colormode: 1
enabled: true
onFailure: buffer
@@ -412,7 +414,9 @@ cam_ids_rgb:
deviceConfig:
camera_id: 203
bits_per_pixel: 24
# channels: 3
num_rotation_90: 3
transpose: false
force_monochrome: true
m_n_colormode: 1
enabled: true
onFailure: buffer

View File

@@ -18,6 +18,7 @@ import atexit
from typing import Literal
import numpy as np
import time
from bec_lib.logger import bec_logger
from csaxs_bec.devices.ids_cameras.base_integration.utils import check_error
@@ -164,10 +165,12 @@ class Camera:
m_n_colormode: Literal[0, 1, 2, 3] = 1,
bits_per_pixel: int = 24,
connect: bool = True,
force_monochrome: bool = False,
):
self.ueye = ueye
self.camera_id = camera_id
self._inputs = {"m_n_colormode": m_n_colormode, "bits_per_pixel": bits_per_pixel}
self.force_monochrome = force_monochrome
self._connected = False
self.cam = None
atexit.register(self.on_disconnect)
@@ -197,14 +200,16 @@ class Camera:
self.cam = IDSCameraObject(self.camera_id, **self._inputs)
self._connected = True
def on_disconnect(self):
"""Disconnect from the camera."""
def on_disconnect(self, delay_after: float = 0.3):
"""Disconnect from the camera and optionally wait a short time for driver cleanup."""
try:
if self.cam and self.cam.h_cam:
check_error(self.ueye.is_ExitCamera(self.cam.h_cam), "IDSCameraObject")
self._connected = False
self.cam = None
logger.info("Camera disconnected.")
if delay_after > 0:
time.sleep(delay_after)
logger.debug(f"Waited {delay_after:.2f}s after camera disconnect for cleanup.")
except Exception as e:
logger.info(f"Error during camera disconnection: {e}")
@@ -269,6 +274,12 @@ class Camera:
# If RGB image (H, W, 3), reshuffle channels from BGR → RGB
if img.ndim == 3 and img.shape[2] == 3:
img = img[:, :, ::-1]
if self.force_monochrome:
gray = np.dot(img[..., :3], [0.2989, 0.5870, 0.1140]).astype(np.uint8)
# expand to 3D shape (H, W, 1) for consistency with real mono cams
img = np.expand_dims(gray, axis=-1)
img = np.ascontiguousarray(img)
return img

View File

@@ -54,6 +54,7 @@ class IDSCamera(PSIDeviceBase):
live_mode: bool = False,
num_rotation_90: int = 0,
transpose: bool = False,
force_monochrome: bool = False,
**kwargs,
):
"""Initialize the IDS Camera.
@@ -81,6 +82,7 @@ class IDSCamera(PSIDeviceBase):
self._mask = np.zeros((1, 1), dtype=np.uint8)
self.image.num_rotation_90 = num_rotation_90
self.image.transpose = transpose
self._force_monochrome = force_monochrome
############## Live Mode Methods ##############
@@ -184,6 +186,7 @@ class IDSCamera(PSIDeviceBase):
def on_connected(self):
"""Connect to the camera."""
self.cam.force_monochrome = self._force_monochrome
self.cam.on_connect()
self.live_mode = self._inputs.get("live_mode", False)
self.set_rect_roi(0, 0, self.cam.cam.width.value, self.cam.cam.height.value)