class PhaseNetworkElements(QWidget): def __init__(self, camera=None, log=None, fps=10.): super().__init__() self.feedback = False # --- --- # if log != None: self.log = log else: self.log = LogDisplay() #self.log.showLog() # --- default --- # self.fps = fps self.cmap = 'jet' self.sepration = ' ' self.param_peak= [] # a N x 3 array where each line is [x0, a, b] the parameter of the fit, N being the number of peaks. self.dicspan = {} self.postprocss_func = None self.procssfunc_default = True # --- main attriute --- # self.camera = camera if not self.camera.isCameraInit: self.camera.__init__(cam_id=0, log=self.log) self.qlabl_max = QLabel() self.dataframe = np.zeros([10,10]) # --- --- # self.initUI() def initUI(self): self.splitter = QSplitter(PyQt5.QtCore.Qt.Horizontal) self.fitting_frame = None # --- --- # self.layout = QVBoxLayout(self) # --- guassian fit init --- # self.gaussianfit = GaussianFit(log=self.log) self.gaussian_plots = {} self.fittingactivate = QCheckBox() self.fittingactivate.setTristate(False) self.fittingactivate.stateChanged.connect(self.acceptOrNot) # --- init frames --- # self.initView() self.initParameterZone() self.initVertHistogram() self.initMultiplotPeak() self.initLissajousPlot() # --- default --- # self.updatePtNbrLabel() # --- layout --- # vsplitter = QSplitter(PyQt5.QtCore.Qt.Vertical) vsplitter.addWidget( self.camera_view ) vsplitter.addWidget( self.paramFrame ) self.splitter.addWidget( vsplitter ) self.splitter.addWidget( self.histogFrame ) self.splitter.addWidget( self.multiplotFrame ) vsplitter = QSplitter(PyQt5.QtCore.Qt.Vertical) vsplitter.addWidget( self.lissajousFrame ) vsplitter.addWidget( QFrame() ) self.splitter.addWidget( vsplitter ) self.layout.addWidget( self.splitter ) self.setLayout(self.layout) # --- --- # def initView(self): self.camera_view = CameraDisplay(camera=self.camera, log=self.log) # --- --- # self.camera_view.image_view.setMinimumWidth(100) self.camera_view.image_view.setMinimumHeight(200) def initParameterZone(self): self.paramFrame = QFrame() self.paramFrame.setToolTip('Frame where we control the main parameter for the data sampling.') self.paramFrame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised) self.paramFrame.setLineWidth(3) self.paramFrame.setMidLineWidth(1) # --- widgets --- # self.histogram_data = QComboBox() self.histogram_data.addItem('raw') self.histogram_data.addItem('remove backgrnd') self.histogram_data.addItem('normalise') self.histogram_data.setCurrentIndex(0) self.histrealtime = QCheckBox() self.histrealtime.setTristate(False) self.histrealtime.setCheckState(2) self.setLinkToCameraTimer() self.button_save = QPushButton('Save sampling data') self.button_save.setToolTip('Save the plots in the milti-plot window in a txt file such that each line corresponds to the y-data. Moreover we save the total intensity.') self.savefile = QFileDialog(self) self.savefile_name = QLabel('Select a file') self.savefile_name.setWordWrap(True) self.choosedirectory = QPushButton('&Change file') self.postprocss = QComboBox() self.postprocss.addItem('Max peak') self.postprocss.addItem('Sum area span') # --- connections --- # self.choosedirectory.clicked.connect(self.setNewSaveFile) self.button_save.clicked.connect( self.saveDataFromMultiplot ) self.histrealtime.stateChanged.connect( self.setLinkToCameraTimer ) self.histogram_data.currentIndexChanged.connect( self.setHistgrmPlotRange ) self.postprocss.currentIndexChanged.connect( self.setPostProcessFunction ) # --- make layout --- # label_1 = QLabel('Histogram data: ') label_1.setWordWrap(True) label_1.setToolTip('Set what transformation we operate from the image data to the histogram data.\n"raw" means we integrate over the Y-axis and divide by the number of line.\n"normalise" like "raw" but we normalise to the maximum afterward.') label_2 = QLabel('Histogram in continuous mode: ') label_2.setWordWrap(True) label_2.setToolTip('When unchecked, stop the updating of the histogram. In other words, allow to stop the histogram without stopping the video image.') label_3 = QLabel('Sampling post-processing: ') label_3.setWordWrap(True) label_3.setToolTip('The post-processing refer to the data processing from the vertivcal histogram of the image.') grid = QGridLayout() grid.addWidget(label_1 , 1,0) grid.addWidget( self.histogram_data , 1,1) grid.addWidget(label_2 , 0,0) grid.addWidget( self.histrealtime , 0,1) grid.addWidget(label_3 , 2,0) grid.addWidget(self.postprocss , 2,1) grid.addWidget( QHLine() , 3,0 , 1,2) grid.addWidget( self.button_save , 4,0 , 1,2) grid.addWidget( self.choosedirectory , 5,0) grid.addWidget(self.savefile_name , 5,1) self.paramFrame.setLayout( grid ) def initVertHistogram(self): self.plot_hist = pg.PlotWidget() self.plot_hist.setMinimumHeight(600) self.plot_hist.setMinimumWidth(100) plot_viewbox = self.plot_hist.getViewBox() plot_viewbox.invertX(True) self.plot_hist.showAxis('right') self.plot_hist.hideAxis('left') self.plot_hist.showGrid(x=True) plot_viewbox.setAspectLocked(False) plot_viewbox.enableAutoRange(pg.ViewBox.YAxis, enable=True) # --- measured data --- # self.data_hist = pg.PlotDataItem() self.plot_hist.addItem(self.data_hist) # --- widgets --- # self.spanNumber = QSpinBox()#QPushButton('add new span') self.spanNumber.setMaximum(20) self.spanNumber.setValue(0) self.spanNumber.valueChanged.connect( self.makeSpans ) # --- make layout --- # self.histogFrame = QFrame() self.histogFrame.setToolTip('Vertical histogram of the image. We integrated over the Y-axis of the image.') layout = QGridLayout() layout.addWidget(QLabel('Span Number:') , 0,0) layout.addWidget( self.spanNumber , 0,1) layout.addWidget(self.plot_hist , 1,0 , 1,2) self.histogFrame.setLayout( layout ) def initMultiplotPeak(self): self.multi_plot = pg.GraphicsLayoutWidget() self.samplingtime = QSpinBox() self.samplingtime.setRange(1, 60) self.samplingtime.setValue(5) self.dicmultiplot = {} self.samplingPtNbr = QLabel() # --- --- # self.plot_max = PeakPlot(name='plot_max', span=None, log=self.log) #self.dicmultiplot[self.plot_max.name] = [self.plot_max] # --- --- # self.spanNumber.valueChanged.connect( self.updateMultiplots ) self.samplingtime.valueChanged.connect( self.updatePtNbrLabel ) self.camera_view.fps_input.valueChanged.connect( self.updatePtNbrLabel ) # --- make layout --- # label_1 = QLabel('Sampling time (s): ') label_1.setWordWrap(True) label_2 = QLabel('(s) --> pts nbr:') label_2.setWordWrap(True) self.multiplotFrame = QFrame() self.multiplotFrame.setToolTip('Multiplot frame. Each plot correspond to the post-processed data sampling of the corresponding span number.') layout = QGridLayout() layout.addWidget(label_1 , 0,0) layout.addWidget(self.samplingtime , 0,1) layout.addWidget(label_2 , 0,2) layout.addWidget(self.samplingPtNbr , 0,3) layout.addWidget(self.multi_plot , 1,0 , 1,4) self.multiplotFrame.setLayout( layout ) def initLissajousPlot(self): self.lissajousFrame = QFrame() self.lissajousFrame.setToolTip('Lissajous plot. We plot the post processed intensities as expressed below the graph.') self.lissajousFrame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised) self.lissajousFrame.setLineWidth(3) self.lissajousFrame.setMidLineWidth(1) # --- --- # self.plot_lissjs = pg.PlotWidget() self.plot_lissjs.setMinimumHeight(300) self.plot_lissjs.setMinimumWidth(300) self.plot_lissjs.showGrid(x=True, y=True) lissjs_viewbox = self.plot_lissjs.getViewBox() self.data_lissjs = pg.ScatterPlotItem() #pg.PlotDataItem() #self.data_lissjs.setSymbol('o') self.plot_lissjs.addItem(self.data_lissjs) # --- --- # lissjs_viewbox.setRange(xRange=(-1,+1), yRange=(-1,+1)) self.plot_xaxis = QComboBox() self.plot_yaxis = QComboBox() self.makeLissajousAxisSelection() self.button_plot_lissajs = QPushButton('Plot') self.button_plot_lissajs.setCheckable(True) # --- make layout --- # label_equation = QLabel('- i = (I/I_tot)\n- x,y = [i-(i_Max+i_min)/2]/(i_Max-i_min)/2') label_equation.setWordWrap(True) layout = QGridLayout() layout.addWidget( QLabel('X axis') , 0,1) layout.addWidget( QLabel('Y axis') , 0,2) layout.addWidget( QLabel('Plot : '), 1,0) layout.addWidget( self.plot_xaxis , 1,1) layout.addWidget( self.plot_yaxis , 1,2) layout.addWidget( self.button_plot_lissajs, 2,0 , 1,3) layout.addWidget( self.plot_lissjs , 3,0 , 1,3) layout.addWidget( QHLine() , 4,0 , 1,3) layout.addWidget( label_equation , 5,0 , 1,3) self.lissajousFrame.setLayout( layout ) def setNewSaveFile(self): # --- stop timers to avoid over load --- # wasOn = self.camera_view.isOn self.camera_view.stop_continuous_view() # --- --- # filename = self.savefile.getSaveFileName(None) if filename == '': # --- restart processes --- # if wasOn: self.camera_view.start_continuous_view() return False dir_path = self.savefile.directory().absolutePath() os.chdir(dir_path) self.savefile_name.setText( filename[0] ) # --- restart processes --- # if wasOn: self.camera_view.start_continuous_view() # --- --- # return True def saveDataFromMultiplot(self): # --- stop timers to avoid over load --- # # we stop the process because it does not work while timer is running wasOn = self.camera_view.isOn self.camera_view.stop_continuous_view() # --- check if there are spans --- # if self.spanNumber.value() == 0: # --- restart processes --- # if wasOn: self.camera_view.start_continuous_view() return None # --- set file name --- # hasWorked = self.setNewSaveFile() if not hasWorked: # --- restart processes --- # if wasOn: self.camera_view.start_continuous_view() return None # --- open file save --- # filename = self.savefile_name.text() try: f = open(filename, 'w+') except: err_msg = 'Error: in saveDataFromMultiplot, not able to open file.' err_msg += '\nFilename is: {}'.format(filename) self.log.addText( err_msg ) # --- make save --- # min_len = np.inf data_list = [] for key in self.dicmultiplot: # adding data from each plot in multiplot view data_list.append( self.dicmultiplot[key][0].plot.yData ) min_len = np.min( [min_len, len(data_list[-1])] ) # --- adding the data fot the total intensity --- # data_list.append( self.plot_max.plot.yData ) min_len = np.min( [min_len, len(data_list[-1])] ) # --- --- # min_len = int(min_len) if len(data_list) == 0: return None # --- equalise the length of the data, from the end since it is the most recent one --- # for i in range(len(data_list)): data_list[i] = data_list[i][-min_len:] data_list = np.array(data_list) # --- --- # np.savetxt(filename, data_list) # --- restart processes --- # if wasOn: self.camera_view.start_continuous_view() def makeLissajousAxisSelection(self): nx = self.plot_xaxis.count() ny = self.plot_yaxis.count() if nx != ny: self.log.addText('Error in makeLissajousAxisSelection, the two axis combobox do not have the same item number.') return None for i in reversed(range(nx)): self.plot_xaxis.removeItem(i) self.plot_yaxis.removeItem(i) for i in range(self.spanNumber.value()): self.plot_xaxis.addItem(str(i+1)) self.plot_yaxis.addItem(str(i+1)) def toggleLissajousPlot(self): if self.button_plot_lissajs.isChecked(): self.doLissajous = True else: self.doLissajous = False def addSpan(self): N = len( list(self.dicspan.keys()) ) newspan = SpanObject(name='span_{}'.format(N+1), pos_init=N*50 +1, log=self.log) self.dicspan[N+1] = newspan # --- --- # self.plot_hist.addItem( newspan.span ) # --- add label --- # #newspan.label.setParentItem(self.plot_hist.getViewBox()) self.plot_hist.addItem( newspan.label ) # --- --- # self.addPlot(newspan) def removeSpan(self): N = len( list(self.dicspan.keys()) ) if N == 0: return None # --- --- # self.removePlot( self.dicspan[N] ) # --- --- # self.plot_hist.removeItem( self.dicspan[N].span ) self.plot_hist.removeItem( self.dicspan[N].label ) self.dicspan[N].setParent(None) del self.dicspan[N] def makeSpans(self): n = self.spanNumber.value() n_current = len(list(self.dicspan.keys())) if n == n_current: pass elif n > n_current: for i in range(n-n_current): self.addSpan() elif n < n_current: for i in range(n_current-n): self.removeSpan() self.makeLissajousAxisSelection() self.setSameYAxisMultiplots() def addPlot(self, span): N = len( list(self.dicspan.keys()) ) newplot = PeakPlot(name='plot_{}'.format(span.name), span=span, log=self.log) self.dicmultiplot[newplot.name] = [newplot] # --- --- # span.span.sigRegionChangeFinished.connect( self.updateMultiplots ) # --- --- # self.multi_plot.nextRow() self.multi_plot.addItem( newplot ) # --- --- # label_item = self.multi_plot.addLabel(newplot.name[10:], angle = -90) self.dicmultiplot[newplot.name].append( label_item ) def removePlot(self, span): ''' In dictionary of plots, we retreive the plot list [plot_item, label_item], associated to the span region. ''' N = len( list(self.dicspan.keys()) ) plot_to_remove = self.dicmultiplot['plot_{}'.format(span.name)] # --- remove plot --- # self.multi_plot.removeItem( plot_to_remove[0] ) plot_to_remove[0].setParent(None) # --- remove label --- # self.multi_plot.removeItem( plot_to_remove[1] ) # --- --- # del self.dicmultiplot['plot_{}'.format(span.name)] span.setAssigned(False) def setSameYAxisMultiplots(self): key_init = list(self.dicmultiplot.keys())[0] common_viewBox = self.dicmultiplot[key_init][0].getViewBox() common_viewBox.enableAutoRange(pg.ViewBox.YAxis, enable=True) for key in self.dicmultiplot: plot = self.dicmultiplot[key][0] plot.setYLink(common_viewBox) def setLinkToCameraTimer(self): if self.histrealtime.checkState() == 0: self.camera_view.timer.timeout.disconnect(self.updatePlotHistogram) elif self.histrealtime.checkState() == 2: self.camera_view.timer.timeout.connect(self.updatePlotHistogram) def addDataToFile(self): # --- stop timers to avoid over load --- # wasOn = self.isOn self.stop_continuous_view() self.fittingtimer.stop() # --- --- # f = open(self.savefile_name.text(), 'a') coretxt = '' coretxt += '\n' if self.peakcount == 0: pass elif self.peakcount == 1: coretxt += self.sepration+str(self.param_peak[0][1]) else: for i in range(self.peakcount): coretxt += self.sepration+str(self.param_peak[i,1]) f.write(coretxt) f.close() # --- restart processes --- # if self.fittingactivate.checkState() != 0: self.fittingtimer.start() if wasOn: self.start_continuous_view() def acceptOrNot(self, i): if type(self.data_hist.xData)==type(None): self.fittingactivate.setCheckState(0) return None def changeMode(self): ind = self.modeselect.currentIndex() if ind == 0: self.gaussianfit.setMode('all') elif ind == 1: self.gaussianfit.setMode('pbp') def setPostProcessFunction(self): ind = self.postprocss.currentIndex() if ind == 0: func = eval("lambda x_data: np.max(x_data)") self.postprocss_func = func elif ind == 1: func = eval("lambda x_data: np.sum(x_data)") self.postprocss_func = func return None def setFittingRate(self): self.fittingtimer.setInterval(1e3/self.frqcyfitting.value()) def setHistgrmPlotRange(self): ind = self.histogram_data.currentIndex() if ind == 0 or ind == 1: self.plot_hist.getViewBox().enableAutoRange(pg.ViewBox.XAxis, enable=True) elif ind == 2: self.plot_hist.setXRange(0, 1.) def postProcessLissajous(self, xy_data): Max_ = np.max(xy_data) min_ = np.min(xy_data) A = (Max_ + min_)*0.5 B = (Max_ - min_)*0.5 return (xy_data-A)/B def updatePlotHistogram(self): frame = self.camera_view.frame if type(frame) == type(None): return None # --- mode data --- # ind = self.histogram_data.currentIndex() if ind == 0: # raw ydata = np.sum(frame,axis=0)/frame.shape[0] elif ind == 1: # remove background frame = frame-np.mean(frame) ydata = np.sum(frame,axis=0)/frame.shape[0] ydata = ydata + np.abs(np.min([0, np.min(ydata)])) elif ind == 2: # normalise ydata = np.sum(frame,axis=0)/frame.shape[0] ydata = ydata/np.max(ydata) # --- plot data --- # self.data_hist.setData( ydata, np.arange(len(ydata)) ) # --- --- # self.updateMultiplots() def updateMultiplots(self): if type(self.postprocss_func) == type(None): self.setPostProcessFunction() # --- --- # sum_max_peak = 0 data = self.data_hist.xData for key in self.dicmultiplot: plot = self.dicmultiplot[key][0] plot.setLengthMax( int(self.samplingtime.value()*self.camera_view.fps) ) # --- --- # region = plot.span.span.getRegion() m , M = int(np.min(region)), int(np.max(region)) err_msg = '' cond_1 = type(data) != type(None) and m != M cond_2 = len(data) >= m or len(data) >= M cond_3 = len(data[m:M]) != 0 if cond_1 and cond_2 and cond_3: try: new_val = self.postprocss_func(data[m:M])# np.max(data[m:M]) plot.addDataElement( new_val ) except: err_msg += 'Error: in updatePlot for object PeakPlot: '+plot.name err_msg += '\nIssue with: self.addDataElement( np.max(self.data[m:M]) ),' err_msg += '\nsample: {}'.format(self.data[m:M]) else: err_msg += '\nOne of the following condition is unsatisfied:\n \ type(data) != type(None) and m != M: {0}\n \ len(data) >= m or len(data) >= M: {1}\n \ len(data[m:M]) != 0: {2}'.format(cond_1,cond_2,cond_3) self.log.addText( err_msg ) # --- --- # sum_max_peak += plot.peakdata[-1] self.plot_max.setLengthMax( int(self.samplingtime.value()*self.camera_view.fps) ) self.plot_max.addDataElement(sum_max_peak) # --- --- # if self.button_plot_lissajs.isChecked():# if self.doLissajous: self.updateLissajousPlot() def updateLissajousPlot(self): xaxis_ind = self.plot_xaxis.currentText() yaxis_ind = self.plot_yaxis.currentText() try: xplot = self.dicmultiplot['plot_span_{}'.format(xaxis_ind)][0] yplot = self.dicmultiplot['plot_span_{}'.format(yaxis_ind)][0] except: if self.feedback: err_msg = 'Error: in updateLissajousPlot. Wrong key for dicmultiplot.' self.log.addText( err_msg ) return None xdata = xplot.plot.yData ydata = yplot.plot.yData max_data = self.plot_max.plot.yData if type(xdata) != type(None) and type(ydata) != type(None): n = np.min( [len(xdata), len(ydata), len(max_data)] ) xdata = xdata[-n:]/max_data[-n:] ydata = ydata[-n:]/max_data[-n:] xdata = self.postProcessLissajous(xdata) ydata = self.postProcessLissajous(ydata) self.data_lissjs.setData( xdata, ydata ) def updatePtNbrLabel(self): self.samplingPtNbr.setText( str(self.samplingtime.value()*self.camera_view.fps) )
class Preview(QWidget): def __init__(self, camera=None, log=None, fps=10.): super().__init__() # --- --- # if log != None: self.log = log else: self.log = LogDisplay() #self.log.show() # --- default --- # self.fps = fps self.normalise_hist = True self.cmap = 'jet' # --- main attriute --- # self.camera = camera if self.camera == None: dir_path = '/home/cgou/ENS/STAGE/M2--stage/Camera_acquisition/Miscellaneous/Camera_views/' self.camera = Camera(cam_id=0, log=self.log) if not self.camera.isCameraInit: self.camera = SimuCamera(0, directory_path=dir_path, log=self.log) self.camera.__info__() elif not self.camera.isCameraInit: self.camera.__init__(cam_id=0, log=self.log) # --- --- # self.contview = ContinuousView(fps=self.fps) self.timer = pg.QtCore.QTimer() #QTimer()# pg.QtCore.QTimer() self.qlabl_max = QLabel() self.isOn = False # --- --- # self.initUI() # --- --- # self.camera.setExposure(self.image_widget.exposure.value()) def initUI(self): # --- --- # self.layout = QVBoxLayout(self) self.initView() # --- button widget --- # self.button_acquire = QPushButton('Acquire frame') self.button_acquire.setStyleSheet("background-color: orange") self.button_acq_movie = QPushButton('Acquire movie') self.button_acq_movie.setStyleSheet("background-color: orange") # --- --- # self.movie_frameNbre = QSpinBox() self.movie_frameNbre.setMinimum(0) self.movie_frameNbre.setMaximum(1000) self.movie_frameNbre.setValue(200) self.dir_save = QFileDialog() self.dir_save_label = QLabel('No file selected') self.dir_save_label.setWordWrap(True) self.name_save = QLineEdit() self.name_save.setText('img_data') self.progressbar = QProgressBar() self.progressbar.setValue(0) self.format_save = QComboBox() self.format_save.addItem('tif') self.format_save.addItem('tiff') self.format_save.addItem('png') self.format_save.addItem('jpg') self.histogram_mode = QComboBox() self.histogram_mode.addItem('Normalise') self.histogram_mode.addItem('Raw') # --- connections --- # self.button_acquire.clicked.connect(self.acquireFrame) self.button_acq_movie.clicked.connect(self.acquireMovie) self.histogram_mode.currentIndexChanged.connect(self.setHistogramMode) # --- layout --- # self.layout.addWidget(self.view_layout) grid = QGridLayout() grid.addWidget(self.histogram_mode, 0, 0) grid.addWidget(self.button_acquire, 0, 1, 1, 2) grid.addWidget(QLabel('Number of frame'), 1, 0) grid.addWidget(self.movie_frameNbre, 1, 1) grid.addWidget(self.button_acq_movie, 1, 2) grid.addWidget(QLabel('Filemane prefix:'), 2, 0) grid.addWidget(self.name_save, 2, 1) grid.addWidget(self.format_save, 2, 2) grid.addWidget(QLabel('Directory:'), 3, 0) grid.addWidget(self.dir_save_label, 3, 1, 1, 2) grid.addWidget(self.progressbar, 4, 0, 1, 3) self.layout.addLayout(grid) self.setLayout(self.layout) # --- --- # self.update_timer = QTimer() def initView(self): self.image_widget = CameraDisplay(camera=self.camera, log=self.log) self.image_view = self.image_widget.image_view # --- histogram --- # self.hist_layWidget = pg.GraphicsLayoutWidget() self.plot_hist = self.hist_layWidget.addPlot() self.plot_hist.setXLink(self.image_view.getView()) if self.normalise_hist: self.plot_hist.setYRange(0, 1) else: self.plot_hist.enableAutoRange(y=True) # --- --- # self.data_hist = pg.PlotDataItem() self.plot_hist.addItem(self.data_hist) # --- link histogram to image view --- # self.image_widget.frame_updated.connect(self.updatePlotHistogram) # --- --- # self.image_view.setLevels(0, 255) self.image_view.getHistogramWidget().item.setHistogramRange( 0, 255) #not working when update self.image_view.ui.roiBtn.hide() self.image_view.ui.menuBtn.hide() # --- --- # self.image_view.setMinimumWidth(400) self.image_view.setMinimumHeight(200) self.hist_layWidget.setMinimumWidth(400) self.hist_layWidget.setMinimumHeight(100) # --- --- # self.view_layout = QSplitter(PyQt5.QtCore.Qt.Vertical) self.view_layout.addWidget(self.image_widget) self.view_layout.addWidget(self.hist_layWidget) def setFPS(self): self.fps = self.fps_input.value() self.contview.setFPS(self.fps) self.timer.setInterval(1e3 / self.fps) def setHistogramMode(self, indx): val = self.histogram_mode.currentText() if val == 'Normalise': self.normalise_hist = True self.plot_hist.setYRange(0, 1) elif val == 'Raw': self.normalise_hist = False self.plot_hist.enableAutoRange(y=True) def nextFrame(self): wasOn = self.isOn if not self.isOn: self.camera.capture_video() # --- --- # self.update_image() # --- --- # if not wasOn: self.camera.capture_video() def updatePlotHistogram(self): frame = self.image_widget.frame if self.normalise_hist: bckgrnd = np.mean(frame) frame = frame - bckgrnd ydata = np.sum(frame, axis=0) / frame.shape[0] if self.normalise_hist: ydata -= np.min([0, np.min(ydata)]) ydata = ydata / np.max(ydata) self.data_hist.setData(ydata) def update_slider(self): self.exposure_slider.setValue(self.exposure_spinb.value() * 100) self.update_exposure() def update_spinbox(self): self.exposure_spinb.setValue(float(self.exposure_slider.value()) / 100) self.update_exposure() def update_exposure(self): exp_val = self.exposure_spinb.value() self.camera.setExposure(exp_val) def acquireFrame(self): wasOn = self.isOn if self.isOn: self.startStop_continuous_view() # --- --- # try: frame = self.camera.frame plt.imshow(frame, cmap=self.cmap) plt.show() except: pass # --- --- # if wasOn: self.startStop_continuous_view() def acquireMovie(self): wasOn = self.isOn if self.isOn: self.startStop_continuous_view() # --- --- # dir_save_path = self.dir_save.getExistingDirectory() + '/' self.dir_save_label.setText(dir_save_path) filename = self.name_save.text() format_ = self.format_save.currentText() # --- --- # self.progressbar.setValue(0) self.progressbar.setMaximum(self.movie_frameNbre.value()) # --- --- # movie = self.camera.acquire_movie(self.movie_frameNbre.value()) try: img_to_save = Image.fromarray(movie[0]) img_to_save.save(dir_save_path + filename + '_{0:03d}.{1}'.format(0, format_)) self.progressbar.setValue(1) except: err_msg = 'Error: in acquireMovie. The filename is not accepted\nFilename: {0}\nDirectory path: {1}'.format( filename, dir_save_path) self.log.addText(err_msg) return None for i in range(1, len(movie)): img_to_save = Image.fromarray(movie[i]) img_to_save.save(dir_save_path + filename + '_{0:03d}.{1}'.format(i, format_)) self.progressbar.setValue(i + 1) # --- --- # if wasOn: self.startStop_continuous_view()
class DCMeasurement(QWidget): def __init__(self, camera=None, log=None, fps=10.): super().__init__() # --- --- # if log != None: self.log = log else: self.log = LogDisplay() #self.log.showLog() # --- default --- # self.fps = fps self.cmap = 'jet' self.normalise = True self.sepration = ' ' self.param_peak = [ ] # a N x 3 array where each line is [x0, a, b] the parameter of the fit, N being the number of peaks. self.measured_max = [] self.power_peak = [] self.fittingtimer = pg.QtCore.QTimer() # --- main attriute --- # self.camera = camera if not self.camera.isCameraInit: self.camera.__init__(cam_id=0, log=self.log) self.contview = ContinuousView(fps=self.fps) self.qlabl_max = QLabel() # --- --- # self.initUI() def initUI(self): self.splitter = QSplitter(PyQt5.QtCore.Qt.Horizontal) self.fitting_frame = None # --- --- # self.layout = QVBoxLayout(self) # --- guassian fit init --- # self.dic_spanfitting = {} self.gaussianfit = GaussianFit(log=self.log) self.gaussian_plots = {} self.fittingactivate = QCheckBox() self.fittingactivate.setTristate(False) self.fittingactivate.stateChanged.connect(self.acceptOrNot) self.fittingactivate.stateChanged.connect( self.fittingActivationDeactivation) # --- init frames --- # self.initView() self.initDisplayFittingFrame() self.initParameterFittingFrame() self.relativeHeightsLayout() # --- layout --- # self.splitter.addWidget(self.viewFrame) vsplitter = QSplitter(PyQt5.QtCore.Qt.Vertical) vsplitter.addWidget(self.fittingFrame) vsplitter.addWidget(self.paramfittingframe) vsplitter.addWidget(self.matrelatFrame) self.splitter.addWidget(vsplitter) self.layout.addWidget(self.splitter) self.setLayout(self.layout) # --- --- # self.fittingtimer.start() self.setXdataPoints() self.setFittingMethod() def initView(self): self.camera_view = CameraDisplay(camera=self.camera, log=self.log) # --- --- # self.camera_view.image_view.setMinimumWidth(600) self.camera_view.image_view.setMinimumHeight(200) # --- --- # self.viewFrame = QFrame() self.viewFrame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised) self.viewFrame.setLineWidth(3) self.viewFrame.setMidLineWidth(1) layout = QVBoxLayout() layout.addWidget(self.camera_view) self.viewFrame.setLayout(layout) def initDisplayFittingFrame(self): self.plot_hist = pg.PlotWidget() self.plot_hist.setMinimumWidth(800) plot_viewbox = self.plot_hist.getViewBox() plot_viewbox.setAspectLocked(False) plot_viewbox.enableAutoRange(pg.ViewBox.XAxis, enable=True) # --- measured data --- # self.data_hist = pg.PlotDataItem() self.plot_hist.addItem(self.data_hist) # --- threshold line object --- # self.threshold = pg.InfiniteLine(pos=1., angle=0, movable=True) self.plot_hist.addItem(self.threshold) # --- widgets --- # self.normalise_hist = QComboBox() self.normalise_hist.addItem('raw') self.normalise_hist.addItem('normalise') self.normalise_hist.setCurrentIndex(0) self.nbrpeak = QSpinBox() self.nbrpeak.setRange(1, 20) self.nbrpeak.setValue(2) self.histrealtime = QCheckBox() self.histrealtime.setTristate(False) self.histrealtime.setCheckState(2) self.setLinkToCameraTimer() # --- connections --- # self.threshold.sigPositionChangeFinished.connect(self.updatePlots) self.normalise_hist.currentIndexChanged.connect(self.setModeFitting) self.nbrpeak.valueChanged.connect(self.updatePlots) self.histrealtime.stateChanged.connect(self.setLinkToCameraTimer) # --- default --- # self.setModeFitting() plot_viewbox.enableAutoRange(pg.ViewBox.YAxis, enable=True) if self.normalise: self.plot_hist.setYRange(0, 1) # --- make layout --- # self.fittingFrame = QFrame() vlayout = QVBoxLayout() hlayout = QHBoxLayout() hlayout.addWidget(QLabel('mode fitting:')) hlayout.addWidget(self.normalise_hist) hlayout.addWidget(QLabel('Number maximum of peaks:')) hlayout.addWidget(self.nbrpeak) hlayout.addWidget(QLabel('Continuous mode:')) hlayout.addWidget(self.histrealtime) vlayout.addLayout(hlayout) vlayout.addWidget(self.plot_hist) self.fittingFrame.setLayout(vlayout) def initParameterFittingFrame(self): # --- widgets --- # self.peakcount_lab = QLabel('#') self.modeselect = QComboBox() self.modeselect.addItem('all') self.modeselect.addItem('peak by peak') self.choosedirectory = QPushButton('&New file') self.savefile_name = QLabel('Select a file') self.savefile_name.setWordWrap(True) self.savefile = QFileDialog() self.button_addData = QPushButton('Add data') self.button_addData.setStyleSheet("background-color: green") self.button_makefit = QPushButton('Make fit') self.frqcyfitting = QSpinBox() self.frqcyfitting.setRange(1, 12) self.frqcyfitting.setValue(10) self.fitting_xdataNbre = QSpinBox() self.fitting_xdataNbre.setRange(100, 5e3) self.fitting_xdataNbre.setValue(10**3) self.fitting_param_dspl = QTableWidget() self.fitting_param_dspl.setRowCount(5) self.saving_state = QLabel('###') self.saving_state.setWordWrap(True) self.save_count = QSpinBox() self.save_count.setRange(0, 1e4) self.save_count.setValue(0) self.button_test = QPushButton('TEST') # --- --- # self.fittingtimer.setInterval(self.frqcyfitting.value()) # --- connections --- # self.modeselect.currentIndexChanged.connect(self.setFittingMethod) self.choosedirectory.clicked.connect(self.setNewSaveFile) self.button_addData.clicked.connect(self.addDataToFile) self.frqcyfitting.valueChanged.connect(self.setFittingRate) self.fittingtimer.timeout.connect(self.updatePlots) self.fitting_xdataNbre.valueChanged.connect(self.setXdataPoints) self.button_makefit.clicked.connect(self.singleShotFittingPlot) self.nbrpeak.valueChanged.connect(self.initPeakByPeakFitting) # --- make layout --- # self.paramfittingframe = QFrame() self.param_grid = QGridLayout() self.param_grid.addWidget(QLabel('Activate fitting '), 0, 0) self.param_grid.addWidget(self.fittingactivate, 0, 1) self.param_grid.addWidget(QLabel('Fitting rate:'), 0, 2) self.param_grid.addWidget(self.frqcyfitting, 0, 3) self.param_grid.addWidget(QLabel('Fitting Sampling number'), 0, 4) self.param_grid.addWidget(self.fitting_xdataNbre, 0, 5) self.param_grid.addWidget(QLabel('Peak nbr:'), 1, 0) self.param_grid.addWidget(self.peakcount_lab, 1, 1) self.param_grid.addWidget(QLabel('Fitting method:'), 1, 2) self.param_grid.addWidget(self.modeselect, 1, 3) self.param_grid.addWidget(self.button_makefit, 1, 4, 1, 2) self.param_grid.addWidget(self.fitting_param_dspl, 2, 0, 4, 6) self.param_grid.setRowMinimumHeight(2, 35) self.param_grid.setRowMinimumHeight(3, 35) self.param_grid.setRowMinimumHeight(4, 35) self.param_grid.setRowMinimumHeight(5, 35) self.updateParamLayout() self.param_grid.addWidget(self.choosedirectory, 6, 0) self.param_grid.addWidget(self.savefile_name, 6, 1, 1, 6) self.param_grid.addWidget(self.button_addData, 7, 0, 1, 4) self.param_grid.addWidget(self.saving_state, 7, 4) self.param_grid.addWidget(self.save_count, 7, 5) for i in range(self.param_grid.rowCount() + 1): self.param_grid.setRowStretch(i, 1) # --- --- # self.paramfittingframe.setLayout(self.param_grid) def initPeakByPeakFitting(self): if self.modeselect.currentIndex() != 1: return None # --- reset spans --- # self.removeAllSpans() # --- --- # for i in range(self.nbrpeak.value()): newspan = SpanObject(name='span_{}'.format(i), orientation='vertical', log=self.log, pos_init=i * 50 + 1) newspan.span.sigRegionChangeFinished.connect(self.updatePowerPeak) self.dic_spanfitting[newspan.name] = newspan self.plot_hist.addItem(newspan.span) self.plot_hist.addItem(newspan.label) self.gaussianfit.setSpanDictionary(self.dic_spanfitting) # --- --- # self.power_peak = np.zeros(self.nbrpeak.value()) def initPowerEstimation(self): if self.modeselect.currentIndex() != 2: return None # --- reset spans --- # self.removeAllSpans() # --- --- # for i in range(self.nbrpeak.value()): newspan = SpanObject(name='span_{}'.format(i), orientation='vertical', log=self.log, pos_init=i * 50 + 1) newspan.span.sigRegionChangeFinished.connect(self.updatePowerPeak) self.dic_spanfitting[newspan.name] = newspan self.plot_hist.addItem(newspan.span) # --- --- # self.power_peak = np.zeros(self.nbrpeak.value()) def removeAllSpans(self): KEYS = list(self.dic_spanfitting.keys()) for key in KEYS: self.plot_hist.removeItem(self.dic_spanfitting[key].span) self.dic_spanfitting[key].setParent(None) del self.dic_spanfitting[key] def removeAllLabels(self): KEYS = list(self.dic_spanfitting.keys()) for key in KEYS: self.plot_hist.removeItem(self.dic_spanfitting[key].label) def addDataToFile(self): # --- stop timers to avoid over load --- # wasOn = self.camera_view.isOn self.camera_view.stop_continuous_view() self.fittingtimer.stop() # --- --- # self.saving_state.setText('Saving ...') self.button_addData.setStyleSheet("background-color: red") time.sleep(.5) self.img_count = self.save_count.value() # --- --- # if len(self.param_peak) == 0: # --- restart processes --- # if self.fittingactivate.checkState() != 0: self.fittingtimer.start() if wasOn: self.camera_view.start_continuous_view() # --- --- # self.saving_state.setText('Save unsuccessful: param of length 0.') return None elif len(self.power_peak) == 0: self.power_peak = np.zeros(self.nbrpeak.value()) # --- --- # N = self.param_peak.shape[0] try: open(self.savefile_name.text(), 'r') except: f = open(self.savefile_name.text(), 'a') header = '' for i in range(N): header += 'Peak_measured_{}'.format(i) + self.sepration header += 'Peak_power_{}'.format(i) + self.sepration header += 'Peak_fitted_{}'.format(i) + self.sepration f.write(header) f.close() self.log.addText('Creating new file') # --- --- # f = open(self.savefile_name.text(), 'a') coretxt = '' coretxt += '\n' for i in range(N): coretxt += str(self.measured_max[i]) + self.sepration coretxt += str(self.power_peak[i]) + self.sepration coretxt += str(self.param_peak[i, 1]) + self.sepration f.write(coretxt) f.close() # --- save coresponding frame as tif --- # img_to_save = Image.fromarray(self.camera_view.frame) if self.savefile_name.text()[:-4] == '.': img_to_save.save(self.savefile_name.text()[:-4] + '_{0:03d}.tif'.format(self.img_count)) else: img_to_save.save(self.savefile_name.text() + '_{0:03d}.tif'.format(self.img_count)) self.img_count += 1 # --- --- # self.saving_state.setText('Saved No:') self.save_count.setValue(self.img_count) self.button_addData.setStyleSheet("background-color: green") time.sleep(0.5) # --- restart processes --- # if self.fittingactivate.checkState() != 0: self.fittingtimer.start() if wasOn: self.camera_view.start_continuous_view() def acceptOrNot(self, i): if type(self.data_hist.xData) == type(None): self.fittingactivate.setCheckState(0) # --- --- # self.setXdataPoints() def clearGaussianFits(self): KEYS = list(self.gaussian_plots.keys()) for i in reversed(range(len(KEYS))): key = KEYS[i] #self.plot_hist.removeItem(self.gaussian_plots[key]) self.gaussian_plots[key].clear() del self.gaussian_plots[key] #self.log.addText('Deleting plot: {}'.format(key)) self.gaussian_plots = {} def clearLayout(self, layout): for i in reversed(range(layout.count())): item = layout.itemAt(i) layout.removeItem(item) def fittingActivationDeactivation(self, i): if self.fittingactivate.checkState() == 0: self.fittingtimer.stop() elif self.fittingactivate.checkState() == 2: self.fittingtimer.start() def getParamFit(self): # --- fitting --- # self.gaussianfit.setXData(self.data_hist.xData) self.gaussianfit.setYData(self.data_hist.yData) self.gaussianfit.setPeakNumber(self.peakcount) self.gaussianfit.setCenters(self.param_peak[:, 0]) self.gaussianfit.setAmplitudes(self.param_peak[:, 1]) self.gaussianfit.setSTD(self.param_peak[:, 2]) # --- --- # self.gaussianfit.makeGaussianFit() # --- --- # self.param_peak = self.gaussianfit.param if self.modeselect.currentIndex() == 1: self.measured_max = self.gaussianfit.maximums def quickPeakCount(self): xdata = self.data_hist.xData ydata = self.data_hist.yData if type(xdata) == type(None) or type(ydata) == type(None): self.peakcount = 0 return None # --- threshold value --- # threshold = self.threshold.value() self.gaussianfit.setThreshold(self.threshold.value()) truth_list = (np.abs(ydata - threshold) + (ydata - threshold)).astype(bool) # --- --- # block_list = [[i for i, value in it] for key, it in itertools.groupby( enumerate(truth_list), key=operator.itemgetter(1)) if key != 0] self.peakcount = len(block_list) self.param_peak = np.ones([self.peakcount, 3]) self.measured_max = np.ones(self.peakcount) for i in range(self.peakcount): x0 = (block_list[i][-1] + block_list[i][0]) / 2. a = np.max(ydata[block_list[i]]) b = (block_list[i][-1] - block_list[i][0]) / 2. if b != 0: b = b**-1 self.param_peak[i] = [x0, a, b] self.measured_max[i] = a # --- --- # self.peakcount_lab.setText(str(self.peakcount)) self.updateParamLayout() def plotGaussianFit(self): # --- remove old gaussian plots --- # self.clearGaussianFits() # --- --- # for key in self.gaussianfit.dic_gauss: x = self.xdataFit #self.data_hist.xData y_fit = self.gaussianfit.gaussian(x, *self.gaussianfit.dic_gauss[key]) self.gaussian_plots[key] = pg.PlotCurveItem(x=x, y=y_fit, pen='r') # --- --- # for key in self.gaussian_plots: self.plot_hist.addItem(self.gaussian_plots[key]) def relativeHeightsLayout(self): self.matrelatFrame = QFrame() self.matrelat_layout = QGridLayout() self.matrelat_layout.setColumnMinimumWidth(0, 200) n = 0 self.matrelat = np.zeros([n, n]) numbering = np.arange(n) # --- with qtable --- # self.table = QTableWidget() self.matrelat_layout.addWidget(self.table) # --- --- # self.matrelatFrame.setLayout(self.matrelat_layout) def removeAllSpans(self): KEYS = list(self.dic_spanfitting.keys()) for key in KEYS: span_to_remove = self.dic_spanfitting[key] self.plot_hist.removeItem(span_to_remove.span) del self.dic_spanfitting[key] def setNewSaveFile(self): # --- stop timers to avoid over load --- # wasOn = self.camera_view.isOn self.camera_view.stop_continuous_view() self.fittingtimer.stop() # --- --- # filename = self.savefile.getSaveFileName() dir_path = self.savefile.directory().absolutePath() os.chdir(dir_path) self.savefile_name.setText(filename[0]) # --- set image count --- # self.img_count = 0 # --- restart processes --- # if self.fittingactivate.checkState() != 0: self.fittingtimer.start() if wasOn: self.camera_view.start_continuous_view() def setXdataPoints(self): if type(self.data_hist.xData) != type(None): self.xdataFit = np.linspace(np.min(self.data_hist.xData), np.max(self.data_hist.xData), self.fitting_xdataNbre.value()) else: self.xdataFit = np.linspace(0, 100, self.fitting_xdataNbre.value()) def setFittingMethod(self): ind = self.modeselect.currentIndex() if ind == 0: self.gaussianfit.setMode('all') self.button_makefit.setEnabled(False) self.button_makefit.setFlat(True) self.fittingactivate.setCheckState(2) self.removeAllLabels() self.removeAllSpans() self.power_peak = [] elif ind == 1: self.gaussianfit.setMode('pbp') self.button_makefit.setEnabled(True) self.button_makefit.setFlat(False) self.fittingactivate.setCheckState(0) self.initPeakByPeakFitting() self.initPowerEstimation() def setFPS(self): self.fps = self.fps_input.value() self.contview.setFPS(self.fps) self.timer.setInterval(1e3 / self.fps) def setFittingRate(self): self.fittingtimer.setInterval(1e3 / self.frqcyfitting.value()) def setModeFitting(self): ind = self.normalise_hist.currentIndex() if ind == 0: self.normalise = False self.gaussianfit.setMaxAmp(255) #self.plot_hist.setYRange(0, 255) self.plot_hist.getViewBox().enableAutoRange(pg.ViewBox.YAxis, enable=True) #self.threshold.setValue(255) elif ind == 1: self.normalise = True self.gaussianfit.setMaxAmp(1.) self.plot_hist.setYRange(0, 1.) self.threshold.setValue(1.) # --- --- # self.updatePlots() def setLinkToCameraTimer(self): if self.histrealtime.checkState() == 0: self.camera_view.frame_updated.disconnect(self.updatePlotHistogram) elif self.histrealtime.checkState() == 2: self.camera_view.frame_updated.connect(self.updatePlotHistogram) def singleShotFittingPlot(self): self.quickPeakCount() self.getParamFit() self.plotGaussianFit() self.updatePowerPeak() self.updateParamLayout() self.updateRelativeHeightMatrix() def updatePowerPeak(self): if len(self.power_peak) != len(list(self.dic_spanfitting.keys())): self.log.addText( 'Error: in updatePowerPeak, length of power_peak list and number of span do not coincide.' ) return None # --- --- # for i in range(len(self.power_peak)): region = self.dic_spanfitting['span_{}'.format(i)].span.getRegion() m, M = int(np.min(region)), int(np.max(region)) self.power_peak[i] = np.sum(self.data_hist.yData[m:M]) # --- --- # self.updateParamLayout() def updateParamLayout(self): try: n = self.param_peak.shape[0] except: self.log.addText('self.peakcount most likely not defined yet') return None self.fitting_param_dspl.clear() self.fitting_param_dspl.setItem(0, 0, QTableWidgetItem('Peak position')) self.fitting_param_dspl.setItem(1, 0, QTableWidgetItem('Peak amplitudes')) self.fitting_param_dspl.setItem(2, 0, QTableWidgetItem('STD')) self.fitting_param_dspl.setItem(3, 0, QTableWidgetItem('Measured max')) self.fitting_param_dspl.setItem(4, 0, QTableWidgetItem('Peak power')) self.fitting_param_dspl.setColumnCount(n + 1) # --- --- # if not n >= 1: return None for i in range(n): try: self.fitting_param_dspl.setItem( 0, i + 1, QTableWidgetItem('{:.3f}'.format(self.param_peak[i, 0]))) self.fitting_param_dspl.setItem( 1, i + 1, QTableWidgetItem('{:.3f}'.format(self.param_peak[i, 1]))) self.fitting_param_dspl.setItem( 2, i + 1, QTableWidgetItem('{:.3f}'.format(self.param_peak[i, 2]))) self.fitting_param_dspl.setItem( 3, i + 1, QTableWidgetItem('{:.3f}'.format(self.measured_max[i]))) if len(self.power_peak) != 0: self.fitting_param_dspl.setItem( 4, i + 1, QTableWidgetItem('{:.3f}'.format(self.power_peak[i]))) except: pass def updateRelativeHeightMatrix(self): n = self.param_peak.shape[0] self.table.clear() self.table.setRowCount(n) self.table.setColumnCount(n) self.matrelat = np.zeros([n, n]) # --- --- # if not n >= 1: return None for i in range(n): for j in range(n): try: self.table.setItem( i, j, QTableWidgetItem( str( round( self.param_peak[i, 1] / self.param_peak[j, 1], 3)))) except: pass #self.matrelat_layout.setRowMinimumHeight(0, 35*n) def updatePlots(self): self.quickPeakCount() if self.peakcount > self.nbrpeak.value(): return None if self.fittingactivate.checkState() == 2: self.getParamFit() self.plotGaussianFit() self.updateParamLayout() self.updateRelativeHeightMatrix() def updatePlotHistogram(self): frame = self.camera_view.frame if type(frame) == type(None): return None # --- --- # # --- --- # ydata = np.sum(frame, axis=0) / frame.shape[0] if self.normalise: try: ydata = ydata / np.max(ydata) except: err_msg = 'Error: in updatePlotHistogram. ydata/np.max(ydata) does not work.' err_msg += '\nydata max: {}'.format(np.max(ydata)) self.log.addText(err_msg) # --- plot data --- # self.data_hist.setData(ydata)
class CameraDisplay(QWidget): frame_updated = pyqtSignal() # ~~~~~~~~~~~~~~~~~~~~~~~~ # def __init__(self, camera=None, log=None, fps=10.): super().__init__() # --- --- # if log != None: self.log = log else: self.log = LogDisplay() #self.log.show() # --- default --- # self.fps = fps self.normalise_hist = True self.cmap = 'jet' # --- main attriute --- # self.camera = camera self.contview = ContinuousView(fps=self.fps) self.timer = pg.QtCore.QTimer() #QTimer()# pg.QtCore.QTimer() self.qlabl_max = QLabel() self.isOn = False self.frame = None # --- color acuisition --- # self.initColorDic() # --- --- # self.initUI() self.initCamera(camera) # --- --- # self.camera.setExposure( self.exposure.value() ) def initUI(self): # --- --- # self.layout = QVBoxLayout(self) self.initView() # --- button widget --- # self.button_startstop = QPushButton('Start/Stop') self.button_startstop.setStyleSheet("background-color: red") self.button_nextFrame = QPushButton('Next frame') # --- --- # self.fps_input = QSpinBox() self.fps_input.setRange(1, 48) self.fps_input.setValue(self.fps) self.exposure = QDoubleSpinBox() self.exposure.setSingleStep(0.01) self.cam_framerate = QDoubleSpinBox() self.exposure.setSingleStep(0.01) self.pixelclock = QDoubleSpinBox() self.which_camera = QComboBox() self.which_camera.addItem('USB camera') self.which_camera.addItem('From Image Dir.') # --- set default --- # self.exposure.setRange(0.10, 99.0) self.exposure.setValue(12.5) self.cam_framerate.setRange(1.00, 15.0) self.cam_framerate.setValue( 10.0 ) self.pixelclock.setRange(5, 30) self.pixelclock.setValue(20) # --- connections --- # self.button_startstop.clicked.connect(self.startStop_continuous_view) self.fps_input.valueChanged.connect(self.setFPS) self.button_nextFrame.clicked.connect( self.nextFrame ) self.exposure.valueChanged.connect( self.update_exposure ) self.cam_framerate.valueChanged.connect( self.update_camFPS ) self.pixelclock.valueChanged.connect( self.update_pixelClock ) self.which_camera.currentIndexChanged.connect( self.changeCameraStyle ) # --- layout --- # label_1 = QLabel('fps :') label_1.setWordWrap(True) label_2 = QLabel('value max:') label_2.setWordWrap(True) label_3 = QLabel('Which camera') label_3.setWordWrap(True) label_4 = QLabel('Exposure (ms):') label_4.setWordWrap(True) label_5 = QLabel('Camera fps:') label_5.setWordWrap(True) label_6 = QLabel('Pixel clock (MHz):') label_6.setWordWrap(True) grid = QGridLayout() grid.addWidget( self.button_startstop, 0,0) grid.addWidget( self.button_nextFrame, 0,1) grid.addWidget( label_1 , 0,2) grid.addWidget( self.fps_input , 0,3) grid.addWidget( label_2 , 0,4) grid.addWidget( self.qlabl_max , 0,5) grid.addWidget(QVLine() , 0,6 , 2,1) grid.addWidget(label_3 , 0,7) grid.addWidget( self.which_camera , 1,7 , 2,1) grid.addWidget(label_4 , 1,0) grid.addWidget( self.exposure , 1,1) grid.addWidget(label_5 , 1,2) grid.addWidget( self.cam_framerate , 1,3) grid.addWidget(label_6 , 1,4) grid.addWidget( self.pixelclock , 1,5) self.layout.addLayout(grid) self.layout.addWidget(self.image_view) self.setLayout(self.layout) def initColorDic(self): self.colordic = {} # --- jet-like cmap --- # alpha = 1.0 positions = [0.2, 0.5, 0.75, 1.0] colors = [[0,0,1.,alpha],[0,1.,1.,alpha],[1.,1.,0,alpha],[170/255,0,0,alpha]] #colors = ['#0000ff', '#00ffff', '#ffff00', '#aa0000'] self.colordic['jet'] = pg.ColorMap(positions, colors) # --- jet reversed cmap --- # positions_r = [1-p_ for p_ in positions] self.colordic['jet_r'] = pg.ColorMap(positions_r, colors) # --- plasma cmap --- # self.colordic['plasma'] = generatePgColormap('plasma') def initView(self): self.image_view = pg.ImageView() # --- --- # self.image_view.setColorMap(self.colordic[self.cmap]) self.image_view.setLevels(0,255) self.image_view.getHistogramWidget().item.setHistogramRange(0,255) # --- --- # self.image_view.setMinimumWidth(800) self.image_view.setMinimumHeight(600) def initCamera(self, camera): self.default_camera = camera self.simu_camera = SimuCamera(directory_path=os.getcwd(), log=self.log) # --- --- # self.camera = self.default_camera if not self.camera.isCameraInit: self.camera.__init__() def hideHistogram(self): self.image_view.ui.histogram.hide() def hidePlotButtons(self): self.image_view.ui.roiBtn.hide() self.image_view.ui.menuBtn.hide() def setFPS(self): self.fps = self.fps_input.value() self.contview.setFPS( self.fps ) self.timer.setInterval(1e3/self.fps) def update_frame(self): self.frame = self.camera.get_frame() self.qlabl_max.setText( str(np.max(self.frame)) ) self.image_view.setImage(self.frame.T, autoHistogramRange=False, autoLevels=False) self.frame_updated.emit() def update_exposure(self): self.camera.setExposure( self.exposure.value() ) self.log.addText( 'New exposure: {}ms'.format( self.camera.getExposure() ) ) # --- --- # new_pixelclock = self.camera.getPixelClock() self.pixelclock.setValue( new_pixelclock ) new_camFPS = self.camera.getFrameRate() self.cam_framerate.setValue( new_camFPS ) def update_camFPS(self): newfps = self.camera.setFrameRate( self.cam_framerate.value() ) self.log.addText('New camera fps: {:.3f}'.format( self.camera.getFrameRate() ) ) self.cam_framerate.setValue(newfps) # --- --- # new_pixelclock = self.camera.getPixelClock() self.pixelclock.setValue( new_pixelclock ) new_exposure = self.camera.getExposure() self.exposure.setValue( new_exposure ) def update_pixelClock(self): self.camera.setPixelClock( int(self.pixelclock.value()) ) self.log.addText( 'New pixel clock: {}Mhz'.format( self.camera.getPixelClock() )) # --- --- # new_camFPS = self.camera.getFrameRate() self.cam_framerate.setValue( new_camFPS ) new_exposure = self.camera.getExposure() self.exposure.setValue( new_exposure ) def nextFrame(self): wasOn = self.isOn if not self.isOn: self.camera.capture_video() # --- --- # self.update_frame() # --- --- # if not wasOn: self.camera.capture_video() def startStop_continuous_view(self): if self.isOn: self.stop_continuous_view() self.button_startstop.setStyleSheet("background-color: red") self.button_nextFrame.setFlat(False) self.button_nextFrame.setEnabled(True) else: self.start_continuous_view() self.button_startstop.setStyleSheet("background-color: green") self.button_nextFrame.setFlat(True) self.button_nextFrame.setEnabled(False) def start_continuous_view(self): self.camera.capture_video() if True: self.start_continuous_view_qtimer() elif False: self.start_continuous_view_qthread() # --- --- # self.isOn = True def stop_continuous_view(self): self.camera.stop_video() if True: self.stop_continuous_view_qtimer() elif False: self.stop_continuous_view_qthread() # --- --- # self.isOn = False def start_continuous_view_qthread(self): # --- --- # self.thread = QThread() self.thread.setTerminationEnabled(True) # --- connect --- # self.contview.moveToThread(self.thread) self.thread.started.connect(self.contview.startFeed) self.contview.newshot.connect(self.update_image) self.contview.finished.connect(self.thread.quit) # --- --- # self.thread.start() def stop_continuous_view_qthread(self): self.contview.stopFeed() def start_continuous_view_qtimer(self): # --- --- # self.timer.timeout.connect(self.update_frame) self.timer.start(1e3/self.fps) #ms def stop_continuous_view_qtimer(self): self.timer.stop() def changeCameraStyle(self): self.camera.stop_video() # --- --- # indx = self.which_camera.currentIndex() if indx == 0: self.camera = self.default_camera # --- --- # self.exposure.setEnabled(True) self.cam_framerate.setEnabled(True) self.pixelclock.setEnabled(True) elif indx == 1: self.camera.stop_video() dir_path = QFileDialog().getExistingDirectory() self.log.addText('NEW DIR PATH: {}'.format(dir_path)) self.simu_camera.setDirectoryPath( dir_path ) self.simu_camera.initialize() self.camera = self.simu_camera # --- --- # self.exposure.setEnabled(False) self.cam_framerate.setEnabled(False) self.pixelclock.setEnabled(False)
class MainWindow(QMainWindow): # inherits from the QMainWindow class def __init__(self): super().__init__() # The super() method returns the parent object of the MainWindow class, and we call its constructor. This means that we first initiate the QWidget class constructor. #self.app = QApplication([]) # only one per application # --- paths --- # self.localpath = os.path.dirname(os.path.realpath(__file__)) self.importpath = 'Dependencies_import/' self.iconpath = 'IMGdirectory/' # --- initialisations --- # self.initWindow() self.initWindowMenu() #self.show() #self.app.exec_() def initWindow(self): ''' Initialize the MainWindow configuration and display. ''' # --- geometry and position --- # x0, y0, w, h = 150, 100, 900, 800 self.setGeometry(x0, y0, w, h) self.setWindToCenter() # use the method defined below to center the window in the screen # --- names and titles --- # mytitle = "Main window" self.setWindowTitle(mytitle) mainapp_iconpath = r"./" + self.importpath + self.iconpath + "icon_mainapp.png" self.setWindowIcon(QIcon(mainapp_iconpath)) # --- Parent Widget : central widget --- # self.initMainWidget() self.initTabLayout() # --- make log display tab --- # self.log = LogDisplay() self.insertNewTabLogDisplay(self.log) # --- main attributes --- # self.cameraManag = CameraManagementWindow() self.initCamera() def initWindowMenu(self): ''' Initialize the menu of the MainWindow. ''' self.menubar = self.menuBar() # we define an attribute, menubar, which derives from the method menuBar() that comes from the QMainWindow parent object. # --- set the main menus --- # self.filemenu = self.menubar.addMenu('&File') self.setupmenu = self.menubar.addMenu('&Setups') self.toolsmenu = self.menubar.addMenu('&Tools') self.cameramenu = self.menubar.addMenu('&Camera') self.statusBar() # --- set the actions in the different menues --- # self.initFileMenu() self.initSetupMenu() self.initToolsMenu() self.initCameraMenu() #self.getFile() def initMainWidget(self): self.centralwidget = QWidget() # QMainWindow needs a QWidget to display Layouts. Thus we define a central widget so that all def initTabLayout(self): # --- --- # self.centraltab = QTabWidget() self.centraltab.setTabShape(0) self.centraltab.setTabsClosable(True) self.centraltab.tabCloseRequested.connect( self.closeTabe ) self.setCentralWidget(self.centraltab) def initCamera(self): dir_path = '/home/cgou/ENS/STAGE/M2--stage/Camera_acquisition/Miscellaneous/Camera_views/' self.camera = Camera(cam_id=0, log=self.log) if not self.camera.isCameraInit: self.camera = SimuCamera(0, directory_path=dir_path, log=self.log) self.log.addText( self.camera.__str__() ) else: self.log.addText('Camera in use is: USB camera') def setWindToCenter(self): ''' Set the MainWindow at the center of the desktop. ''' qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def closeTabe(self, index): ''' Remove the Tab of index index (integer). ''' self.centraltab.removeTab(index) self.camera.stop_video() self.camera.close_camera() self.log.addText('Is camera closed ? {}'.format( not self.camera.isCameraInit ) ) def getFile(self): ''' Set the menue bar such that we can fetch a text file and display it on a textEdit widget ''' self.textEdit = QTextEdit() grid = QGridLayout() grid.addWidget(self.textEdit,3,1,5,1) self.centralwidget.setLayout(grid) openFile = QAction('Open', self) openFile.setShortcut('Ctrl+O') openFile.setStatusTip('Open new File') openFile.triggered.connect(self.showDialog) self.filemenu.addAction(openFile) def initFileMenu(self): # --- Exit application --- # closeapp = QAction('&Exit', self) # QAction(QIcon('incon.png'), '&Exit', self) closeapp.triggered.connect(self.closeMainWindow) self.filemenu.addAction( '------' ) self.filemenu.addAction(closeapp) def initSetupMenu(self): ''' Make a new tab window with the display of the chosen structure (SWG, BS, ...). ''' # --- Preview --- # openNewtab = QAction('Preview', self) openNewtab.triggered.connect(self.insertNewTabPreview) self.setupmenu.addAction(openNewtab) # --- DC plot tab --- # openNewtab = QAction('Peak comparison (PkComp)', self) openNewtab.triggered.connect(self.insertNewTabPeakComparison) self.setupmenu.addAction(openNewtab) # --- Lissajous plot tab --- # openNewtab = QAction('Lissajous (Li)', self) openNewtab.triggered.connect(self.insertNewTabLissajousPlot) self.setupmenu.addAction(openNewtab) def initToolsMenu(self): ''' Make a new tab window with the display of the chosen structure (SWG, BS, ...). ''' # --- Application diagram --- # openNewtab = QAction('App diagram', self) openNewtab.triggered.connect(self.insertNewTabAppDiagram) self.toolsmenu.addAction(openNewtab) def initCameraMenu(self): ''' Make a new tab window with the display of the chosen structure (SWG, BS, ...). ''' # --- Camera tab --- # openNewtab = QAction('&Camera setup', self) openNewtab.triggered.connect(self.cameraManagementWindow) self.cameramenu.addAction(openNewtab) def cameraManagementWindow(self): self.cameraManag.show() def showDialog(self): ''' Generate the window where we can browse for the wanted text file. ''' fname = QFileDialog.getOpenFileName(self, 'Open file', './') #'/home/cgou') if fname[0]: f = open(fname[0], 'r') with f: data = f.read() self.textEdit.setText(data) def insertNewTabLogDisplay(self, log_objct): newtabindex = self.centraltab.addTab(log_objct,"Log") currentTbaBar = self.centraltab.tabBar() currentTbaBar.setTabButton(newtabindex, PyQt5.QtWidgets.QTabBar.RightSide, QLabel('')) # hide the close button self.centraltab.setCurrentIndex( newtabindex ) def insertNewTabMainWidget(self): newtabindex = self.centraltab.addTab( self.centralwidget, "Main" ) # also: addTab(QWidget , QIcon , QString ) self.centraltab.setCurrentIndex( newtabindex ) def insertNewTabPreview(self): newtabindex = self.centraltab.addTab( Preview(camera=self.camera, log=self.log), "Preview" ) # also: addTab(QWidget , QIcon , QString ) self.centraltab.setCurrentIndex( newtabindex ) def insertNewTabAppDiagram(self): newtabindex = self.centraltab.addTab( self.centralwidget, "Main" ) # also: addTab(QWidget , QIcon , QString ) self.centraltab.setCurrentIndex( newtabindex ) def insertNewTabPeakComparison(self): newtabindex = self.centraltab.addTab( DCMeasurement(camera=self.camera, log=self.log), "PkComp" ) # also: addTab(QWidget , QIcon , QString ) self.centraltab.setCurrentIndex( newtabindex ) def insertNewTabLissajousPlot(self): newtabindex = self.centraltab.addTab( PhaseNetworkElements(camera=self.camera, log=self.log), "Lissa" ) # also: addTab(QWidget , QIcon , QString ) self.centraltab.setCurrentIndex( newtabindex ) def closeMainWindow(self): try: self.camera.stop_video() self.camera.close_camera() except: pass print('Is camera closed ? {}'.format( not self.camera.isCameraInit ) ) self.close()