Commit 5ae7e63b authored by Martin Drechsler's avatar Martin Drechsler

readme deleted

parents 86feb45d b7572d61
# total_control_app
# -*- coding: utf-8 -*-
"""
Created on Mon Jan 11 16:14:02 2016
@author: Admin
"""
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Apr 4 10:35:32 2019
@author: martindrech
"""
from PyQt5.QtWidgets import QMainWindow, QPushButton, QLabel
from pyqtgraph.Qt import QtGui, QtCore
from pyqtgraph import dockarea
import pyqtgraph as pg
from pyqtgraph import console
from pyqtgraph_subclasses import CustomRectangularROI
from zylaCameraWorker import CameraWorker
from cameraParameterTree import CameraParameterTree
from drivers.andorzyla import AndorZyla
#from dummyAndor import AndorZyla
import sys
import numpy as np
class CameraGuiMainWindow(QMainWindow):
def __init__(self):
super().__init__()
# self.__init__
self.counter = 0
self.frames_checker_timer = QtCore.QTimer()
self.initUI()
def initUI(self):
self.win = QtGui.QMainWindow()
self.win.setWindowTitle("Toy GUI")
self.win.resize(1000, 500)
self.area = dockarea.DockArea()
self.win.setCentralWidget(self.area)
self.cw = QtGui.QWidget()
self.win.show()
self.d1 = dockarea.Dock("Zyla Camera View")
self.d2 = dockarea.Dock("Zyla Camera Analysis")
self.d3 = dockarea.Dock("Zyla Camera Control")
self.d4 = dockarea.Dock("Measurement and saving")
self.area.addDock(self.d1)
self.area.addDock(self.d2, "left", self.d1)
self.area.addDock(self.d3, "right", self.d1)
self.area.addDock(self.d4, "bottom", self.d3)
# button spinbox and label
self.cameraButton = QPushButton("Start Acquisition")
self.isCameraAcquiring = False
self.d3.addWidget(self.cameraButton)
self.label = QLabel("Counter of frames")
self.d1.addWidget(self.label)
self.param_tree = CameraParameterTree()
self.d3.addWidget(self.param_tree.t)
# layouts and viewboxes
self.ImageLayout = pg.GraphicsLayoutWidget()
self.view = self.ImageLayout.addViewBox()
self.AnalysisLayout = pg.GraphicsLayoutWidget()
# image layout
self.img = pg.ImageItem(border="w")
self.imv = pg.ImageView(imageItem=self.img, view=self.view)
self.imv.ui.roiBtn.setText('Useless')
self.d1.addWidget(self.imv)
# analysis layout
self.d2.addWidget(self.AnalysisLayout)
self.p = self.AnalysisLayout.addPlot(row=0, col=0, title="Time plot")
self.p.setRange(QtCore.QRectF(0, 0, 50, 255))
self.p.setAutoPan(y=True)
# self.p.setRange(xRange = (0, 10), yRange = (0, 255))
self.curve = self.p.plot(pen="y")
# rOI
self.rois = []
self.rois.append(CustomRectangularROI([0, 0]))
for r in self.rois:
self.view.addItem(r)
# r.sigRegionChanged.connect(self.updateRoi)
self.ROIdata = np.zeros(1000)
self.iROIdata = 0
self.current_image_size = 2048
self._initialize_image()
def make_connections(self, backend):
# backend connections
backend.imageReadySignal.connect(self.updateImage)
# internal connections
self.frames_checker_timer.timeout.connect(self.frame_counter)
self.cameraButton.clicked.connect(self.camera_button_pressed)
self.console = console.ConsoleWidget(
namespace = {'np': np, 'cam': backend.cam, 'roi': self.rois[0]}
)
self.d4.addWidget(self.console)
def camera_button_pressed(self):
if self.isCameraAcquiring:
self.frames_checker_timer.stop()
self.cameraButton.setText('Start Acquisition')
self.isCameraAcquiring = False
else:
self.repositionRoi()
self.cameraButton.setText('Stop Acquisition')
self.frame_index = 0
self.previous_frame_index = 0
self.frames_checker_timer.start(1000)
self.isCameraAcquiring = True
def _initialize_image(self):
# lock the aspect ratio so pixels are always square
self.view.setAspectLocked(True)
self.view.addItem(self.img)
self.frame_index = 0
self.previous_frame_index = 0
self.frames_checker_timer.start(1000)
def updateRois(self):
for roi in self.rois:
roiSlice = roi.getArrayRegion(self.img.image, img=self.img)
self.newData = roiSlice.sum()
self.ROIdata[self.iROIdata] = self.newData
self.iROIdata = np.mod(self.frame_index + 1, len(self.ROIdata))
self.curve.setData(self.ROIdata)
def repositionRoi(self):
old_size = self.current_image_size
aux_dict = {'1x1': 2048, '2x2': 1024, '4x4': 512, '8x8': 256}
new_size = aux_dict[
self.param_tree.p.child('Basic acq parameters')
.child('Pixel Binning').value()
]
print('sizes:', old_size, new_size)
for roi in self.rois:
x, y, sx, sy = roi.pos()[0], roi.pos()[1], roi.size()[0], roi.size()[1]
new_x, new_y = new_size/old_size * x, new_size/old_size * y
new_sx, new_sy = new_size/old_size * sx, new_size/old_size * sy
roi.setPos([new_x, new_y])
roi.setSize([new_sx, new_sy])
@QtCore.pyqtSlot(np.ndarray, int)
def updateImage(self, image, acq_index):
if self.frame_index is not 0 and not self.frame_index == acq_index:
print(
"Dephasing in camera gui has occured: while frame index is %i, the acq index is %i"
% (self.frame_index, acq_index)
)
# n = 1024
self.img.setImage(image, autoDownsample=True)
self.updateRois()
self.frame_index = self.frame_index + 1
self.current_image_size = image.shape[0]
def frame_counter(self):
self.counter = self.counter + 1
self.label.setText(
"Frames in last second: "
+ str(self.frame_index - self.previous_frame_index)
+ " "
+ "Seconds since start: "
+ str(self.counter)
)
self.previous_frame_index = self.frame_index
def __del__(self):
print("chau gui")
###############################################################################
if __name__ == "__main__":
app = QtGui.QApplication([])
camera = AndorZyla(0)
myGuiMainWindow = CameraGuiMainWindow()
cameraWorker = CameraWorker(andor_camera=camera)
cameraWorker.make_connections(myGuiMainWindow)
myGuiMainWindow.make_connections(cameraWorker)
cameraThread = QtCore.QThread()
cameraWorker.moveToThread(cameraThread)
cameraThread.start()
sys.exit(app.exec_())
# -*- coding: utf-8 -*-
"""
This example demonstrates the use of pyqtgraph's parametertree system. This provides
a simple way to generate user interfaces that control sets of parameters. The example
demonstrates a variety of different parameter types (int, float, list, etc.)
as well as some customized parameter types
"""
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph.parametertree.parameterTypes as pTypes
from pyqtgraph.parametertree import Parameter, ParameterTree, ParameterItem, registerParameterType
app = QtGui.QApplication([])
## test subclassing parameters
## This parameter automatically generates two child parameters which are always reciprocals of each other
class BasicAcquisitonParameters(pTypes.GroupParameter):
def __init__(self, **opts):
super().__init__(**opts)
self.addChild({'name': 'Camera name', 'type': 'str', 'value': ' ', 'readonly': True})
self.addChild({'name': 'Acquisition mode', 'type': 'list', 'values': ['acq1', 'acq2']})
self.addChild({'name': 'Pixel Binning', 'type': 'list', 'values': ['1x1', '2x2', '4x4', '8x8']})
self.addChild({'name': 'Image Area', 'type': 'list', 'values': ['2048x2048', '1024x1024', '512x512', '256x256'], 'readonly': True})
self.addChild({'name': 'Exposure Time', 'type': 'float', 'value': .1, 'suffix': 's', 'siPrefix': True, 'step': 0.05})
self.addChild({'name': 'Frame Rate', 'type': 'float', 'value': 0, 'readonly': True})
#exposure time and frame rate connected because they are the inverse of each other
#later, they should be set so that the framerate is the maximum possible value given an exposure time
# self.exposureTimeWidget = self.param('Exposure Time')
# self.frameRateWidget = self.param('Frame Rate')
# self.exposureTimeWidget.sigValueChanged.connect(self.expTimeChanged)
# self.frameRateWidget.sigValueChanged.connect(self.frameRateChanged)
#set image area according to binning
self.param('Pixel Binning').sigValueChanged.connect(self.binningChanged)
# def expTimeChanged(self):
# self.frameRateWidget.setValue(1.0 / self.exposureTimeWidget.value(), blockSignal=self.frameRateChanged)
# def frameRateChanged(self):
# self.exposureTimeWidget.setValue(1.0 / self.frameRateWidget.value(), blockSignal=self.expTimeChanged)
def binningChanged(self):
if self.param('Pixel Binning').value() == '1x1':
self.param('Image Area').setValue('2048x2048')
if self.param('Pixel Binning').value() == '2x2':
self.param('Image Area').setValue('1024x1024')
if self.param('Pixel Binning').value() == '4x4':
self.param('Image Area').setValue('512x512')
if self.param('Pixel Binning').value() == '8x8':
self.param('Image Area').setValue('256x256')
class BasicActionParameters(pTypes.GroupParameter):
def __init__(self, **opts):
super().__init__(**opts)
self.addChild({'name': 'Save State', 'type': 'action'})
self.addChild({'name': 'Restore State', 'type': 'action'})
class CameraParameterTree(ParameterTree):
def __init__(self):
super().__init__()
self.params = [
BasicAcquisitonParameters(name = 'Basic acq parameters'),
BasicActionParameters(name = 'Save/Restore functionality')
]
self.p = Parameter.create(name='params', type='group', children=self.params)
self.p.sigTreeStateChanged.connect(self.change)
self.p.param('Save/Restore functionality', 'Save State').sigActivated.connect(self.save)
self.p.param('Save/Restore functionality', 'Restore State').sigActivated.connect(self.restore)
self.t = ParameterTree()
self.t.setParameters(self.p, showTop=False)
self.t.setWindowTitle('Parameter Tree')
def change(self, param, changes):
print("tree changes:")
for param, change, data in changes:
path = self.p.childPath(param)
if path is not None:
childName = '.'.join(path)
else:
childName = param.name()
print(' parameter: %s'% childName)
print(' change: %s'% change)
print(' data: %s'% str(data))
print(' ----------')
def save(self):
self.state = self.p.saveState()
def restore(self):
self.p.restoreState(self.state)
## Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
import sys
param_tree = CameraParameterTree()
win = QtGui.QWidget()
layout = QtGui.QGridLayout()
win.setLayout(layout)
layout.addWidget(QtGui.QLabel("Explanation of parameter tree."), 0, 0, 1, 2)
layout.addWidget(param_tree.t)
win.show()
win.resize(400,800)
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
This diff is collapsed.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Apr 6 22:17:00 2019
@author: martindrech
"""
import numpy as np
from PyQt5 import QtCore
import time
import threading
from queue import Queue
class Helper_messager(QtCore.QObject):
imageAquiredSignal = QtCore.pyqtSignal(int)
class AndorZyla:
def __init__(self, num):
self.ExposureTime = AndorFeats()
self.FrameRate = AndorFeats()
self.CameraAcquiring = AndorFeats()
self.AOIBinning = AndorFeats()
self.ImageArea = AndorFeats()
self.CameraModel = AndorFeats()
self.acq_queue = Queue(maxsize=10)
self.helper = Helper_messager()
self.current_image = None
self.CameraAcquiring.setValue(False)
self.acq_index_i = 0
self.ExposureTime.setValue(0.5)
self.FrameRate.setValue(10)
self.AOIBinning.setValue('1x1')
self.ImageArea.setValue(2048)
self.CameraModel.setValue('dummy')
def Init(self):
print("Dummy camera initialized")
def live_acquisition_loop(self):
t = threading.currentThread()
while getattr(t, "do_run", True):
self.current_image = self._twoD_gaussian()
self.acq_queue.put(self.current_image)
self.helper.imageAquiredSignal.emit(self.acq_index_i)
self.acq_index_i = self.acq_index_i + 1
time.sleep(self.ExposureTime.getValue())
print("stopping acq loop thread")
def live_acquisition_configure(self):
self.acq_index_i = 0
def AcquisitionStart(self):
self.CameraAcquiring.setValue(True)
self._set_image_area()
def AcquisitionStop(self):
self.CameraAcquiring.setValue(False)
def _flush(self):
pass
def _set_image_area(self):
d = {'1x1': 2048, '2x2': 1024, '4x4': 512, '8x8': 256}
self.ImageArea.setValue(d[self.AOIBinning.getValue()])
def _twoD_gaussian(self, lim=10, sigma=1, x0=0, y0=0):
start = time.time()
N = self.ImageArea.getValue()
x, y = np.meshgrid(np.linspace(-lim, lim, N), np.linspace(-lim, lim, N))
d = np.sqrt((x - x0) ** 2 + (y - y0) ** 2)
g = np.exp(-((d) ** 2 / (2.0 * sigma ** 2)))
noise = np.random.rand(N, N)
end = time.time()
time.sleep(self.ExposureTime.getValue())
return noise * 10
class AndorFeats:
def __init__(self):
self.value = None
def getValue(self):
return self.value
def setValue(self, val):
self.value = val
def _twoD_gaussian(self, lim=10, N=100, sigma=1, x0=0, y0=0):
x, y = np.meshgrid(np.linspace(-lim, lim, N), np.linspace(-lim, lim, N))
d = np.sqrt((x - x0) ** 2 + (y - y0) ** 2)
g = np.exp(-((d) ** 2 / (2.0 * sigma ** 2)))
noise = np.random.rand(N, N)
return g + noise
def max(self):
return 0
def setString(self, s):
self.value = s
\ No newline at end of file
# -*- coding: utf-8 -*-
"""
Some sub-classes from pyqtgraph.
"""
from pyqtgraph import ROI
class CustomRectangularROI(ROI):
"""
Rectangular ROI subclass with a single scale handle at the top-right corner.
============== =============================================================
**Arguments**
pos (length-2 sequence) The position of the ROI origin.
See ROI().
size (length-2 sequence) The size of the ROI. See ROI().
centered (bool) If True, scale handles affect the ROI relative to its
center, rather than its origin.
sideScalers (bool) If True, extra scale handles are added at the top and
right edges.
**args All extra keyword arguments are passed to ROI()
============== =============================================================
"""
def __init__(self, pos, size = [8, 8], centered=False, sideScalers=False):
#ROI.__init__(self, pos, size, **args)
super().__init__(pos, size, centered, sideScalers)
## handles scaling horizontally around center
self.addScaleHandle([1, 0.5], [0.5, 0.5])
self.addScaleHandle([0, 0.5], [0.5, 0.5])
## handles scaling vertically from opposite edge
self.addScaleHandle([0.5, 0], [0.5, 1])
self.addScaleHandle([0.5, 1], [0.5, 0])
## handles scaling both vertically and horizontally
self.addScaleHandle([1, 1], [0, 0])
self.addScaleHandle([0, 0], [1, 1])
#self.sigRegionChangeFinished.connect(self.correct_scaling)
def correct_scaling(self):
x, y = self.pos()[0], self.pos()[1]
if x%8 != 0 or y%8 != 0:
self.setPos((x//8)*8, (y//8)*8)
sx, sy = self.size()[0], self.size()[1]
if sx%8 != 0 or sy%8 != 0:
self.setSize((sx//8)*8, (sy//8)*8)
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Apr 4 11:10:20 2019
@author: martindrech
"""
import numpy as np
from PyQt5 import QtCore
# from drivers.andorzyla import AndorZyla
from dummyAndor import AndorZyla
import threading
class CameraWorker(QtCore.QObject):
imageReadySignal = QtCore.pyqtSignal(np.ndarray, int)
def __init__(self, andor_camera):
super().__init__()
self.cam = andor_camera
self.cam.Init()
print("camera worker initialized")
def make_connections(self, frontend):
# frontend connections
params = frontend.param_tree.p
frontend.cameraButton.clicked.connect(lambda: self.run(params))
# internal connections
self.cam.helper.imageAquiredSignal.connect(self.new_image_acquired)
def __del__(self):
print("adios camera worker")
# @QtCore.pyqtSlot()
def run(self, params):
if self.cam.CameraAcquiring.getValue():
self._stop_acquisition_loop()
print("acquisition now stopping")
else:
self._configure_acq_parameters(params)
self._start_acquisition_loop()
self.acq_thread = threading.Thread(
target=self.cam.live_acquisition_loop
)
self.acq_thread.start()
print("acquisiting now starting")
def _start_acquisition_loop(self):
self.cam.live_acquisition_configure()
self.cam.AcquisitionStart()
print("frame rate: ", self.cam.FrameRate.getValue())
print("Exp time: ", self.cam.ExposureTime.getValue())
def _stop_acquisition_loop(self):
self.acq_thread.do_run = False
self.acq_thread.join()
self.cam.AcquisitionStop()
self.cam._flush()
def _configure_acq_parameters(self, params):
print('Acq parameters: ')
for p in params.children()[0].children():
print(p.name(), p.value())
params.child('Basic acq parameters').child('Camera name').setValue(
self.cam.CameraModel.getValue())
self.cam.ExposureTime.setValue(
params.child('Basic acq parameters').child('Exposure Time').value()
)
self.cam.FrameRate.setValue(self.cam.FrameRate.max())
params.child('Basic acq parameters').child('Frame Rate').setValue(
self.cam.FrameRate.getValue())
self.cam.AOIBinning.setString(
params.child('Basic acq parameters').child('Pixel Binning').value()
)
@QtCore.pyqtSlot(int)
def new_image_acquired(self, acq_index):
self.imageReadySignal.emit(self.cam.acq_queue.get(), acq_index)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment