class Config(SignalNode.Config): """Config widget displayed for BandpassFilter.""" def __init__(self, parent=None): super().__init__(parent=parent) # Upper bound ---------------------------------------------------------------------------------------------- self.lower_bound_enable = QCheckBox() self.lower_bound_enable.setChecked(True) self.lower_bound_enable.stateChanged.connect(self.updateModel) self.lower_bound = QDoubleSpinBox() self.lower_bound.valueChanged.connect(self.updateModel) self.lower_bound.setMinimum(0) self.lower_bound.setMaximum(250) self.lower_bound.setSuffix(" Hz") layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) lower_bound_widget = QWidget() lower_bound_widget.setContentsMargins(0, 0, 0, 0) lower_bound_widget.setLayout(layout) layout.addWidget(self.lower_bound_enable) layout.addWidget(self.lower_bound) # Lower bound ---------------------------------------------------------------------------------------------- self.upper_bound_enable = QCheckBox() self.upper_bound_enable.setChecked(True) self.upper_bound_enable.stateChanged.connect(self.updateModel) self.upper_bound = QDoubleSpinBox() self.upper_bound.valueChanged.connect(self.updateModel) self.upper_bound.setMinimum(0) self.upper_bound.setMaximum(250) self.upper_bound.setSuffix(" Hz") layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) upper_bound_widget = QWidget() upper_bound_widget.setContentsMargins(0, 0, 0, 0) upper_bound_widget.setLayout(layout) layout.addWidget(self.upper_bound_enable) layout.addWidget(self.upper_bound) # Filter type and length ----------------------------------------------------------------------------------- self.filter_type = QComboBox() for name in BandpassFilter.filter_name_to_type: self.filter_type.addItem(name) self.filter_type.currentTextChanged.connect(self.updateModel) self.filter_length = QSpinBox() self.filter_length.setMinimum(2) self.filter_length.setMaximum(1000000) self.filter_length.setValue(1000) self.filter_length.valueChanged.connect(self.updateModel) self.filter_order = QSpinBox() self.filter_order.setRange(1, 4) self.filter_order.valueChanged.connect(self.updateModel) # ---------------------------------------------------------------------------------------------------------- layout = QFormLayout() layout.addRow("Lower bound:", lower_bound_widget) layout.addRow("Upper bound:", upper_bound_widget) layout.addRow("Filter type:", self.filter_type) layout.addRow("Filter order:", self.filter_order) layout.addRow("Filter length:", self.filter_length) self.setLayout(layout) def updateModel(self): n = self.node() if n is None: return if self.lower_bound_enable.isChecked(): lower_bound = self.lower_bound.value() else: lower_bound = None if self.upper_bound_enable.isChecked(): upper_bound = self.upper_bound.value() else: upper_bound = None filter_type = n.filter_name_to_type[self.filter_type.currentText()] filter_length = self.filter_length.value() filter_order = self.filter_order.value() n.setLowerBound(lower_bound) n.setUpperBound(upper_bound) n.setFilterType(filter_type) n.setFilterLength(filter_length) n.setFilterOrder(filter_order) def updateView(self): n = self.node() if n is None: return # Prevent view fields from emitting signals while they are updated self.lower_bound.blockSignals(True) self.upper_bound.blockSignals(True) self.filter_type.blockSignals(True) self.filter_length.blockSignals(True) self.filter_order.blockSignals(True) if n.upperBound() is None: self.upper_bound_enable.setChecked(False) else: self.upper_bound_enable.setChecked(True) self.upper_bound.setValue(n.upperBound()) if n.lowerBound() is None: self.lower_bound_enable.setChecked(False) else: self.lower_bound_enable.setChecked(True) self.lower_bound.setValue(n.lowerBound()) self.filter_type.setCurrentText( n.filter_type_to_name[n.filterType()]) self.filter_length.setValue(n.filterLength()) self.filter_order.setValue(n.filterOrder()) # Release the block and call adjust self.lower_bound.blockSignals(False) self.upper_bound.blockSignals(False) self.filter_type.blockSignals(False) self.filter_length.blockSignals(False) self.filter_order.blockSignals(False) self._adjust() def _adjust(self): """Adjust displayed values and limits in response to changes.""" # Enable spinbox widgets based on their checkbox self.lower_bound.setEnabled(self.lower_bound_enable.isChecked()) self.upper_bound.setEnabled(self.upper_bound_enable.isChecked()) # Adjust min and max so that lower_bound is never higher than upper_bound if self.lower_bound_enable.isChecked(): self.upper_bound.setMinimum(self.lower_bound.value()) else: self.upper_bound.setMinimum(0) if self.upper_bound_enable.isChecked(): self.lower_bound.setMaximum(self.upper_bound.value()) else: self.lower_bound.setMaximum(250) if self.filter_type.currentText() == "Butterworth": self.filter_order.setEnabled(True) else: self.filter_order.setEnabled(False)
def __init_advanced_features_widget__(self, parent=None): self.__advanced_widget = QGroupBox("Advanced Features Options", parent) fixed_layer_check = QCheckBox("Fixed Layer", self.__advanced_widget) fixed_layer_check.setChecked(self.dlp_controller.fixed_layer) fixed_layer_check.toggled.connect(self.dlp_controller.set_fixed_layer) incremental_amplitude_check = QCheckBox("Incremental Amplitude", self.__advanced_widget) incremental_amplitude_check.setChecked( self.dlp_controller.incremental_amplitude) incremental_amplitude_check.toggled.connect( self.dlp_controller.set_incremental_amplitude) starting_amplitude_label = QLabel("Starting Amplitude", self.__advanced_widget) starting_amplitude_edit = QSpinBox(self.__advanced_widget) starting_amplitude_edit.setMaximum(1000) starting_amplitude_edit.setMinimum(0) starting_amplitude_edit.setSingleStep(1) starting_amplitude_edit.setValue( self.dlp_controller.starting_incremental_amplitude) starting_amplitude_edit.valueChanged.connect( self.dlp_controller.set_starting_incremental_amplitude) amplitude_step_label = QLabel("Step Size", self.__advanced_widget) amplitude_step_edit = QSpinBox(self.__advanced_widget) amplitude_step_edit.setMaximum(1000) amplitude_step_edit.setMinimum(0) amplitude_step_edit.setSingleStep(1) amplitude_step_edit.setValue( self.dlp_controller.incremental_step_amplitude) amplitude_step_edit.valueChanged.connect( self.dlp_controller.set_incremental_step_amplitude) incremental_exposure_check = QCheckBox("Incremental Exposure", self.__advanced_widget) incremental_exposure_check.setChecked( self.dlp_controller.incremental_exposure) incremental_exposure_check.toggled.connect( self.dlp_controller.set_incremental_exposure) starting_exposure_label = QLabel("Starting Exposure", self.__advanced_widget) starting_exposure_edit = QDoubleSpinBox(self.__advanced_widget) starting_exposure_edit.setSuffix(str('ms')) starting_exposure_edit.setMaximum(100000) starting_exposure_edit.setMinimum(0) starting_exposure_edit.setDecimals(1) starting_exposure_edit.setSingleStep(0.1) starting_exposure_edit.valueChanged.connect( self.dlp_controller.set_starting_incremental_exposure) starting_exposure_edit.setValue( self.dlp_controller.starting_incremental_exposure) exposure_step_label = QLabel("Step Size", self.__advanced_widget) exposure_step_edit = QDoubleSpinBox(self.__advanced_widget) exposure_step_edit.setSuffix(str('ms')) exposure_step_edit.setMaximum(100000) exposure_step_edit.setMinimum(0) exposure_step_edit.setDecimals(1) exposure_step_edit.setSingleStep(0.1) exposure_step_edit.valueChanged.connect( self.dlp_controller.set_incremental_step_exposure) exposure_step_edit.setValue( self.dlp_controller.incremental_step_exposure) incremental_thickness_check = QCheckBox("Incremental Thickness", self.__advanced_widget) incremental_thickness_check.setChecked( self.dlp_controller.incremental_thickness) incremental_thickness_check.toggled.connect( self.dlp_controller.set_incremental_thickness) thickness_label = QLabel("Starting Thickness", self.__features_widget) self.starting_thickness_edit = MyDiscreteStepsSpinBox( self.dlp_controller.get_step_length_microns(), self.__features_widget) self.starting_thickness_edit.setSuffix(str('\u03BCm')) self.starting_thickness_edit.setMaximum(1000000) self.starting_thickness_edit.setMinimum(0) self.starting_thickness_edit.setDecimals(3) self.starting_thickness_edit.my_value_changed_signal.connect( self.dlp_controller.set_starting_incremental_thickness) self.starting_thickness_edit.setValue( self.dlp_controller.starting_incremental_thickness * 1000) thickness_step_label = QLabel("Step Size", self.__features_widget) self.thickness_step_edit = MyDiscreteStepsSpinBox( self.dlp_controller.get_step_length_microns(), self.__features_widget) self.thickness_step_edit.setSuffix(str('\u03BCm')) self.thickness_step_edit.setMaximum(1000000) self.thickness_step_edit.setMinimum(0) self.thickness_step_edit.setDecimals(3) self.thickness_step_edit.my_value_changed_signal.connect( self.dlp_controller.set_incremental_step_thickness) self.thickness_step_edit.setValue( self.dlp_controller.incremental_step_thickness * 1000) apply_grayscale_correction_check = QCheckBox("Grayscale Correction", self.__advanced_widget) apply_grayscale_correction_check.setChecked( self.dlp_controller.grayscale_correction) apply_grayscale_correction_check.toggled.connect( self.dlp_controller.set_grayscale_correction) grayscale_parameters_widget = QWidget(self.__features_widget) a_parameter_label = QLabel("\u03B1", grayscale_parameters_widget) alpha_parameter_edit = QDoubleSpinBox(grayscale_parameters_widget) alpha_parameter_edit.setMaximum(1000) alpha_parameter_edit.setMinimum(0) alpha_parameter_edit.setDecimals(3) alpha_parameter_edit.setSingleStep(0.001) alpha_parameter_edit.valueChanged.connect( self.dlp_controller.set_grayscale_alpha) alpha_parameter_edit.setValue(self.dlp_controller.grayscale_alpha) beta_parameter_label = QLabel("\u03B2", grayscale_parameters_widget) beta_parameter_edit = QDoubleSpinBox(grayscale_parameters_widget) beta_parameter_edit.setMaximum(1000) beta_parameter_edit.setMinimum(0) beta_parameter_edit.setDecimals(3) beta_parameter_edit.setSingleStep(0.001) beta_parameter_edit.valueChanged.connect( self.dlp_controller.set_grayscale_beta) beta_parameter_edit.setValue(self.dlp_controller.grayscale_beta) gamma_parameter_label = QLabel("\u03B3", grayscale_parameters_widget) gamma_parameter_edit = QDoubleSpinBox(grayscale_parameters_widget) gamma_parameter_edit.setMaximum(1000) gamma_parameter_edit.setMinimum(0) gamma_parameter_edit.setDecimals(3) gamma_parameter_edit.setSingleStep(0.001) gamma_parameter_edit.valueChanged.connect( self.dlp_controller.set_grayscale_gamma) gamma_parameter_edit.setValue(self.dlp_controller.grayscale_gamma) grayscale_parameters_layout = QHBoxLayout(grayscale_parameters_widget) grayscale_parameters_layout.addWidget(a_parameter_label) grayscale_parameters_layout.addWidget(alpha_parameter_edit) grayscale_parameters_layout.addWidget(beta_parameter_label) grayscale_parameters_layout.addWidget(beta_parameter_edit) grayscale_parameters_layout.addWidget(gamma_parameter_label) grayscale_parameters_layout.addWidget(gamma_parameter_edit) grayscale_parameters_widget.setLayout(grayscale_parameters_layout) advanced_features_layout = QGridLayout(self.__advanced_widget) advanced_features_layout.addWidget(incremental_amplitude_check, 1, 0, 1, 2) advanced_features_layout.addWidget(fixed_layer_check, 1, 3) advanced_features_layout.addWidget(starting_amplitude_label, 2, 0) advanced_features_layout.addWidget(starting_amplitude_edit, 2, 1) advanced_features_layout.addWidget(amplitude_step_label, 2, 2) advanced_features_layout.addWidget(amplitude_step_edit, 2, 3) advanced_features_layout.addWidget(incremental_exposure_check, 3, 0, 1, 2) advanced_features_layout.addWidget(starting_exposure_label, 4, 0) advanced_features_layout.addWidget(starting_exposure_edit, 4, 1) advanced_features_layout.addWidget(exposure_step_label, 4, 2) advanced_features_layout.addWidget(exposure_step_edit, 4, 3) advanced_features_layout.addWidget(incremental_thickness_check, 5, 0, 1, 2) advanced_features_layout.addWidget(thickness_label, 6, 0) advanced_features_layout.addWidget(self.starting_thickness_edit, 6, 1) advanced_features_layout.addWidget(thickness_step_label, 6, 2) advanced_features_layout.addWidget(self.thickness_step_edit, 6, 3) advanced_features_layout.addWidget(apply_grayscale_correction_check, 7, 0, 1, 2) advanced_features_layout.addWidget(grayscale_parameters_widget, 8, 0, 1, 4) self.__advanced_widget.setLayout(advanced_features_layout)
class Canvas (QWidget): def __init__(self): QWidget.__init__(self) self.file = "mug.webp" self.__img = cv2.imread(self.file) self.__mask = np.zeros(1) self.original = cv2.imread(self.file) self.__thirdChannelMask = np.dstack((self.__mask, self.__mask, self.__mask)) self.__nseg = 1 self.__sig = 1 self.__comp = 1 self.nSlider = QSlider(orientation=Qt.Horizontal) self.sigSlider = QSlider(orientation=Qt.Horizontal) self.thicSlider = QSlider(orientation=Qt.Horizontal) self.resize_spinbox = QSpinBox(self) self.resize_spinbox.setRange(1, 100) self.resize_spinbox.setValue(100) self.resize_spinbox.setSuffix(" %") self.double_spin_width = QDoubleSpinBox(self) self.double_spin_width.setSuffix(" px") self.double_spin_width.setValue(0) self.double_spin_width.setRange(1, 2000) self.double_spin_height = QDoubleSpinBox(self) self.double_spin_height.setSuffix(" px") self.double_spin_height.setValue(0) self.double_spin_height.setRange(1, 2000) self.zeroModeCheck = QCheckBox("Usar SLIC0") self.__highlightcolor = QColor(255, 255, 255) self.__transparency = 0.5 self.__AllColors = [self.__highlightcolor.toTuple()[:3]] nLabel = QLabel("Numero de segmentos:") sigLabel = QLabel("Sigma:") thicLabel = QLabel("Compactação:") resizeLabel = QLabel("Fator de resize da image:") makssizeLabel = QLabel("Dimensão da mascara de saída:") self.__label = QLabel() nLabel.setToolTip("O número aproximado de labels da imagem segmentada") sigLabel.setToolTip("A largura da Gaussiana") thicLabel.setToolTip("Equilibra a proximidade das cores e a proximidade do espaço, maiores valores tornam os Superpixels mais quadrados") self.nSlider.setMinimum(1) self.nSlider.setMaximum(100) self.sigSlider.setMinimum(1) self.sigSlider.setMaximum(100) self.thicSlider.setMinimum(1) self.thicSlider.setMaximum(100) glayout1 = QGridLayout() glayout1.addWidget(nLabel, 0, 0) glayout1.addWidget(self.nSlider, 0, 1) glayout1.addWidget(sigLabel, 1, 0) glayout1.addWidget(self.sigSlider, 1, 1) glayout1.addWidget(thicLabel, 2, 0) glayout1.addWidget(self.thicSlider, 2, 1) glayout2 = QGridLayout() glayout2.addWidget(resizeLabel, 0, 0) glayout2.addWidget(self.resize_spinbox, 0, 1) glayout2.addWidget(self.zeroModeCheck, 0, 2) glayout2.addWidget(makssizeLabel, 1, 0) glayout2.addWidget(self.double_spin_width, 1, 1) glayout2.addWidget(self.double_spin_height, 1, 2) glayout2.setColumnStretch(3, 1) self.__label.setAlignment(Qt.AlignLeft | Qt.AlignTop) mainlayout = QVBoxLayout() mainlayout.addLayout(glayout1) mainlayout.addLayout(glayout2) mainlayout.addStretch(1) mainlayout.addWidget(self.__label) mainlayout.addStretch(1) mainlayout.setAlignment(Qt.AlignCenter) self.setLayout(mainlayout) self.nSlider.sliderReleased.connect(self.onNsegChange) self.sigSlider.sliderReleased.connect(self.onSigChange) self.thicSlider.sliderReleased.connect(self.onCompChange) self.__label.mousePressEvent = self.Highlight self.resize_spinbox.valueChanged.connect(self.Resize) self.open_image(self.__img) def getBackground(self): mask = self.__thirdChannelMask.copy() mask_r = mask[:, :, 2] mask_g = mask[:, :, 1] mask_b = mask[:, :, 0] offImage = list() for color in self.__AllColors: b_off = mask_b != color[2] g_off = mask_g != color[1] r_off = mask_r != color[0] aux = np.logical_and(b_off, g_off) offImage.append(np.logical_and(aux, r_off)) final = offImage[0] for cut in offImage: final = np.logical_or(final, cut) return final def changeImage(self): self.__mask = slic(self.__img, n_segments=self.__nseg, compactness=self.__comp, sigma=self.__sig, convert2lab=True, slic_zero=self.zeroModeCheck.isChecked()) mask = self.__mask.copy() mask = np.dstack((mask, mask, mask)) mask = img_as_ubyte(mask) self.__thirdChannelMask = mask img = cv2.addWeighted(self.__img, 1, mask, 0.5, 0) marc_img = mark_boundaries(img, self.__mask) self.open_image(marc_img) def load_image(self): self.__img = cv2.imread(self.file) self.original = self.__img self.double_spin_width.setValue(self.__img.shape[1]) self.double_spin_height.setValue(self.__img.shape[0]) val = self.resize_spinbox.value() newDim = int(self.__img.shape[1]*val/100), int(self.__img.shape[0]*val/100) self.__img = cv2.resize(self.__img, newDim) self.open_image(self.__img) def open_image(self, img): if img.shape[2] == 4: qformat = QImage.Format_RGBA8888 else: qformat = QImage.Format_RGB888 copy = img_as_ubyte(img) qimg = QImage(copy.data, copy.shape[1], copy.shape[0], copy.strides[0], qformat).rgbSwapped() pixmap = QPixmap.fromImage(qimg) self.__label.setPixmap(pixmap) self.__label.adjustSize() @Slot() def onNsegChange(self): self.__nseg = self.nSlider.value() self.changeImage() @Slot() def onSigChange(self): self.__sig = self.sigSlider.value() self.changeImage() @Slot() def onCompChange(self): self.__comp = self.thicSlider.value() self.changeImage() @Slot() def onFileOpen(self): self.thicSlider.setValue(1) self.nSlider.setValue(1) self.sigSlider.setValue(1) diag = QFileDialog() file = diag.getOpenFileName()[0] if file != "": self.file = file self.load_image() @Slot() def onSaveFile(self): diag = QFileDialog() file = diag.getSaveFileName()[0] if self.file != "": self.__label.pixmap().save(file) @Slot() def onSaveMask(self): diag = QFileDialog() file = diag.getSaveFileName()[0] final_img = cv2.resize(self.__mask, (self.double_spin_width.value(), self.double_spin_height.value())) if file != "": cv2.imwrite(file, final_img) @Slot() def Highlight(self, e): if e.x() < 0 or e.x() > self.__img.shape[1] or e.y() < 0 or e.y() > self.__img.shape[0]: return self.__mask = flood_fill(self.__mask, (e.y(), e.x()), 255) self.__thirdChannelMask[:, :, 2] = flood_fill(self.__thirdChannelMask[:, :, 2], (e.y(), e.x()), self.__highlightcolor.red()) self.__thirdChannelMask[:, :, 1] = flood_fill(self.__thirdChannelMask[:, :, 1], (e.y(), e.x()), self.__highlightcolor.green()) self.__thirdChannelMask[:, :, 0] = flood_fill(self.__thirdChannelMask[:, :, 0], (e.y(), e.x()), self.__highlightcolor.blue()) img = cv2.addWeighted(self.__img, 1, self.__thirdChannelMask, self.__transparency, 0) marc_img = mark_boundaries(img, self.__mask) self.open_image(marc_img) @Slot() def exportBinary(self): diag = QFileDialog() file = diag.getSaveFileName()[0] mask = self.__thirdChannelMask.copy() final = self.getBackground() b = mask[:, :, 0] g = mask[:, :, 1] r = mask[:, :, 2] b[final] = 0 g[final] = 0 r[final] = 0 final_img = cv2.resize(mask, (int(self.double_spin_width.value()), int(self.double_spin_height.value()))) if file != "": cv2.imwrite(file, final_img) @Slot() def onRemoveBackgroud(self): box = QMessageBox() box.setText("Selecione a cor do background") box.setIcon(QMessageBox.Information) box.exec() diag = QColorDialog() backColor = diag.getColor() final = self.getBackground() b = self.__img[:, :, 0] g = self.__img[:, :, 1] r = self.__img[:, :, 2] b[final] = backColor.blue() g[final] = backColor.green() r[final] = backColor.red() self.open_image(self.__img) @Slot() def Resize(self): val = self.resize_spinbox.value() newDim = int(self.original.shape[1] * val / 100), int(self.original.shape[0] * val / 100) self.__img = cv2.resize(self.original, newDim) self.open_image(self.__img) @Slot() def setHighlightColor(self, color): self.__highlightcolor = color @Slot() def getAllColors(self, colors): self.__AllColors = colors @Slot() def setTran(self, value): self.__transparency = 1- value/100 @Slot() def onUndo(self): self.thicSlider.setValue(1) self.nSlider.setValue(1) self.sigSlider.setValue(1) self.onNsegChange() self.onSigChange() self.onCompChange() self.__img = self.original self.open_image(self.__img)
def __init_projector_widget__(self, parent=None): self.__projector_widget = QGroupBox("Projector Options", parent) # self.__projector_widget.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) mirror_x = QCheckBox("Mirror X") mirror_x.setChecked(self.dlp_controller.is_horizontal_mirrored()) mirror_x.toggled.connect(self.dlp_controller.set_horizontal_mirroring) mirror_y = QCheckBox("Mirror Y") mirror_y.setChecked(self.dlp_controller.is_vertical_mirrored()) mirror_y.toggled.connect(self.dlp_controller.set_vertical_mirroring) start_projector_button = QPushButton("Start Projector", self.__projector_widget) start_projector_button.clicked.connect( self.dlp_controller.start_projector) project_pattern_button = QPushButton("Project Pattern", self.__projector_widget) project_pattern_button.clicked.connect( self.dlp_controller.project_calibration_pattern) print_position_button = QPushButton("Print Position", self.__projector_widget) print_position_button.clicked.connect( self.dlp_controller.print_motor_position) home_projector_button = QPushButton("Home Projector", self.__projector_widget) home_projector_button.clicked.connect( self.dlp_controller.home_projector) move_projector_button = QPushButton("Move Projector", self.__projector_widget) move_projector_button.clicked.connect( self.dlp_controller.move_projector) move_projector_edit = QDoubleSpinBox(self.__projector_widget) move_projector_edit.setSuffix("mm") move_projector_edit.setMaximum(10000) move_projector_edit.setMinimum(-10000) move_projector_edit.setDecimals(3) move_projector_edit.setSingleStep(0.001) move_projector_edit.valueChanged.connect( self.dlp_controller.update_projector_distance) set_amplitude_button = QPushButton("Set Projector Amplitude", self.__projector_widget) set_amplitude_button.clicked.connect( self.dlp_controller.set_projector_amplitude) set_amplitude_edit = QSpinBox(self.__projector_widget) set_amplitude_edit.setMaximum(1000) set_amplitude_edit.setMinimum(0) set_amplitude_edit.setValue(self.dlp_controller.projector_amplitude) set_amplitude_edit.valueChanged.connect( self.dlp_controller.update_projector_amplitude) lock_unlock_projector_button = QPushButton("Lock/Unlock Projector", self.__projector_widget) lock_unlock_projector_button.clicked.connect( self.dlp_controller.lock_unlock_projector) projector_layout = QGridLayout(self.__projector_widget) # projector_layout.addWidget(projector_label, 0, 0) projector_layout.addWidget(mirror_x, 0, 1) projector_layout.addWidget(mirror_y, 0, 2) projector_layout.addWidget(start_projector_button, 1, 0, 1, 1) projector_layout.addWidget(project_pattern_button, 1, 1, 1, 1) projector_layout.addWidget(print_position_button, 1, 2, 1, 1) projector_layout.addWidget(home_projector_button, 2, 0, 1, 1) projector_layout.addWidget(move_projector_button, 2, 1, 1, 1) projector_layout.addWidget(move_projector_edit, 2, 2) projector_layout.addWidget(set_amplitude_button, 3, 0, 1, 1) projector_layout.addWidget(set_amplitude_edit, 3, 1) projector_layout.addWidget(lock_unlock_projector_button, 3, 2, 1, 1) self.__projector_widget.setLayout(projector_layout)
def __init_features_widget__(self, parent=None): self.__features_widget = QGroupBox("Features Layers Parameters", parent) # self.__features_widget.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) thickness_label = QLabel("Layer Thickness", self.__features_widget) self.features_thickness_edit = MyDiscreteStepsSpinBox( self.dlp_controller.get_step_length_microns(), self.__features_widget) self.features_thickness_edit.setSuffix(str('\u03BCm')) self.features_thickness_edit.setMaximum(1000000) self.features_thickness_edit.setMinimum(0) self.features_thickness_edit.setDecimals(3) self.features_thickness_edit.my_value_changed_signal.connect( self.dlp_controller.set_features_thickness) self.features_thickness_edit.setValue( self.dlp_controller.features_thickness * 1000) exposure_label = QLabel("Exposure Time", self.__features_widget) exposure_edit = QDoubleSpinBox(self.__features_widget) exposure_edit.setSuffix(str('ms')) exposure_edit.setMaximum(10000000) exposure_edit.setMinimum(0) exposure_edit.setDecimals(1) exposure_edit.setSingleStep(0.1) exposure_edit.setValue(self.dlp_controller.features_exposure) exposure_edit.valueChanged.connect( self.dlp_controller.set_features_exposure_time) amplitude_label = QLabel("Light Amplitude", self.__features_widget) amplitude_edit = QSpinBox(self.__features_widget) amplitude_edit.setMaximum(1600) amplitude_edit.setMinimum(0) amplitude_edit.setSingleStep(1) amplitude_edit.setValue(self.dlp_controller.features_amplitude) amplitude_edit.valueChanged.connect( self.dlp_controller.set_features_amplitude) burn_layers_label = QLabel("Burn Layers", self.__features_widget) burn_layers_edit = QSpinBox(self.__features_widget) burn_layers_edit.setMaximum(1000) burn_layers_edit.setMinimum(0) burn_layers_edit.setSingleStep(1) burn_layers_edit.setValue(self.dlp_controller.features_burn_layers) burn_layers_edit.valueChanged.connect( self.dlp_controller.set_features_burning_layers) burn_exposure_label = QLabel("Burn Exposure", self.__features_widget) burn_exposure_edit = QDoubleSpinBox(self.__features_widget) burn_exposure_edit.setSuffix(str('ms')) burn_exposure_edit.setMaximum(100000) burn_exposure_edit.setMinimum(0) burn_exposure_edit.setDecimals(1) burn_exposure_edit.setSingleStep(0.1) burn_exposure_edit.setValue(self.dlp_controller.features_burn_exposure) burn_exposure_edit.valueChanged.connect( self.dlp_controller.set_features_burning_exposure_time) burn_amplitude_label = QLabel("Burn Amplitude", self.__features_widget) burn_amplitude_edit = QSpinBox(self.__features_widget) burn_amplitude_edit.setMaximum(1600) burn_amplitude_edit.setMinimum(0) burn_amplitude_edit.setSingleStep(1) burn_amplitude_edit.setValue( self.dlp_controller.features_burn_amplitude) burn_amplitude_edit.valueChanged.connect( self.dlp_controller.set_features_burning_amplitude) select_layers_button = QPushButton("Select Features Images") select_layers_button.clicked.connect(self.load_features_images) features_layout = QGridLayout(self.__features_widget) features_layout.addWidget(thickness_label, 1, 0) features_layout.addWidget(self.features_thickness_edit, 1, 1) features_layout.addWidget(exposure_label, 2, 0) features_layout.addWidget(exposure_edit, 2, 1) features_layout.addWidget(amplitude_label, 3, 0) features_layout.addWidget(amplitude_edit, 3, 1) features_layout.addWidget(burn_layers_label, 4, 0) features_layout.addWidget(burn_layers_edit, 4, 1) features_layout.addWidget(burn_exposure_label, 5, 0) features_layout.addWidget(burn_exposure_edit, 5, 1) features_layout.addWidget(burn_amplitude_label, 6, 0) features_layout.addWidget(burn_amplitude_edit, 6, 1) features_layout.addWidget(select_layers_button, 7, 0, 1, 2) self.__features_widget.setLayout(features_layout)
def __init_slicer_options_widget__(self): self.__slicer_options_widget = QGroupBox("Slicer Options", self) thickness_label = QLabel("Layer Thickness", self.__slicer_options_widget) thickness_edit = QDoubleSpinBox(self.__slicer_options_widget) thickness_edit.setSuffix(str('\u03BCm')) thickness_edit.setMaximum(1000000) thickness_edit.setMinimum(0) thickness_edit.setDecimals(3) thickness_edit.setSingleStep(0.001) thickness_edit.setValue(self.dlp_controller.support_thickness * 1000) # self.__opengl_widget.set_slice_thickness(self.dlp_controller.support_thickness) thickness_edit.valueChanged.connect( self.__slicer_widget.set_slice_thickness) pixel_size_label = QLabel("Projector Pixel Size", self.__slicer_options_widget) pixel_size_edit = QDoubleSpinBox(self.__slicer_options_widget) pixel_size_edit.setSuffix(str('\u03BCm')) pixel_size_edit.setMaximum(1000000) pixel_size_edit.setMinimum(0) pixel_size_edit.setDecimals(2) pixel_size_edit.setSingleStep(0.01) pixel_size_edit.setValue(self.dlp_controller.projector_pixel_size * 1000) pixel_size_edit.valueChanged.connect( self.__slicer_widget.set_pixel_size) projector_resolution_label = QLabel("Projector Resolution", self.__slicer_options_widget) projector_resolution_edit_x = QSpinBox(self.__slicer_options_widget) projector_resolution_edit_x.setSuffix(str('W')) projector_resolution_edit_x.setMaximum(1000000) projector_resolution_edit_x.setMinimum(0) projector_resolution_edit_x.setValue( self.dlp_controller.projector_width) projector_resolution_edit_x.valueChanged.connect( self.__slicer_widget.set_projector_width) projector_resolution_edit_y = QSpinBox(self.__slicer_options_widget) projector_resolution_edit_y.setSuffix(str('H')) projector_resolution_edit_y.setMaximum(1000000) projector_resolution_edit_y.setMinimum(0) projector_resolution_edit_y.setValue( self.dlp_controller.projector_height) projector_resolution_edit_y.valueChanged.connect( self.__slicer_widget.set_projector_height) samples_per_pixel_label = QLabel("Samples per Pixel", self.__slicer_options_widget) samples_per_pixel_edit = QSpinBox(self.__slicer_options_widget) samples_per_pixel_edit.setMaximum(1000000) samples_per_pixel_edit.setMinimum(1) samples_per_pixel_edit.setValue(self.dlp_controller.samples_per_pixel) samples_per_pixel_edit.valueChanged.connect( self.__slicer_widget.set_samples_per_pixel) slice_geometry_button = QPushButton("Slice Geometry") slice_geometry_button.clicked.connect(self.start_slicing_process) slice_interrupt_button = QPushButton("Stop Slicing") slice_interrupt_button.clicked.connect( self.__slicer_widget.interrupt_slicing) self.slices_label = QLabel(f'Slicing progress: {0:.0f}/{0:.0f}', self.__info_widget) thickness_label_row = 0 pixel_size_row = 1 projector_resolution_row = 2 samples_per_pixel_row = 3 slice_button_row = 4 slices_label_row = 5 # slice_interrupt_row = slice_button_row slice_layout = QGridLayout(self.__slicer_options_widget) slice_layout.addWidget(thickness_label, thickness_label_row, 0) slice_layout.addWidget(thickness_edit, thickness_label_row, 1) slice_layout.addWidget(pixel_size_label, pixel_size_row, 0) slice_layout.addWidget(pixel_size_edit, pixel_size_row, 1) slice_layout.addWidget(projector_resolution_label, projector_resolution_row, 0) slice_layout.addWidget(projector_resolution_edit_x, projector_resolution_row, 1) slice_layout.addWidget(projector_resolution_edit_y, projector_resolution_row, 2) slice_layout.addWidget(self.slices_label, slice_button_row, 0) slice_layout.addWidget(slice_geometry_button, slice_button_row, 1) slice_layout.addWidget(slice_interrupt_button, slice_button_row, 2) slice_layout.addWidget(samples_per_pixel_label, samples_per_pixel_row, 0) slice_layout.addWidget(samples_per_pixel_edit, samples_per_pixel_row, 1) self.__slicer_options_widget.setLayout(slice_layout)
class BlockView(QWidget): """Config widget for a single experiment block. In a model-view paradigm, this is a view, and block is a model. A new block can be set using setModel. """ statistics_type_to_name = { "max": "Min/Max", "meanstd": "Standardise" } statistics_name_to_type = {v: k for k, v in statistics_type_to_name.items()} def __init__(self, parent=None): super().__init__(parent) layout = QFormLayout() self.setLayout(layout) self._model = None # Block properties --------------------------------------------------------------------------------------------- self.duration = QWidget() self.duration.setContentsMargins(0, 0, 0, 0) ly = QHBoxLayout() ly.setContentsMargins(0, 0, 0, 0) self.duration.setLayout(ly) self.duration_base = QDoubleSpinBox() self.duration_base.setRange(0, 1000) self.duration_base.setValue(10) self.duration_deviation = QDoubleSpinBox() self.duration_deviation.setRange(0, 10) self.duration_deviation.setValue(0) self.duration_deviation.setSingleStep(0.1) self.duration_deviation.setSuffix(" s") self.duration_base.valueChanged.connect(self.duration_deviation.setMaximum) ly.addWidget(self.duration_base) ly.addWidget(QLabel("±")) ly.addWidget(self.duration_deviation) self.feedback_source = QLineEdit("All") self.feedback_type = QComboBox() self.feedback_type.addItem("Baseline") self.feedback_type.addItem("Feedback") self.mock_signal_path = QLineEdit() self.mock_signal_dataset = QLineEdit() self.mock_previous = QSpinBox() self.mock_previous_reverse = QCheckBox() self.mock_previous_random = QCheckBox() self.pause = QCheckBox() self.beep = QCheckBox() self.start_data_driven_filter_designer = QCheckBox() self.update_statistics = QCheckBox() self.update_statistics.stateChanged.connect(lambda state: self.statistics_type.setEnabled(bool(state))) self.statistics_type = QComboBox() self.statistics_type.setEnabled(False) for name in self.statistics_name_to_type: self.statistics_type.addItem(name) self.statistics_type.setCurrentText("Standardise") self.random_bound = QComboBox() self.random_bound.addItem("SimCircle") self.random_bound.addItem("RandomCircle") self.random_bound.addItem("Bar") self.video_path = QLineEdit() self.message = QLineEdit() self.feedback_type.currentTextChanged.connect(lambda ftype: self.message.setEnabled(ftype == "Baseline")) self.voiceover = QCheckBox() # Grouped properties ------------------------------------------------------------------------------------------- # Mock signal mock_signal_groupbox = QGroupBox("Mock signal") mock_signal_gblayout = QFormLayout() mock_signal_groupbox.setLayout(mock_signal_gblayout) mock_signal_gblayout.addRow("Mock signal file path", self.mock_signal_path) mock_signal_gblayout.addRow("Mock signal file dataset", self.mock_signal_dataset) mock_signal_gblayout.addRow("Mock previous", self.mock_previous) mock_signal_gblayout.addRow("Reverse mock previous", self.mock_previous_reverse) mock_signal_gblayout.addRow("Random mock previous", self.mock_previous_random) # After block actions after_block_groupbox = QGroupBox("After block actions") after_block_gblayout = QFormLayout() after_block_groupbox.setLayout(after_block_gblayout) after_block_gblayout.addRow("Start data driven filter designer", self.start_data_driven_filter_designer) after_block_gblayout.addRow("Pause", self.pause) after_block_gblayout.addRow("Beep", self.beep) after_block_gblayout.addRow("Update statistics", self.update_statistics) after_block_gblayout.addRow("Statistics type", self.statistics_type) # Adding properties to the widget ------------------------------------------------------------------------------ layout.addRow("Duration", self.duration) layout.addRow("Source", self.feedback_source) layout.addRow("FB Type", self.feedback_type) layout.addRow("Random bound", self.random_bound) layout.addRow("Video path", self.video_path) layout.addRow("Message for test subject", self.message) layout.addRow("Voiceover for message", self.voiceover) layout.addRow(mock_signal_groupbox) layout.addRow(after_block_groupbox) def model(self): return self._model def setModel(self, block, /): """Set the model block for this view. Data in the view will be updated to reflect the new block. """ self._model = block self.updateView() def updateModel(self): """Copy data from this view to the block model. A similarly named function in the block copies data the opposite way. Use one or the other depending on where data was changed. """ model = self.model() if model is None: return model.duration = self.duration_base.value() model.duration_deviation = self.duration_deviation.value() model.feedback_source = self.feedback_source.text() model.feedback_type = self.feedback_type.currentText() model.random_bound = self.random_bound.currentText() model.video_path = self.video_path.text() model.message = self.message.text() model.voiceover = self.voiceover.isChecked() model.mock_signal_path = self.mock_signal_path.text() model.mock_signal_dataset = self.mock_signal_dataset.text() model.mock_previous = self.mock_previous.value() model.mock_previous_reverse = self.mock_previous_reverse.isChecked() model.mock_previous_random = self.mock_previous_random.isChecked() model.start_data_driven_filter_designer = self.start_data_driven_filter_designer.isChecked() model.pause = self.pause.isChecked() model.beep = self.beep.isChecked() model.update_statistics = self.update_statistics.isChecked() model.statistics_type = self.statistics_name_to_type[self.statistics_type.currentText()] def updateView(self): model = self.model() if model is None: return self.duration_base.setValue(model.duration) self.duration_deviation.setValue(model.duration_deviation) self.feedback_source.setText(model.feedback_source) self.feedback_type.setCurrentText(model.feedback_type) self.mock_signal_path.setText(model.mock_signal_path) self.mock_signal_dataset.setText(model.mock_signal_dataset) self.mock_previous.setValue(model.mock_previous) self.mock_previous_reverse.setChecked(model.mock_previous_reverse) self.mock_previous_random.setChecked(model.mock_previous_random) self.pause.setChecked(model.pause) self.beep.setChecked(model.beep) self.start_data_driven_filter_designer.setChecked(model.start_data_driven_filter_designer) self.update_statistics.setChecked(model.update_statistics) self.statistics_type.setCurrentText(self.statistics_type_to_name[model.statistics_type]) self.random_bound.setCurrentText(model.random_bound) self.video_path.setText(model.video_path) self.message.setText(model.message) self.voiceover.setChecked(model.voiceover)
class ConfigDialog(QDialog): config_changed = Signal() def __init__(self, requester, config, parent=None): super().__init__(parent) self.requester = requester self.requester.pin_needed.connect(self.input_pin) self.requester.umi_made.connect(self.write_umi) self.requester.msg_passed.connect(self.error_msg) self.config = config self.lbl_id = QLabel('계정명') self.lbl_id.setAlignment(Qt.AlignCenter) self.lbl_pw = QLabel('비밀번호') self.lbl_pw.setAlignment(Qt.AlignCenter) self.lbl_umi = QLabel('umi 쿠키') self.lbl_umi.setAlignment(Qt.AlignCenter) self.lbl_ua = QLabel('유저 에이전트') self.lbl_ua.setAlignment(Qt.AlignCenter) self.lbl_delay = QLabel('저속 간격') self.lbl_delay.setAlignment(Qt.AlignCenter) self.lbl_msg = QLabel('') self.line_id = QLineEdit() self.line_pw = QLineEdit() self.line_pw.setEchoMode(QLineEdit.PasswordEchoOnEdit) self.line_umi = QLineEdit() self.line_umi.setPlaceholderText('로그인 시 자동 입력') self.line_ua = QLineEdit() self.line_delay = QDoubleSpinBox() self.line_delay.setMinimum(3) self.line_delay.setDecimals(1) self.line_delay.setSuffix('초') self.line_delay.setSingleStep(0.1) self.btn_save = NPButton('저장', 10, self) self.btn_save.clicked.connect(self.save) self.btn_cancel = NPButton('취소', 10, self) self.btn_cancel.clicked.connect(self.reject) self.btn_get_umi = NPButton('로그인', 10, self) self.btn_get_umi.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.MinimumExpanding) self.btn_get_umi.clicked.connect(self.get_umi) grid = QGridLayout() grid.addWidget(self.lbl_id, 0, 0, 1, 1) grid.addWidget(self.line_id, 0, 1, 1, 6) grid.addWidget(self.lbl_pw, 1, 0, 1, 1) grid.addWidget(self.line_pw, 1, 1, 1, 6) grid.addWidget(self.btn_get_umi, 0, 7, 2, 2) grid.addWidget(self.lbl_umi, 2, 0, 1, 1) grid.addWidget(self.line_umi, 2, 1, 1, 8) grid.addWidget(self.lbl_ua, 3, 0, 1, 1) grid.addWidget(self.line_ua, 3, 1, 1, 8) grid.addWidget(self.lbl_delay, 4, 0, 1, 1) grid.addWidget(self.line_delay, 4, 1, 1, 8) grid.addWidget(self.lbl_msg, 5, 0, 1, 4) grid.addWidget(self.btn_save, 5, 5, 1, 2) grid.addWidget(self.btn_cancel, 5, 7, 1, 2) self.setLayout(grid) self.input_dialog = InputDialog(self) self.input_dialog.input.setInputMask('999999') self.setWindowTitle('개인정보') self.setWindowIcon(QIcon('icon.png')) self.setStyleSheet('font: 10pt \'맑은 고딕\'') self.setWindowFlag(Qt.WindowContextHelpButtonHint, False) self.c_login, self.c_work = {}, {} @Slot(str) def error_msg(self, t): self.lbl_msg.setText(t) def load(self): self.line_id.setText(self.config.c['login']['ID']) self.line_pw.setText(self.config.c['login']['PW']) self.line_umi.setText(self.config.c['login']['UMI']) self.line_ua.setText(self.config.c['login']['UA']) self.line_ua.setCursorPosition(0) self.line_delay.setValue(float(self.config.c['work']['DELAY'])) self.lbl_msg.clear() ok = self.exec_() if ok == QDialog.Accepted: self.config_changed.emit() def save(self): self.config.save(login={ 'ID': self.line_id.text().strip(), 'PW': self.line_pw.text().strip(), 'UMI': self.line_umi.text().strip(), 'UA': self.line_ua.text().strip() }, delay=self.line_delay.value()) self.accept() def get_umi(self): self.lbl_msg.setText('로그인 시도...') self.line_umi.clear() self.input_dialog.input.clear() self.requester.init_login(self.line_id.text().strip(), self.line_pw.text().strip()) @Slot(str) def write_umi(self, umi): self.line_umi.setText(umi) @Slot(str) def input_pin(self, mail): pin, ok = self.input_dialog.get_text('로그인 PIN 입력', f'이메일({mail})로 전송된 PIN을 입력해주세요.') if ok: if pin: self.requester.typed_pin = pin else: self.requester.typed_pin = 'nothing' else: self.requester.typed_pin = 'deny'
class GeneralView(QWidget): """Config widget for general properties of an experiment. This "view" does not have a model. Instead, it is a part of a bigger view called ExperimentView, and gets updated with it. """ inlet_type_export_values = { "LSL stream": "lsl", "LSL file stream": "lsl_from_file", "LSL generator": "lsl_generator", "Field trip buffer": "ftbuffer" } inlet_type_import_values = { v: k for k, v in inlet_type_export_values.items() } def __init__(self, parent=None): super().__init__(parent=parent) layout = QFormLayout() self.setLayout(layout) self.name = QLineEdit() # prefilter_lower_bound --------------------------------------------------------------------------------------------- self.prefilter_lower_bound_enable = QCheckBox() self.prefilter_lower_bound_enable.stateChanged.connect(self._adjust) self.prefilter_lower_bound = QDoubleSpinBox() self.prefilter_lower_bound.setEnabled(False) self.prefilter_lower_bound.valueChanged.connect(self._adjust) self.prefilter_lower_bound.setMinimum(0) self.prefilter_lower_bound.setMaximum(0) # TODO: add proper value self.prefilter_lower_bound.setValue(0) # TODO: add proper value prefilter_lower_bound_widget = QWidget() prefilter_lower_bound_widget.setContentsMargins(0, 0, 0, 0) prefilter_lower_bound_widget.setLayout(QHBoxLayout()) prefilter_lower_bound_widget.layout().setContentsMargins(0, 0, 0, 0) prefilter_lower_bound_widget.layout().addWidget( self.prefilter_lower_bound_enable) prefilter_lower_bound_widget.layout().addWidget( self.prefilter_lower_bound) # prefilter_upper_bound -------------------------------------------------------------------------------------------- self.prefilter_upper_bound_enable = QCheckBox() self.prefilter_upper_bound_enable.stateChanged.connect(self._adjust) self.prefilter_upper_bound = QDoubleSpinBox() self.prefilter_upper_bound.setEnabled(False) self.prefilter_upper_bound.valueChanged.connect(self._adjust) self.prefilter_upper_bound.setMinimum( self.prefilter_lower_bound.value()) self.prefilter_upper_bound.setMaximum(10000) # TODO: add proper value self.prefilter_upper_bound.setValue(0) # TODO: add proper value prefilter_upper_bound_widget = QWidget() prefilter_upper_bound_widget.setContentsMargins(0, 0, 0, 0) prefilter_upper_bound_widget.setLayout(QHBoxLayout()) prefilter_upper_bound_widget.layout().setContentsMargins(0, 0, 0, 0) prefilter_upper_bound_widget.layout().addWidget( self.prefilter_upper_bound_enable) prefilter_upper_bound_widget.layout().addWidget( self.prefilter_upper_bound) # Inlet selection ---------------------------------------------------------------------------------------------- self.inlet_type = QComboBox() self.inlet_type.addItem("LSL stream") self.inlet_type.addItem("LSL file stream") self.inlet_type.addItem("LSL generator") self.inlet_type.addItem("Field trip buffer") self.lsl_stream_name = QComboBox() self.lsl_stream_name.addItem("NVX136_Data") self.lsl_stream_name.addItem("Mitsar") self.lsl_filename = PathEdit() dialog = QFileDialog(self, "Open") dialog.setFileMode(dialog.AnyFile) self.lsl_filename.setDialog(dialog) self.hostname_port = QLineEdit("localhost:1972") self.inlet_params = StackedDictWidget() self.inlet_params.setMaximumHeight(25) self.inlet_params.addWidget("LSL stream", self.lsl_stream_name) self.inlet_params.addWidget("LSL file stream", self.lsl_filename) self.inlet_params.addWidget("LSL generator", QWidget()) self.inlet_params.addWidget("Field trip buffer", self.hostname_port) # TODO: LSL generator is not reflected in the exported file, even when selected. self.inlet_type.currentTextChanged.connect( self.inlet_params.setCurrentKey) self.inlet_config = QWidget() self.inlet_config.setContentsMargins(0, 0, 0, 0) inlet_layout = QHBoxLayout() inlet_layout.setContentsMargins(0, 0, 0, 0) inlet_layout.addWidget(self.inlet_type) inlet_layout.addWidget(self.inlet_params) self.inlet_config.setLayout(inlet_layout) # -------------------------------------------------------------------------------------------------------------- self.name = QLineEdit("Experiment") self.dc = QCheckBox() self.plot_raw = QCheckBox() self.plot_raw.setChecked(True) self.plot_signals = QCheckBox() self.plot_signals.setChecked(True) self.discard_channels = QLineEdit() self.reference_sub = QLineEdit() self.show_photo_rectangle = QCheckBox() self.show_notch_filters = QCheckBox() self.reward_refractory_period = QDoubleSpinBox() self.reward_refractory_period.setRange(0.1, 10) self.reward_refractory_period.setValue(0.25) self.reward_refractory_period.setSuffix(" s") # Adding properties to the widget ------------------------------------------------------------------------------ layout.addRow("Name", self.name) layout.addRow("Inlet", self.inlet_config) layout.addRow("Enable DC blocker", self.dc) layout.addRow("Prefilter band (lower bound)", prefilter_lower_bound_widget) layout.addRow("Prefilter band (upper bound)", prefilter_upper_bound_widget) layout.addRow("Plot raw", self.plot_raw) layout.addRow("Plot signals", self.plot_signals) layout.addRow("Discard channels", self.discard_channels) layout.addRow("Reference sub", self.reference_sub) layout.addRow("Show photo-sensor rectangle", self.show_photo_rectangle) layout.addRow("Show notch filters", self.show_notch_filters) layout.addRow("Reward refractory period", self.reward_refractory_period) def updateModel(self, ex, /): ex.name = self.name.text() ex.inlet = self.inlet_type_export_values[self.inlet_type.currentText()] ex.lsl_stream_name = self.lsl_stream_name.currentText() ex.raw_data_path = self.lsl_filename.text() ex.hostname_port = self.hostname_port.text() ex.dc = self.dc.isChecked() if self.prefilter_lower_bound_enable.isChecked(): prefilter_lower_bound = self.prefilter_lower_bound.value() else: prefilter_lower_bound = None if self.prefilter_upper_bound_enable.isChecked(): prefilter_upper_bound = self.prefilter_upper_bound.value() else: prefilter_upper_bound = None ex.prefilter_band = (prefilter_lower_bound, prefilter_upper_bound) ex.plot_raw = self.plot_raw.isChecked() ex.plot_signals = self.plot_signals.isChecked() ex.discard_channels = self.discard_channels.text() ex.reference_sub = self.reference_sub.text() ex.show_photo_rectangle = self.show_photo_rectangle.isChecked() ex.show_notch_filters = self.show_notch_filters.isChecked() ex.reward_refractory_period = self.reward_refractory_period.value() def _adjust(self): if self.prefilter_lower_bound_enable.isChecked(): self.prefilter_lower_bound.setEnabled(True) self.prefilter_upper_bound.setMinimum( self.prefilter_lower_bound.value()) else: self.prefilter_lower_bound.setEnabled(False) self.prefilter_upper_bound.setMinimum(0) if self.prefilter_upper_bound_enable.isChecked(): self.prefilter_upper_bound.setEnabled(True) self.prefilter_lower_bound.setMaximum( self.prefilter_upper_bound.value()) else: self.prefilter_upper_bound.setEnabled(False) self.prefilter_lower_bound.setMaximum( 10000) # TODO: add proper value
class FilterGroup(AbstractProcessGroup): def __init__(self, title, fs): AbstractProcessGroup.__init__(self, title, fs) self.setupFilterLayout() def setupFilterLayout(self): filterLayout = QVBoxLayout(self) filterSettLayout = QHBoxLayout() self.filterBandChooser = QComboBox() self.filterTypeChooser = QComboBox() filterTypeLayout = QFormLayout() filterTypeLayout.addWidget(QLabel('Type')) filterTypeLayout.addWidget(self.filterBandChooser) bandTypes = { 'Low Pass': '******', 'Band Pass': '******', 'High Pass': '******', 'Band Stop': 'bandstop' } [self.filterBandChooser.addItem(i, bandTypes[i]) for i in bandTypes] self.filterBandChooser.setCurrentText('Band Pass') filterTypeLayout.addWidget(self.filterTypeChooser) filterTypes = {'Butter': 'butter', 'Bessel': 'bessel'} [ self.filterTypeChooser.addItem(i, filterTypes[i]) for i in filterTypes ] self.lowFreqEdit = QDoubleSpinBox() self.lowFreqEdit.setSuffix(' Hz') self.lowFreqEdit.setDecimals(1) self.lowFreqEdit.setRange(0.1, self.fs / 2 - 0.1) self.highFreqEdit = QDoubleSpinBox() self.highFreqEdit.setSuffix(' Hz') self.highFreqEdit.setDecimals(1) self.highFreqEdit.setLocale( QLocale(QLocale.Polish, QLocale.EuropeanUnion)) self.highFreqEdit.setRange(0.1, self.fs / 2 - 0.1) self.filterBandChooser.currentTextChanged.connect(self.setFilterBand) filterFreqLayout = QFormLayout() filterFreqLayout.addRow(QLabel('Cutoff Frequencies')) filterFreqLayout.addRow('Low', self.lowFreqEdit) filterFreqLayout.addRow('High', self.highFreqEdit) filterOrdLayout = QFormLayout() self.filterOrdEdit = QSpinBox() self.filterOrdEdit.setMinimum(1) self.filterOrdEdit.setValue(5) filterOrdLayout.addRow(QLabel('Order')) filterOrdLayout.addRow(self.filterOrdEdit) filterSettLayout.addLayout(filterTypeLayout) filterSettLayout.addSpacing(10) filterSettLayout.addLayout(filterFreqLayout) filterSettLayout.addSpacing(10) filterSettLayout.addLayout(filterOrdLayout) btn = QPushButton('Show filter response') btn.clicked.connect(self.showFilterResponse) filterLayout.addLayout(filterSettLayout) filterLayout.addWidget(btn, 0, Qt.AlignRight) def setFilterBand(self): if self.filterBandChooser.currentText() == 'Low Pass': self.lowFreqEdit.setDisabled(True) else: self.lowFreqEdit.setEnabled(True) if self.filterBandChooser.currentText() == 'High Pass': self.highFreqEdit.setDisabled(True) else: self.highFreqEdit.setEnabled(True) def calcFilter(self): bandArr = [ x.value() for x in (self.lowFreqEdit, self.highFreqEdit) if x.isEnabled() == True ] return filterCalc(order=self.filterOrdEdit.value(), bandarr=bandArr, fs=self.fs, btype=self.filterBandChooser.currentData(), ftype=self.filterTypeChooser.currentData()) def showFilterResponse(self): bandArr = [ x.value() for x in (self.lowFreqEdit, self.highFreqEdit) if x.isEnabled() == True ] b, a = self.calcFilter() w, h = signal.freqz(b, a) fig = plt.figure() ax1 = fig.add_subplot(111) ax1.set_title( label='Filter frequency response\n{}, {}, {}Hz, ord={}'.format( self.filterBandChooser.currentText(), self.filterTypeChooser.currentText(), bandArr, self.filterOrdEdit.value())) ax1.plot(w * (self.fs / (2 * np.pi)), 20 * np.log10(abs(h)), 'b') ax1.set_ylabel('Amplitude [dB]', color='b') ax1.set_xlabel('Frequency [Hz]') ax1.tick_params(axis='y', colors='b') ax2 = ax1.twinx() angles = np.unwrap(np.angle(h)) ax2.plot(w * (self.fs / (2 * np.pi)), angles, 'g') ax2.set_ylabel('Angle (radians)', color='g') ax2.tick_params(axis='y', colors='g') plt.grid() plt.axis('tight') plt.show() def process(self, inData): b, a = self.calcFilter() outData = [] progStep = 100.0 / len(inData) prog = 0 for data in inData: newData = signal.lfilter(b, a, data) outData.append(newData) prog = prog + progStep self.progress.emit(int(prog)) return outData