480 lines
16 KiB
Python
480 lines
16 KiB
Python
from ijutils import *
|
|
from ch.psi.pshell.imaging.Overlays import *
|
|
from ch.psi.pshell.imaging.Utils import *
|
|
import ch.psi.pshell.imaging.Pen as Pen
|
|
import java.awt.Rectangle as Rectangle
|
|
import ch.psi.pshell.imaging.Data as Data
|
|
import ch.psi.pshell.device.Camera.DataType as DataType
|
|
import ch.psi.pshell.utils.Chrono as Chrono
|
|
import subprocess
|
|
|
|
#GRAB_MIN_TIME = 1000
|
|
CONTINOUS_MODE_MIN_TIME = 4000
|
|
###############################################################################
|
|
# ROI Integration
|
|
###############################################################################
|
|
|
|
|
|
def start_eiger_ioc():
|
|
subprocess.call("/work/sls/bin/X_X11MA_EigerStart.sh")
|
|
print "IOC started"
|
|
|
|
|
|
|
|
def stop_eiger_ioc():
|
|
subprocess.call("/work/sls/bin/X_X11MA_EigerStop.sh")
|
|
print "IOC stopped"
|
|
|
|
"""
|
|
def integrate_roi(source, x,y, w, h):
|
|
if source.data is None:
|
|
source.update()
|
|
roi = source.data.getRoi(Rectangle(x,y, w, h))
|
|
return roi.integrate(False)
|
|
"""
|
|
|
|
def integrate_roi(source, x,y, w, h):
|
|
if source.data is None:
|
|
source.update()
|
|
rect = Rectangle(x,y, w, h)
|
|
roi = source.data.getRoi(rect)
|
|
"""
|
|
outliers_mask = get_outliers_mask()
|
|
if outliers_mask is not None:
|
|
mask = outliers_mask.getRoi(rect)
|
|
roi.mult(mask)
|
|
|
|
outliers_threshold = get_outliers_threshold()
|
|
if outliers_threshold>0:
|
|
roi.threshold(outliers_threshold, False, 0.0)
|
|
"""
|
|
return roi.integrate(False)
|
|
|
|
|
|
class RoiIntensitySourceListener (ImageListener):
|
|
def __init__(self, parent):
|
|
self.parent = parent
|
|
def onImage(self, origin, image, data):
|
|
self.parent.update()
|
|
def onError(self, origin, ex):
|
|
pass
|
|
|
|
|
|
class RoiIntensity(ReadonlyRegisterBase):
|
|
def __init__(self, name, source, x,y, w, h):
|
|
ReadonlyRegisterBase.__init__(self, name)
|
|
self.source=source
|
|
self.roi = x,y, w, h
|
|
self.source_listener = RoiIntensitySourceListener(self)
|
|
|
|
def doRead(self):
|
|
x,y, w, h = self.roi
|
|
return integrate_roi(self.source, x,y, w, h)
|
|
|
|
def doSetMonitored(self, value):
|
|
if value:
|
|
self.source.addListener(self.source_listener)
|
|
else:
|
|
self.source.removeListener(self.source_listener)
|
|
|
|
def doClose(self):
|
|
self.source.removeListener(self.source_listener)
|
|
|
|
def create_roi_devices(roi_list, add = True):
|
|
rois = []
|
|
for r in roi_list:
|
|
roi = RoiIntensity(r, image, roi_list[r][0], roi_list[r][1], roi_list[r][2], roi_list[r][3])
|
|
if add:
|
|
add_device(roi, True)
|
|
rois.append(roi)
|
|
return rois
|
|
|
|
###############################################################################
|
|
# Frame integration
|
|
###############################################################################
|
|
#chrono_grab= Chrono()
|
|
def grab_frame(source, roi=None, wait_next=False, outliers_threshold=None, outliers_mask=None, retries=None, timeout=None):
|
|
global eiger_averaging_number_of_samples #, chrono_grab
|
|
#chrono_grab.waitTimeout(GRAB_MIN_TIME)
|
|
"""
|
|
if outliers_threshold is None:
|
|
outliers_threshold = get_outliers_threshold()
|
|
if outliers_mask is None:
|
|
outliers_mask = get_outliers_mask()
|
|
"""
|
|
if wait_next:
|
|
if retries is None:
|
|
retries = 3
|
|
if timeout is None:
|
|
timeout=10.0
|
|
exposures = 1 if (eiger_averaging_number_of_samples is None) else eiger_averaging_number_of_samples
|
|
retries=max(retries,1)
|
|
timeout = int(((eiger.exposure * exposures) + timeout) * 1000)
|
|
for try_count in range(retries):
|
|
if str(eiger.grabMode)=="Single":
|
|
eiger.waitReady(5000)
|
|
eiger.start()
|
|
elif str(eiger.grabMode)=="Continuous":
|
|
if not eiger.isStarted():
|
|
eiger.start()
|
|
try:
|
|
#eiger.getDataArray().waitCacheChange(timeout)
|
|
source.waitNext(timeout)
|
|
break
|
|
except java.util.concurrent.TimeoutException:
|
|
if try_count == (retries-1):
|
|
raise
|
|
msg = "Eiger timeout - retrying #" + str(try_count)
|
|
print msg
|
|
log(msg)
|
|
|
|
#ret = load_image(Utils.grayscale(source.output, Rectangle(roi[0], roi[1], roi[2], roi[3]) if (roi is not None) else None))
|
|
time.sleep(0.01)
|
|
data=source.data
|
|
if roi is not None:
|
|
data = data.getRoi(Rectangle(roi[0], roi[1], roi[2], roi[3]))
|
|
#ret = load_image(img)
|
|
if outliers_mask is not None:
|
|
data.mult(outliers_mask)
|
|
if outliers_threshold>0:
|
|
data.threshold(outliers_threshold, False, None)
|
|
#chrono_grab = Chrono()
|
|
return data
|
|
|
|
def grab_frames(source, samples, roi=None, wait_next=False, sleep=0, outliers_threshold=None, outliers_mask=None, retries=None, timeout=None):
|
|
frames = []
|
|
for i in range(samples):
|
|
if (i>0) and (sleep>0):
|
|
time.sleep(sleep)
|
|
aux = grab_frame(source, roi, wait_next, outliers_threshold, outliers_mask, retries, timeout)
|
|
frames.append(aux)
|
|
return frames
|
|
|
|
def integrate_frames(frames):
|
|
if frames is None or (len(frames)==0):
|
|
return None
|
|
ret = frames[0].copy()
|
|
for data in frames[1:]:
|
|
ret.sum(data)
|
|
return ret
|
|
|
|
def average_frames(frames):
|
|
ret = integrate_frames(frames)
|
|
if ret is not None:
|
|
ret.div(len(frames))
|
|
return ret
|
|
|
|
|
|
|
|
def _timestamp(prec=0):
|
|
t = time.time()
|
|
s = time.strftime("%y/%m/%d %H:%M:%S", time.localtime(t))
|
|
if prec > 0:
|
|
s += ("%.9f" % (t % 1,))[1:2+prec]
|
|
return s
|
|
|
|
def _save_as_tiff(data, filename, check=False, show = False, metadata={}):
|
|
if type(data) == Data:
|
|
ip = load_array(data.matrix)
|
|
else:
|
|
ip = data
|
|
#info = "Timestamp: " + _timestamp(3)
|
|
#for key,val in metadata.items():
|
|
# info = info + "\n" + str(key) + ": " + str(val)
|
|
#print "Info:" ,info
|
|
#ip.setProperty("Info", info)
|
|
metadata["Timestamp"] = time.strftime("%y/%m/%d %H:%M:%S",time.localtime())
|
|
|
|
if not os.path.exists(os.path.dirname(filename)):
|
|
os.makedirs(os.path.dirname(filename))
|
|
save_image(ip, filename,"tiff", metadata)
|
|
|
|
#finfo = open(filename + ".info", "w")
|
|
#for k, v in metadata.items():
|
|
# finfo.write(str(k) + ': '+ str(v) + '\n')
|
|
#info.close()
|
|
|
|
if check:
|
|
data = get_ip_array(ip)
|
|
import java.util.Arrays as Arrays
|
|
ip=open_image(filename)
|
|
read = get_ip_array(ip)
|
|
#print (" ------> Error reading array: " + str(filename))
|
|
#TODO: Original checkcode was deleted!
|
|
|
|
|
|
calculated_shifts={}
|
|
def save_as_tiff(data, filename, check=False, show = False, parallel=True, metadata={}):
|
|
if parallel:
|
|
return fork((_save_as_tiff,(data, filename, check, show, metadata)),)
|
|
else:
|
|
_save_as_tiff(data, filename, check, show, metadata)
|
|
|
|
def _shift_and_save_as_tiff(data, filename, reference=None, roi=None, image_drift =None, check=False, show = False, metadata={}):
|
|
global calculated_shifts
|
|
try:
|
|
if image_drift is None:
|
|
xoff, yoff, error, diffphase, image_drift = calculate_shift(reference,data, roi)
|
|
print xoff, yoff, error, diffphase, image_drift
|
|
if (abs(xoff) > MAX_SHIFT) or (abs(yoff) > MAX_SHIFT):
|
|
raise Exception("Shift too big:" + str(xoff, yoff))
|
|
print "-> Calculated shift: ", xoff, yoff, error, diffphase
|
|
shifted_frame = apply_shift(data, image_drift)
|
|
calculated_shifts[filename]=image_drift
|
|
except:
|
|
print "-> Error shifting image: " + str(sys.exc_info()[1])
|
|
return
|
|
metadata["roi"] = str(roi)
|
|
save_as_tiff(shifted_frame, filename, check, show, parallel=False, metadata=metadata)
|
|
|
|
def shift_and_save_as_tiff(data, filename, reference=None, roi=None, shift=None, check=False, show = False, parallel=True, metadata={}):
|
|
if parallel:
|
|
return fork((_shift_and_save_as_tiff,(data, filename, reference, roi, shift, check, show, metadata)),)
|
|
else:
|
|
_shift_and_save_as_tiff(data, filename, reference, roi, shift, check, show, metadata)
|
|
|
|
|
|
def trigger_eiger(wait=True):
|
|
eiger.waitReady(5000)
|
|
eiger.start()
|
|
if wait:
|
|
image.waitNext(20000 + int(eiger.exposure * 1000))
|
|
#eiger.waitNewImage(20000 + int(eiger.exposure * 1000))
|
|
|
|
def get_eiger_exposure_readback():
|
|
return caget("X11MA-ES1-SD1:cam1:AcquireTime_RBV",'f')
|
|
|
|
def set_exposure_time(value, check = True, retries=5):
|
|
if value == eiger.getExposure():
|
|
return
|
|
started = eiger.isStarted()
|
|
if started:
|
|
stop_eiger()
|
|
for i in range(retries):
|
|
try:
|
|
eiger.setExposure(value)
|
|
if check:
|
|
readback=get_eiger_exposure_readback()
|
|
if abs(value - readback) > 0.01:
|
|
raise Exception("Error changing Eiger exposure time to %f: readback=%f" % (value, readback))
|
|
except:
|
|
if i==(retries-1):
|
|
raise
|
|
else:
|
|
print "Error changing Eiger exposure time: retrying"
|
|
time.sleep(0.3)
|
|
|
|
if started:
|
|
if eiger.grabMode==eiger.GrabMode.Continuous:
|
|
eiger.start()
|
|
|
|
def get_eiger_number_of_frames():
|
|
return caget("X11MA-ES1-SD1:cam1:NumFrames_RBV",'i')
|
|
|
|
def set_eiger_number_of_frames(value, check = True):
|
|
if value == get_eiger_number_of_frames():
|
|
return
|
|
started = eiger.isStarted()
|
|
if started:
|
|
stop_eiger()
|
|
|
|
caput("X11MA-ES1-SD1:cam1:NumFrames",value)
|
|
if check:
|
|
readback = get_eiger_number_of_frames()
|
|
if value != readback:
|
|
raise Exception("Error changing Eiger number of frames to %d: readback=%d" % (value, readback))
|
|
|
|
if started:
|
|
if eiger.grabMode==eiger.GrabMode.Continuous:
|
|
eiger.start()
|
|
|
|
|
|
#Wait for channel to chenge
|
|
|
|
def stop_eiger():
|
|
global chrono_eiger
|
|
chrono_eiger.waitTimeout(CONTINOUS_MODE_MIN_TIME)
|
|
started = eiger.isStarted()
|
|
if started:
|
|
eiger.stop()
|
|
eiger.grabMode=eiger.GrabMode.Single
|
|
eiger.waitReady(5000)
|
|
else:
|
|
eiger.grabMode=eiger.GrabMode.Single
|
|
time.sleep(0.1)
|
|
#if eiger.acquire.read() >0:
|
|
# raise Exception("Error stopping Eiger")
|
|
|
|
chrono_eiger = Chrono()
|
|
|
|
def init_eiger(exposure=None, check=True, retries=2):
|
|
"""
|
|
Set Eiger scan mode
|
|
"""
|
|
global chrono_eiger
|
|
chrono_eiger.waitTimeout(CONTINOUS_MODE_MIN_TIME)
|
|
for i in range(retries):
|
|
try:
|
|
stop_eiger() #Set mode single
|
|
eiger.setNumImages(1)# Is it relevant?
|
|
set_eiger_number_of_frames(1)
|
|
if exposure:
|
|
set_exposure_time(exposure, check)
|
|
apply_averaging_detector(is_averaging_detector())
|
|
break
|
|
except:
|
|
if i==(retries-1):
|
|
raise
|
|
else:
|
|
print "Error initializing Eiger, retrying: " + str(sys.exc_info()[1])
|
|
|
|
def restore_eiger(check=True, retries=2, exposure_time = 0.2):
|
|
"""
|
|
Set Eiger default mode
|
|
"""
|
|
global chrono_eiger
|
|
for i in range(retries):
|
|
try:
|
|
stop_eiger()
|
|
eiger.setNumImages(1)# Is it relevant?
|
|
set_eiger_number_of_frames(1, check)
|
|
set_exposure_time(exposure_time, check)
|
|
apply_averaging_detector(False)
|
|
eiger.grabMode=eiger.GrabMode.Continuous
|
|
eiger.start()
|
|
chrono_eiger = Chrono()
|
|
break
|
|
except:
|
|
if i==(retries-1):
|
|
raise
|
|
else:
|
|
print "Error restoring Eiger, retrying " + str(sys.exc_info()[1])
|
|
|
|
def is_averaging_detector():
|
|
return str(get_setting("AVERAGING_DETECTOR")).lower()=="true"
|
|
|
|
eiger_averaging_number_of_samples=None
|
|
|
|
def apply_averaging_detector(value):
|
|
global eiger_averaging_number_of_samples
|
|
if value:
|
|
caput("X11MA-ES1-SD1:Proc1:EnableCallbacks", True)
|
|
caput("X11MA-ES1-SD1:Proc1:EnableFilter", True)
|
|
caput("X11MA-ES1-SD1:Proc1:AutoResetFilter", 1)
|
|
caput("X11MA-ES1-SD1:Proc1:FilterCallbacks", 1)
|
|
else:
|
|
caput("X11MA-ES1-SD1:Proc1:EnableFilter", False)
|
|
caput("X11MA-ES1-SD1:Proc1:NumFilter", 1)
|
|
caput("X11MA-ES1-SD1:cam1:NumCycles", 1)
|
|
eiger_averaging_number_of_samples = None
|
|
|
|
|
|
def average_eiger_frames(samples, roi=None, wait_next=False, sleep=0, outliers_threshold=None, outliers_mask=None, retries=None, timeout=None):
|
|
global eiger_averaging_number_of_samples #, chrono_eiger
|
|
sample = int(samples)
|
|
if is_averaging_detector():
|
|
if caget("X11MA-ES1-SD1:Proc1:EnableFilter")!="Enable":
|
|
raise Excetion("Cannot average frames in Eiger: filter is disabled")
|
|
#chrono_eiger.waitTimeout(1000)
|
|
caput("X11MA-ES1-SD1:Proc1:NumFilter", samples)
|
|
caput("X11MA-ES1-SD1:cam1:NumCycles", samples)
|
|
if samples != eiger_averaging_number_of_samples:
|
|
log ("Changed Eiger averaging number of samples: " + str(samples))
|
|
# TODO: if increasing number of samples next read returns quicly, as if using previous sample number
|
|
eiger_averaging_number_of_samples = samples
|
|
caput("X11MA-ES1-SD1:Proc1:ResetFilter", 1)
|
|
chrono_eiger=Chrono()
|
|
return grab_frame(image, roi, wait_next, outliers_threshold, outliers_mask, retries, timeout)
|
|
else:
|
|
ret = grab_frames(image, samples, roi, wait_next, sleep, outliers_threshold, outliers_mask, retries, timeout)
|
|
return average_frames(ret) if samples > 1 else ret[0]
|
|
|
|
|
|
|
|
_outliers_mask_timestamp = 0
|
|
_outliers_mask = None
|
|
|
|
def get_outliers_mask(data_type='f'):
|
|
global _outliers_mask_timestamp, _outliers_mask
|
|
|
|
if get_exec_pars().start == _outliers_mask_timestamp:
|
|
return _outliers_mask
|
|
_outliers_mask_timestamp = get_exec_pars().start
|
|
try:
|
|
_outliers_mask = None
|
|
filename = get_outliers_mask_file()
|
|
if filename:
|
|
ip=open_image(filename)
|
|
|
|
#TRANSPOSE - ImageJ stores the data transposed
|
|
ip.getProcessor().rotate(-90)
|
|
ip.getProcessor().flipVertical()
|
|
|
|
array = get_ip_array(ip)
|
|
array = Convert.toPrimitiveArray(array, ScriptUtils.getType(data_type))
|
|
_outliers_mask = Data(array)
|
|
print "Generated outliers mask"
|
|
except:
|
|
pass
|
|
return _outliers_mask
|
|
|
|
|
|
class ProcImage(Filter):
|
|
def __init__(self):
|
|
Filter.__init__(self, "image_filter")
|
|
self.roi=None
|
|
self.outliers_threshold=None
|
|
self.outliers_mask =None
|
|
|
|
def processData(self, data):
|
|
if data is None:
|
|
return None
|
|
outliers_threshold = get_outliers_threshold() if (self.outliers_threshold is None) else self.outliers_threshold
|
|
outliers_mask = get_outliers_mask() if (self.outliers_mask is None) else self.outliers_mask
|
|
roi = self.roi
|
|
data=data.copy()
|
|
if roi is not None:
|
|
data = data.getRoi(Rectangle(roi[0], roi[1], roi[2], roi[3]))
|
|
#ret = load_image(img)
|
|
if outliers_mask is not None:
|
|
data.mult(outliers_mask)
|
|
if outliers_threshold>0:
|
|
data.threshold(outliers_threshold, False, None)
|
|
#chrono_grab = Chrono()
|
|
return data
|
|
|
|
def process(self, image, data):
|
|
return None #Does not generate BufferedImage here
|
|
|
|
#image.removeAllListeners()
|
|
proc_image_filter=ProcImage()
|
|
raw.addListener(proc_image_filter)
|
|
|
|
proc_image=ColormapAdapter("image", proc_image_filter)
|
|
add_device(proc_image, True)
|
|
raw.refresh()
|
|
|
|
eiger.setDataType(DataType.Float32)
|
|
eiger.getDataArray().monitored=True
|
|
|
|
if False:
|
|
integrate_roi(image, 10, 5, 20, 10)
|
|
|
|
add_device(RoiIntensity("Region1", image, 10, 5, 20, 10), True)
|
|
add_device(RoiIntensity("Region2", image, 10, 5, 40, 20), True)
|
|
|
|
|
|
FormatCSV.setDefaultItemSeparator(" ")
|
|
tscan((Region1, Region2), 10, 0.1, layout="table", format = "csv")
|
|
|
|
ret = grab_frames(image, 10, sleep=0.1)
|
|
av = integrate_frames(ret)
|
|
save_as_tiff(av,"{images}/data.tif", True)
|
|
|
|
|
|
print "Success"
|
|
|
|
|
|
|
|
|