Skip to content
cameraGui.py 13.5 KiB
Newer Older
#!/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 PyQt5 import QtCore, QtGui
from pyqtgraph import dockarea
import pyqtgraph as pg
from pyqtgraph import console
from subclasses.pyqtgraph_subclasses import CustomRectangularROI
from zylaCameraWorker import CameraWorker
from subclasses.controllayouts import LaserControlLayout, LaserScanLayout
from subclasses.cameraParameterFrame import CameraParameterFrame
from resources.scanFunctions import create_measurement_array
from measurement import MeasurementFrame
Martin Drechsler's avatar
Martin Drechsler committed
import logging
LOG = logging.getLogger('Main logger')
GUI_LOG = LOG.getChild('GUI logger')
class CameraGuiMainWindow(QMainWindow):
    
    signalWithMeasurementParameters = QtCore.pyqtSignal(object)
    roiDataReadySignal = QtCore.pyqtSignal(float)
Martin Drechsler's avatar
Martin Drechsler committed
    def __init__(self):
        self.counter = 0
        self.frames_checker_timer = QtCore.QTimer()
        self.initUI()
Martin Drechsler's avatar
Martin Drechsler committed
    def initUI(self):
Martin Drechsler's avatar
Martin Drechsler committed
        GUI_LOG.info('Initializing gui')
        self.win = QtGui.QMainWindow()
Martin Drechsler's avatar
Martin Drechsler committed
        self.win.setWindowTitle("Camera GUI")
        self.win.setWindowIcon(QtGui.QIcon('Butter_robot.png'))

        self.win.resize(1000, 500)

        self.area = dockarea.DockArea()
        self.win.setCentralWidget(self.area)
        self.cw = QtGui.QWidget()
        self.win.show()

        self.dCameraView = dockarea.Dock("Zyla Camera View")
        self.dCameraTimeAnal = dockarea.Dock("Zyla Camera Time Analysis")
        self.dCameraControl = dockarea.Dock("Zyla Camera Control")
        self.dMeasurement = dockarea.Dock("Measurement and saving")
        self.dConsole = dockarea.Dock("Console for debugging")
        self.dCameraScanAnal = dockarea.Dock("Zyla Camera Scan Analysis")
        
        self.area.addDock(self.dCameraView)
        self.area.addDock(self.dCameraScanAnal, "left", self.dCameraView)
Martin Drechsler's avatar
Martin Drechsler committed
        self.area.addDock(self.dCameraTimeAnal, "below", self.dCameraScanAnal)
        self.area.addDock(self.dCameraControl, "right", self.dCameraView)
Martin Drechsler's avatar
Martin Drechsler committed
        self.area.addDock(self.dConsole, "right", self.dCameraControl)
        self.area.addDock(self.dMeasurement, "above", self.dConsole)

        #measurement frame
        self.measurementFrame = MeasurementFrame()
        self.dMeasurement.addWidget(self.measurementFrame)
        
Martin Drechsler's avatar
Martin Drechsler committed
        # button spinbox and label
        self.cameraButton = QPushButton("Start Acquisition")
        self.isCameraAcquiring = False
        self.dCameraControl.addWidget(self.cameraButton)
        self.label = QLabel("Counter of frames")
        self.dCameraView.addWidget(self.label)
        #self.param_tree = CameraParameterTree()
        self.cameraParamFrame = CameraParameterFrame()  
        self.cameraParamFrame.paramTree.load()
        self.dCameraControl.addWidget(self.cameraParamFrame)
        self.ImageLayout = pg.GraphicsLayoutWidget()
        self.imageView = self.ImageLayout.addViewBox()
        self.timeAnalysisLayout = pg.GraphicsLayoutWidget()
        self.scanAnalysisLayout = pg.GraphicsLayoutWidget()
        
        # image layout
        self.img = pg.ImageItem(border="w")
        self.img.rotate(90)
        self.imv = pg.ImageView(imageItem=self.img, view=self.imageView)
        self.imv.ui.roiBtn.setText('Useless')
        self.dCameraView.addWidget(self.imv)
        # time analysis layout
        self.dCameraTimeAnal.addWidget(self.timeAnalysisLayout)
        self.timePlot = self.timeAnalysisLayout.addPlot(row=0, col=0, title="Time plot")
        self.timePlot.setRange(QtCore.QRectF(0, 0, 50, 255))
        self.timePlot.setAutoPan(y=True)
        # self.p.setRange(xRange = (0, 10), yRange = (0, 255))
        self.timeCurve = self.timePlot.plot(pen="y")

        # scan analysis layout
        self.dCameraScanAnal.addWidget(self.scanAnalysisLayout)
        self.scanPlot = self.scanAnalysisLayout.addPlot(row=0, col=0, title="Scan plot")
        self.scanPlot.setRange(QtCore.QRectF(0, 0, 50, 255))
        self.scanPlot.setAutoPan(y=True)
        # self.p.setRange(xRange = (0, 10), yRange = (0, 255))
        self.scanCurve = self.scanPlot.plot(pen="y")
Martin Drechsler's avatar
Martin Drechsler committed
        # rOI
        self.rois.append(CustomRectangularROI([0, 0]))
        self.timeROIdataY = np.zeros(2000)
        self.scanROIdataX = np.linspace(0, 1, 2000)
        self.scanROIdataY = np.zeros(2000)
        self.current_image_size = 2048
Martin Drechsler's avatar
Martin Drechsler committed
    def make_connections(self, backend):
Martin Drechsler's avatar
Martin Drechsler committed
        # backend connections
Martin Drechsler's avatar
Martin Drechsler committed
        backend.imageReadySignal.connect(self.updateImage)
        backend.measurementStartingSignal.connect(self.measurement_starting)
        backend.measurementEndingSignal.connect(self.measurement_ending)
        
Martin Drechsler's avatar
Martin Drechsler committed
        # internal connections
Martin Drechsler's avatar
Martin Drechsler committed
        self.frames_checker_timer.timeout.connect(self.frame_counter)
Martin Drechsler's avatar
Martin Drechsler committed
        self.cameraButton.clicked.connect(self.camera_button_pressed)
Martin Drechsler's avatar
Martin Drechsler committed
        self.console = console.ConsoleWidget(
            namespace = {'np': np, 'cam': backend.cam, 'roi': self.rois[0], 
                         'storage': backend.storage, 'param_tree': self.cameraParamFrame.paramTree,
                         'gui': self
Martin Drechsler's avatar
Martin Drechsler committed
        )
        self.dConsole.addWidget(self.console)
        self.measurementFrame.startMeasureButton.clicked.connect(self.emit_measurement_parameters_and_start)
        self.measurementFrame.folderButton.clicked.connect(self.measurementFrame.select_folder)
        self.measurementFrame.selectScanSignal.activated[str].connect(self.measurementFrame.configure_spinBoxes)   
        self.measurementFrame.startValue.valueChanged.connect(self.measurementFrame.update_tree)
        self.measurementFrame.endValue.valueChanged.connect(self.measurementFrame.update_tree)
        self.measurementFrame.stepsNum.valueChanged.connect(self.measurementFrame.update_tree)
        self.measurementFrame.saveMeasureButton.clicked.connect(
                lambda: self.measurementFrame.saveMeasureButton.setEnabled(False)
                )
        self.measurementFrame.abortMeasureButton.clicked.connect(backend.abort_measurement)
Martin Drechsler's avatar
Martin Drechsler committed
        for roi in self.rois:
            self.cameraParamFrame.saveRoiButton.clicked.connect(lambda: roi.save(
                current_binning=self.cameraParamFrame.paramTree.p.child('Basic acq parameters')
            .child('Pixel Binning').value() ))
            self.cameraParamFrame.loadRoiButton.clicked.connect(lambda: roi.load(
                current_binning=self.cameraParamFrame.paramTree.p.child('Basic acq parameters')
            .child('Pixel Binning').value() ))
            
            roi.sigRegionChanged.connect(self.cameraParamFrame.updateRoiSpinBoxes)
            
Martin Drechsler's avatar
Martin Drechsler committed
    
    def camera_button_pressed(self):

        if self.isCameraAcquiring:
Martin Drechsler's avatar
Martin Drechsler committed
            self.frames_checker_timer.stop()
            self.cameraButton.setText('Start Acquisition')
            self.measurementFrame.startMeasureButton.setEnabled(True)
            self.isCameraAcquiring = False
Martin Drechsler's avatar
Martin Drechsler committed
            self.cameraParamFrame.paramTree.t.setEnabled(True)
Martin Drechsler's avatar
Martin Drechsler committed
        else:
Martin Drechsler's avatar
Martin Drechsler committed
            self.repositionRoi(self.current_image_size)
            self.scanROIdataX = np.linspace(0, 1, 10000)
            self.scanROIdataY = np.zeros(10000)
            self.timeROIdataY = np.zeros(10000)
            self.cameraButton.setText('Stop Acquisition')
            self.measurementFrame.startMeasureButton.setEnabled(False)
Martin Drechsler's avatar
Martin Drechsler committed
            self.frame_index = 0
            self.previous_frame_index = 0
            self.frames_checker_timer.start(1000)
            self.isCameraAcquiring = True
Martin Drechsler's avatar
Martin Drechsler committed
            self.cameraParamFrame.paramTree.t.setEnabled(False)
Martin Drechsler's avatar
Martin Drechsler committed

Martin Drechsler's avatar
Martin Drechsler committed
    def _initialize_image(self):
Martin Drechsler's avatar
Martin Drechsler committed
        # lock the aspect ratio so pixels are always square
        self.imageView.setAspectLocked(True)
        self.imageView.addItem(self.img)
        self.frame_index = 0
        self.previous_frame_index = 0
        self.frames_checker_timer.start(1000)
        for roi in self.rois:
            roiSlice = roi.getArrayRegion(self.img.image, img=self.img)
            self.newData = np.mean(roiSlice)
            if self.isMeasuring:
                self.roiDataReadySignal.emit(self.newData)
            self.timeROIdataY = np.roll(self.timeROIdataY, -1)
            self.scanROIdataY[self.iROIdata] = self.newData
            self.timeROIdataY[-1] = self.newData
            self.iROIdata = np.mod(self.frame_index + 1, len(self.timeROIdataY))
            self.timeCurve.setData(self.timeROIdataY)
            self.scanCurve.setData(self.scanROIdataX, self.scanROIdataY)
Martin Drechsler's avatar
Martin Drechsler committed
    def repositionRoi(self, old_size):
        aux_dict = {'1x1': 2048, '2x2': 1024, '4x4': 512, '8x8': 256}
Martin Drechsler's avatar
Martin Drechsler committed
        new_size = aux_dict[
            self.cameraParamFrame.paramTree.p.child('Basic acq parameters')
Martin Drechsler's avatar
Martin Drechsler committed
            .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)
Martin Drechsler's avatar
Martin Drechsler committed
    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)
            )
        self.img.setImage(image, autoDownsample=True, autoHistogramRange=False, autoLevels=False,
                 autoRange=False)
        self.frame_index = self.frame_index + 1
Martin Drechsler's avatar
Martin Drechsler committed
    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)
        )
Martin Drechsler's avatar
Martin Drechsler committed
        self.previous_frame_index = self.frame_index
    #@QtCore.pyqtSlot()
    def measurement_starting(self):
        self.cameraButton.setEnabled(False)
        self.measurementFrame.startMeasureButton.setEnabled(False)
        start = self.measurementFrame.startValue.value()
        end = self.measurementFrame.endValue.value()
        steps = self.measurementFrame.stepsNum.value()
    
        self.frame_index = 0
        self.iROIdata = 0
        self.scanROIdataX = create_measurement_array(start, end, steps)
        self.scanROIdataY = np.zeros(steps)
        self.timeROIdataY = np.zeros(steps)
                
        for l in LaserControlLayout._registry + LaserScanLayout._registry :
            l.freeze()
            
        print('gui meas start')
    #@QtCore.pyqtSlot()
    def measurement_ending(self):
        print('entering gui measure ending')
        self.cameraButton.setEnabled(True)
        self.measurementFrame.startMeasureButton.setEnabled(True)
        self.measurementFrame.saveMeasureButton.setEnabled(True)
        
        scanned_sb_name = self.measurementFrame.selectScanSignal.currentText()
        
        for l in LaserControlLayout._registry + LaserScanLayout._registry :
            l.unfreeze()
            for sb_name, sb in l.spinboxes.items():
                if sb_name == scanned_sb_name:
                    sb.setValue(self.measurementFrame.endValue.value())
                
        print('gui meas end')

        plot = pg.plot(self.scanROIdataX, self.scanROIdataY)
        plot.setLabel('bottom', 'X Axis', self.measurementFrame.selectScanSignal.currentText())
        plot.setLabel('left', 'Y Axis', 'Counts')


Martin Drechsler's avatar
Martin Drechsler committed
    def __del__(self):
    def emit_measurement_parameters_and_start(self):
        measure_params = dict()
        measure_params['signal_to_scan'] = self.measurementFrame.selectScanSignal.currentText()
        measure_params['start'] = self.measurementFrame.startValue.value()
        measure_params['end'] = self.measurementFrame.endValue.value()
        measure_params['steps'] = self.measurementFrame.stepsNum.value()
        measure_params['directory'] = self.measurementFrame.folderBrowser.toPlainText()
        measure_params['comment'] = self.measurementFrame.comments.toPlainText()
        for roi in self.rois:
            measure_params['Roi Pos'] = roi.pos()
            measure_params['Roi Size'] = roi.size()
            

        self.signalWithMeasurementParameters.emit(measure_params)
###############################################################################

if __name__ == "__main__":
    app = QtGui.QApplication([])
    myGuiMainWindow = CameraGuiMainWindow()
    cameraWorker = CameraWorker(andor_camera=camera)
    cameraWorker.make_connections(myGuiMainWindow)
    myGuiMainWindow.make_connections(cameraWorker)

    cameraThread = QtCore.QThread()
    cameraWorker.moveToThread(cameraThread)
    measurementGui = MeasurementGui()
    MeasurementWorker = MeasurementWorker(camera)
    myGuiMainWindow.dMeasurement.addWidget(measurementGui)