def testFloatSignal(self): foo1 = QDoubleSpinBox() foo2 = QDoubleSpinBox() foo1.valueChanged[float].connect(foo2.setValue) foo2.valueChanged[float].connect(foo1.setValue) foo1.setValue(0.42) self.assertEqual(foo1.value(), foo2.value())
class WidgetConfig(QGroupBox): def __init__(self): super(WidgetConfig, self).__init__() HEIGHT = 30 grid = QGridLayout() # 使用默认摄像头复选框 self.check_camera = QCheckBox('Use default camera') self.check_camera.setChecked(False) self.check_camera.stateChanged.connect(self.slot_check_camera) grid.addWidget(self.check_camera, 0, 0, 1, 3) # 一行三列 # 选择视频文件 label_video = QLabel('Detect File') self.line_video = QLineEdit() if 'video' in GLOBAL.config: self.line_video.setText(GLOBAL.config['video']) self.line_video.setFixedHeight(HEIGHT) self.line_video.setEnabled(False) self.line_video.editingFinished.connect( lambda: GLOBAL.record_config({'video': self.line_video.text()})) self.btn_video = QPushButton('Choose') self.btn_video.setFixedHeight(HEIGHT) self.btn_video.setEnabled(False) self.btn_video.clicked.connect(self.choose_video_file) self.slot_check_camera() grid.addWidget(label_video, 1, 0) grid.addWidget(self.line_video, 1, 1) grid.addWidget(self.btn_video, 1, 2) # 选择权重文件 label_weights = QLabel('Weights File') self.line_weights = QLineEdit() if 'weights' in GLOBAL.config: self.line_weights.setText(GLOBAL.config['weights']) self.line_weights.setFixedHeight(HEIGHT) self.line_weights.editingFinished.connect(lambda: GLOBAL.record_config( {'weights': self.line_weights.text()})) self.btn_weights = QPushButton('Choose') self.btn_weights.setFixedHeight(HEIGHT) self.btn_weights.clicked.connect(self.choose_weights_file) grid.addWidget(label_weights, 2, 0) grid.addWidget(self.line_weights, 2, 1) grid.addWidget(self.btn_weights, 2, 2) # 是否使用GPU label_device = QLabel('CUDA device') self.line_device = QLineEdit('gpu') if 'device' in GLOBAL.config: self.line_device.setText(GLOBAL.config['device']) else: self.line_device.setText('cpu') self.line_device.setPlaceholderText('cpu or 0 or 0,1,2,3') self.line_device.setFixedHeight(HEIGHT) self.line_device.editingFinished.connect( lambda: GLOBAL.record_config({'device': self.line_device.text()})) grid.addWidget(label_device, 3, 0) grid.addWidget(self.line_device, 3, 1, 1, 2) # 设置图像大小 label_size = QLabel('Img Size') self.combo_size = QComboBox() self.combo_size.setFixedHeight(HEIGHT) self.combo_size.setStyleSheet( 'QAbstractItemView::item {height: 40px;}') self.combo_size.setView(QListView()) self.combo_size.addItem('320', 320) self.combo_size.addItem('416', 416) self.combo_size.addItem('480', 480) self.combo_size.addItem('544', 544) self.combo_size.addItem('640', 640) self.combo_size.setCurrentIndex(2) self.combo_size.currentIndexChanged.connect( lambda: GLOBAL.record_config( {'img_size': self.combo_size.currentData()})) grid.addWidget(label_size, 4, 0) grid.addWidget(self.combo_size, 4, 1, 1, 2) #choose net camera label_stream = QLabel('NetVedioStream') self.combo_stream = QComboBox() self.combo_stream.setFixedHeight(HEIGHT) self.combo_stream.setStyleSheet( 'QAbstractItemView::item {height: 40px;}') self.combo_stream.setView(QListView()) self.combo_stream.addItem('rtsp://*****:*****@192.168.0.65/', 'rtsp://*****:*****@192.168.0.65/') self.combo_stream.addItem('rtsp://*****:*****@192.168.0.66/', 'rtsp://*****:*****@192.168.0.66/') self.combo_stream.addItem('rtsp://*****:*****@192.168.0.67/', 'rtsp://*****:*****@192.168.0.67/') self.combo_stream.addItem('rtsp://*****:*****@192.168.0.68/', 'rtsp://*****:*****@192.168.0.68/') self.combo_stream.addItem('rtsp://*****:*****@192.168.0.65/', 'rtsp://*****:*****@192.168.0.65/') self.combo_stream.setCurrentIndex(0) self.combo_stream.currentIndexChanged.connect( lambda: GLOBAL.record_config( {'netstreamvedio': self.combo_stream.currentData()})) grid.addWidget(label_stream, 5, 0) grid.addWidget(self.combo_stream, 5, 1, 1, 2) # 设置置信度阈值 label_conf = QLabel('Confidence') self.spin_conf = QDoubleSpinBox() self.spin_conf.setFixedHeight(HEIGHT) self.spin_conf.setDecimals(1) self.spin_conf.setRange(0.1, 0.9) self.spin_conf.setSingleStep(0.1) if 'conf_thresh' in GLOBAL.config: self.spin_conf.setValue(GLOBAL.config['conf_thresh']) else: self.spin_conf.setValue(0.4) # 默认值 GLOBAL.record_config({'conf_thresh': 0.4}) self.spin_conf.valueChanged.connect(lambda: GLOBAL.record_config( {'conf_thresh': round(self.spin_conf.value(), 1)})) grid.addWidget(label_conf, 6, 0) grid.addWidget(self.spin_conf, 6, 1, 1, 2) # 设置IOU阈值 label_iou = QLabel('IOU') self.spin_iou = QDoubleSpinBox() self.spin_iou.setFixedHeight(HEIGHT) self.spin_iou.setDecimals(1) self.spin_iou.setRange(0.1, 0.9) self.spin_iou.setSingleStep(0.1) if 'iou_thresh' in GLOBAL.config: self.spin_iou.setValue(GLOBAL.config['iou_thresh']) else: self.spin_iou.setValue(0.5) # 默认值 GLOBAL.record_config({'iou_thresh': 0.5}) self.spin_iou.valueChanged.connect(lambda: GLOBAL.record_config( {'iou_thresh': round(self.spin_iou.value(), 1)})) grid.addWidget(label_iou, 7, 0) grid.addWidget(self.spin_iou, 7, 1, 1, 2) # class-agnostic NMS self.check_agnostic = QCheckBox('Agnostic') if 'agnostic' in GLOBAL.config: self.check_agnostic.setChecked(GLOBAL.config['agnostic']) else: self.check_agnostic.setChecked(True) self.check_agnostic.stateChanged.connect(lambda: GLOBAL.record_config( {'agnostic': self.check_agnostic.isChecked()})) grid.addWidget(self.check_agnostic, 8, 0, 1, 3) # 一行三列 # augmented inference self.check_augment = QCheckBox('Augment') if 'augment' in GLOBAL.config: self.check_augment.setChecked(GLOBAL.config['augment']) else: self.check_augment.setChecked(True) self.check_augment.stateChanged.connect(lambda: GLOBAL.record_config( {'augment': self.check_augment.isChecked()})) grid.addWidget(self.check_augment, 9, 0, 1, 3) # 一行三列 self.setLayout(grid) # 设置布局 def slot_check_camera(self): check = self.check_camera.isChecked() GLOBAL.record_config({'use_camera': check}) # 保存配置 if check: self.line_video.setEnabled(False) self.btn_video.setEnabled(False) else: self.line_video.setEnabled(True) self.btn_video.setEnabled(True) def choose_weights_file(self): """从系统中选择权重文件""" file = QFileDialog.getOpenFileName( self, "Pre-trained YOLOv5 Weights", "./", "Weights Files (*.pt);;All Files (*)") if file[0] != '': self.line_weights.setText(file[0]) GLOBAL.record_config({'weights': file[0]}) def choose_video_file(self): """从系统中选择视频文件""" file = QFileDialog.getOpenFileName(self, "Video Files", "./", "Video Files (*)") if file[0] != '': self.line_video.setText(file[0]) GLOBAL.record_config({'video': file[0]}) def save_config(self): """保存当前的配置到配置文件""" config = { 'use_camera': self.check_camera.isChecked(), 'video': self.line_video.text(), 'weights': self.line_weights.text(), 'device': self.line_device.text(), 'img_size': self.combo_size.currentData(), 'conf_thresh': round(self.spin_conf.value(), 1), 'iou_thresh': round(self.spin_iou.value(), 1), 'agnostic': self.check_agnostic.isChecked(), 'augment': self.check_augment.isChecked(), 'netstreamvedio': self.combo_stream.currentData() } GLOBAL.record_config(config)
class EUI(QDialog): def __init__(self, ip, port, sal, parent=None): super(EUI, self).__init__(parent) self.ip = ip self.port = port self.client = liveview.AsyncLiveViewClient(self.ip, self.port) self.event_loop = asyncio.get_event_loop() self.event_loop.run_until_complete(self.client.start()) # self.sal = salobj.Remote(SALPY_GenericCamera, index=salIndex) self.sal = sal # self.sal.subscribeEvent self.layout = QHBoxLayout() self.controlsLayout = QVBoxLayout() self.imageLayout = QVBoxLayout() layout = QHBoxLayout() self.startLiveViewButton = QPushButton("Start Live") self.startLiveViewButton.clicked.connect(self.startLiveView) self.stopLiveViewButton = QPushButton("Stop Live") self.stopLiveViewButton.clicked.connect(self.stopLiveView) layout.addWidget(self.startLiveViewButton) layout.addWidget(self.stopLiveViewButton) self.controlsLayout.addLayout(layout) layout = QHBoxLayout() layout.addWidget(QLabel("Exposure")) self.exposureTimeEdit = QDoubleSpinBox() self.exposureTimeEdit.setRange(0, 900.0) self.exposureTimeEdit.setDecimals(6) layout.addWidget(self.exposureTimeEdit) self.controlsLayout.addLayout(layout) layout = QVBoxLayout() subLayout = QHBoxLayout() subLayout.addWidget(QLabel("Top")) self.roiTopEdit = QDoubleSpinBox() self.roiTopEdit.setRange(0, 4095) self.roiTopEdit.setDecimals(0) subLayout.addWidget(self.roiTopEdit) layout.addLayout(subLayout) subLayout = QHBoxLayout() subLayout.addWidget(QLabel("Left")) self.roiLeftEdit = QDoubleSpinBox() self.roiLeftEdit.setRange(0, 4095) self.roiLeftEdit.setDecimals(0) subLayout.addWidget(self.roiLeftEdit) layout.addLayout(subLayout) subLayout = QHBoxLayout() subLayout.addWidget(QLabel("Width")) self.roiWidthEdit = QDoubleSpinBox() self.roiWidthEdit.setRange(0, 4095) self.roiWidthEdit.setDecimals(0) subLayout.addWidget(self.roiWidthEdit) layout.addLayout(subLayout) subLayout = QHBoxLayout() subLayout.addWidget(QLabel("Height")) self.roiHeightEdit = QDoubleSpinBox() self.roiHeightEdit.setRange(0, 4095) self.roiHeightEdit.setDecimals(0) subLayout.addWidget(self.roiHeightEdit) layout.addLayout(subLayout) self.setROIButton = QPushButton("Set") self.setROIButton.clicked.connect(self.setROI) layout.addWidget(self.setROIButton) self.setFullFrameButton = QPushButton("Set Full Frame") self.setFullFrameButton.clicked.connect(self.setFullFrame) layout.addWidget(self.setFullFrameButton) self.controlsLayout.addLayout(layout) layout = QVBoxLayout() layout.addWidget(QLabel("File Path:")) self.filePathEdit = QTextEdit() layout.addWidget(self.filePathEdit) self.takeExposureButton = QPushButton("Take Images") self.takeExposureButton.clicked.connect(self.takeImages) layout.addWidget(self.takeExposureButton) self.controlsLayout.addLayout(layout) img = Image.fromarray(np.zeros((1024, 1014))).convert("I") img.save("/tmp/foo.png") self.pix = QPixmap("/tmp/foo.png") self.imageLabel = QLabel() self.imageLabel.setPixmap(self.pix) self.imageLabel.setGeometry(QtCore.QRect(40, 40, 800, 800)) self.imageLayout.addWidget(self.imageLabel) self.layout.addLayout(self.controlsLayout) self.layout.addLayout(self.imageLayout) self.setLayout(self.layout) self.setFixedSize(1000, 880) def updateDisplays(self): print("updateDisplays - Here - 1") try: if self.client is None or self.client.reader is not None: try: print("updateDisplays - Here - 2") self.client = liveview.AsyncLiveViewClient( self.ip, self.port) self.event_loop.run_until_complete(self.client.start()) except Exception: print("Error on client!") self.client = None print("updateDisplays - Here - 3") exposure = self.event_loop.run_until_complete( self.client.receive_exposure()) print("New exposure.") # exposure.makeJPEG() # img = Image.open(BytesIO(exposure.buffer)) # width = img.size[0] # height = img.size[1] # ratio = width / height # deltaWidth = width - 760 # deltaHeight = height - 760 # if deltaWidth > 0 or deltaHeight > 0: # newWidth = 760 # newHeight = 760 # if deltaWidth > deltaHeight: # newWidth = newWidth # newHeight = newHeight / ratio # elif deltaHeight > deltaWidth: # newWidth = newWidth / ratio # newHeight = newHeight # img = img.resize((int(newWidth), int(newHeight))) as8 = exposure.buffer.astype(np.uint8) img = Image.fromarray(as8.reshape(exposure.height, exposure.width)) img.save("/tmp/foo.png") self.pix = QPixmap("/tmp/foo.png") self.imageLabel.setPixmap(self.pix) except liveview.ImageReceiveError as e: print("updateDisplays - Exception") traceback.format_exc(e) pass def startLiveView(self): print("startLiveView - Start") # data = self.sal.cmd_startLiveView.DataType() # data.expTime = self.exposureTimeEdit.value() # asyncio.get_event_loop().run_until_complete( # self.sal.cmd_startLiveView.start(data, timeout=10.0) # ) self.sal.issueCommand_startLiveView(self.exposureTimeEdit.value()) print("startLiveView - End") def stopLiveView(self): print("stopLiveView - Start") # asyncio.get_event_loop().run_until_complete( # self.sal.cmd_stopLiveView.start( # self.sal.cmd_stopLiveView.DataType(), timeout=10.0)) self.sal.issueCommand_stopLiveView(True) print("stopLiveView - End") def setROI(self): print("setROI - Start") # data = self.sal.cmd_setROI.DataType() # data.topPixel = int(self.roiTopEdit.value()) # data.leftPixel = int(self.roiLeftEdit.value()) # data.width = int(self.roiWidthEdit.value()) # data.height = int(self.roiHeightEdit.value()) # asyncio.get_event_loop().run_until_complete( # self.sal.cmd_setROI.start(data, timeout=5.0) # ) self.sal.issueCommand_setROI( int(self.roiTopEdit.value()), int(self.roiLeftEdit.value()), int(self.roiWidthEdit.value()), int(self.roiHeightEdit.value()), ) print("setROI - End") def setFullFrame(self): print("setFullFrame - Start") # asyncio.get_event_loop().run_until_complete(self.sal.cmd_setFullFrame.start( # self.sal.cmd_setFullFrame.DataType(), timeout=5.0)) self.sal.issueCommand_setFullFrame(True) print("setFullFrame - End") def takeImages(self): print("takeImages - Start") # data = self.sal.cmd_takeImages.DataType() # data.numImages = 1 # data.expTime = self.exposureTimeEdit.value() # data.shutter = 1 # data.imageSequenceName = "Foo" # asyncio.get_event_loop().run_until_complete(self.sal.cmd_takeImages.start(data, # timeout=30.0)) self.sal.issueCommand_takeImages(1, self.exposureTimeEdit.value(), 1, "Foo") print("takeImages - End")
class SubtitleInfoDialog(QDialog): def __init__(self, subtitles_name, subtitles_delay, subtitles_language, subtitles_track_name, subtitles_set_default, subtitles_set_forced, subtitles_default_value_delay, subtitles_default_value_language, subtitles_default_value_track_name, subtitles_default_value_set_default, subtitles_default_value_set_forced, subtitle_set_default_disabled=False, subtitle_set_forced_disabled=False, disable_edit=False, parent=None): super().__init__(parent) self.window_title = "Subtitle Info" self.state = "no" self.subtitles_count = len(subtitles_delay) self.messageIcon = QLabel() self.subtitle_tab_comboBox = InfoCellDialogTabComboBox( hint="Subtitles Groups") for i in range(self.subtitles_count): self.subtitle_tab_comboBox.addItem("Subtitle #" + str(i + 1)) self.subtitle_tab_comboBox.setCurrentIndex(0) self.subtitle_tab_comboBox.currentIndexChanged.connect( self.update_current_subtitle_index) self.current_subtitle_index = 0 self.disable_edit = disable_edit self.current_subtitle_name = subtitles_name self.current_subtitle_language = subtitles_language self.current_subtitle_delay = subtitles_delay self.current_subtitle_track_name = subtitles_track_name self.current_subtitle_set_default = subtitles_set_default self.current_subtitle_set_forced = subtitles_set_forced self.default_subtitle_language = subtitles_default_value_language self.default_subtitle_delay = subtitles_default_value_delay self.default_subtitle_track_name = subtitles_default_value_track_name self.default_subtitle_set_default = subtitles_default_value_set_default self.default_subtitle_set_forced = subtitles_default_value_set_forced self.subtitle_set_default_disabled = subtitle_set_default_disabled self.subtitle_set_forced_disabled = subtitle_set_forced_disabled self.subtitle_name_label = QLabel("Subtitle Name:") self.subtitle_name_value = QLabel( str(self.current_subtitle_name[self.current_subtitle_index])) width_to_be_fixed = 0 for i in range(len(self.current_subtitle_name)): width_to_be_fixed = max( width_to_be_fixed, self.subtitle_name_value.fontMetrics().boundingRect( self.current_subtitle_name[i]).width()) self.subtitle_name_value.setFixedWidth(width_to_be_fixed + 10) self.subtitle_delay_label = QLabel("Subtitle Delay:") self.subtitle_delay_spin = QDoubleSpinBox() self.setup_subtitle_delay_spin() self.subtitle_language_label = QLabel("Subtitle Language:") self.subtitle_language_comboBox = QComboBox() self.setup_subtitle_language_comboBox() self.subtitle_track_name_label = QLabel("Subtitle Track Name:") self.subtitle_track_name_lineEdit = QLineEdit() self.setup_subtitle_track_name_lineEdit() self.subtitle_set_forced_label = QLabel("Subtitle Forced State:") self.subtitle_set_forced_checkBox = QCheckBox() self.setup_subtitle_set_forced_checkBox() self.subtitle_set_default_label = QLabel("Subtitle Default State:") self.subtitle_set_default_checkBox = QCheckBox() self.setup_subtitle_set_default_checkBox() self.yes_button = QPushButton("OK") self.no_button = QPushButton("Cancel") self.reset_button = QPushButton("Reset To Default") self.buttons_layout = QHBoxLayout() self.subtitle_delay_layout = QHBoxLayout() self.subtitle_language_layout = QHBoxLayout() self.subtitle_track_name_layout = QHBoxLayout() self.subtitle_set_default_layout = QHBoxLayout() self.subtitle_set_forced_layout = QHBoxLayout() self.buttons_layout.addWidget(QLabel(""), stretch=3) self.buttons_layout.addWidget(self.reset_button, stretch=2) self.buttons_layout.addWidget(self.yes_button, stretch=2) self.buttons_layout.addWidget(self.no_button, stretch=2) self.buttons_layout.addWidget(QLabel(""), stretch=3) self.subtitle_setting_layout = QGridLayout() self.subtitle_editable_setting_layout = QFormLayout() self.subtitle_editable_setting_layout.addRow(self.subtitle_name_label, self.subtitle_name_value) self.subtitle_editable_setting_layout.addRow( self.subtitle_track_name_label, self.subtitle_track_name_lineEdit) self.subtitle_editable_setting_layout.addRow( self.subtitle_language_label, self.subtitle_language_comboBox) self.subtitle_editable_setting_layout.addRow(self.subtitle_delay_label, self.subtitle_delay_spin) self.subtitle_editable_setting_layout.addRow( self.subtitle_set_default_label, self.subtitle_set_default_checkBox) self.subtitle_editable_setting_layout.addRow( self.subtitle_set_forced_label, self.subtitle_set_forced_checkBox) self.subtitle_setting_layout.addWidget(self.subtitle_tab_comboBox, 0, 0) self.subtitle_setting_layout.addLayout( self.subtitle_editable_setting_layout, 1, 0, 5, 2) self.subtitle_setting_layout.addWidget(self.messageIcon, 1, 3, 5, -1) self.main_layout = QGridLayout() self.main_layout.addLayout(self.subtitle_setting_layout, 0, 0, 2, 3) self.main_layout.addLayout(self.buttons_layout, 2, 0, 1, -1) self.main_layout.setContentsMargins(20, 20, 20, 20) self.setLayout(self.main_layout) self.setup_ui() self.signal_connect() def setup_ui(self): self.disable_question_mark_window() self.messageIcon.setPixmap( QtGui.QPixmap(GlobalFiles.SubtitleIconPath).scaledToHeight(100)) self.set_dialog_values() self.set_default_buttons() if self.subtitle_set_default_disabled: self.subtitle_set_default_disable() if self.subtitle_set_forced_disabled: self.subtitle_set_forced_disable() if self.disable_edit: self.subtitle_track_name_lineEdit.setEnabled(False) self.subtitle_language_comboBox.setEnabled(False) self.subtitle_delay_spin.setEnabled(False) self.subtitle_set_default_checkBox.setEnabled(False) self.subtitle_set_forced_checkBox.setEnabled(False) self.reset_button.setEnabled(False) self.setup_tool_tip_hint_subtitle_set_default() self.setup_tool_tip_hint_subtitle_set_forced() def signal_connect(self): self.subtitle_track_name_lineEdit.textEdited.connect( self.update_current_subtitle_track_name) self.subtitle_delay_spin.editingFinished.connect( self.update_current_subtitle_delay) self.subtitle_language_comboBox.currentTextChanged.connect( self.update_current_subtitle_language) self.subtitle_set_default_checkBox.stateChanged.connect( self.update_current_subtitle_set_default) self.subtitle_set_forced_checkBox.stateChanged.connect( self.update_current_subtitle_set_forced) self.yes_button.clicked.connect(self.click_yes) self.no_button.clicked.connect(self.click_no) self.reset_button.clicked.connect(self.reset_subtitle_setting) def click_yes(self): self.state = "yes" self.close() def click_no(self): self.state = "no" self.close() def set_dialog_values(self): self.setWindowTitle(self.window_title) self.setWindowIcon(GlobalFiles.InfoSettingIcon) def disable_question_mark_window(self): self.setWindowFlag(Qt.WindowContextHelpButtonHint, on=False) def increase_message_font_size(self, value): message_font = self.message.font() message_font.setPointSize(self.message.fontInfo().pointSize() + value) self.message.setFont(message_font) def set_default_buttons(self): self.yes_button.setDefault(True) self.yes_button.setFocus() def showEvent(self, a0: QtGui.QShowEvent) -> None: super().showEvent(a0) self.setFixedSize(self.size()) def setup_subtitle_track_name_lineEdit(self): self.subtitle_track_name_lineEdit.setClearButtonEnabled(True) self.subtitle_track_name_lineEdit.setText( self.current_subtitle_track_name[self.current_subtitle_index]) def setup_subtitle_language_comboBox(self): self.subtitle_language_comboBox.addItems(AllSubtitlesLanguages) self.subtitle_language_comboBox.setCurrentIndex( AllSubtitlesLanguages.index( self.current_subtitle_language[self.current_subtitle_index])) self.subtitle_language_comboBox.setMaxVisibleItems(8) self.subtitle_language_comboBox.setStyleSheet( "QComboBox { combobox-popup: 0; }") def setup_subtitle_delay_spin(self): # self.subtitle_delay_spin.setMaximumWidth(screen_size.width() // 16) self.subtitle_delay_spin.setDecimals(3) self.subtitle_delay_spin.setMinimum(-9999.0) self.subtitle_delay_spin.setMaximum(9999.0) self.subtitle_delay_spin.setSingleStep(0.5) self.subtitle_delay_spin.setValue( float(self.current_subtitle_delay[self.current_subtitle_index])) def setup_subtitle_set_default_checkBox(self): self.subtitle_set_default_checkBox.setText("Set Default") self.subtitle_set_default_checkBox.setChecked( bool(self.current_subtitle_set_default[ self.current_subtitle_index])) def setup_subtitle_set_forced_checkBox(self): self.subtitle_set_forced_checkBox.setText("Set Forced") self.subtitle_set_forced_checkBox.setChecked( bool( self.current_subtitle_set_forced[self.current_subtitle_index])) def update_current_subtitle_track_name(self): self.current_subtitle_track_name[self.current_subtitle_index] = str( self.subtitle_track_name_lineEdit.text()) def update_current_subtitle_delay(self): self.current_subtitle_delay[self.current_subtitle_index] = round( self.subtitle_delay_spin.value(), 5) def update_current_subtitle_language(self): self.current_subtitle_language[self.current_subtitle_index] = str( self.subtitle_language_comboBox.currentText()) def update_current_subtitle_set_default(self): new_state = self.subtitle_set_default_checkBox.checkState( ) == Qt.Checked self.current_subtitle_set_default[ self.current_subtitle_index] = new_state if new_state: for i in range(len(self.current_subtitle_set_default)): if i != self.current_subtitle_index: self.current_subtitle_set_default[i] = False def update_current_subtitle_set_forced(self): new_state = self.subtitle_set_forced_checkBox.checkState( ) == Qt.Checked self.current_subtitle_set_forced[ self.current_subtitle_index] = new_state if new_state: for i in range(len(self.current_subtitle_set_forced)): if i != self.current_subtitle_index: self.current_subtitle_set_forced[i] = False def reset_subtitle_setting(self): self.current_subtitle_language[ self.current_subtitle_index] = self.default_subtitle_language[ self.current_subtitle_index] self.current_subtitle_delay[ self.current_subtitle_index] = self.default_subtitle_delay[ self.current_subtitle_index] self.current_subtitle_track_name[ self.current_subtitle_index] = self.default_subtitle_track_name[ self.current_subtitle_index] self.current_subtitle_set_default[ self.current_subtitle_index] = self.default_subtitle_set_default[ self.current_subtitle_index] self.current_subtitle_set_forced[ self.current_subtitle_index] = self.default_subtitle_set_forced[ self.current_subtitle_index] self.subtitle_language_comboBox.setCurrentIndex( AllSubtitlesLanguages.index( self.current_subtitle_language[self.current_subtitle_index])) self.subtitle_delay_spin.setValue( float(self.current_subtitle_delay[self.current_subtitle_index])) self.subtitle_track_name_lineEdit.setText( self.current_subtitle_track_name[self.current_subtitle_index]) self.subtitle_set_default_checkBox.setChecked( bool(self.current_subtitle_set_default[ self.current_subtitle_index])) self.subtitle_set_forced_checkBox.setChecked( bool( self.current_subtitle_set_forced[self.current_subtitle_index])) def subtitle_set_default_disable(self): self.subtitle_set_default_checkBox.setDisabled(True) def subtitle_set_forced_disable(self): self.subtitle_set_forced_checkBox.setDisabled(True) def setup_tool_tip_hint_subtitle_set_default(self): if self.subtitle_set_default_checkBox.isEnabled(): self.subtitle_set_default_checkBox.setToolTip( "<nobr>set this subtitle to be the default subtitle track " "when play") self.subtitle_set_default_checkBox.setToolTipDuration(12000) else: self.subtitle_set_default_checkBox.setToolTip( "<nobr>set this subtitle to be the default subtitle track when play<br><b>Disabled</b> because " "option " "<b>make this subtitle default</b> is enabled on mux setting tab " ) self.subtitle_set_default_checkBox.setToolTipDuration(12000) def setup_tool_tip_hint_subtitle_set_forced(self): if self.subtitle_set_forced_checkBox.isEnabled(): self.subtitle_set_forced_checkBox.setToolTip( "<nobr>set this subtitle to be the forced subtitle track when " "play") self.subtitle_set_forced_checkBox.setToolTipDuration(12000) else: self.subtitle_set_forced_checkBox.setToolTip( "<nobr>set this subtitle to be the forced subtitle track when play<br><b>Disabled</b> because " "option " "<b>make this subtitle default and forced</b> is enabled on mux setting tab " ) self.subtitle_set_forced_checkBox.setToolTipDuration(12000) def update_current_subtitle_index(self, new_index): self.current_subtitle_index = new_index self.subtitle_delay_spin.setValue( float(self.current_subtitle_delay[self.current_subtitle_index])) self.subtitle_set_default_checkBox.setChecked( bool(self.current_subtitle_set_default[ self.current_subtitle_index])) self.subtitle_set_forced_checkBox.setChecked( bool( self.current_subtitle_set_forced[self.current_subtitle_index])) self.subtitle_language_comboBox.setCurrentIndex( AllSubtitlesLanguages.index( self.current_subtitle_language[self.current_subtitle_index])) self.subtitle_track_name_lineEdit.setText( self.current_subtitle_track_name[self.current_subtitle_index]) self.subtitle_name_value.setText( str(self.current_subtitle_name[self.current_subtitle_index])) def execute(self): self.exec_()
def testQRealSignal(self): foo1 = QDoubleSpinBox() effect = QGraphicsBlurEffect() effect.blurRadiusChanged['qreal'].connect(foo1.setValue) # check if qreal is a valid type effect.setBlurRadius(0.42) self.assertAlmostEqual(foo1.value(), effect.blurRadius())
class SettingsDialog(QDialog): def __init__(self): super(SettingsDialog, self).__init__() self.setWindowTitle('Settings') self.setWindowIcon(QIcon('img/yologo.png')) self.setWindowFlags(Qt.WindowCloseButtonHint) self.setMinimumWidth(600) HEIGHT = 30 grid = QGridLayout() # 选择权重文件 label_weights = QLabel('Weights') self.line_weights = QLineEdit() self.line_weights.setFixedHeight(HEIGHT) self.btn_weights = QPushButton('...') self.btn_weights.setFixedWidth(40) self.btn_weights.setFixedHeight(HEIGHT) self.btn_weights.clicked.connect(self.choose_weights_file) grid.addWidget(label_weights, 2, 0) grid.addWidget(self.line_weights, 2, 1, 1, 2) grid.addWidget(self.btn_weights, 2, 3) # 是否使用GPU label_device = QLabel('CUDA device') self.line_device = QLineEdit('cpu') self.line_device.setToolTip('cuda device, i.e. 0 or 0,1,2,3 or cpu') self.line_device.setPlaceholderText('cpu or 0 or 0,1,2,3') self.line_device.setFixedHeight(HEIGHT) grid.addWidget(label_device, 3, 0) grid.addWidget(self.line_device, 3, 1, 1, 3) # 设置图像大小 label_size = QLabel('Img Size') self.combo_size = QComboBox() self.combo_size.setToolTip('inference size (pixels)') self.combo_size.setFixedHeight(HEIGHT) self.combo_size.setStyleSheet( 'QAbstractItemView::item {height: 40px;}') self.combo_size.setView(QListView()) self.combo_size.addItem('320', 320) self.combo_size.addItem('384', 384) self.combo_size.addItem('448', 448) self.combo_size.addItem('512', 512) self.combo_size.addItem('576', 576) self.combo_size.addItem('640', 640) grid.addWidget(label_size, 4, 0) grid.addWidget(self.combo_size, 4, 1, 1, 3) # 设置置信度阈值 label_conf = QLabel('Confidence') self.spin_conf = QDoubleSpinBox() self.spin_conf.setToolTip('confidence threshold') self.spin_conf.setFixedHeight(HEIGHT) self.spin_conf.setDecimals(1) self.spin_conf.setRange(0.1, 0.9) self.spin_conf.setSingleStep(0.1) grid.addWidget(label_conf, 5, 0) grid.addWidget(self.spin_conf, 5, 1, 1, 3) # 设置IOU阈值 label_iou = QLabel('IOU') self.spin_iou = QDoubleSpinBox() self.spin_iou.setToolTip('NMS IoU threshold') self.spin_iou.setFixedHeight(HEIGHT) self.spin_iou.setDecimals(1) self.spin_iou.setRange(0.1, 0.9) self.spin_iou.setSingleStep(0.1) grid.addWidget(label_iou, 6, 0) grid.addWidget(self.spin_iou, 6, 1, 1, 3) # maximum detections per image label_max_det = QLabel('maximum detections') self.spin_max_det = QDoubleSpinBox() self.spin_max_det.setToolTip('Maximum detections per image') self.spin_max_det.setFixedHeight(HEIGHT) self.spin_max_det.setDecimals(0) self.spin_max_det.setRange(10, 1000) self.spin_max_det.setSingleStep(10) grid.addWidget(label_max_det, 7, 0) grid.addWidget(self.spin_max_det, 7, 1, 1, 3) # class-agnostic NMS self.check_agnostic = QCheckBox('Agnostic') self.check_agnostic.setToolTip('class-agnostic NMS') # augmented inference self.check_augment = QCheckBox('Augment') self.check_augment.setToolTip('augmented inference') # half self.check_half = QCheckBox('Half') self.check_half.setToolTip('use FP16 half-precision inference') grid.addWidget(self.check_agnostic, 8, 0) grid.addWidget(self.check_augment, 8, 1) grid.addWidget(self.check_half, 8, 2) # use OpenCV DNN for ONNX inference self.check_dnn = QCheckBox('DNN') self.check_dnn.setToolTip('Use OpenCV DNN for ONNX inference') grid.addWidget(self.check_dnn, 9, 0) box = QGroupBox() box.setLayout(grid) hbox = QHBoxLayout() self.btn_cancel = QPushButton('Cancel') self.btn_cancel.clicked.connect(self.restore) self.btn_ok = QPushButton('Ok') self.btn_ok.clicked.connect(self.save_settings) hbox.addStretch() hbox.addWidget(self.btn_cancel) hbox.addWidget(self.btn_ok) vbox = QVBoxLayout() vbox.addWidget(box) vbox.addLayout(hbox) self.setLayout(vbox) self.load_settings() def choose_weights_file(self): """从系统中选择权重文件""" weights_path = '.' weights = gb.get_config('weights', '') if os.path.exists(weights): weights_path = os.path.dirname(weights) file = QFileDialog.getOpenFileName( self, "Pre-trained YOLOv5 Weights", weights_path, "Weights Files (*.pt);;All Files (*)") if file[0] != '': self.line_weights.setText(file[0]) def load_settings(self): self.line_weights.setText(gb.get_config('weights', '')) self.line_device.setText(gb.get_config('device', 'cpu')) self.combo_size.setCurrentText(gb.get_config('img_size', '640')) self.spin_conf.setValue(gb.get_config('conf_thresh', 0.5)) self.spin_iou.setValue(gb.get_config('iou_thresh', 0.5)) self.spin_max_det.setValue(gb.get_config('max_det', 50)) self.check_agnostic.setChecked(gb.get_config('agnostic', True)) self.check_augment.setChecked(gb.get_config('augment', True)) self.check_half.setChecked(gb.get_config('half', True)) self.check_dnn.setChecked(gb.get_config('dnn', False)) def save_settings(self): """更新配置""" config = { 'weights': self.line_weights.text(), 'device': self.line_device.text(), 'img_size': self.combo_size.currentText(), 'conf_thresh': round(self.spin_conf.value(), 1), 'iou_thresh': round(self.spin_iou.value(), 1), 'max_det': int(self.spin_max_det.value()), 'agnostic': self.check_agnostic.isChecked(), 'augment': self.check_augment.isChecked(), 'half': self.check_half.isChecked(), 'dnn': self.check_dnn.isChecked() } gb.record_config(config) self.accept() def restore(self): """恢复原配置""" self.load_settings() self.reject() def closeEvent(self, event): self.restore()
class Dicom_ImageToolsWidget(QWidget): __tab_name__ = 'Tools' pen_selected = Signal() mask_color: QColor() = QColor('green') pen: bool = False def __init__(self): super().__init__() self.width = 20 self.init_ui() def init_ui(self): self.slider = self.__init_slider__() self.color_btn = ColorButton(self.mask_color) self.color_btn.clicked.connect(self.open_color_dialog) self.pen_btn = QPushButton('Pen') self.pen_size = QDoubleSpinBox() self.pen_size.setRange(1, 30) self.pen_size.setValue(1) self.pen_size.setDecimals(0) self.pen_size.setSingleStep(1) self.pen_btn.setCheckable(True) self.pen_btn.clicked.connect(self.pen_selected.emit) self.erase_btn = QPushButton('Erase') self.erase_btn.setCheckable(True) self.processing_btn = QPushButton('Segment with NN') self.nj_segment_btn = QPushButton('Semi automated segment') self.load_mask_btn = QPushButton('Load mask from NIFTI') self.save_mask_btn = QPushButton('Save mask to NIFTI') self.scope_btn = QPushButton('Scope') drawing_layout = QHBoxLayout() drawing_layout.addWidget(self.pen_btn) drawing_layout.addWidget(self.erase_btn) segmentation_layout = QHBoxLayout() segmentation_layout.addWidget(self.processing_btn) segmentation_layout.addWidget(self.nj_segment_btn) files_managment_layout = QHBoxLayout() files_managment_layout.addWidget(self.load_mask_btn) files_managment_layout.addWidget(self.save_mask_btn) layout = QVBoxLayout(self) layout.setAlignment(Qt.AlignTop) layout.addWidget(QLabel('Image slice: ')) layout.addWidget(self.slider) layout.addWidget(QLabel('Mask color: ')) layout.addWidget(self.color_btn) layout.addWidget(self.pen_size) layout.addLayout(drawing_layout) layout.addLayout(segmentation_layout) layout.addLayout(files_managment_layout) def open_color_dialog(self): self.mask_color = QColorDialog.getColor(self.color_btn.color) self.color_btn.color = self.mask_color self.color_btn.update() def get_color(self) -> QColor: return self.mask_color def get_size(self) -> int: return int(self.pen_size.value()) def set_slider_maximum(self, max: int): self.slider.setMaximum(max) @property def tab_name(self): return self.__tab_name__ def __init_slider__(self, max: int = 1) -> QSlider: slider = QSlider() slider.setOrientation(Qt.Horizontal) slider.setMinimum(0) slider.setMaximum(max) slider.setTickInterval(1) slider.setSliderPosition(1) return slider
def testQRealSignal(self): foo1 = QDoubleSpinBox() effect = QGraphicsBlurEffect() effect.blurRadiusChanged['qreal'].connect(foo1.setValue) # check if qreal is a valid type effect.setBlurRadius(0.42) self.assertAlmostEqual(foo1.value(), effect.blurRadius())
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 ToolBar(QToolBar): """Toolbar for VMS. Provides widget to setup frequency range and window width. """ frequencyChanged = Signal(float, float) intervalChanged = Signal(float) def __init__(self): super().__init__() settings = QSettings("LSST.TS", "VMSGUI") self.setObjectName("VMSToolBar") self.addAction(self.style().standardIcon(QStyle.SP_MediaStop), "Stop") self.addWidget(QLabel("Frequency")) self.minFreq = QDoubleSpinBox() self.minFreq.setDecimals(1) self.minFreq.setRange(0, 10000) self.minFreq.setSingleStep(5) self.minFreq.setValue(float(settings.value("minFreq", 0))) self.minFreq.editingFinished.connect(self.minMaxChanged) self.addWidget(self.minFreq) self.addWidget(QLabel("-")) self.maxFreq = QDoubleSpinBox() self.maxFreq.setDecimals(1) self.maxFreq.setRange(0.1, 10000) self.maxFreq.setSingleStep(5) self.maxFreq.setValue(float(settings.value("maxFreq", 200))) self.maxFreq.editingFinished.connect(self.minMaxChanged) self.addWidget(self.maxFreq) self.addWidget(QLabel("Interval:")) self.interval = QDoubleSpinBox() self.interval.setDecimals(3) self.interval.setRange(0.01, 3600) self.interval.setSingleStep(0.1) self.interval.setValue(float(settings.value("interval", 50.0))) self.interval.editingFinished.connect(self.newInterval) self.addWidget(self.interval) self.frequencyChanged.emit(self.minFreq.value(), self.maxFreq.value()) def storeSettings(self): """Store settings through QSettings.""" settings = QSettings("LSST.TS", "VMSGUI") settings.setValue("minFreq", self.minFreq.value()) settings.setValue("maxFreq", self.maxFreq.value()) settings.setValue("interval", self.interval.value()) @Slot() def minMaxChanged(self): self.frequencyChanged.emit(*self.getFrequencyRange()) @Slot() def newInterval(self): self.intervalChanged.emit(self.interval.value()) def getFrequencyRange(self): return (self.minFreq.value(), self.maxFreq.value())
class NifBatchTools(MainWindow): def __init__(self): super().__init__("HTools - NifBatchTools") log.info("Opening NifBatchTools window") self.source_folder = CONFIG.get("DEFAULT", "SourceFolder") self.keywords = list( map(lambda x: x.encode("ascii"), CONFIG.get("NIF", "keywords").replace(" ", "").split(","))) self.nif_files = set( ) # improve performance (better to check in a set rather than in a QListWidget self.ignored_nif_files = set( ) # improve performance (better to check in a set rather than in a QListWidget self.setSize(QSize(700, 600)) self.processed_files = itertools.count() log.info("Source folder : " + self.source_folder) log.info("Keywords : " + str(self.keywords)) self.init_ui() def init_ui(self): main_splitter = QSplitter(self, Qt.Horizontal) left_pane = QWidget(self) left_pane.setMaximumWidth(370) left_v_box = QVBoxLayout(self) left_pane.setLayout(left_v_box) right_pane = QWidget(self) right_v_box = QVBoxLayout(self) right_pane.setLayout(right_v_box) main_splitter.addWidget(left_pane) main_splitter.addWidget(right_pane) # ===== Details ===== self.group_box_details = QuickyGui.create_group_box(self, "Details") nif_files_loaded = QuickyGui.create_label(self, ".nif files loaded") self.lcd_nif_files_loaded = QuickyGui.create_lcd(self) nif_files_ignored = QuickyGui.create_label(self, ".nif files ignored") self.lcd_nif_files_ignored = QuickyGui.create_lcd(self) self.nif_files_list_widget = NifList(self) self.ignored_nif_files_list_widget = NifList(self) self.update_nif_files() self.group_box_legends = QuickyGui.create_group_box(self, "Legends") instructions_4 = QuickyGui.create_label( self, "Green - File correctly processed\n") instructions_4.setStyleSheet( "QLabel { color : darkGreen; font-weight : bold }") instructions_5 = QuickyGui.create_label(self, "Blue - File is processing\n") instructions_5.setStyleSheet( "QLabel { color : darkBlue; font-weight : bold }") instructions_6 = QuickyGui.create_label( self, "Red - File ignored/with errors.") instructions_6.setStyleSheet( "QLabel { color : darkRed; font-weight : bold }") instructions_7 = QuickyGui.create_label( self, "Reasons : " "\n * Check log to see if there is an error concerning this file, or try to open it with NifSkope" "\n * Otherwise it couldn't find a NiTriShape block whose name is specified in provided keywords. It may be normal, if there is no body part. But if there is and you want this file to be processed by the tool, then you must add the corresponding NiTriShape block's name (use nikskope to find it) to the list of keywords, located in the .ini file, situated alongside the executable." " If you have Nikskope, you can open the file by double-clicking on in, in the list view, or from your explorer. Restart the tool to load the new .ini file." ) instructions_7.setStyleSheet("QLabel { color : darkRed}") vbox = QVBoxLayout() vbox.setSpacing(5) vbox.addWidget(instructions_4) vbox.addWidget(instructions_5) vbox.addWidget(instructions_6) vbox.addWidget(instructions_7) self.group_box_legends.setLayout(vbox) vbox = QVBoxLayout(self) hbox = QHBoxLayout(self) hbox.addWidget(nif_files_loaded) hbox.addWidget(self.lcd_nif_files_loaded) vbox.addItem(hbox) vbox.addWidget(self.nif_files_list_widget) hbox = QHBoxLayout(self) hbox.addWidget(nif_files_ignored) hbox.addWidget(self.lcd_nif_files_ignored) vbox.addItem(hbox) vbox.addWidget(self.ignored_nif_files_list_widget) vbox.addWidget(self.group_box_legends) self.group_box_details.setLayout(vbox) right_v_box.addWidget(self.group_box_details) # ===== STEP 0 - Instructions ===== self.group_box_instructions = QuickyGui.create_group_box( self, "Instructions") instructions_1 = QuickyGui.create_label( self, "I. By clicking on \"Scan Folder\", all .nif contained in this folder (subfolders and so on), will be added to the set of files to be processed. You can scan multiple folder, by clicking again. All files not already present will be added." ) instructions_2 = QuickyGui.create_label( self, "II. Once your desired parameters are set, click on \"Apply\". Bewary, the process is quite slow (just opening the file is quite consuming somehow)" ) vbox = QVBoxLayout() vbox.setSpacing(5) vbox.addWidget(instructions_1) vbox.addWidget(instructions_2) self.group_box_instructions.setLayout(vbox) left_v_box.addWidget(self.group_box_instructions) # ===== STEP I - Load Files ===== self.group_box_load_files = QuickyGui.create_group_box( self, "STEP I - Load .nif files") button_load_files = QuickyGui.create_button(self, "Scan Folder", self.action_load_files) button_clear_files = QuickyGui.create_button(self, "Clear loaded files", self.action_clear_files) hbox = QHBoxLayout() hbox.addWidget(button_load_files) hbox.addWidget(button_clear_files) self.group_box_load_files.setLayout(hbox) left_v_box.addWidget(self.group_box_load_files) # ===== STEP II - Set parameters ===== self.group_box_parameters = QuickyGui.create_group_box( self, "STEP II - Set parameters") vbox = QVBoxLayout() # Glossiness label_glossiness = QuickyGui.create_label(self, "Glossiness") self.spin_box_glossiness = QDoubleSpinBox() self.spin_box_glossiness.setMinimum(0) self.spin_box_glossiness.setMaximum(1000) self.spin_box_glossiness.setValue(CONFIG.getfloat("NIF", "Glossiness")) log.info("Glossiness target : " + str(self.spin_box_glossiness.value())) hbox = QHBoxLayout() hbox.addWidget(label_glossiness) hbox.addWidget(self.spin_box_glossiness) vbox.addItem(hbox) # Specular Strength label_specular_strength = QuickyGui.create_label( self, "Specular Strength") self.spin_box_specular_strength = QDoubleSpinBox() self.spin_box_specular_strength.setMinimum(0) self.spin_box_specular_strength.setMaximum(1000) self.spin_box_specular_strength.setValue( CONFIG.getfloat("NIF", "SpecularStrength")) log.info("Specular Strength target : " + str(self.spin_box_specular_strength.value())) hbox = QHBoxLayout() hbox.addWidget(label_specular_strength) hbox.addWidget(self.spin_box_specular_strength) vbox.addItem(hbox) self.group_box_parameters.setLayout(vbox) left_v_box.addWidget(self.group_box_parameters) # ===== STEP III - Apply ===== self.group_box_apply = QuickyGui.create_group_box( self, "STEP III - Apply") button_load_files = QuickyGui.create_button(self, "Apply", self.action_apply) hbox = QHBoxLayout() hbox.addWidget(button_load_files) self.group_box_apply.setLayout(hbox) left_v_box.addWidget(self.group_box_apply) # ===== Finalizing ===== self.progress_bar = QProgressBar(self) left_v_box.addWidget(self.progress_bar) left_v_box.setSpacing(10) self.mainLayout.addWidget(main_splitter) def toggle(self, value): self.group_box_parameters.setEnabled(value) self.group_box_load_files.setEnabled(value) self.group_box_apply.setEnabled(value) def update_nif_files(self, value=0): self.lcd_nif_files_loaded.display(self.nif_files_list_widget.count()) self.lcd_nif_files_ignored.display( self.ignored_nif_files_list_widget.count()) self.nif_files_list_widget.sortItems() self.ignored_nif_files_list_widget.sortItems() def finish_action(self): self.progress_bar.setMinimum(0) self.progress_bar.setMaximum(max(1, self.nif_files_list_widget.count())) self.progress_bar.setValue(self.nif_files_list_widget.count()) self.toggle(True) log.info("Done !") def finish_load_action(self, result): self.finish_action() QMessageBox.information( self, "Results", "Done !\n\n" + str(self.nif_files_list_widget.count()) + " .nif file(s) loaded.\n" + str(result) + " .nif files ignored.") def start_apply_action(self, index): item = self.nif_files_list_widget.item(index) item.setForeground(Qt.blue) def result_apply_action(self, index, result): item = self.nif_files_list_widget.item(index) if result: item.setForeground(Qt.darkGreen) else: item.setForeground(Qt.darkRed) self.progress_bar.setValue(next(self.processed_files) + 1) def finish_apply_action(self): if self.progress_bar.value() == self.nif_files_list_widget.count(): self.finish_action() QMessageBox.information( self, "Results", "Done !\n\n" + str(self.progress_bar.value()) + " .nif file(s) loaded.\n") def action_clear_files(self): log.info("Clearing loaded .nif files ...") self.nif_files_list_widget.clear() self.ignored_nif_files_list_widget.clear() self.nif_files.clear() self.ignored_nif_files.clear() self.update_nif_files() self.progress_bar.reset() def action_load_files(self): log.info("Loading .nif files ...") self.toggle(False) self.progress_bar.setMinimum(0) self.progress_bar.setMaximum(0) file_dialog = QFileDialog() file_dialog.setFileMode(QFileDialog.DirectoryOnly) file_dialog.setDirectory(self.source_folder) if file_dialog.exec_(): scan_dirs = file_dialog.selectedFiles() if len(scan_dirs) >= 1: self.source_folder = scan_dirs[0] else: self.source_folder = file_dialog.directory() if self.source_folder: log.info("Scanning directory : " + self.source_folder) CONFIG.set("DEFAULT", "SourceFolder", self.source_folder), save_config() worker = Worker(self.load_files) worker.signals.progress.connect(self.update_nif_files) worker.signals.result.connect(self.finish_load_action) QThreadPool.globalInstance().start(worker) def load_files(self, progress_callback): """ Traverse folder to find .nif files """ ignored_files = 0 for root, dirs, files in os.walk(self.source_folder): for file in files: path = root + "/" + file if file.endswith( ".nif" ) and path not in self.nif_files and path not in self.ignored_nif_files: stream = open(path, "rb") data = NifFormat.Data() success = False add_to_ignored_list = False try: data.inspect(stream) if "NiNode".encode( 'ascii') == data.header.block_types[0]: if any(keyword in self.keywords for keyword in data.header.strings): success = True else: add_to_ignored_list = True except ValueError: log.exception("[" + file + "] - Too Big to inspect - skipping") except Exception: log.exception("[" + file + "] - Error") finally: if success: self.nif_files.add(path) self.nif_files_list_widget.addItem(path) elif add_to_ignored_list: item = QListWidgetItem( path, self.ignored_nif_files_list_widget) item.setForeground(Qt.darkRed) ignored_files += 1 progress_callback.emit(0) # emit parameter is not used return ignored_files def action_apply(self): """ Apply parameters to relevant .nif files """ if self.nif_files_list_widget.count() == 0: QMessageBox.warning(self, "No .nif files loaded", "Don't forget to load .nif files !") return if self.nif_files_list_widget.count() >= get_config().getint( "DEFAULT", "softLimit"): box = QMessageBox() box.setIcon(QMessageBox.Question) box.setWindowTitle('Are you sure ?') box.setText( "The tool may struggle with more than 100 .nif files at once. We advise you to process small batches.\n\nAre you sure you wish to continue ?" ) box.setStandardButtons(QMessageBox.Yes | QMessageBox.No) buttonY = box.button(QMessageBox.Yes) buttonY.setText('Yes') buttonN = box.button(QMessageBox.No) buttonN.setText('No') box.exec_() if box.clickedButton() == buttonN: return log.info("Applying parameters to " + str(self.nif_files_list_widget.count()) + " files ...") self.toggle(False) self.progress_bar.setValue(0) self.processed_files = itertools.count() CONFIG.set("NIF", "Glossiness", str(self.spin_box_glossiness.value())), CONFIG.set("NIF", "SpecularStrength", str(self.spin_box_specular_strength.value())), save_config() QMessageBox.warning( self, "Attention !", "The process is quite slow.\n\nThe gui will be mostly unresponsive to your input. Don't close the application, unless the completion pourcentage has not been updated in a long time (several minutes).\nIt took me 13 minutes to process 100 files for example." ) #for indices in chunkify(range(self.nif_files_list_widget.count()), QThreadPool.globalInstance().maxThreadCount()-1): QThreadPool.globalInstance().setExpiryTimeout(-1) for index in range(self.nif_files_list_widget.count()): item = self.nif_files_list_widget.item(index) worker = NifProcessWorker( index=index, path=item.text(), keywords=self.keywords, glossiness=self.spin_box_glossiness.value(), specular_strength=self.spin_box_specular_strength.value()) worker.signals.start.connect(self.start_apply_action) worker.signals.result.connect(self.result_apply_action) worker.signals.finished.connect(self.finish_apply_action) QThreadPool.globalInstance().start(worker)
# equation = input('Enter polynomial function:') # equation = '3*x^2-2*x+10' equation = equationinput.toPlainText() print('equation is', equation) # def getvalue(variablename, boxname): # variablename = boxname.value() # return (0) # min = input ("Enter minimum value for x:") # min = float(min) # min = 0 # minbutton.clicked.connect(getvalue(min,mininput)) # minbutton.clicked.connect() min = mininput.value() print("minimum value is", min) # max = input ("Enter maximum value for x:") # max = float(max) # max = 9 max = maxinput.value() print("maximum value is", max) # step = input ("Enter step for function:") # step = float(step) # step = 1 step = stepinput.value() print("step value is", step)
class NNResolverSettingWidget(QDialog): def __init__(self, parent=None, filename=None, group=None): super().__init__(parent=parent, f=Qt.Window) self.setWindowTitle(self.tr("NN Resolver Setting")) if filename is not None: self.setting_file = QSettings(filename, QSettings.Format.IniFormat) if group is not None: self.setting_file.beginGroup(group) else: self.setting_file = None self.setAttribute(Qt.WA_StyledBackground, True) self.initialize_ui() def initialize_ui(self): self.main_layout = QGridLayout(self) self.device_label = QLabel(self.tr("Device")) self.device_label.setToolTip( self. tr("The neural netowrk framwork, pytorch, also can use the GPU of Nvidia to do calculations." )) self.device_combo_box = QComboBox() self.device_combo_box.addItem("cpu") if torch.cuda.is_available(): self.device_combo_box.addItem("cuda") self.main_layout.addWidget(self.device_label, 0, 0) self.main_layout.addWidget(self.device_combo_box, 0, 1) self.distance_label = QLabel(self.tr("Distance (Loss) Function")) self.distance_label.setToolTip( self. tr("It's the function to calculate the difference (on the contrary, similarity) between two samples." )) self.distance_combo_box = QComboBox() self.distance_combo_box.addItems(built_in_distances) # self.distance_combo_box.setCurrentText("log10MSE") self.distance_combo_box.currentTextChanged.connect( self.on_distance_changed) self.main_layout.addWidget(self.distance_label, 1, 0) self.main_layout.addWidget(self.distance_combo_box, 1, 1) self.min_niter_label = QLabel(self.tr("Minimum N<sub>iteration</sub>")) self.min_niter_label.setToolTip( self.tr("Minimum number of iterations to perform")) self.min_niter_input = QSpinBox() self.min_niter_input.setRange(10, 10000) self.min_niter_input.setValue(2000) self.main_layout.addWidget(self.min_niter_label, 2, 0) self.main_layout.addWidget(self.min_niter_input, 2, 1) self.max_niter_label = QLabel(self.tr("Maximum N<sub>iteration</sub>")) self.max_niter_label.setToolTip( self.tr("Maximum number of iterations to perform")) self.max_niter_input = QSpinBox() self.max_niter_input.setRange(100, 100000) self.max_niter_input.setValue(5000) self.main_layout.addWidget(self.max_niter_label, 3, 0) self.main_layout.addWidget(self.max_niter_input, 3, 1) self.tol_label = QLabel(self.tr("-lg(loss<sub>tolerance</sub>)")) self.tol_label.setToolTip( self. tr("Controls the tolerance of the loss function for termination.")) self.tol_input = QSpinBox() self.tol_input.setRange(1, 100) self.tol_input.setValue(10) self.main_layout.addWidget(self.tol_label, 4, 0) self.main_layout.addWidget(self.tol_input, 4, 1) self.ftol_label = QLabel(self.tr("-lg(δ<sub>loss</sub>)")) self.ftol_label.setToolTip( self. tr("Controls the precision goal for the value of loss function in the stopping criterion." )) self.ftol_input = QSpinBox() self.ftol_input.setRange(1, 100) self.ftol_input.setValue(10) self.main_layout.addWidget(self.ftol_label, 5, 0) self.main_layout.addWidget(self.ftol_input, 5, 1) self.lr_label = QLabel(self.tr("Learning Rate (x10<sup>-3</sup>)")) self.lr_label.setToolTip( self. tr("The learning rate of the neural network to update its weights from gradient." )) self.lr_input = QDoubleSpinBox() self.lr_input.setDecimals(3) self.lr_input.setRange(0.001, 1000) self.lr_input.setValue(15) self.main_layout.addWidget(self.lr_label, 6, 0) self.main_layout.addWidget(self.lr_input, 6, 1) self.eps_label = QLabel(self.tr("-lg(δ<sub>eps</sub>)")) self.eps_label.setToolTip( self. tr("Controls the step size used for numerical approximation of the jacobian" )) self.eps_input = QSpinBox() self.eps_input.setRange(1, 100) self.eps_input.setValue(8) self.main_layout.addWidget(self.eps_label, 7, 0) self.main_layout.addWidget(self.eps_input, 7, 1) def on_distance_changed(self, distance: str): if distance == "log10MSE": self.tol_label.setText(self.tr("-loss<sub>tolerance</sub>")) else: self.tol_label.setText(self.tr("-lg(loss<sub>tolerance</sub>)")) @property def setting(self): devices = ["cpu", "cuda"] device = devices[self.device_combo_box.currentIndex()] distance = self.distance_combo_box.currentText() min_niter = self.min_niter_input.value() max_niter = self.max_niter_input.value() # when using Lg(MSE) distance tol = -self.tol_input.value() if distance == "log10MSE" else 10**( -self.tol_input.value()) ftol = 10**(-self.ftol_input.value()) lr = self.lr_input.value() / 1000.0 eps = 10**(-self.eps_input.value()) setting = NNResolverSetting(device=device, distance=distance, min_niter=min_niter, max_niter=max_niter, tol=tol, ftol=ftol, lr=lr, eps=eps) return setting @setting.setter def setting(self, setting: NNResolverSetting): self.device_combo_box.setCurrentText(setting.device) self.distance_combo_box.setCurrentText(setting.distance) self.min_niter_input.setValue(setting.min_niter) self.max_niter_input.setValue(setting.max_niter) if setting.distance == "log10MSE": self.tol_input.setValue(-setting.tol) else: self.tol_input.setValue(-np.log10(setting.tol)) self.ftol_input.setValue(-np.log10(setting.ftol)) self.lr_input.setValue(setting.lr * 1000.0) self.eps_input.setValue(-np.log10(setting.eps)) def save(self): if self.setting_file is not None: setting_bytes = pickle.dumps(self.setting) self.setting_file.setValue("nn_resolver_setting", setting_bytes) def restore(self): if self.setting_file is not None: setting_bytes = self.setting_file.value("nn_resolver_setting", defaultValue=None) if setting_bytes is not None: setting = pickle.loads(setting_bytes) self.setting = setting else: self.setting = NNResolverSetting()
class SliderSpinBox(QWidget): valueChanged = Signal(float) def __init__(self, parent=None, *args, **kwargs): super(SliderSpinBox, self).__init__(parent=parent, *args, **kwargs) self._outerLayout = QHBoxLayout(self) self._outerLayout.setSpacing(0) self._outerLayout.setMargin(0) self._slider = Slider(self) self._slider.setOrientation(Qt.Horizontal) self._spinBox = QDoubleSpinBox(self) self._labelMinValue = QLabel(self) self._labelMaxValue = QLabel(self) self._labelTitle = QLabel(self) self._outerLayout.addWidget(self._labelMinValue) self._outerLayout.addWidget(self._slider) self._outerLayout.addWidget(self._labelMaxValue) self._outerLayout.addWidget(self._spinBox) self._outerLayout.addWidget(self._labelTitle) self.setMinimum(self._slider.minimum()) self.setMaximum(self._slider.maximum()) self._spinBox.setSingleStep(self._slider.getRange()/10.0) self._connect() def _connect(self): self._slider.signalValueChanged.connect(self._on_slider_value_changed) self._spinBox.valueChanged.connect(self._on_spin_box_value_changed) self._spinBox.valueChanged.connect(self.valueChanged) @Slot(float) def _on_slider_value_changed(self, value): if abs(self._spinBox.value() - value) > sys.float_info.epsilon: self._spinBox.setValue(value) @Slot(float) def _on_spin_box_value_changed(self, value): if abs(self._slider.value() - value) > sys.float_info.epsilon: self._slider.setValue(value) def setValue(self, value): self._on_spin_box_value_changed(value) def setMinimum(self, value): self._slider.setMinimum(value) self._spinBox.setMinimum(value) self._labelMinValue.setText(str(value)) self._spinBox.setSingleStep(self._slider.getRange()/10.0) def setMaximum(self, value): self._slider.setMaximum(value) self._spinBox.setMaximum(value) self._labelMaxValue.setText(str(value)) self._spinBox.setSingleStep(self._slider.getRange()/10.0) def setRange(self, values): self.setMinimum(values[0]) self.setMaximum(values[1]) def setTitle(self, value): self._labelTitle.setText(value) def setSliderFactor(self, value): self._slider.setFactor(value)
class GeoWidget(QWidget): coordinate_changed = Signal(name="coordinateChanged") def __init__(self, parent=None): super().__init__(parent) self._coordinate = QGeoCoordinate(0, 0) # The coordinate bounds below only bound England, they can be expanded if more countries are added self._lat_spinbox = QDoubleSpinBox(minimum=49.0, maximum=56.0) self._lng_spinbox = QDoubleSpinBox(minimum=-8, maximum=2) self.map_button = QToolButton(text="Map", clicked=self.handle_clicked_map) self.post_button = QToolButton(text='Postcode', clicked=self.handle_clicked_post) self.map_view = MapDialog(self) lay = QHBoxLayout(self) lay.addWidget(QLabel("Latitude:")) lay.addWidget(self._lat_spinbox) lay.addWidget(QLabel("Longitude:")) lay.addWidget(self._lng_spinbox) lay.addWidget(self.map_button) lay.addWidget(self.post_button) @Property(QGeoCoordinate, notify=coordinate_changed) def coordinate(self): return self._coordinate @coordinate.setter def coordinate(self, coordinate): if self.coordinate == coordinate: return self._coordinate = coordinate self.coordinate_changed.emit() def handle_value_changed(self): coordinate = QGeoCoordinate(self._lat_spinbox.value(), self._lng_spinbox.value()) self.coordinate = coordinate @Slot(QGeoCoordinate) def update_from_map(self, coordinate): self.coordinate = coordinate self._lat_spinbox.setValue(self.coordinate.latitude()) self._lng_spinbox.setValue(self.coordinate.longitude()) def handle_clicked_map(self): self.map_view.exec_() def handle_clicked_post(self): api = pst.Api() valid = False retry = False while not valid: if retry: pcode, ok = QInputDialog.getText( self, 'Postcode', 'Postcode Invalid, please try again') else: pcode, ok = QInputDialog.getText(self, 'Postcode', 'Postcode:') retry = True if not ok: return valid = api.is_postcode_valid(pcode) if valid: data = api.get_postcode(pcode) self.coordinate = QGeoCoordinate(data['result']['latitude'], data['result']['longitude']) self._lat_spinbox.setValue(self.coordinate.latitude()) self._lng_spinbox.setValue(self.coordinate.longitude())
class App(QMainWindow): def __init__(self): super().__init__() self.init_ui() self.attach_event() self.setAcceptDrops(True) def init_ui(self): # Define & Configure Components normal_button_size = QSize(80, 24) icon_button_size = QSize(24, 24) icon_size = QSize(18, 18) self.central_widget = QWidget() self.central_layout = QGridLayout() self.central_widget.setLayout(self.central_layout) self.tab_group_widget = QTabWidget() self.tab_group_widget.setMinimumSize(400, 0) self.tab_group_widget.setFixedHeight(150) self.tab1_name = '스폰서 변환' self.tab2_name = '싱크 조절(초)' self.tab3_name = '싱크 조절(%)' self.tab_page_1 = QWidget() self.tab_grid_1 = QGridLayout() self.tab1_search_label = QLabel('검색 텍스트') self.tab1_search = QLineEdit() self.tab1_sponsor = QWidget() self.tab1_sponsor_layout = QHBoxLayout() self.tab1_sponsor_layout.setContentsMargins(0, 0, 0, 0) self.tab1_sponsor_label = QLabel('스폰서 영상 길이') self.tab1_sponsor_value = QDoubleSpinBox() self.tab1_sponsor_value.setFixedWidth(60) self.tab1_sponsor_value.setMinimum(-1000000000) self.tab1_sponsor_value.setValue(10) self.tab1_offset = QWidget() self.tab1_offset_layout = QHBoxLayout() self.tab1_offset_layout.setContentsMargins(0, 0, 0, 0) self.tab1_offset_label = QLabel('라인 오프셋') self.tab1_offset_value = QSpinBox() self.tab1_offset_value.setMinimum(-1000000000) self.tab1_offset_value.setValue(2) self.tab1_offset_value.setFixedWidth(50) self.tab1_ignore = QWidget() self.tab1_ignore_layout = QHBoxLayout() self.tab1_ignore_layout.setContentsMargins(0, 0, 0, 0) self.tab1_ignore_label1 = QLabel('시작부터') self.tab1_ignore_value = QSpinBox() self.tab1_ignore_value.setFixedWidth(50) self.tab1_ignore_value.setValue(5) self.tab1_ignore_label2 = QLabel('줄 ') self.tab1_ignore_sec = QSpinBox() self.tab1_ignore_sec.setFixedWidth(60) self.tab1_ignore_sec.setMaximum(1000) self.tab1_ignore_sec.setValue(90) self.tab1_ignore_label3 = QLabel('초 무시하기') self.tab1_add_button = QPushButton('추가하기') self.tab_page_2 = QWidget() self.tab_grid_2 = QGridLayout() self.tab2_shift = QWidget() self.tab2_shift_layout = QHBoxLayout() self.tab2_shift_layout.setContentsMargins(0, 0, 0, 0) self.tab2_shift_label1 = QLabel('자막 싱크') self.tab2_shift_value = QDoubleSpinBox() self.tab2_shift_value.setFixedWidth(60) self.tab2_shift_label2 = QLabel('초 ') self.tab2_slow_radio = QRadioButton('느리게') self.tab2_slow_radio.setChecked(True) self.tab2_fast_radio = QRadioButton('빠르게') self.tab2_add_button = QPushButton('추가하기') self.tab_page_3 = QWidget() self.tab_grid_3 = QGridLayout() self.tab3_speed_label1 = QLabel('자막 싱크') self.tab3_speed_value = QSpinBox() self.tab3_speed_value.setFixedWidth(70) self.tab3_speed_value.setRange(1, 1000) self.tab3_speed_value.setValue(100) self.tab3_speed_label2 = QLabel('%') self.tab3_add_button = QPushButton('추가하기') self.que_label = QLabel('작업 목록') self.que_label.setFixedHeight(24) self.que_widget = QWidget() self.que_widget.setFixedHeight(114) self.que_layout = QGridLayout() self.que_layout.setContentsMargins(0, 0, 0, 0) self.que_list = QTreeWidget() self.que_list.setHeaderLabels(['작업', '옵션']) self.que_delete_button = QPushButton(QIcon(':/remove.png'), '') self.que_delete_button.setFixedSize(icon_button_size) self.que_delete_button.setIconSize(icon_size) self.que_delete_button.setToolTip('목록 삭제') self.que_up_button = QPushButton(QIcon(':/up.png'), '') self.que_up_button.setIconSize(icon_size) self.que_up_button.setFixedSize(icon_button_size) self.que_up_button.setToolTip('위로') self.que_down_button = QPushButton(QIcon(':/down.png'), '') self.que_down_button.setIconSize(icon_size) self.que_down_button.setFixedSize(icon_button_size) self.que_down_button.setToolTip('아래로') self.que_clear_button = QPushButton(QIcon(':/clear.png'), '') self.que_clear_button.setIconSize(icon_size) self.que_clear_button.setFixedSize(icon_button_size) self.que_clear_button.setToolTip('비우기') self.file_label = QLabel('파일 목록') self.file_label.setFixedHeight(24) self.file_widget = QWidget() self.file_layout = QGridLayout() self.file_layout.setContentsMargins(0, 0, 0, 0) self.file_list = QTreeWidget() self.file_list.setAcceptDrops(True) self.file_list.setHeaderLabels(['이름', '경로']) self.file_file_open = QPushButton(QIcon(':/file.png'), '') self.file_file_open.setFixedSize(icon_button_size) self.file_file_open.setIconSize(icon_size) self.file_file_open.setToolTip('파일 열기') self.file_dir_open = QPushButton(QIcon(':/folder.png'), '') self.file_dir_open.setFixedSize(icon_button_size) self.file_dir_open.setIconSize(icon_size) self.file_dir_open.setToolTip('폴더 열기') self.file_delete = QPushButton(QIcon(':/remove.png'), '') self.file_delete.setFixedSize(icon_button_size) self.file_delete.setIconSize(icon_size) self.file_delete.setToolTip('목록 삭제') self.file_clear = QPushButton(QIcon(':/clear.png'), '') self.file_clear.setFixedSize(icon_button_size) self.file_clear.setIconSize(icon_size) self.file_clear.setToolTip('비우기') self.file_encode = QPushButton(QIcon(':/encode.png'), '') self.file_encode.setFixedSize(icon_button_size) self.file_encode.setIconSize(icon_size) self.file_encode.setToolTip('인코딩 설정') self.save_widget = QGroupBox('저장 옵션') self.save_widget.setMinimumSize(400, 0) self.save_widget.setFixedHeight(82) self.save_layout = QGridLayout() self.save_orig_radio = QRadioButton('원본 위치에 저장') self.save_orig_radio.setChecked(True) self.save_strip = QCheckBox('싱크 꼬임 무시') self.save_strip.setToolTip('싱크 꼬임을 무시하고 모든 자막을 보존합니다.') self.save_dir_radio = QRadioButton('다른 위치에 저장') self.save_dir_line = QLineEdit() self.save_dir_find = QPushButton('...') self.save_dir_find.setFixedWidth(40) self.ok_button = QPushButton('적용') self.ok_button.setFixedSize(normal_button_size) self.cancel_button = QPushButton('취소') self.cancel_button.setFixedSize(normal_button_size) # Display GUI Components self.central_layout.addWidget(self.tab_group_widget, 0, 0, 1, 3) self.central_layout.addWidget(self.que_label, 1, 0, 1, 3) self.central_layout.addWidget(self.que_widget, 2, 0, 1, 3) self.central_layout.addWidget(self.file_label, 3, 0, 1, 3) self.central_layout.addWidget(self.file_widget, 4, 0, 1, 3) self.central_layout.addWidget(self.save_widget, 5, 0, 1, 3) self.central_layout.addWidget(self.ok_button, 6, 1, 1, 1) self.central_layout.addWidget(self.cancel_button, 6, 2, 1, 1) self.tab_group_widget.addTab(self.tab_page_1, QIcon(), self.tab1_name) self.tab_group_widget.addTab(self.tab_page_2, QIcon(), self.tab2_name) self.tab_group_widget.addTab(self.tab_page_3, QIcon(), self.tab3_name) self.tab_page_1.setLayout(self.tab_grid_1) self.tab_grid_1.addWidget(self.tab1_search_label, 0, 0, 1, 1) self.tab_grid_1.addWidget(self.tab1_search, 0, 1, 1, 2) self.tab_grid_1.addWidget(self.tab1_sponsor, 1, 1, 1, 1) self.tab_grid_1.addWidget(self.tab1_offset, 1, 2, 1, 1) self.tab_grid_1.addWidget(self.tab1_ignore, 2, 1, 1, 2) self.tab_grid_1.addWidget(self.tab1_add_button, 3, 0, 1, 3) self.tab1_sponsor.setLayout(self.tab1_sponsor_layout) self.tab1_sponsor_layout.addWidget(self.tab1_sponsor_label) self.tab1_sponsor_layout.addWidget(self.tab1_sponsor_value) self.tab1_sponsor_layout.addStretch(1) self.tab1_offset.setLayout(self.tab1_offset_layout) self.tab1_offset_layout.addWidget(self.tab1_offset_label) self.tab1_offset_layout.addWidget(self.tab1_offset_value) self.tab1_offset_layout.addStretch(1) self.tab1_ignore.setLayout(self.tab1_ignore_layout) self.tab1_ignore_layout.addWidget(self.tab1_ignore_label1) self.tab1_ignore_layout.addWidget(self.tab1_ignore_value) self.tab1_ignore_layout.addWidget(self.tab1_ignore_label2) self.tab1_ignore_layout.addWidget(self.tab1_ignore_sec) self.tab1_ignore_layout.addWidget(self.tab1_ignore_label3) self.tab1_ignore_layout.addStretch(1) self.tab_page_2.setLayout(self.tab_grid_2) self.tab_grid_2.setRowStretch(0, 1) self.tab_grid_2.addWidget(self.tab2_shift, 1, 0, 2, 1) self.tab_grid_2.addWidget(self.tab2_slow_radio, 1, 1, 1, 1) self.tab_grid_2.addWidget(self.tab2_fast_radio, 2, 1, 1, 1) self.tab_grid_2.setColumnStretch(2, 1) self.tab_grid_2.setRowStretch(3, 1) self.tab_grid_2.addWidget(self.tab2_add_button, 4, 0, 1, 3) self.tab2_shift.setLayout(self.tab2_shift_layout) self.tab2_shift_layout.addWidget(self.tab2_shift_label1) self.tab2_shift_layout.addWidget(self.tab2_shift_value) self.tab2_shift_layout.addWidget(self.tab2_shift_label2) self.tab_page_3.setLayout(self.tab_grid_3) self.tab_grid_3.setRowStretch(0, 1) self.tab_grid_3.addWidget(self.tab3_speed_label1, 1, 0, 1, 1) self.tab_grid_3.addWidget(self.tab3_speed_value, 1, 1, 1, 1) self.tab_grid_3.addWidget(self.tab3_speed_label2, 1, 2, 1, 1) self.tab_grid_3.setColumnStretch(3, 1) self.tab_grid_3.setRowStretch(2, 1) self.tab_grid_3.addWidget(self.tab3_add_button, 3, 0, 1, 4) self.que_widget.setLayout(self.que_layout) self.que_layout.addWidget(self.que_list, 0, 0, 4, 1) self.que_layout.addWidget(self.que_delete_button, 0, 1, 1, 1) self.que_layout.addWidget(self.que_up_button, 1, 1, 1, 1) self.que_layout.addWidget(self.que_down_button, 2, 1, 1, 1) self.que_layout.addWidget(self.que_clear_button, 3, 1, 1, 1) self.file_widget.setLayout(self.file_layout) self.file_layout.addWidget(self.file_list, 0, 0, 6, 1) self.file_layout.addWidget(self.file_file_open, 0, 1, 1, 1) self.file_layout.addWidget(self.file_dir_open, 1, 1, 1, 1) self.file_layout.addWidget(self.file_delete, 2, 1, 1, 1) self.file_layout.addWidget(self.file_clear, 3, 1, 1, 1) self.file_layout.addWidget(self.file_encode, 5, 1, 1, 1) self.save_widget.setLayout(self.save_layout) self.save_layout.addWidget(self.save_orig_radio, 0, 0, 1, 1) self.save_layout.setColumnStretch(1, 1) self.save_layout.addWidget(self.save_strip, 0, 2, 1, 2) self.save_layout.addWidget(self.save_dir_radio, 1, 0, 1, 1) self.save_layout.addWidget(self.save_dir_line, 1, 1, 1, 2) self.save_layout.addWidget(self.save_dir_find, 1, 3, 1, 1) self.setWindowTitle('Batch SAMI Sync v0.2') self.setCentralWidget(self.central_widget) self.adjustSize() def attach_event(self): # Default encoding hack self.encoding = '자동' # Define and Connect event handlers def tab1_add(): sponsor_text = self.tab1_search.text() sponsor_time = self.tab1_sponsor_value.value() line_offset = self.tab1_offset_value.value() line_ignore = self.tab1_ignore_value.value() time_ignore = self.tab1_ignore_sec.value() data = [1, sponsor_time, sponsor_text, line_offset, line_ignore, time_ignore] item = QTreeWidgetItem(self.que_list, [self.tab1_name, '스폰서 영상 시간 : ' + str(sponsor_time) + '초, 오프셋 : ' + str(line_offset) + '줄, 시작부터 ' + str(line_ignore) + '번째 줄, ' + str(time_ignore) + '초 무시 - 검색어 : ' + sponsor_text]) item.setData(2, 2, data) def tab2_add(): shift_time = self.tab2_shift_value.value() shift_direction = self.tab2_fast_radio.isChecked() direction_text = '빠르게' if shift_direction else '느리게' data = [2, shift_time, shift_direction] item = QTreeWidgetItem(self.que_list, [self.tab2_name, '자막 싱크 ' + str(shift_time) + '초 ' + direction_text]) item.setData(2, 2, data) def tab3_add(): speed_rate = self.tab3_speed_value.value() data = [3, speed_rate] item = QTreeWidgetItem(self.que_list, [self.tab3_name, '자막 속도 ' + str(speed_rate) + '%']) item.setData(2, 2, data) def file_open(): selected = QFileDialog.getOpenFileNames(self, "자막 파일 선택", "", "SAMI Files (*.smi);;All Files (*)") for file in selected[0]: name = ntpath.basename(file) Utils.insert_list(self.file_list, name, file) def dir_open(): selected = QFileDialog.getExistingDirectory(self, "자막 폴더 선택") for paths, subdirs, files in os.walk(selected): for file in files: if fnmatch(file, '*.smi'): name = ntpath.basename(file) Utils.insert_list(self.file_list, name, file) def open_encode_dialog(): self.dialog = QInputDialog(self) self.dialog.setWindowTitle('인코딩 설정') self.dialog.setLabelText('텍스트 인코딩 설정') self.dialog.setComboBoxItems(['자동', 'EUC-KR', 'UTF-8', 'UTF-16LE', 'UTF-16BE', '직접 입력']) self.dialog.show() self.dialog.textValueChanged.connect(type_encode) self.dialog.textValueSelected.connect(set_encode) def type_encode(text): if text == '직접 입력': self.dialog.setComboBoxItems([]) self.dialog.setComboBoxEditable(True) def set_encode(text): self.encoding = text def save_dir(): selected = QFileDialog.getExistingDirectory(self, "저장 위치 선택") self.save_dir_line.setText(selected) def apply(): self.ok_button.setEnabled(False) ques = Utils.read_list(self.que_list, False) files = Utils.read_list(self.file_list, False) strip = False if self.save_strip.isChecked() else True log = [] for file in files: try: text = Utils.launch_que(file[1], ques, self.encoding, strip) if len(text): if self.save_orig_radio.isChecked(): savepath = file[1] else: savepath = self.save_dir_line.text() + '/' + file[0] Utils.save_file(savepath, text) except Exception as e: log.append(file[0] + ' 처리 오류 : ' + str(e)) if log: ScrollMessageBox(QMessageBox.Warning, 'Batch SAMI Sync', "\n".join(log)) else: QMessageBox.information(self, 'Batch SAMI Sync', '변환 완료!') self.ok_button.setEnabled(True) self.tab1_add_button.clicked.connect(tab1_add) self.tab2_add_button.clicked.connect(tab2_add) self.tab3_add_button.clicked.connect(tab3_add) self.que_delete_button.clicked.connect(lambda: Utils.delete_list(self.que_list)) self.que_clear_button.clicked.connect(lambda: Utils.clear_list(self.que_list)) self.que_up_button.clicked.connect(lambda: Utils.up_list(self.que_list)) self.que_down_button.clicked.connect(lambda: Utils.down_list(self.que_list)) self.file_file_open.clicked.connect(file_open) self.file_dir_open.clicked.connect(dir_open) self.file_delete.clicked.connect(lambda: Utils.delete_list(self.file_list)) self.file_clear.clicked.connect(lambda: Utils.clear_list(self.file_list)) self.file_encode.clicked.connect(open_encode_dialog) self.save_dir_find.clicked.connect(save_dir) self.ok_button.clicked.connect(apply) self.cancel_button.clicked.connect(sys.exit) def dragEnterEvent(self, event): if event.mimeData().hasUrls: event.accept() else: event.ignore() def dragMoveEvent(self, event): if event.mimeData().hasUrls(): event.setDropAction(Qt.CopyAction) event.accept() else: event.ignore() def dropEvent(self, event): if event.mimeData().hasUrls(): event.setDropAction(Qt.CopyAction) event.accept() for url in event.mimeData().urls(): if url.isLocalFile(): file = str(url.toLocalFile()) if fnmatch(file, '*.smi'): name = ntpath.basename(file) Utils.insert_list(self.file_list, name, file) elif not fnmatch(file, '*.*'): for paths, subdirs, files in os.walk(file): for file in files: if fnmatch(file, '*.smi'): name = ntpath.basename(file) Utils.insert_list(self.file_list, name, file) else: event.ignore()
class RandomDatasetGenerator(QDialog): logger = logging.getLogger("root.ui.RandomGeneratorWidget") gui_logger = logging.getLogger("GUI") def __init__(self, parent=None): super().__init__(parent=parent, f=Qt.Window) self.setWindowTitle(self.tr("Dataset Generator")) self.last_n_components = 0 self.components = [] # typing.List[RandomGeneratorComponentWidget] self.component_series = [] self.init_ui() self.target = LOESS self.minimum_size_input.setValue(0.02) self.maximum_size_input.setValue(2000.0) self.n_classes_input.setValue(101) self.precision_input.setValue(4) self.file_dialog = QFileDialog(parent=self) self.update_timer = QTimer() self.update_timer.timeout.connect(lambda: self.update_chart(True)) self.cancel_flag = False def init_ui(self): self.setAttribute(Qt.WA_StyledBackground, True) self.main_layout = QGridLayout(self) # self.main_layout.setContentsMargins(0, 0, 0, 0) self.sampling_group = QGroupBox(self.tr("Sampling")) # self.control_group.setFixedSize(400, 160) self.control_layout = QGridLayout(self.sampling_group) self.minimum_size_label = QLabel(self.tr("Minimum Size [μm]")) self.minimum_size_input = QDoubleSpinBox() self.minimum_size_input.setDecimals(2) self.minimum_size_input.setRange(1e-4, 1e6) self.minimum_size_input.setValue(0.0200) self.maximum_size_label = QLabel(self.tr("Maximum Size [μm]")) self.maximum_size_input = QDoubleSpinBox() self.maximum_size_input.setDecimals(2) self.maximum_size_input.setRange(1e-4, 1e6) self.maximum_size_input.setValue(2000.0000) self.control_layout.addWidget(self.minimum_size_label, 0, 0) self.control_layout.addWidget(self.minimum_size_input, 0, 1) self.control_layout.addWidget(self.maximum_size_label, 0, 2) self.control_layout.addWidget(self.maximum_size_input, 0, 3) self.n_classes_label = QLabel(self.tr("N<sub>classes</sub>")) self.n_classes_input = QSpinBox() self.n_classes_input.setRange(10, 1e4) self.n_classes_input.setValue(101) self.precision_label = QLabel(self.tr("Data Precision")) self.precision_input = QSpinBox() self.precision_input.setRange(2, 8) self.precision_input.setValue(4) self.control_layout.addWidget(self.n_classes_label, 1, 0) self.control_layout.addWidget(self.n_classes_input, 1, 1) self.control_layout.addWidget(self.precision_label, 1, 2) self.control_layout.addWidget(self.precision_input, 1, 3) self.component_number_label = QLabel(self.tr("N<sub>components</sub>")) self.component_number_input = QSpinBox() self.component_number_input.setRange(1, 10) self.component_number_input.valueChanged.connect( self.on_n_components_changed) self.preview_button = QPushButton(qta.icon("mdi.animation-play"), self.tr("Preview")) self.preview_button.clicked.connect(self.on_preview_clicked) self.control_layout.addWidget(self.component_number_label, 2, 0) self.control_layout.addWidget(self.component_number_input, 2, 1) self.control_layout.addWidget(self.preview_button, 2, 2, 1, 2) self.main_layout.addWidget(self.sampling_group, 0, 0) self.save_group = QGroupBox(self.tr("Save")) # self.save_group.setFixedHeight(160) self.save_layout = QGridLayout(self.save_group) self.n_samples_label = QLabel(self.tr("N<sub>samples</sub>")) self.n_samples_input = QSpinBox() self.n_samples_input.setRange(100, 100000) self.save_layout.addWidget(self.n_samples_label, 0, 0) self.save_layout.addWidget(self.n_samples_input, 0, 1) self.cancel_button = QPushButton(qta.icon("mdi.cancel"), self.tr("Cancel")) self.cancel_button.setEnabled(False) self.cancel_button.clicked.connect(self.on_cancel_clicked) self.generate_button = QPushButton(qta.icon("mdi.cube-send"), self.tr("Generate")) self.generate_button.clicked.connect(self.on_generate_clicked) self.progress_bar = QProgressBar() self.progress_bar.setRange(0, 100) self.progress_bar.setOrientation(Qt.Horizontal) self.progress_bar.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) self.save_layout.addWidget(self.cancel_button, 1, 0) self.save_layout.addWidget(self.generate_button, 1, 1) self.save_layout.addWidget(self.progress_bar, 2, 0, 1, 2) self.main_layout.addWidget(self.save_group, 0, 1) self.param_group = QGroupBox("Random Parameter") # self.param_group.setFixedWidth(400) self.param_layout = QGridLayout(self.param_group) self.main_layout.addWidget(self.param_group, 1, 0) self.preview_group = QGroupBox(self.tr("Preview")) self.chart_layout = QGridLayout(self.preview_group) self.chart = MixedDistributionChart(parent=self, toolbar=False) self.chart_layout.addWidget(self.chart, 0, 0) self.chart.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.main_layout.addWidget(self.preview_group, 1, 1) @staticmethod def to_points(x, y): return [QPointF(x_value, y_value) for x_value, y_value in zip(x, y)] def on_n_components_changed(self, n_components: int): if self.last_n_components < n_components: for component_index in range(self.last_n_components, n_components): component = RandomGeneratorComponentWidget( name=f"AC{component_index+1}") component.value_changed.connect(self.on_value_changed) self.param_layout.addWidget(component, component_index + 1, 0) self.components.append(component) if self.last_n_components > n_components: for i in range(n_components, self.last_n_components): before_component = self.components[i] before_component.value_changed.disconnect( self.on_value_changed) self.param_layout.removeWidget(before_component) # if not hide, the widget will still display on screen before_component.hide() self.components.pop(n_components) self.last_n_components = n_components def on_preview_clicked(self): if self.update_timer.isActive(): self.preview_button.setText(self.tr("Preview")) self.update_timer.stop() self.update_chart() else: self.preview_button.setText(self.tr("Stop")) self.update_timer.start(200) def on_cancel_clicked(self): self.cancel_flag = True def on_generate_clicked(self): if self.update_timer.isActive(): self.preview_button.setText(self.tr("Preview")) self.update_timer.stop() self.update_chart() filename, _ = self.file_dialog.getSaveFileName( self, self.tr("Choose a filename to save the generated dataset"), None, "Microsoft Excel (*.xlsx)") if filename is None or filename == "": return n_samples = self.n_samples_input.value() dataset = self.get_random_dataset(n_samples) # generate samples self.cancel_button.setEnabled(True) self.generate_button.setEnabled(False) format_str = self.tr("Generating {0} samples: %p%").format(n_samples) self.progress_bar.setFormat(format_str) self.progress_bar.setValue(0) def cancel(): self.progress_bar.setFormat(self.tr("Task canceled")) self.progress_bar.setValue(0) self.cancel_button.setEnabled(False) self.generate_button.setEnabled(True) self.cancel_flag = False samples = [] for i in range(n_samples): if self.cancel_flag: cancel() return sample = dataset.get_sample(i) samples.append(sample) progress = (i + 1) / n_samples * 50 self.progress_bar.setValue(progress) QCoreApplication.processEvents() # save file to excel file format_str = self.tr("Writing {0} samples to excel file: %p%").format( n_samples) self.progress_bar.setFormat(format_str) self.progress_bar.setValue(50) wb = openpyxl.Workbook() prepare_styles(wb) ws = wb.active ws.title = self.tr("README") description = \ """ This Excel file was generated by QGrain ({0}). Please cite: Liu, Y., Liu, X., Sun, Y., 2021. QGrain: An open-source and easy-to-use software for the comprehensive analysis of grain size distributions. Sedimentary Geology 423, 105980. https://doi.org/10.1016/j.sedgeo.2021.105980 It contanins n_components + 3 sheets: 1. The first sheet is the random settings which were used to generate random parameters. 2. The second sheet is the generated dataset. 3. The third sheet is random parameters which were used to calulate the component distributions and their mixture. 4. The left sheets are the component distributions of all samples. Artificial dataset Using skew normal distribution as the base distribution of each component (i.e. end-member). Skew normal distribution has three parameters, shape, location and scale. Where shape controls the skewness, location and scale are simliar to that of the Normal distribution. When shape = 0, it becomes Normal distribution. The weight parameter controls the fraction of the component, where fraction_i = weight_i / sum(weight_i). By assigning the mean and std of each parameter, random parameters was generate by the `scipy.stats.truncnorm.rvs` function of Scipy. Sampling settings Minimum size [μm]: {1}, Maximum size [μm]: {2}, N_classes: {3}, Precision: {4}, Noise: {5}, N_samples: {6} """.format(QGRAIN_VERSION, self.minimum_size_input.value(), self.maximum_size_input.value(), self.n_classes_input.value(), self.precision_input.value(), self.precision_input.value()+1, n_samples) def write(row, col, value, style="normal_light"): cell = ws.cell(row + 1, col + 1, value=value) cell.style = style lines_of_desc = description.split("\n") for row, line in enumerate(lines_of_desc): write(row, 0, line, style="description") ws.column_dimensions[column_to_char(0)].width = 200 ws = wb.create_sheet(self.tr("Random Settings")) write(0, 0, self.tr("Parameter"), style="header") ws.merge_cells(start_row=1, start_column=1, end_row=2, end_column=1) write(0, 1, self.tr("Shape"), style="header") ws.merge_cells(start_row=1, start_column=2, end_row=1, end_column=3) write(0, 3, self.tr("Location"), style="header") ws.merge_cells(start_row=1, start_column=4, end_row=1, end_column=5) write(0, 5, self.tr("Scale"), style="header") ws.merge_cells(start_row=1, start_column=6, end_row=1, end_column=7) write(0, 7, self.tr("Weight"), style="header") ws.merge_cells(start_row=1, start_column=8, end_row=1, end_column=9) ws.column_dimensions[column_to_char(0)].width = 16 for col in range(1, 9): ws.column_dimensions[column_to_char(col)].width = 16 if col % 2 == 0: write(1, col, self.tr("Mean"), style="header") else: write(1, col, self.tr("STD"), style="header") for row, comp_params in enumerate(self.target, 2): if row % 2 == 1: style = "normal_dark" else: style = "normal_light" write(row, 0, self.tr("Component{0}").format(row - 1), style=style) for i, key in enumerate(["shape", "loc", "scale", "weight"]): mean, std = comp_params[key] write(row, i * 2 + 1, mean, style=style) write(row, i * 2 + 2, std, style=style) ws = wb.create_sheet(self.tr("Dataset")) write(0, 0, self.tr("Sample Name"), style="header") ws.column_dimensions[column_to_char(0)].width = 24 for col, value in enumerate(dataset.classes_μm, 1): write(0, col, value, style="header") ws.column_dimensions[column_to_char(col)].width = 10 for row, sample in enumerate(samples, 1): if row % 2 == 0: style = "normal_dark" else: style = "normal_light" write(row, 0, sample.name, style=style) for col, value in enumerate(sample.distribution, 1): write(row, col, value, style=style) if self.cancel_flag: cancel() return progress = 50 + (row / n_samples) * 10 self.progress_bar.setValue(progress) QCoreApplication.processEvents() ws = wb.create_sheet(self.tr("Parameters")) write(0, 0, self.tr("Sample Name"), style="header") ws.merge_cells(start_row=1, start_column=1, end_row=2, end_column=1) ws.column_dimensions[column_to_char(0)].width = 24 for i in range(dataset.n_components): write(0, 4 * i + 1, self.tr("Component{0}").format(i + 1), style="header") ws.merge_cells(start_row=1, start_column=4 * i + 2, end_row=1, end_column=4 * i + 5) for j, header_name in enumerate([ self.tr("Shape"), self.tr("Location"), self.tr("Scale"), self.tr("Weight") ]): write(1, 4 * i + 1 + j, header_name, style="header") ws.column_dimensions[column_to_char(4 * i + 1 + j)].width = 16 for row, sample in enumerate(samples, 2): if row % 2 == 1: style = "normal_dark" else: style = "normal_light" write(row, 0, sample.name, style=style) for i, comp_param in enumerate(sample.parameter.components): write(row, 4 * i + 1, comp_param.shape, style=style) write(row, 4 * i + 2, comp_param.loc, style=style) write(row, 4 * i + 3, comp_param.scale, style=style) write(row, 4 * i + 4, comp_param.weight, style=style) if self.cancel_flag: cancel() return progress = 60 + (row / n_samples) * 10 self.progress_bar.setValue(progress) QCoreApplication.processEvents() for i in range(dataset.n_components): ws = wb.create_sheet(self.tr("Component{0}").format(i + 1)) write(0, 0, self.tr("Sample Name"), style="header") ws.column_dimensions[column_to_char(0)].width = 24 for col, value in enumerate(dataset.classes_μm, 1): write(0, col, value, style="header") ws.column_dimensions[column_to_char(col)].width = 10 for row, sample in enumerate(samples, 1): if row % 2 == 0: style = "normal_dark" else: style = "normal_light" write(row, 0, sample.name, style=style) for col, value in enumerate(sample.components[i].distribution, 1): write(row, col, value, style=style) if self.cancel_flag: cancel() return progress = 70 + ( (i * n_samples + row) / n_samples * dataset.n_components) * 30 self.progress_bar.setValue(progress) QCoreApplication.processEvents() wb.save(filename) wb.close() self.progress_bar.setValue(100) self.progress_bar.setFormat(self.tr("Task finished")) self.cancel_button.setEnabled(False) self.generate_button.setEnabled(True) @property def target(self): return [comp.target for comp in self.components] @target.setter def target(self, values): if len(values) != len(self.components): self.component_number_input.setValue(len(values)) for comp, comp_target in zip(self.components, values): comp.blockSignals(True) comp.target = comp_target comp.blockSignals(False) self.update_chart() def get_random_sample(self): dataset = self.get_random_dataset(n_samples=1) sample = dataset.get_sample(0) sample.name = self.tr("Artificial Sample") return sample def get_random_mean(self): dataset = self.get_random_dataset(n_samples=1) random_setting = RandomSetting(self.target) sample = dataset.get_sample_by_params(self.tr("Artificial Sample"), random_setting.mean_param) return sample def get_random_dataset(self, n_samples): min_μm = self.minimum_size_input.value() max_μm = self.maximum_size_input.value() n_classes = self.n_classes_input.value() if min_μm == max_μm: return if min_μm > max_μm: min_μm, max_μm = max_μm, min_μm precision = self.precision_input.value() noise = precision + 1 dataset = get_random_dataset(target=self.target, n_samples=n_samples, min_μm=min_μm, max_μm=max_μm, n_classes=n_classes, precision=precision, noise=noise) return dataset def on_value_changed(self): self.update_chart() def update_chart(self, random=False): if not random: sample = self.get_random_mean() else: sample = self.get_random_sample() self.chart.show_model(sample.view_model) def closeEvent(self, event): if self.cancel_button.isEnabled(): self.on_cancel_clicked() event.accept()
class LissajousInterface(QWidget): def __init__(self, lissCurve): QWidget.__init__(self) self.lissCurve = lissCurve # set amplitudes self.aAmpLabel = QLabel("A:") self.aAmpLabel.setFixedWidth(20) self.aAmplitude_spinBox = QDoubleSpinBox() self.configureAmpSpinBox(self.aAmplitude_spinBox) self.aAmplitude_spinBox.valueChanged.connect(self.valueChanged) self.bAmpLabel = QLabel("B:") self.bAmpLabel.setFixedWidth(20) self.bAmplitude_spinBox = QDoubleSpinBox() self.configureAmpSpinBox(self.bAmplitude_spinBox) self.bAmplitude_spinBox.valueChanged.connect(self.valueChanged) # set omegas self.aOmegaLabel = QLabel("ɷA:") self.aOmegaLabel.setFixedWidth(30) self.aOmega_spinBox = QSpinBox() self.configureOmegaSpinBox(self.aOmega_spinBox) self.aOmega_spinBox.valueChanged.connect(self.valueChanged) self.bOmegaLabel = QLabel("ɷB:") self.bOmegaLabel.setFixedWidth(30) self.bOmega_spinBox = QSpinBox() self.configureOmegaSpinBox(self.bOmega_spinBox) self.bOmega_spinBox.valueChanged.connect(self.valueChanged) self.phiLabel = QLabel("φ") self.phiLabel.setFixedWidth(20) self.phi_spinBox = QDoubleSpinBox() self.configurePhaseSpinBox(self.phi_spinBox) self.phi_spinBox.valueChanged.connect(self.valueChanged) self.configureLayout() @Slot() def valueChanged(self): self.lissCurve.setVariables(self.aAmplitude_spinBox.value(), self.bAmplitude_spinBox.value(), self.aOmega_spinBox.value(), self.bOmega_spinBox.value(), self.phi_spinBox.value()) def configureAmpSpinBox(self, amp): amp.setRange(0, 10) amp.setWrapping(False) amp.setValue(5) amp.setSingleStep(0.01) def configureOmegaSpinBox(self, ome): ome.setRange(-10, 10) ome.setWrapping(False) ome.setValue(5) def configurePhaseSpinBox(self, phi): phi.setRange(-10, 10) phi.setWrapping(False) phi.setValue(5) phi.setSingleStep(0.01) def configureLayout(self): self.interfaceLayout = QHBoxLayout() # set amplitude layout self.aAmpWithLayout = QHBoxLayout() self.aAmpWithLayout.addWidget(self.aAmpLabel) self.aAmpWithLayout.addWidget(self.aAmplitude_spinBox) self.bAmpWithLayout = QHBoxLayout() self.bAmpWithLayout.addWidget(self.bAmpLabel) self.bAmpWithLayout.addWidget(self.bAmplitude_spinBox) self.amplitudeLayout = QVBoxLayout() self.amplitudeLayout.addLayout(self.aAmpWithLayout) self.amplitudeLayout.addLayout(self.bAmpWithLayout) # set omega layout self.aOmegaWithLayout = QHBoxLayout() self.aOmegaWithLayout.addWidget(self.aOmegaLabel) self.aOmegaWithLayout.addWidget(self.aOmega_spinBox) self.bOmegaWithLayout = QHBoxLayout() self.bOmegaWithLayout.addWidget(self.bOmegaLabel) self.bOmegaWithLayout.addWidget(self.bOmega_spinBox) self.omegaLayout = QVBoxLayout() self.omegaLayout.addLayout(self.aOmegaWithLayout) self.omegaLayout.addLayout(self.bOmegaWithLayout) # set omega layout self.phiLayout = QHBoxLayout() self.phiLayout.addWidget(self.phiLabel) self.phiLayout.addWidget(self.phi_spinBox) # set general interface layout self.interfaceLayout.addLayout(self.amplitudeLayout) self.interfaceLayout.addLayout(self.omegaLayout) self.interfaceLayout.addLayout(self.phiLayout) self.setLayout(self.interfaceLayout)
class MedianWidget(ToolWidget): def __init__(self, image, parent=None): super(MedianWidget, self).__init__(parent) self.variance_spin = QSpinBox() self.variance_spin.setRange(0, 50) self.variance_spin.setValue(10) self.threshold_spin = QDoubleSpinBox() self.threshold_spin.setRange(0, 1) self.threshold_spin.setValue(0.45) self.threshold_spin.setSingleStep(0.01) self.showprob_check = QCheckBox(self.tr('Probability map')) self.filter_check = QCheckBox(self.tr('Speckle filter')) self.filter_check.setChecked(True) self.process_button = QPushButton(self.tr('Process')) self.avgprob_label = QLabel(self.tr('Press "Process" to start')) top_layout = QHBoxLayout() top_layout.addWidget(QLabel(self.tr('Min variance:'))) top_layout.addWidget(self.variance_spin) top_layout.addWidget(QLabel(self.tr('Threshold:'))) top_layout.addWidget(self.threshold_spin) top_layout.addWidget(self.showprob_check) top_layout.addWidget(self.filter_check) top_layout.addWidget(self.process_button) # top_layout.addWidget(self.avgprob_label) top_layout.addStretch() self.image = image self.viewer = ImageViewer(self.image, self.image) self.gray = cv.cvtColor(self.image, cv.COLOR_BGR2GRAY) self.prob = self.var = None self.block = 64 self.canceled = False self.process_button.clicked.connect(self.prepare) self.variance_spin.valueChanged.connect(self.process) self.threshold_spin.valueChanged.connect(self.process) self.showprob_check.stateChanged.connect(self.process) self.filter_check.stateChanged.connect(self.process) main_layout = QVBoxLayout() main_layout.addLayout(top_layout) main_layout.addWidget(self.viewer) self.setLayout(main_layout) def prepare(self): modelfile = 'models/median_b{}.mdl'.format(self.block) try: model = load(modelfile) except FileNotFoundError: QMessageBox.critical( self, self.tr('Error'), self.tr('Model not found ("{}")!'.format(modelfile))) return limit = model.best_ntree_limit if hasattr(model, 'best_ntree_limit') else None columns = model._features_count if columns == 8: levels = 1 windows = 1 elif columns == 24: levels = 3 windows = 1 elif columns == 96: levels = 3 windows = 4 elif columns == 128: levels = 4 windows = 4 else: QMessageBox.critical(self, self.tr('Error'), self.tr('Unknown model format!')) return padded = pad_image(self.gray, self.block) rows, cols = padded.shape self.prob = np.zeros( ((rows // self.block) + 1, (cols // self.block) + 1)) self.var = np.zeros_like(self.prob) progress = QProgressDialog(self.tr('Detecting median filter...'), self.tr('Cancel'), 0, self.prob.size, self) progress.canceled.connect(self.cancel) progress.setWindowModality(Qt.WindowModal) k = 0 self.canceled = False for i in range(0, rows, self.block): for j in range(0, cols, self.block): roi = padded[i:i + self.block, j:j + self.block] x = np.reshape(get_features(roi, levels, windows), (1, columns)) y = model.predict_proba(x, ntree_limit=limit)[0, 1] ib = i // self.block jb = j // self.block self.var[ib, jb] = np.var(roi) self.prob[ib, jb] = y if self.canceled: self.prob = self.var = None progress.close() return progress.setValue(k) k += 1 progress.close() self.process() def cancel(self): self.canceled = True def process(self): if self.prob is None: return mask = self.var < self.variance_spin.value() if self.filter_check.isChecked(): prob = cv.medianBlur(self.prob.astype(np.float32), 3) else: prob = self.prob.astype(np.float32) if self.showprob_check.isChecked(): output = np.repeat(prob[:, :, np.newaxis], 3, axis=2) output[mask] = 0 else: thr = self.threshold_spin.value() output = np.zeros((prob.shape[0], prob.shape[1], 3)) blue, green, red = cv.split(output) blue[mask] = 1 green[prob < thr] = 1 green[mask] = 0 red[prob >= thr] = 1 red[mask] = 0 output = cv.merge((blue, green, red)) output = cv.convertScaleAbs(output, None, 255) output = cv.resize(output, None, None, self.block, self.block, cv.INTER_LINEAR) self.viewer.update_processed( np.copy(output[:self.image.shape[0], :self.image.shape[1]])) avgprob = cv.mean(prob, 1 - mask.astype(np.uint8))[0] * 100 self.avgprob_label.setText(self.tr( 'Average = {:.2f}%'.format(avgprob))) modify_font(self.avgprob_label, italic=False, bold=True) self.process_button.setEnabled(False)
class PlotsWidget(ToolWidget): def __init__(self, image, parent=None): super(PlotsWidget, self).__init__(parent) choices = ["Red", "Green", "Blue", "Hue", "Saturation", "Value"] self.xaxis_combo = QComboBox() self.xaxis_combo.addItems(choices) self.xaxis_combo.setCurrentIndex(3) self.yaxis_combo = QComboBox() self.yaxis_combo.addItems(choices) self.yaxis_combo.setCurrentIndex(4) self.zaxis_combo = QComboBox() self.zaxis_combo.addItems(choices) self.zaxis_combo.setCurrentIndex(5) self.sampling_spin = QSpinBox() levels = int(np.log2(min(image.shape[:-1]))) self.sampling_spin.setRange(0, levels) self.sampling_spin.setSpecialValueText(self.tr("Off")) # self.sampling_spin.setSuffix(self.tr(' level(s)')) self.sampling_spin.setValue(1) self.size_spin = QSpinBox() self.size_spin.setRange(1, 10) self.size_spin.setValue(1) self.size_spin.setSuffix(self.tr(" pt")) self.markers = [ ",", ".", "o", "8", "s", "p", "P", "*", "h", "H", "X", "D" ] self.alpha_spin = QDoubleSpinBox() self.alpha_spin.setRange(0, 1) self.alpha_spin.setDecimals(2) self.alpha_spin.setSingleStep(0.05) self.alpha_spin.setValue(1) self.colors_check = QCheckBox(self.tr("Show colors")) self.grid_check = QCheckBox(self.tr("Show grid")) self.norm_check = QCheckBox(self.tr("Normalized")) self.total_label = QLabel() img = np.copy(image) self.colors = [None] * (levels + 1) for scale in range(levels + 1): rgb = cv.cvtColor(img.astype(np.float32) / 255, cv.COLOR_BGR2RGB) hsv = cv.cvtColor(rgb, cv.COLOR_RGB2HSV) hsv[:, :, 0] /= 360 shape = (img.shape[0] * img.shape[1], img.shape[2]) self.colors[scale] = np.concatenate( (np.reshape(rgb, shape), np.reshape(hsv, shape)), axis=1) img = cv.pyrDown(img) figure2 = Figure() plot2_canvas = FigureCanvas(figure2) self.axes2 = plot2_canvas.figure.subplots() toolbar2 = NavigationToolbar(plot2_canvas, self) plot2_layout = QVBoxLayout() plot2_layout.addWidget(plot2_canvas) plot2_layout.addWidget(toolbar2) plot2_widget = QWidget() plot2_widget.setLayout(plot2_layout) figure3 = Figure() plot3_canvas = FigureCanvas(figure3) self.axes3 = plot3_canvas.figure.add_subplot(111, projection="3d") toolbar3 = NavigationToolbar(plot3_canvas, self) plot3_layout = QVBoxLayout() plot3_layout.addWidget(plot3_canvas) plot3_layout.addWidget(toolbar3) plot3_widget = QWidget() plot3_widget.setLayout(plot3_layout) self.tab_widget = QTabWidget() self.tab_widget.addTab(plot2_widget, "2D Plot") self.tab_widget.addTab(plot3_widget, "3D Plot") self.redraw() figure2.set_tight_layout(True) figure3.set_tight_layout(True) self.xaxis_combo.currentIndexChanged.connect(self.redraw) self.yaxis_combo.currentIndexChanged.connect(self.redraw) self.zaxis_combo.currentIndexChanged.connect(self.redraw) self.sampling_spin.valueChanged.connect(self.redraw) self.size_spin.valueChanged.connect(self.redraw) self.alpha_spin.valueChanged.connect(self.redraw) self.colors_check.stateChanged.connect(self.redraw) self.grid_check.stateChanged.connect(self.redraw) self.norm_check.stateChanged.connect(self.redraw) self.tab_widget.currentChanged.connect(self.redraw) params_layout = QGridLayout() params_layout.addWidget(QLabel(self.tr("X axis:")), 0, 0) params_layout.addWidget(self.xaxis_combo, 0, 1) params_layout.addWidget(QLabel(self.tr("Y axis:")), 1, 0) params_layout.addWidget(self.yaxis_combo, 1, 1) params_layout.addWidget(QLabel(self.tr("Z axis:")), 2, 0) params_layout.addWidget(self.zaxis_combo, 2, 1) params_layout.addWidget(QLabel(self.tr("Subsampling:")), 0, 2) params_layout.addWidget(self.sampling_spin, 0, 3) params_layout.addWidget(QLabel(self.tr("Point size:")), 1, 2) params_layout.addWidget(self.size_spin, 1, 3) params_layout.addWidget(QLabel(self.tr("Point alpha:")), 2, 2) params_layout.addWidget(self.alpha_spin, 2, 3) params_layout.addWidget(self.colors_check, 0, 4) params_layout.addWidget(self.grid_check, 1, 4) params_layout.addWidget(self.total_label, 2, 4) bottom_layout = QHBoxLayout() bottom_layout.addLayout(params_layout) bottom_layout.addStretch() main_layout = QVBoxLayout() main_layout.addWidget(self.tab_widget) main_layout.addLayout(bottom_layout) self.setLayout(main_layout) def redraw(self): start = time() v = self.sampling_spin.value() x = self.colors[v][:, self.xaxis_combo.currentIndex()] y = self.colors[v][:, self.yaxis_combo.currentIndex()] s = self.size_spin.value()**2 c = None if not self.colors_check.isChecked( ) else self.colors[v][:, :3] if self.tab_widget.currentIndex() == 0: self.zaxis_combo.setEnabled(False) self.grid_check.setEnabled(True) self.alpha_spin.setEnabled(True) a = self.alpha_spin.value() xlim = self.axes2.get_xlim() ylim = self.axes2.get_ylim() self.axes2.clear() self.axes2.set_facecolor([0.5] * 3 if c is not None else [1.0] * 3) self.axes2.scatter(x, y, s, c, ".", alpha=a) self.axes2.set_xlabel(self.xaxis_combo.currentText()) self.axes2.set_ylabel(self.yaxis_combo.currentText()) self.axes2.grid(self.grid_check.isChecked(), which="both") self.axes2.set_xlim(xlim) self.axes2.set_ylim(ylim) self.axes2.figure.canvas.draw() else: self.zaxis_combo.setEnabled(True) self.grid_check.setEnabled(False) self.alpha_spin.setEnabled(False) z = self.colors[v][:, self.zaxis_combo.currentIndex()] self.axes3.clear() self.axes3.set_facecolor([0.5] * 3 if c is not None else [1.0] * 3) self.axes3.scatter(x, y, z, s=s, c=c, marker=".", depthshade=True) self.axes3.set_xlabel(self.xaxis_combo.currentText()) self.axes3.set_ylabel(self.yaxis_combo.currentText()) self.axes3.set_zlabel(self.zaxis_combo.currentText()) self.axes3.grid(self.grid_check.isChecked(), which="both") self.axes3.figure.canvas.draw() self.total_label.setText(self.tr(f"[{len(x)} points]")) self.info_message.emit(f"Plot redraw = {elapsed_time(start)}")