class MainWindow(QMainWindow, Ui_MainWindow): """ Main application window """ WIDTH = 150 HEIGHT = 50 MARGIN = 5 max_ping = 0 max_loss = 0 def __init__(self, host, history, history_size, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.host = host self.history = history self.history_size = history_size self.setupUi(self) self.setWindowFlag(Qt.WindowStaysOnTopHint) self.position_to_dock() self.series_delay = QLineSeries() self.series_loss = QLineSeries() self.axis_X = QDateTimeAxis() # pylint: disable=invalid-name self.axis_X.setTickCount(3) self.axis_X.setFormat("HH:mm") self.axis_X.setTitleText("Time") self.chart = QChart() self.chart.addSeries(self.series_delay) self.chart.addSeries(self.series_loss) self.chart.setTitle(f"Connection to {self.host}") self.init_series(self.series_delay, "Delay ms") self.init_series(self.series_loss, "Loss %") self.chart.legend().setVisible(False) self.chart.legend().setAlignment(Qt.AlignBottom) self.chart.layout().setContentsMargins(0, 0, 0, 0) self.chart.setBackgroundRoundness(0) self.chart.setMargins(QMargins(0, 0, 0, 0)) self.chartWidget.setChart(self.chart) self.chartWidget.setRenderHint(QPainter.Antialiasing) def init_series(self, series, label): """ Series settings """ self.chart.setAxisX(self.axis_X, series) axis_Y = QValueAxis() # pylint: disable=invalid-name axis_Y.setLabelFormat("%i") axis_Y.setTitleText(label) axis_Y.setRange(0, 100) self.chart.addAxis(axis_Y, Qt.AlignLeft) self.chart.setAxisY(axis_Y, series) def add_series(self, ping, loss): """ Append series data """ self.max_ping = max(ping or 0, self.max_ping) self.max_loss = max(loss, self.max_loss) if self.series_delay.count() > self.history_size: self.series_delay.remove(0) self.series_delay.append( QDateTime.currentDateTime().toMSecsSinceEpoch(), ping or 0) if self.series_loss.count() > self.history_size: self.series_loss.remove(0) self.series_loss.append( QDateTime.currentDateTime().toMSecsSinceEpoch(), loss) self.axis_X.setRange( QDateTime.currentDateTime().addSecs(-self.history), QDateTime.currentDateTime()) self.chart.axisY().setRange(0, self.max_ping + self.MARGIN) def position_to_dock(self): """ Adjust main window position according to it's size and desktop """ desktop_geometry = QDesktopWidget().availableGeometry() self.setGeometry( desktop_geometry.width() - self.width() - self.MARGIN, desktop_geometry.height() - self.height() - self.MARGIN, self.width(), self.height()) def set_labels(self, mean_=None, curr=None, loss=None): """ Update window text """ mean_text = curr_text = loss_text = "No connection" if mean_ is not None: mean_text = f"Mean ping: {mean_}ms" if curr is not None: curr_text = f"Last ping: {curr}ms" if loss is not None: loss_text = f"Ping loss: {loss}%" self.meanLabel.setText(mean_text) self.currLabel.setText(curr_text) self.lossLabel.setText(loss_text) def toggle(self, reason): """ Toggle window visibility """ if reason == QSystemTrayIcon.ActivationReason.DoubleClick: # pylint: disable=no-member self.setVisible(not self.isVisible()) if self.isVisible(): self.activateWindow()
class Graph(QChartView): def __init__(self, parent=None): super().__init__(parent=parent) self.setpoint_temperature = None self.chart = QChart() self.chart.legend().hide() self.setChart( self.chart ) self.setRenderHint(QPainter.Antialiasing) self.chart.setPlotAreaBackgroundBrush( QBrush(Qt.black) ) self.chart.setPlotAreaBackgroundVisible( True ) self.setpointTemperatureSeries = QLineSeries( self.chart ) pen = self.setpointTemperatureSeries.pen() pen.setWidthF(2.) pen.setColor( Qt.green ) self.setpointTemperatureSeries.setPen( pen ) #self.setpointTemperatureSeries.setUseOpenGL( True ) self.chart.addSeries( self.setpointTemperatureSeries ) self.temperatureSeries = QLineSeries( self.chart ) pen = self.temperatureSeries.pen() pen.setWidthF(2.) pen.setColor( Qt.red ) self.temperatureSeries.setPen( pen ) #self.temperatureSeries.setUseOpenGL( True ) self.chart.addSeries( self.temperatureSeries ) self.number_of_samples_to_keep = 2 * 5 * 60 self.xMin = QDateTime.currentDateTime().toMSecsSinceEpoch() self.xMax = QDateTime.currentDateTime().toMSecsSinceEpoch() self.yMin = 400 self.yMax = 0 #self.chart.createDefaultAxes() #x_axis = QValueAxis() x_axis = QDateTimeAxis() x_axis.setTitleText( "Time" ) x_axis.setFormat("HH:mm:ss") self.chart.addAxis( x_axis, Qt.AlignBottom ) self.temperatureSeries.attachAxis( x_axis ) self.setpointTemperatureSeries.attachAxis( x_axis ) startDate = QDateTime.currentDateTime().addSecs( -5 * 60 ) endDate = QDateTime.currentDateTime().addSecs( 5 * 60 ) #startDate = QDateTime(QDate(2017, 1, 9), QTime(17, 25, 0)) #endDate = QDateTime(QDate(2017, 1, 9), QTime(17, 50, 0)) #self.chart.axisX().setRange( startDate, endDate ) #self.chart.axisX().setRange( 0, 100 ) y_axis = QValueAxis() y_axis.setTitleText( "Temperature (K)" ) self.chart.addAxis( y_axis, Qt.AlignLeft ) self.temperatureSeries.attachAxis( y_axis ) self.setpointTemperatureSeries.attachAxis( y_axis ) self.chart.axisY().setRange( 0, 400 ) #self.chart.axisY().setRange( 260., 290. ) self.temperatureSeries.pointAdded.connect( self.Rescale_Axes ) #self.setpointTemperatureSeries.pointAdded.connect( self.Rescale_Axes ) self.setRubberBand( QChartView.HorizontalRubberBand ) # Customize chart title font = QFont() font.setPixelSize(24); self.chart.setTitleFont(font); self.chart.setTitleBrush(QBrush(Qt.white)); ## Customize chart background #backgroundGradient = QLinearGradient() #backgroundGradient.setStart(QPointF(0, 0)); #backgroundGradient.setFinalStop(QPointF(0, 1)); #backgroundGradient.setColorAt(0.0, QColor(0x000147)); #backgroundGradient.setColorAt(1.0, QColor(0x000117)); #backgroundGradient.setCoordinateMode(QGradient.ObjectBoundingMode); #self.chart.setBackgroundBrush(backgroundGradient); transparent_background = QBrush(QColor(0,0,0,0)) self.chart.setBackgroundBrush( transparent_background ) # Customize axis label font labelsFont = QFont() labelsFont.setPixelSize(16); x_axis.setLabelsFont(labelsFont) y_axis.setLabelsFont(labelsFont) x_axis.setTitleFont(labelsFont) y_axis.setTitleFont(labelsFont) # Customize axis colors axisPen = QPen(QColor(0xd18952)) axisPen.setWidth(2) x_axis.setLinePen(axisPen) y_axis.setLinePen(axisPen) # Customize axis label colors axisBrush = QBrush(Qt.white) x_axis.setLabelsBrush(axisBrush) y_axis.setLabelsBrush(axisBrush) x_axis.setTitleBrush(axisBrush) y_axis.setTitleBrush(axisBrush) def set_title(self, title): self.chart.setTitle(title) def add_new_data_point( self, x, y ): x_as_millisecs = x.toMSecsSinceEpoch() self.temperatureSeries.append( x_as_millisecs, y ) if( self.setpoint_temperature ): self.setpointTemperatureSeries.append( x_as_millisecs, self.setpoint_temperature ) num_of_datapoints = self.temperatureSeries.count() #if( num_of_datapoints > self.number_of_samples_to_keep ): # self.number_of_samples_to_keep. #print( x_as_millisecs, y ) #self.chart.scroll( x_as_millisecs - 5 * 60 * 1000, x_as_millisecs ) #self.temperatureSeries.append( x, float(y) ) #self.repaint() def Rescale_Axes( self, index ): x = self.temperatureSeries.at( index ).x() x_rescaled = False if( x < self.xMin ): self.xMin = x x_rescaled = True if( x > self.xMax ): self.xMax = x x_rescaled = True if( x_rescaled ): full_range = min( self.xMax - self.xMin, 5 * 60 * 1000 ) margin = full_range * 0.05 self.chart.axisX().setRange( QDateTime.fromMSecsSinceEpoch(self.xMax - full_range - margin), QDateTime.fromMSecsSinceEpoch(self.xMax + margin) ) y = self.temperatureSeries.at( index ).y() y_rescaled = False if( y < self.yMin ): self.yMin = y y_rescaled = True if( y > self.yMax ): self.yMax = y y_rescaled = True if( y_rescaled ): full_range = self.yMax - self.yMin margin = full_range * 0.05 self.chart.axisY().setRange( self.yMin - margin, self.yMax + margin )
class Display(QWidget): def __init__(self, trainer='MLP', debug=False): # QWidget Setup QWidget.__init__(self, flags=Qt.CustomizeWindowHint | Qt.WindowTitleHint) self.setWindowTitle("NeuroSky GUI") self.resize(1400, 1000) # Linker Params self._linker = Linker(debug=debug, trainer=trainer) self.TRAINER_FORWARD = self._linker.trainer.add_identifier('forward') self.TRAINER_BACKWARD = self._linker.trainer.add_identifier('backward') self.TRAINER_IDLE = self._linker.trainer.add_identifier('idle') # Indicators self._raw_data_indicator = self._create_indicator('Raw Data:') self._poor_level_indicator = self._create_indicator( 'Poor Level Signal:') self._sample_rate_indicator = self._create_indicator('Sample Rate:') self._prediction_indicator = self._create_indicator('Prediction:') self._training_status_indicator = self._create_indicator( 'Training Status:') self._forward_counter_indicator = self._create_indicator( 'Current Forward Count:') self._backward_counter_indicator = self._create_indicator( 'Current Backward Count:') self._idle_counter_indicator = self._create_indicator( 'Current Idle Count:') # Initializing layout self.main_page() # Series self._x_axis = 0 self._connect_data() def main_page(self): # type: (Display) -> None # Top Layout top_left_layout = QVBoxLayout() top_left_layout.addLayout(self._raw_data_indicator['layout']) top_left_layout.addLayout(self._poor_level_indicator['layout']) top_left_layout.addLayout(self._sample_rate_indicator['layout']) top_right_layout = QVBoxLayout() top_right_layout.addWidget(self._get_connector_chart(), alignment=Qt.AlignCenter) # top_right_layout.setStretchFactor(self._get_connector_chart(), 1) top_layout = QHBoxLayout() top_layout.addLayout(top_left_layout) top_layout.addLayout(top_right_layout) # Bottom Layout bottom_left_layout = QVBoxLayout() bottom_left_layout.addLayout(self._prediction_indicator['layout']) bottom_left_layout.addLayout(self._training_status_indicator['layout']) bottom_left_layout.addLayout(self._idle_counter_indicator['layout']) bottom_left_layout.addLayout(self._forward_counter_indicator['layout']) bottom_left_layout.addLayout( self._backward_counter_indicator['layout']) bottom_right_layout = QVBoxLayout() bottom_right_layout.addWidget(self._get_processor_chart(), alignment=Qt.AlignCenter) bottom_layout = QHBoxLayout() bottom_layout.addLayout(bottom_left_layout) bottom_layout.addLayout(bottom_right_layout) # Outer Layout outer_layout = QVBoxLayout() outer_layout.addLayout(top_layout) outer_layout.addLayout(bottom_layout) # Set Layout self.setLayout(outer_layout) def _get_connector_chart(self): # type: (Display) -> QChartView # Create pen pen = QLineSeries().pen() pen.setColor(Qt.blue) pen.setWidthF(1) # Series self._connector_series = QLineSeries() self._connector_series.setPen(pen) self._connector_series.useOpenGL() # Chart self._connector_chart = QChart() self._connector_chart.legend().hide() self._connector_chart.addSeries(self._connector_series) self._connector_chart.createDefaultAxes() self._connector_chart.axisX().setMax(100) self._connector_chart.axisX().setMin(0) self._connector_chart.axisY().setMax(500) self._connector_chart.axisY().setMin(-500) # Chart View view = QChartView(self._connector_chart) view.setRenderHint(QPainter.Antialiasing) view.setStyleSheet('margin: 0px; height: 250%; width: 400%;') return view def _get_processor_chart(self): # type: (Display) -> QChartView # Create pen pen = QLineSeries().pen() pen.setColor(Qt.red) pen.setWidthF(1) # Series self._processor_series = QLineSeries() self._processor_series.setPen(pen) self._processor_series.useOpenGL() # Chart self._processor_chart = QChart() self._processor_chart.legend().hide() self._processor_chart.addSeries(self._processor_series) self._processor_chart.createDefaultAxes() self._processor_chart.axisX().setMax(100) self._processor_chart.axisX().setMin(0) self._processor_chart.axisY().setMax(5000) self._processor_chart.axisY().setMin(0) self._processor_x_axis = QValueAxis() self._processor_x_axis.setLabelFormat('%i') self._processor_chart.setAxisX(self._processor_x_axis, self._processor_series) self._processor_y_axis = QLogValueAxis() self._processor_y_axis.setLabelFormat('%g') self._processor_y_axis.setBase(8) # Chart View view = QChartView(self._processor_chart) view.setRenderHint(QPainter.Antialiasing) view.setStyleSheet('margin: 0px; height: 250%; width: 400%;') return view def _connect_data(self): # type: (Display) -> None self._linker.raw.connect(self._add_connector_data) self._linker.poor_signal_level.connect( lambda level: self._poor_level_indicator['label'].setText( str(level))) self._linker.sampling_rate.connect( lambda rate: self._sample_rate_indicator['label'].setText(str(rate) )) self._linker.fft.connect(self._add_processor_data) self._linker.prediction.connect( lambda prediction: self._prediction_indicator['label'].setText( str(prediction))) self._linker.training_status.connect( lambda status: self._training_status_indicator['label'].setText( str(status))) self._linker.identifiers.connect(self._connect_identifiers) def keyPressEvent(self, event): # type: (Display, {key}) -> None key = event.key() if key == Qt.Key_Escape: self._linker.close() self.close() elif key == Qt.Key_W: # self._linker.connector.record( # './data/raw_data/' + self._linker.trainer.get_next_connector_label(self.TRAINER_FORWARD) # ) # self._linker.processor.record( # './data/processed_data/' + self._linker.trainer.get_next_processor_label(self.TRAINER_FORWARD) # ) self._linker.trainer.train(self.TRAINER_FORWARD) elif key == Qt.Key_S: # self._linker.connector.record( # './data/raw_data/' + self._linker.trainer.get_next_connector_label(self.TRAINER_BACKWARD) # ) # self._linker.processor.record( # './data/processed_data/' + self._linker.trainer.get_next_processor_label(self.TRAINER_BACKWARD) # ) self._linker.trainer.train(self.TRAINER_BACKWARD) elif key == Qt.Key_Space: # self._linker.connector.record( # './data/raw_data/' + self._linker.trainer.get_next_connector_label(self.TRAINER_IDLE) # ) # self._linker.processor.record( # './data/processed_data/' + self._linker.trainer.get_next_processor_label(self.TRAINER_IDLE) # ) self._linker.trainer.train(self.TRAINER_IDLE) else: print(key) @staticmethod def _create_indicator( label): # type: (Any) -> Dict[str, Union[QHBoxLayout, QLabel]] layout = QHBoxLayout() display_widget = QLabel(label) layout.addWidget(display_widget, alignment=Qt.AlignCenter) label_widget = QLabel('Initializing...') layout.addWidget(label_widget, alignment=Qt.AlignCenter) return { 'layout': layout, 'display': display_widget, 'label': label_widget } @pyqtSlot(int) def _add_connector_data(self, data): # type: (Display, Any) -> Optional[Any] self._raw_data_indicator['label'].setText(str(data)) self._connector_series.append(self._x_axis, data) if self._connector_series.count() >= 100: self._connector_series.clear() self._x_axis = 0 else: self._x_axis += 1 @pyqtSlot(np.ndarray) def _add_processor_data( self, data): # type: (Display, {__getitem__}) -> Optional[Any] self._processor_series.clear() x_axis = data[0] y_axis = data[1] for i in range(len(x_axis)): self._processor_series.append(x_axis[i], y_axis[i]) @pyqtSlot(list) def _connect_identifiers(self, identifiers): for identifier in identifiers: if identifier['name'] == self.TRAINER_IDLE: self._idle_counter_indicator['label'].setText( str(identifier['training_count'])) elif identifier['name'] == self.TRAINER_FORWARD: self._forward_counter_indicator['label'].setText( str(identifier['training_count'])) elif identifier['name'] == self.TRAINER_BACKWARD: self._backward_counter_indicator['label'].setText( str(identifier['training_count']))
class SeeingMonitor(QMainWindow, Ui_MainWindow): def __init__(self): super(SeeingMonitor, self).__init__() self.setupUi(self) self.Camera = None self.THRESH = None self.threshold_auto = False self.frame = None self.draw_only_frame = None self.video_source = VideoSource.NONE self.export_video = False self.select_noiseArea = False self.coordinates_noiseArea = [] self.lineedit_path.setText(QDir.currentPath()) self.lineedit_filename.setText("seeing.csv") self.save_filename = None self._updateFileSave() self.pause_pressed = False self.datetimeedit_start.setMinimumDateTime(QDateTime.currentDateTime()) self.datetimeedit_end.setMinimumDateTime(QDateTime.currentDateTime()) if platform.system() == 'Linux': self.button_start.setEnabled(False) self.button_settings.setEnabled(False) self.button_start.clicked.connect(self.startLiveCamera) self.button_settings.clicked.connect(self.showSettings) self.button_simulation.clicked.connect(self.startSimulation) self.button_import.clicked.connect(self.importVideo) self.button_export.clicked.connect(self.exportVideo) self.button_noise.clicked.connect(self.selectNoiseArea) self.lineedit_path.textEdited.connect(self._updateFileSave) self.lineedit_filename.textEdited.connect(self._updateFileSave) self.slider_threshold.valueChanged.connect(self._updateThreshold) self.checkbox_thresh.stateChanged.connect(self._updateThresholdState) # Update the Tilt value self.spinbox_b.valueChanged.connect(self._updateFormulaZTilt) self.spinbox_d.valueChanged.connect(self._updateFormulaZTilt) # Update the constants in the FWHM seeing formula self.spinbox_d.valueChanged.connect(self._updateFormulaConstants) self.spinbox_lambda.valueChanged.connect(self._updateFormulaConstants) # Timer for acquiring images at regular intervals self.acquisition_timer = QTimer(parent=self.centralwidget) self.timer_interval = None self._updateThreshold() self._updateFormulaZTilt() self._updateFormulaConstants() # Storing the Delta X and Y in an array to calculate the Standard Deviation self.arr_delta_x = deque(maxlen=100) self.arr_delta_y = deque(maxlen=100) self.plot_length = 1000 self.fwhm_lat = 0 self.fwhm_tra = 0 self.max_lat = 1 self.min_lat = 0 self.max_tra = 1 self.min_tra = 0 self.series_lat = QLineSeries() self.series_lat.setName("Lateral") self.series_tra = QLineSeries() self.series_tra.setName("Transversal") self.chart = QChart() self.chart.addSeries(self.series_lat) self.chart.addSeries(self.series_tra) # self.chart.createDefaultAxes() self.axis_horizontal = QDateTimeAxis() self.axis_horizontal.setMin(QDateTime.currentDateTime().addSecs(-60 * 1)) self.axis_horizontal.setMax(QDateTime.currentDateTime().addSecs(0)) self.axis_horizontal.setFormat("HH:mm:ss.zzz") self.axis_horizontal.setLabelsFont( QFont(QFont.defaultFamily(self.font()), pointSize=5)) self.axis_horizontal.setLabelsAngle(-20) self.chart.addAxis(self.axis_horizontal, Qt.AlignBottom) self.axis_vertical_lat = QValueAxis() self.axis_vertical_lat.setRange(self.max_lat, self.min_lat) self.chart.addAxis(self.axis_vertical_lat, Qt.AlignLeft) self.axis_vertical_tra = QValueAxis() self.axis_vertical_tra.setRange(self.max_tra, self.min_tra) self.chart.addAxis(self.axis_vertical_tra, Qt.AlignRight) self.series_lat.attachAxis(self.axis_horizontal) self.series_lat.attachAxis(self.axis_vertical_lat) self.series_tra.attachAxis(self.axis_horizontal) self.series_tra.attachAxis(self.axis_vertical_tra) self.chart.setTitle("Full Width at Half Maximum") self.chart.legend().setVisible(True) self.chart.legend().setAlignment(Qt.AlignBottom) self.chartView = QChartView(self.chart, parent=self.graphicsView) self.chartView.resize(640, 250) self.chartView.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) self.chartView.setRenderHint(QPainter.Antialiasing) def closeEvent(self, event): try: self.Camera.StopLive() except AttributeError: pass try: self.cap.release() except AttributeError: pass try: self.video_writer.release() except AttributeError: pass event.accept() def _callbackFunction(self, hGrabber, pBuffer, framenumber, pData): """ This is an example callback function for image processig with opencv. The image data in pBuffer is converted into a cv Matrix and with cv.mean() the average brightness of the image is measuered. :param: hGrabber: This is the real pointer to the grabber object. :param: pBuffer : Pointer to the first pixel's first byte :param: framenumber : Number of the frame since the stream started :param: pData : Pointer to additional user data structure """ if pData.buffer_size > 0: image = C.cast(pBuffer, C.POINTER(C.c_ubyte * pData.buffer_size)) cvMat = np.ndarray(buffer=image.contents, dtype=np.uint8, shape=(pData.height, pData.width, pData.iBitsPerPixel)) frame = np.uint8(cvMat) self.frame = cv2.resize(frame, (640, 480)) self.draw_only_frame = self.frame.copy() self._monitor() def _startLiveCamera(self): # Create a function pointer Callbackfunc = IC.TIS_GrabberDLL.FRAMEREADYCALLBACK( self._callbackFunction) ImageDescription = CallbackUserData() # Create the camera object self.Camera = IC.TIS_CAM() self.Camera.ShowDeviceSelectionDialog() if self.Camera.IsDevValid() != 1: print("[Error Camera Selection] Couldn't open camera device !") # QMessageBox.warning(self, "Error Camera Selection", "Couldn't open camera device !") # raise Exception("Unable to open camera device !") return # Now pass the function pointer and our user data to the library self.Camera.SetFrameReadyCallback(Callbackfunc, ImageDescription) # Handle each incoming frame automatically self.Camera.SetContinuousMode(0) print('Starting live stream ...') self.Camera.StartLive( 0 ) ####### PAUSE LIVE STREAM WHEN PAUSE CLICKED ??? ############################################## # self.Camera.StartLive(1) Imageformat = self.Camera.GetImageDescription()[:3] ImageDescription.width = Imageformat[0] ImageDescription.height = Imageformat[1] ImageDescription.iBitsPerPixel = Imageformat[2] // 8 ImageDescription.buffer_size = ImageDescription.width * ImageDescription.height * ImageDescription.iBitsPerPixel while self.video_source == VideoSource.CAMERA: pass # self.timer_interval = 20 # try: # self.acquisition_timer.disconnect() # except TypeError: # pass # self.acquisition_timer.timeout.connect(self._updateLiveCamera) # self.acquisition_timer.start(self.timer_interval) def startLiveCamera(self): try: self.acquisition_timer.disconnect() except TypeError: pass self.video_source = VideoSource.CAMERA self.button_export.setEnabled(True) self._setPauseButton() # Disable other functionalities # self.button_simulation.setEnabled(False) t = threading.Thread(target=self._startLiveCamera, args=(), daemon=True) t.start() def showSettings(self): if not self.Camera.IsDevValid(): QMessageBox.warning( self, "Camera Selection Error", "Please select a camera first by clicking on the button <strong>Start</strong>" ) return try: self.Camera.ShowPropertyDialog() except Exception as e: logging.error(traceback.format_exc()) QMessageBox.warning(self, "Property Dialog Error", traceback.format_exc()) # def _updateLiveCamera(self): # # Capturing a frame # self.Camera.SnapImage() # frame = self.Camera.GetImage() # frame = np.uint8(frame) # self.frame = cv2.resize(frame, (640, 480)) # self.draw_only_frame = self.frame.copy() # self._monitor() # self.displayParameters() def displayParameters(self): parameters_text = "" ExposureTime = [0] self.Camera.GetPropertyAbsoluteValue("Exposure", "Value", ExposureTime) parameters_text = parameters_text + str(ExposureTime[0]) + "\n" GainValue = [0] self.Camera.GetPropertyAbsoluteValue("Gain", "Value", GainValue) parameters_text = parameters_text + str(GainValue[0]) + "\n" self.parameters_label.setText(parameters_text) self.parameters_label.adjustSize() def startSimulation(self): if self.Camera != None and self.Camera.IsDevValid() == 1: self.Camera.StopLive() self.video_source = VideoSource.SIMULATION self.button_export.setEnabled(True) self._setPauseButton() # Disable other functionalities # self.button_start.setEnabled(False) self.button_settings.setEnabled(False) # Generating fake images of DIMM star (One single star that is split by the DIMM) self.starsGenerator = FakeStars() self.timer_interval = 100 try: self.acquisition_timer.disconnect() except TypeError: pass self.acquisition_timer.timeout.connect(self._updateSimulation) self.acquisition_timer.start(self.timer_interval) def _updateSimulation(self): frame = self.starsGenerator.generate() self.frame = cv2.resize(frame, (640, 480)) self.draw_only_frame = self.frame.copy() self._monitor() ################################################################################################################################################################ def _writeCSV(self, headerOnly=False): if headerOnly: with open(self.save_filename, "w") as csvFile: fieldnames = ["timestamp", "lateral", "transversal", "star"] writer = csv.DictWriter(csvFile, fieldnames=fieldnames) writer.writeheader() csvFile.close() else: with open(self.save_filename, "a") as csvFile: writer = csv.writer(csvFile) writer.writerow([ self.current.toTime_t(), self.fwhm_lat, self.fwhm_tra, self.lineedit_star.text() ]) # csvFile.write(",".join([str(self.current) , str(self.fwhm_lat), str(self.fwhm_tra), self.lineedit_star.text()])) # csvFile.write("\n") # csvFile.close() def selectNoiseArea(self): self.label_info.setText("Please select on the video a noise area.") self.button_noise.setText("Selecting ...") self.coordinates_noiseArea = [] self.select_noiseArea = True def _set_noiseArea(self, x1, y1, x2, y2): if len(self.coordinates_noiseArea) == 0: self.coordinates_noiseArea.append([x1, y1]) self.coordinates_noiseArea.append([x2, y2]) elif len(self.coordinates_noiseArea) == 2: self.coordinates_noiseArea[0] = [x1, y1] self.coordinates_noiseArea[1] = [x2, y2] def _draw_noiseArea(self): if len(self.coordinates_noiseArea) >= 2: cv2.rectangle(self.draw_only_frame, (self.coordinates_noiseArea[0][0], self.coordinates_noiseArea[0][1]), (self.coordinates_noiseArea[1][0], self.coordinates_noiseArea[1][1]), (0, 255, 0), 1) def _updateFileSave(self): self.save_filename = join(self.lineedit_path.text(), self.lineedit_filename.text()) self._writeCSV(headerOnly=True) def _updateThreshold(self): if self.threshold_auto: if self.coordinates_noiseArea.__len__() >= 2: noise_area = self.frame[self.coordinates_noiseArea[0][1]:self. coordinates_noiseArea[1][1], self.coordinates_noiseArea[0][0]:self. coordinates_noiseArea[1][0]] try: self.THRESH = noise_area.max() + 20 # self.THRESH = int(round(noise_area.mean())) except ValueError: return self.slider_threshold.setValue(self.THRESH) self.checkbox_thresh.setText("Threshold ({}, auto)".format( self.THRESH)) else: self.THRESH = self.slider_threshold.value() self.checkbox_thresh.setText("Threshold ({})".format(self.THRESH)) def _updateThresholdState(self, state): if state == 0: self.threshold_auto = False self.slider_threshold.setEnabled(True) else: if self.coordinates_noiseArea.__len__() < 2: QMessageBox.information(self, "Select Noise Area", "Please select the noise area") self.selectNoiseArea() self.threshold_auto = True self.slider_threshold.setEnabled(False) def _updateFormulaZTilt(self): self.spinbox_d.setStyleSheet("QSpinBox { background-color: blue; }") try: b = float(self.spinbox_b.value()) / float(self.spinbox_d.value()) except ZeroDivisionError: QMessageBox.warning(self, "Zero Division Error", "D (Apertures Diameter cannot be Zero") return self.K_lat = 0.364 * (1 - 0.532 * np.power(b, -1 / 3) - 0.024 * np.power(b, -7 / 3)) self.K_tra = 0.364 * (1 - 0.798 * np.power(b, -1 / 3) - 0.018 * np.power(b, -7 / 3)) def _updateFormulaConstants(self): # Calculate value to make process faster self.A = 0.98 * np.power( float(self.spinbox_d.value()) / float(self.spinbox_lambda.value()), 0.2) def _calcSeeing(self): std_x = np.std(self.arr_delta_x) std_y = np.std(self.arr_delta_y) # Seeing self.current = QDateTime.currentDateTime() self.fwhm_lat = self.A * np.power(std_x / self.K_lat, 0.6) self.fwhm_tra = self.A * np.power(std_y / self.K_tra, 0.6) threading.Thread(target=self._plotSeeing, args=(), daemon=True).start() threading.Thread(target=self._writeCSV, args=(), daemon=True).start() self.label_info.setText("lat: " + str(self.fwhm_lat) + " | lon: " + str(self.fwhm_tra)) def _calcSeeing_arcsec(self): std_x = np.std(self.arr_delta_x) std_y = np.std(self.arr_delta_y) # Seeing self.current = QDateTime.currentDateTime() self.fwhm_lat = self.A * np.power( std_x / self.K_lat, 0.6) * 205.0 * self.spinbox_pwidth.value( ) / self.spinbox_focal.value() self.fwhm_tra = self.A * np.power( std_y / self.K_tra, 0.6) * 205.0 * self.spinbox_pheight.value( ) / self.spinbox_focal.value() threading.Thread(target=self._plotSeeing, args=(), daemon=True).start() threading.Thread(target=self._writeCSV, args=(), daemon=True).start() self.label_info.setText("lat: " + str(self.fwhm_lat) + " | lon: " + str(self.fwhm_tra)) def _monitor(self): tic = time.time() gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY) self._updateThreshold() _, thresholded = cv2.threshold(gray, self.THRESH, 255, cv2.THRESH_TOZERO) # _, contours, _ = cv2.findContours(thresholded, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) contours, _ = cv2.findContours(thresholded, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) contours = contours[:2] # if contours.__len__() > 2: # QMessageBox.warning(self, "Thresholding error", "More than 2 projections were found. " + \ # "Please increase threshold manually or select a better noise area.") cv2.drawContours(self.draw_only_frame, contours, -1, (0, 255, 0), 2) self._draw_noiseArea() try: moments_star_1 = cv2.moments(contours[0]) moments_star_2 = cv2.moments(contours[1]) except IndexError: print("Only {} were found ! (Must be at least 2)".format( len(contours))) else: try: cX_star1 = int(moments_star_1["m10"] / moments_star_1["m00"]) cY_star1 = int(moments_star_1["m01"] / moments_star_1["m00"]) cX_star2 = int(moments_star_2["m10"] / moments_star_2["m00"]) cY_star2 = int(moments_star_2["m01"] / moments_star_2["m00"]) except ZeroDivisionError: return if self.enable_seeing.isChecked(): delta_x = abs(cX_star2 - cX_star1) delta_y = abs(cY_star2 - cY_star1) self.arr_delta_x.append(delta_x) self.arr_delta_y.append(delta_y) # self._calcSeeing() self._calcSeeing_arcsec() cv2.drawMarker(self.draw_only_frame, (cX_star1, cY_star1), color=(0, 0, 255), markerSize=30, thickness=1) cv2.drawMarker(self.draw_only_frame, (cX_star2, cY_star2), color=(0, 0, 255), markerSize=30, thickness=1) finally: self._displayImage() threading.Thread(target=self._writeVideoFile, args=(), daemon=True).start() toc = time.time() elapsed = toc - tic try: print("FPS max = {}".format(int(1.0 / elapsed))) except ZeroDivisionError: pass def _displayImage(self): qImage = array2qimage(self.draw_only_frame) self.stars_capture.setPixmap(QPixmap(qImage)) def _plotSeeing(self): self.axis_horizontal.setMin(QDateTime.currentDateTime().addSecs(-60 * 1)) self.axis_horizontal.setMax(QDateTime.currentDateTime().addSecs(0)) if self.series_lat.count() > self.plot_length - 1: self.series_lat.removePoints( 0, self.series_lat.count() - self.plot_length - 1) if self.series_tra.count() > self.plot_length - 1: self.series_tra.removePoints( 0, self.series_tra.count() - self.plot_length - 1) if self.fwhm_lat > self.max_lat: self.max_lat = self.fwhm_lat self.axis_vertical_lat.setMax(self.max_lat + 10) if self.fwhm_lat < self.min_lat: self.min_lat = self.fwhm_lat self.axis_vertical_lat.setMax(self.min_lat - 10) if self.fwhm_tra > self.max_tra: self.max_tra = self.fwhm_tra self.axis_vertical_tra.setMax(self.max_tra + 10) if self.fwhm_tra < self.min_tra: self.min_tra = self.fwhm_tra self.axis_vertical_tra.setMax(self.min_tra - 10) # print(self.fwhm_lat, self.fwhm_tra) self.series_lat.append(self.current.toMSecsSinceEpoch(), self.fwhm_lat) self.series_tra.append(self.current.toMSecsSinceEpoch(), self.fwhm_tra) def importVideo(self): self.video_source = VideoSource.VIDEO self.button_export.setEnabled(True) self._setPauseButton() options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog filename, _ = QFileDialog.getOpenFileName( self, "Import from Video File", QDir.currentPath(), "Video Files (*.avi *.mp4 *.mpeg *.flv *.3gp *.mov);;All Files (*)", options=options) if filename: if self.Camera != None and self.Camera.IsDevValid() == 1: self.Camera.StopLive() self.cap = cv2.VideoCapture(filename) # print("CAP_PROP_POS_MSEC :", self.cap.get(cv2.CAP_PROP_POS_MSEC)) # print("CAP_PROP_POS_FRAMES :", self.cap.get(cv2.CAP_PROP_POS_FRAMES)) # print("CAP_PROP_POS_AVI_RATIO :", self.cap.get(cv2.CAP_PROP_POS_AVI_RATIO)) # print("CAP_PROP_FRAME_WIDTH :", self.cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # print("CAP_PROP_FRAME_HEIGHT :", self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # print("CAP_PROP_FPS :", self.cap.get(cv2.CAP_PROP_FPS)) # print("CAP_PROP_FOURCC :", self.cap.get(cv2.CAP_PROP_FOURCC)) # print("CAP_PROP_FRAME_COUNT :", self.cap.get(cv2.CAP_PROP_FRAME_COUNT)) # print("CAP_PROP_FORMAT :", self.cap.get(cv2.CAP_PROP_FORMAT)) # print("CAP_PROP_MODE :", self.cap.get(cv2.CAP_PROP_MODE)) # print("CAP_PROP_BRIGHTNESS :", self.cap.get(cv2.CAP_PROP_BRIGHTNESS)) # print("CAP_PROP_CONTRAST :", self.cap.get(cv2.CAP_PROP_CONTRAST)) # print("CAP_PROP_SATURATION :", self.cap.get(cv2.CAP_PROP_SATURATION)) # print("CAP_PROP_HUE :", self.cap.get(cv2.CAP_PROP_HUE)) # print("CAP_PROP_GAIN :", self.cap.get(cv2.CAP_PROP_GAIN)) # print("CAP_PROP_EXPOSURE :", self.cap.get(cv2.CAP_PROP_EXPOSURE)) # print("CAP_PROP_CONVERT_RGB :", self.cap.get(cv2.CAP_PROP_CONVERT_RGB)) # print("CAP_PROP_WHITE_APERTURE :", self.cap.get(cv2.CAP_PROP_APERTURE)) # print("CAP_PROP_RECTIFICATION :", self.cap.get(cv2.CAP_PROP_RECTIFICATION)) # print("CAP_PROP_ISO_SPEED :", self.cap.get(cv2.CAP_PROP_ISO_SPEED)) # print("CAP_PROP_BUFFERSIZE :", self.cap.get(cv2.CAP_PROP_BUFFERSIZE)) if self.cap.isOpened() == False: QMessageBox.warning(self, "Import from Video", "Cannot load file '{}'.".format(filename)) return self.timer_interval = round(1000.0 / self.cap.get(cv2.CAP_PROP_FPS)) try: self.acquisition_timer.disconnect() except TypeError: pass self.acquisition_timer.timeout.connect(self._grabVideoFrame) self.acquisition_timer.start(self.timer_interval) def _grabVideoFrame(self): ret, frame = self.cap.read() if ret == True: self.frame = cv2.resize(frame, (640, 480)) self.draw_only_frame = self.frame.copy() self._monitor() else: try: self.acquisition_timer.disconnect() except TypeError: pass QMessageBox.information(self, "Import from Video", "Video complete !") self.cap.release() def exportVideo(self): # if not self.enable_seeing.isChecked(): # answer = QMessageBox.question(self, # "Export to Video File", # "Seeing Monitoring is not activated. Continue ?", # QMessageBox.Yes|QMessageBox.No, # QMessageBox.No) # if answer == QMessageBox.No: # return options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog filename, _ = QFileDialog.getSaveFileName( self, "Export to Video File", QDir.currentPath(), "All Files (*);;Video Files (*.avi *.mp4 *.mpeg *.flv *.3gp *.mov)", options=options) if filename: if splitext(filename)[1] != ".avi": filename = splitext(filename)[0] + ".avi" QMessageBox.information( self, "Export to Video File", "Only '.avi' extension is supported. Video will be saved as '{}'" .format(filename)) print(round(1000.0 / float(self.timer_interval))) self.video_writer = cv2.VideoWriter( filename, cv2.VideoWriter_fourcc(*'MJPG'), round(1000.0 / float(self.timer_interval)), ( 640, 480 ) ################################################################################# ) self.export_video = True def _writeVideoFile(self): current = QDateTime.currentDateTime() if self.export_video and current >= self.datetimeedit_start.dateTime() and \ current < self.datetimeedit_end.dateTime(): # self.video_writer.write(self.frame) self.video_writer.write(self.draw_only_frame) def _setPauseButton(self): self.button_pause.setEnabled(True) self.button_pause.setText("⏸ Pause") self.button_pause.clicked.connect(self._pause) def _pause(self): self.pause_pressed = True # IC_SuspendLive IC_StopLive ################################################################################## self.button_pause.setText("▶ Resume") self.button_pause.clicked.connect(self._resume) if self.video_source == VideoSource.CAMERA: self.Camera.StopLive() else: self.acquisition_timer.stop() def _resume(self): self.pause_pressed = False self._setPauseButton() if self.video_source == VideoSource.CAMERA: self.Camera.StartLive(0) else: try: self.acquisition_timer.disconnect() except TypeError: pass self.acquisition_timer.start(self.timer_interval) if self.video_source == VideoSource.CAMERA: pass elif self.video_source == VideoSource.SIMULATION: self.acquisition_timer.timeout.connect(self._updateSimulation) elif self.video_source == VideoSource.VIDEO: self.acquisition_timer.timeout.connect(self._grabVideoFrame)
class Chart(QChart): MIN_X = 0 MAX_X = 750 MIN_Y = -1 MAX_Y = 1 TICKS = 5 PENCOLOR = Qt.red PENWIDTH = 1 def __init__(self, parent=None): super(Chart, self).__init__(parent) self.parent = parent # we will draw lines self.series = QLineSeries(parent) # color and pen-width self.series.setPen(QPen(self.PENCOLOR, self.PENWIDTH)) self.addSeries(self.series) self.legend().hide() self.__construct_axises() def setRange_X_axis(self, min_X, max_X): self.MIN_X = min_X self.MAX_X = max_X self.axisX().setRange(self.MIN_X, self.MAX_X) def setRange_Y_axis(self, min_Y, max_Y): self.MIN_Y = min_Y self.MAX_Y = max_Y self.axisY().setRange(self.MIN_Y, self.MAX_Y) def add_point(self, x, y): self.series.append(x, y) def get_series(self) -> list: return self.series.pointsVector() def remove_point(self, index): self.series.remove(index) def remove_points(self, index, count): self.series.removePoints(index, count) def replace_point(self, index, x, y): self.series.replace(index, x, y) def replace_series(self, lst): self.series.replace(lst) def get_series_count(self): return self.series.count() def __construct_axises(self): self.createDefaultAxes() # X-Axis x_axis = self.axisX() x_axis.hide() x_axis.setRange(self.MIN_X, self.MAX_X) # Y-axis y_axis = self.axisY() y_axis.setRange(self.MIN_Y, self.MAX_Y) y_axis.setTickCount(self.TICKS)
class MainView(QWidget, Ui_Dialog): def __init__(self): super().__init__() Ui_Dialog.setupUi(self, self) self.pushButton_3.clicked.connect(self.showRecords) self.pushButton.clicked.connect(self.start) self.recive = False self.s = socket.socket() # Create a socket object self.c = socket.socket() # Create a socket object host = "192.168.1.40" # Get local machine name port = 12345 # Reserve a port for your serv host = "" # Get local machine nameice. self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.c.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.pushButton_3.setDisabled(True) self.pushButton.setText("Stop") try: self.s.bind(("", port)) # Bind to the port except: print("error") # self.s.listen(5) # Now wait for client connection. def __del__(self): self.s.close() def showConfiguration(self): self.hide() self.conf = configureView.configureView(self) self.conf.setMain(self) self.conf.show() def showRecords(self): self.w = QWidget() self.w.show() self.hide() self.gridLayout = QtWidgets.QVBoxLayout(self.w) self.text = QtWidgets.QLabel(self.w) self.chart = QChart() self.chart2 = QChart() self.chart3 = QChart() self.text.setText("none") self.backButton = QtWidgets.QPushButton(self.w) self.chartView = QChartView(self.chart) self.chartView.setRenderHint(QtGui.QPainter.Antialiasing) # self.chartView2.setRenderHint(QtGui.QPainter.Antialiasing) # self.chartView3.setRenderHint(QtGui.QPainter.Antialiasing) self.gridLayout.addWidget(self.chartView) # self.gridLayout.addWidget(self.chartView3) self.backButton.setText("Back") self.gridLayout.addWidget(self.backButton) self.backButton.clicked.connect(self.back) self.recive = True # self.series2 = QLineSeries(self.chart2) # self.series3 = QLineSeries(self.chart3) self.series = QLineSeries(self.chart) self.series2 = QLineSeries(self.chart) self.series3 = QLineSeries(self.chart) # self.series2.setUseOpenGL(True) # self.series3.setUseOpenGL(True) self.series.setUseOpenGL(True) self.series2.setUseOpenGL(True) self.series3.setUseOpenGL(True) # self.chart.addSeries(self.series) self.startServer() def createLineChart(self, dataTable): self.chart.setTitle("Sensor1") series = QLineSeries(self.chart) series2 = QLineSeries(self.chart) series3 = QLineSeries(self.chart) # series2 = QLineSeries(self.chart) # series3 = QLineSeries(self.chart) series.setUseOpenGL(True) series2.setUseOpenGL(True) series3.setUseOpenGL(True) # series2.setUseOpenGL(True) # series3.setUseOpenGL(True) series.replace(self.series.pointsVector()) series2.replace(self.series2.pointsVector()) series3.replace(self.series3.pointsVector()) # series2.replace(self.series2.pointsVector()) # series3.replace(self.series2.pointsVector()) self.chart.removeAllSeries() self.chart.addSeries(series2) self.chart.addSeries(series) self.chart.addSeries(series3) # self.chart2.removeAllSeries() # self.chart2.addSeries(series2) # self.chart3.removeAllSeries() # self.chart3.addSeries(series3) # self.chart.scroll(1,2) def startServer(self): # Establish connection with client. a = [] QApplication.processEvents() self.c.connect(("192.168.1.41", 12346)) self.c.send(b'RecordView True') print("connected") index = 0 while self.recive: QApplication.processEvents() # c, addr = self.s.accept() message, adre = self.s.recvfrom(1024) # print(message) values = message.decode("utf-8").split("-") value1 = int(values[0]) value2 = int(values[1]) value3 = int(values[2]) self.series.append(index, value1) self.series2.append(index, value2) self.series3.append(index, value3) # self.series2.append(index, int(message.decode("utf-8"))) # self.series3.append(index, int(message.decode("utf-8"))) if self.series.count() > 100: self.series.removePoints(0, 1) self.series2.removePoints(0, 1) self.series3.removePoints(0, 1) # self.series2.removePoints(0,1) # self.series3.removePoints(0,1) index += 1 a.append(message.decode("utf-8")) self.createLineChart(a) self.c.connect(("192.168.1.41", 12346)) self.c.send(b'RecordView False') def back(self): self.w.hide() self.show() self.recive = False def configure(self, arguments): print(arguments) self.c.connect(("192.168.1.41", 12346)) self.c.send(b'Sensor ' + arguments) def start(self): self.c.connect(("192.168.1.41", 12346)) if self.pushButton.text() == "Start": text = "Stop" self.pushButton_3.setEnabled(False) self.c.send(b'Record False') else: text = "Start" self.pushButton_3.setEnabled(True) self.c.send(b'Record True') self.recive = self.pushButton.text() == "Start" self.pushButton.setText(text)