Array preview also works
This commit is contained in:
@@ -430,7 +430,7 @@ samcam:
|
|||||||
readoutPriority: monitored
|
readoutPriority: monitored
|
||||||
readOnly: false
|
readOnly: false
|
||||||
softwareTrigger: false
|
softwareTrigger: false
|
||||||
samimg:
|
samstream:
|
||||||
description: Sample camera ZMQ stream
|
description: Sample camera ZMQ stream
|
||||||
deviceClass: pxiii_bec.devices.StdDaqPreviewDetector
|
deviceClass: pxiii_bec.devices.StdDaqPreviewDetector
|
||||||
deviceConfig:
|
deviceConfig:
|
||||||
@@ -441,6 +441,20 @@ samimg:
|
|||||||
readoutPriority: async
|
readoutPriority: async
|
||||||
readOnly: false
|
readOnly: false
|
||||||
softwareTrigger: false
|
softwareTrigger: false
|
||||||
|
samimg:
|
||||||
|
description: Sample camera image from EPICS
|
||||||
|
deviceClass: pxiii_bec.devices.NDArrayPreview
|
||||||
|
deviceConfig:
|
||||||
|
prefix: 'X06DA-SAMCAM:image1:'
|
||||||
|
deviceTags:
|
||||||
|
- detector
|
||||||
|
enabled: true
|
||||||
|
readoutPriority: async
|
||||||
|
readOnly: false
|
||||||
|
softwareTrigger: false
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bstop_pneum:
|
bstop_pneum:
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Standard DAQ preview image stream module
|
||||||
|
|
||||||
|
Created on Thu Jun 27 17:28:43 2024
|
||||||
|
|
||||||
|
@author: mohacsi_i
|
||||||
|
"""
|
||||||
|
import numpy as np
|
||||||
|
from ophyd import Device, Component, EpicsSignal, Kind, Staged
|
||||||
|
from ophyd.areadetector.base import NDDerivedSignal
|
||||||
|
|
||||||
|
from bec_lib import bec_logger
|
||||||
|
logger = bec_logger.logger
|
||||||
|
|
||||||
|
|
||||||
|
class NDArrayPreview(Device):
|
||||||
|
"""Wrapper class around AreaDetector's NDStdArray plugins
|
||||||
|
|
||||||
|
This is a monolithic class to display images from AreaDetector's
|
||||||
|
ImagePlugin without the use of DynamicDeviceComponent or multiple
|
||||||
|
interitance (that doesn't work with BEC).
|
||||||
|
"""
|
||||||
|
# Subscriptions for plotting image
|
||||||
|
USER_ACCESS = ["image"]
|
||||||
|
SUB_MONITOR = "device_monitor_2d"
|
||||||
|
_default_sub = SUB_MONITOR
|
||||||
|
|
||||||
|
# Status attributes
|
||||||
|
array_size_x = Component(EpicsSignal, "ArraySize0_RBV", kind=Kind.config)
|
||||||
|
array_size_y = Component(EpicsSignal, "ArraySize1_RBV", kind=Kind.config)
|
||||||
|
array_size_z = Component(EpicsSignal, "ArraySize2_RBV", kind=Kind.config)
|
||||||
|
ndimensions = Component(EpicsSignal, "NDimensions_RBV", kind=Kind.config)
|
||||||
|
array_data = Component(EpicsSignal, "ArrayData", kind=Kind.omitted)
|
||||||
|
shaped_image = Component(
|
||||||
|
NDDerivedSignal,
|
||||||
|
derived_from="array_data",
|
||||||
|
shape=("array_size_z", "array_size_y", "array_size_x"),
|
||||||
|
num_dimensions="ndimensions",
|
||||||
|
kind=Kind.normal,
|
||||||
|
)
|
||||||
|
|
||||||
|
def read(self):
|
||||||
|
""" Stream out data on every read()"""
|
||||||
|
if self._staged==Staged.yes:
|
||||||
|
image = self.shaped_image.get()
|
||||||
|
self._run_subs(sub_type=self.SUB_MONITOR, value=image)
|
||||||
|
return super().read()
|
||||||
|
|
||||||
|
def image(self):
|
||||||
|
""" Fallback method in case image streaming fills up the BEC"""
|
||||||
|
array_size = (self.array_size_z.get(), self.array_size_y.get(), self.array_size_x.get())
|
||||||
|
if array_size == (0, 0, 0):
|
||||||
|
raise RuntimeError("Invalid image; ensure array_callbacks are on")
|
||||||
|
|
||||||
|
if array_size[-1] == 0:
|
||||||
|
array_size = array_size[:-1]
|
||||||
|
|
||||||
|
pixel_count = np.prod(array_size)
|
||||||
|
image = self.array_data.get()
|
||||||
|
if image.size == pixel_count:
|
||||||
|
return np.array(image).reshape(array_size)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Automatically connect to SAMCAM at PXIII if directly invoked
|
||||||
|
if __name__ == "__main__":
|
||||||
|
img = NDArrayPreview("X06DA-SAMCAM:image1:", name="samimg")
|
||||||
|
img.wait_for_connection()
|
||||||
@@ -43,6 +43,9 @@ class StdDaqPreviewMixin(CustomDetectorMixin):
|
|||||||
self.parent.unstage()
|
self.parent.unstage()
|
||||||
sleep(0.5)
|
sleep(0.5)
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"[{self.parent.name}] Attaching monitor to {self.parent.url.get()}"
|
||||||
|
)
|
||||||
self.parent.connect()
|
self.parent.connect()
|
||||||
self._stop_polling = False
|
self._stop_polling = False
|
||||||
self._mon = Thread(target=self.poll, daemon=True)
|
self._mon = Thread(target=self.poll, daemon=True)
|
||||||
@@ -107,7 +110,7 @@ class StdDaqPreviewMixin(CustomDetectorMixin):
|
|||||||
self.parent._last_image = image
|
self.parent._last_image = image
|
||||||
self.parent._run_subs(sub_type=self.parent.SUB_MONITOR, value=image)
|
self.parent._run_subs(sub_type=self.parent.SUB_MONITOR, value=image)
|
||||||
t_last = t_curr
|
t_last = t_curr
|
||||||
logger.debug(
|
logger.info(
|
||||||
f"[{self.parent.name}] Updated frame {header['frame']}\t"
|
f"[{self.parent.name}] Updated frame {header['frame']}\t"
|
||||||
f"Shape: {header['shape']}\tMean: {np.mean(image):.3f}"
|
f"Shape: {header['shape']}\tMean: {np.mean(image):.3f}"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,3 +8,4 @@ from .A3200 import AerotechAbrStage
|
|||||||
from .A3200utils import A3200Axis
|
from .A3200utils import A3200Axis
|
||||||
from .SmarGon import SmarGonAxis
|
from .SmarGon import SmarGonAxis
|
||||||
from .StdDaqPreview import StdDaqPreviewDetector
|
from .StdDaqPreview import StdDaqPreviewDetector
|
||||||
|
from .NDArrayPreview import NDArrayPreview
|
||||||
Reference in New Issue
Block a user