Source code for etho.services.camera.spinnaker_old

import time
import numpy as np
from typing import Tuple, Union
from .base import BaseCam
import cv2


try:
    import PySpin

    pyspin_error = None
except ImportError as pyspin_error:
    pass


[docs] class Spinnaker_OLD(BaseCam): """Supports older FLIR cameras (Flea3, Grasshopper) with only partial support for the Spinnaker SDK.""" NAME = "SPO" def __init__(self, serialnumber): if pyspin_error is not None: raise pyspin_error self.serialnumber = serialnumber def init(self): self.cam_system = PySpin.System_GetInstance() self.cam_list = self.cam_system.GetCameras() self.c = self.cam_list.GetBySerial(self.serialnumber) self.c.Init() self.c.PixelFormat.SetValue(PySpin.PixelFormat_Mono8) self._generate_attrs() # enable embedding of frame TIME STAMP self.c.ChunkModeActive.SetValue(True) self.c.ChunkSelector.SetValue(PySpin.ChunkSelector_Timestamp) self.c.ChunkEnable.SetValue(True) self.timestamp_offset = 0 # self._estimate_timestamp_offset() # set pixel format self.c.PixelFormat.SetValue(PySpin.PixelFormat_Mono8) # set continuous acquisition self.c.AcquisitionMode.SetValue(PySpin.AcquisitionMode_Continuous) self.timeout = PySpin.EVENT_TIMEOUT_INFINITE self.processor = PySpin.ImageProcessor() self.processor.SetColorProcessing(PySpin.SPINNAKER_COLOR_PROCESSING_ALGORITHM_HQ_LINEAR)
[docs] def get(self, timeout=None): # get image im = self.c.GetNextImage(self.timeout) system_stimestamp = time.time() if im.IsIncomplete(): im.Release() raise ValueError(f"Image incomplete with image status {im.GetImageStatus()}") else: im_converted = self.processor.Convert(im, PySpin.PixelFormat_BGR8) image_timestamp = im.GetTimeStamp() im.Release() BGR = im_converted.GetNDArray() image_timestamp = image_timestamp / 1e9 + self.timestamp_offset return BGR, image_timestamp, system_stimestamp
@property def roi(self) -> Tuple[int, int, int, int]: return self.c.OffsetX.GetValue(), self.c.OffsetY.GetValue(), self.c.Width.GetValue(), self.c.Height.GetValue() @roi.setter def roi(self, x0_y0_x_y: Tuple[int, int, int, int]): try: x0, y0, x, y = x0_y0_x_y except ValueError: raise ValueError("Need 4-tuple with x0_y0_x_y") else: self._min_max_inc(self.c.Width, int(x)) self._min_max_inc(self.c.Height, int(y)) self._min_max_inc(self.c.OffsetX, int(x0)) self._min_max_inc(self.c.OffsetY, int(y0)) @property def framerate(self): return self.c.AcquisitionFrameRate.GetValue() @framerate.setter def framerate(self, value: float): nodemap = self.c.GetNodeMap() self.c.TriggerMode.SetValue(PySpin.TriggerMode_Off) node = PySpin.CEnumerationPtr(nodemap.GetNode("AcquisitionFrameRateAuto")) val = PySpin.CEnumEntryPtr(node.GetEntryByName("Off")).GetValue() # Once, Continuous node.SetIntValue(val) self.c.AcquisitionFrameRate.SetValue(float(value)) @property def gamma(self): return self.c.Gamma.GetValue() @gamma.setter def gamma(self, value: float): # self.c.GammaEnabled.SetValue(bool(True)) self.c.Gamma.SetValue(value) @property def brightness(self) -> float: return self.c.BlackLevel.GetValue() @brightness.setter def brightness(self, value: float): # self.c.BlackLevelSelector.SetValue(PySpin.BlackLevelSelector_All) self.c.BlackLevel.SetValue(float(value)) @property def exposure(self): return self.c.ExposureTime.GetValue() @exposure.setter def exposure(self, value: Union[float, str]): if value == "AUTO": self.c.ExposureAuto.SetValue(PySpin.ExposureAuto_Continuous) else: self.c.ExposureAuto.SetValue(PySpin.ExposureAuto_Off) self.c.ExposureMode.SetValue(PySpin.ExposureMode_Timed) self.c.ExposureTime.SetValue(float(value)) @property def gain(self): self.c.Gain.GetValue() @gain.setter def gain(self, value: Union[float, str]): if value == "AUTO": self.c.GainAuto.SetValue(PySpin.GainAuto_Continuous) else: self.c.GainAuto.SetValue(PySpin.GainAuto_Off) self.c.Gain.SetValue(float(value)) def optimize_auto_exposure(self): self.setattr("AutoExposureControlLoopDamping", 0.1) self.setattr("AutoExposureLightingMode_Val", 2) # Frontlight self.setattr("AutoExposureExposureTimeLowerLimit", 6) self.setattr("AutoExposureExposureTimeUpperLimit", 30000) self.setattr("AutoExposureEVCompensation", 3) @property def external_trigger(self): return self.c.TriggerMode.GetValue() @external_trigger.setter def external_trigger(self, value: bool = False): self.c.TriggerMode.SetValue(PySpin.TriggerMode_Off) if value: self.c.TriggerSource.SetValue(PySpin.TriggerSource_Line3) self.c.TriggerMode.SetValue(PySpin.TriggerMode_On) def _generate_attrs(self): self._rw_modes = {PySpin.RO: "read only", PySpin.RW: "read/write", PySpin.WO: "write only", PySpin.NA: "not available"} self._attr_types = { PySpin.intfIFloat: PySpin.CFloatPtr, PySpin.intfIBoolean: PySpin.CBooleanPtr, PySpin.intfIInteger: PySpin.CIntegerPtr, PySpin.intfIEnumeration: PySpin.CEnumerationPtr, PySpin.intfIString: PySpin.CStringPtr, } self._attr_type_names = { PySpin.intfIFloat: "float", PySpin.intfIBoolean: "bool", PySpin.intfIInteger: "int", PySpin.intfIEnumeration: "enum", PySpin.intfIString: "string", PySpin.intfICommand: "command", } self.camera_attributes = {} self.camera_methods = {} self.camera_node_types = {} for node in self.c.GetNodeMap().GetNodes(): pit = node.GetPrincipalInterfaceType() name = node.GetName() self.camera_node_types[name] = self._attr_type_names.get(pit, pit) if pit == PySpin.intfICommand: self.camera_methods[name] = PySpin.CCommandPtr(node) if pit in self._attr_types: self.camera_attributes[name] = self._attr_types[pit](node) self.initialized = True def getattr(self, attr): if attr in self.camera_attributes: prop = self.camera_attributes[attr] if not PySpin.IsReadable(prop): raise AttributeError("Camera property '%s' is not readable" % attr) if hasattr(prop, "GetValue"): return prop.GetValue() elif hasattr(prop, "ToString"): return prop.ToString() else: raise AttributeError("Camera property '%s' is not readable" % attr) elif attr in self.camera_methods: return self.camera_methods[attr].Execute else: raise AttributeError(attr) def setattr(self, attr, val): if attr in self.camera_attributes: prop = self.camera_attributes[attr] if not PySpin.IsWritable(prop): raise AttributeError("Property '%s' is not currently writable!" % attr) if hasattr(prop, "SetValue"): prop.SetValue(val) else: prop.FromString(val) elif attr in self.camera_methods: raise AttributeError("Camera method '%s' is a function -- you can't assign it a value!" % attr) else: if attr not in self.__dict__ and self.lock and self.initialized: raise AttributeError("Unknown property '%s'." % attr) else: raise AttributeError(attr) def _min_max_inc(self, prop, value=None, set_value=True): min_val, max_val, inc = prop.GetMin(), prop.GetMax(), prop.GetInc() prop_type = type(prop.GetValue()) if value is not None: value = np.clip(value, min_val, max_val) value = np.round(value / inc) * inc if set_value: value = prop_type(value) prop.SetValue(value) value = prop.GetValue() return value def _estimate_timestamp_offset(self, timestamp_offset_iterations=10): """Gets offset between system time and timestamps.""" # This method is required because the timestamp stored in the camera is relative to when it was powered on, so an # offset needs to be applied to get it into epoch time; from tests I’ve done, this appears to be accurate to ~1e-3 # seconds. timestamp_offsets = [] for i in range(timestamp_offset_iterations): # Latch timestamp. This basically “freezes” the current camera timer into a variable that can be read with self.c.TimestampLatch.Execute() system_time = time.time() # Compute timestamp offset in seconds; note that timestamp latch value is in nanoseconds timestamp_offset = system_time - self.c.TimestampLatchValue.GetValue() / 1e9 timestamp_offsets.append(timestamp_offset) # Return the median value return np.median(timestamp_offsets) def enable_gpio_strobe(self): pass # self._set_gpio_strobe(enable=True) def disable_gpio_strobe(self): pass # self._set_gpio_strobe(enable=False) def set_node_and_entry(self, node_name: str, entry_name: str): nodemap = self.c.GetNodeMap() node = PySpin.CEnumerationPtr(nodemap.GetNode(node_name)) if not PySpin.IsAvailable(node) or not PySpin.IsWritable(node): raise ValueError(f"Cannot retrieve node {node_name}.") entry = node.GetEntryByName(entry_name) if not PySpin.IsAvailable(entry) or not PySpin.IsReadable(entry): raise ValueError(f"Cannot retrieve entry {entry_name} from node {node_name}.") node.SetIntValue(entry.GetValue()) # def _set_gpio_strobe(self, line: str = "Line2", enable: bool = True): # # from PySpin/Examples/Python3/CounterAndTimer.py # # from https://github.com/CapAI/misc/blob/a22cd50e90018c03cde3c1339aa622185502bb05/spinnaker/pyspin/Examples/Python3/CounterAndTimer.py#L193 # if enable: # line_mode = "Output" # else: # line_mode = "Input" # # Select line to control # self.set_node_and_entry("LineSelector", line) # self.set_node_and_entry("LineMode", line_mode) # self.set_node_and_entry("LineSource", "ExposureActive")
[docs] def reset(self, sleep: float = 10.0): device_reset = PySpin.CCommandPtr(self.c.GetNodeMap().GetNode("DeviceReset")) device_reset.Execute() self.close() time.sleep(sleep)
def start(self): self.c.BeginAcquisition() def stop(self): try: self.c.EndAcquisition() # not sure this works if BeginAcquistion has not been called except: pass def close(self): self.stop() # should check if cam started self.c.DeInit() del self.c self.cam_list.Clear() del self.cam_list
# self.cam_system.ReleaseInstance() # del self.cam_system