From 3511b94c28700389f3e4b6814126326c39521ad8 Mon Sep 17 00:00:00 2001 From: Yorusora Date: Thu, 15 May 2025 14:28:45 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BA=86<=E4=BD=93=E5=8A=A8?= =?UTF-8?q?=E6=A0=87=E6=B3=A8>=E5=8A=9F=E8=83=BD=E7=9A=84=E9=87=8D?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Module_artifact_label.py | 1294 ++++++++++++++++++++ func/Module_mainwindow.py | 13 + func/utils/ConfigParams.py | 42 +- func/utils/Constants.py | 69 +- ui/MainWindow/MainWindow_artifact_label.py | 24 +- ui/MainWindow/MainWindow_artifact_label.ui | 32 +- 6 files changed, 1418 insertions(+), 56 deletions(-) create mode 100644 func/Module_artifact_label.py diff --git a/func/Module_artifact_label.py b/func/Module_artifact_label.py new file mode 100644 index 0000000..ea52646 --- /dev/null +++ b/func/Module_artifact_label.py @@ -0,0 +1,1294 @@ +from gc import collect +from pathlib import Path +from traceback import format_exc + +import matplotlib.pyplot as plt +from PySide6.QtCore import QCoreApplication, QTimer +from PySide6.QtGui import QAction, QFont +from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication, QTableWidget, QTableWidgetItem +from matplotlib import gridspec, patches +from matplotlib.backends.backend_qt import NavigationToolbar2QT +from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg +from numpy.fft import fft, fftfreq +from overrides import overrides +from pandas import read_csv, DataFrame, concat +from yaml import dump, load, FullLoader + +from func.utils.PublicFunc import PublicFunc +from func.utils.Constants import Constants, ConfigParams +from func.utils.Result import Result + +from ui.MainWindow.MainWindow_artifact_label import Ui_MainWindow_artifact_label +from ui.setting.artifact_label_input_setting import Ui_MainWindow_artifact_label_input_setting + + +Config = { + +} + +ButtonState = { + "Default": { + "pushButton_input_setting": True, + "pushButton_input": True, + "pushButton_prev_move": False, + "pushButton_pause": False, + "pushButton_next_move": False, + "pushButton_save": False, + "pushButton_type_1": False, + "pushButton_type_2": False, + "pushButton_type_3": False, + "pushButton_type_4": False, + "pushButton_type_5": False, + "pushButton_delete": False + }, + "Current": { + "pushButton_input_setting": True, + "pushButton_input": True, + "pushButton_prev_move": False, + "pushButton_pause": False, + "pushButton_next_move": False, + "pushButton_save": False, + "pushButton_type_1": False, + "pushButton_type_2": False, + "pushButton_type_3": False, + "pushButton_type_4": False, + "pushButton_type_5": False, + "pushButton_delete": False + } +} + + +class SettingWindow(QMainWindow): + + def __init__(self, root_path, sampID): + super(SettingWindow, self).__init__() + self.ui = Ui_MainWindow_artifact_label_input_setting() + self.ui.setupUi(self) + + self.root_path = root_path + self.sampID = sampID + + self.config = None + self.__read_config__() + + self.ui.spinBox_input_freq_orgBcg.valueChanged.connect(self.__update_ui__) + self.ui.spinBox_input_freq_BCG.valueChanged.connect(self.__update_ui__) + self.ui.pushButton_confirm.clicked.connect(self.__write_config__) + self.ui.pushButton_cancel.clicked.connect(self.__rollback_config__) + self.ui.pushButton_cancel.clicked.connect(self.close) + + def __read_config__(self): + if not Path(ConfigParams.ARTIFACT_LABEL_CONFIG_FILE_PATH).exists(): + with open(ConfigParams.ARTIFACT_LABEL_CONFIG_FILE_PATH, "w") as f: + dump(ConfigParams.ARTIFACT_LABEL_CONFIG_NEW_CONTENT, f) + + with open(ConfigParams.ARTIFACT_LABEL_CONFIG_FILE_PATH, "r") as f: + file_config = load(f.read(), Loader=FullLoader) + Config.update(file_config) + self.config = file_config + + Config.update({ + "Path": { + "Input_orgBcg": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + Path(str(self.sampID)) / Path(ConfigParams.ARTIFACT_LABEL_INPUT_ORGBCG_FILENAME + + str(Config["InputConfig"]["orgBcgFreq"]) + + ConfigParams.ENDSWITH_TXT))), + "Input_BCG": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + Path(str(self.sampID)) / Path(ConfigParams.ARTIFACT_LABEL_INPUT_BCG_FILENAME + + str(Config["InputConfig"]["BCGFreq"]) + + ConfigParams.ENDSWITH_TXT))), + "Save_a": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + Path(str(self.sampID)) / Path(ConfigParams.ARTIFACT_LABEL_SAVE_FILENAME_A + + ConfigParams.ENDSWITH_TXT))), + "Save_b": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + Path(str(self.sampID)) / Path(ConfigParams.ARTIFACT_LABEL_SAVE_FILENAME_B + + ConfigParams.ENDSWITH_TXT))), + "Save_c": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + Path(str(self.sampID)) / Path(ConfigParams.ARTIFACT_LABEL_SAVE_FILENAME_C + + ConfigParams.ENDSWITH_CSV))) + } + }) + + # 数据回显 + self.ui.spinBox_input_freq_orgBcg.setValue(Config["InputConfig"]["orgBcgFreq"]) + self.ui.spinBox_input_freq_BCG.setValue(Config["InputConfig"]["BCGFreq"]) + self.ui.plainTextEdit_file_path_input_orgBcg.setPlainText(Config["Path"]["Input_orgBcg"]) + self.ui.plainTextEdit_file_path_input_BCG.setPlainText(Config["Path"]["Input_BCG"]) + self.ui.plainTextEdit_file_path_save_a.setPlainText(Config["Path"]["Save_a"]) + self.ui.plainTextEdit_file_path_save_b.setPlainText(Config["Path"]["Save_b"]) + self.ui.plainTextEdit_file_path_save_c.setPlainText(Config["Path"]["Save_c"]) + + def __write_config__(self): + # 从界面写入配置 + Config["InputConfig"]["orgBcgFreq"] = self.ui.spinBox_input_freq_orgBcg.value() + Config["InputConfig"]["BCGFreq"] = self.ui.spinBox_input_freq_BCG.value() + Config["Path"]["Input_orgBcg"] = self.ui.plainTextEdit_file_path_input_orgBcg.toPlainText() + Config["Path"]["Input_BCG"] = self.ui.plainTextEdit_file_path_input_BCG.toPlainText() + Config["Path"]["Save_a"] = self.ui.plainTextEdit_file_path_save_a.toPlainText() + Config["Path"]["Save_b"] = self.ui.plainTextEdit_file_path_save_b.toPlainText() + Config["Path"]["Save_c"] = self.ui.plainTextEdit_file_path_save_c.toPlainText() + + # 保存配置到文件 + self.config["InputConfig"]["orgBcgFreq"] = self.ui.spinBox_input_freq_orgBcg.value() + self.config["InputConfig"]["BCGFreq"] = self.ui.spinBox_input_freq_BCG.value() + + with open(ConfigParams.ARTIFACT_LABEL_CONFIG_FILE_PATH, "w") as f: + dump(self.config, f) + + self.close() + + def __rollback_config__(self): + self.__read_config__() + + def __update_ui__(self): + self.ui.plainTextEdit_file_path_input_orgBcg.setPlainText( + str((Path(self.root_path) / + ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + Path(str(self.sampID)) / + Path(ConfigParams.ARTIFACT_LABEL_INPUT_ORGBCG_FILENAME + + str(self.ui.spinBox_input_freq_orgBcg.value()) + + ConfigParams.ENDSWITH_TXT)))) + self.ui.plainTextEdit_file_path_input_BCG.setPlainText( + str((Path(self.root_path) / + ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + Path(str(self.sampID)) / + Path(ConfigParams.ARTIFACT_LABEL_INPUT_BCG_FILENAME + + str(self.ui.spinBox_input_freq_BCG.value()) + + ConfigParams.ENDSWITH_TXT)))) + + +class MainWindow_artifact_label(QMainWindow): + + def __init__(self): + super(MainWindow_artifact_label, self).__init__() + self.ui = Ui_MainWindow_artifact_label() + self.ui.setupUi(self) + + self.root_path = None + self.sampID = None + + self.data = None + + self.setting = None + + # 初始化进度条 + self.progressbar = None + PublicFunc.add_progressbar(self) + + #初始化画框 + self.fig = None + self.canvas = None + self.figToolbar = None + self.gs = None + self.ax0 = None + self.ax1 = None + self.rectangles_ax0_patches = [] + self.rectangles_ax1_patches = [] + self.annotation_tableWidget = None + self.rect_left = None + self.rect_right = None + self.is_left_button_pressed = None + self.pressed_number = None + + self.rect_up = None + self.rect_down = None + + # 初始化自动播放定时器 + self.autoplay_xlim_start = None + self.autoplay_xlim_end = None + self.timer_autoplay = QTimer() + self.timer_autoplay.timeout.connect(self.autoplay_move_xlim) + Config.update({ + "AutoplayArgs": { + "AutoplayMode": "pause", + "MoveLength": int(self.ui.label_moveLength_preset_1.text()), + "MaxRange": int(self.ui.label_maxRange_preset_1.text()), + "MoveSpeed": int(self.ui.label_moveSpeed_preset_1.text()) + } + }) + + self.msgBox = QMessageBox() + self.msgBox.setWindowTitle(Constants.MAINWINDOW_MSGBOX_TITLE) + + @overrides + def show(self, root_path, sampID): + super().show() + self.root_path = root_path + self.sampID = sampID + + self.setting = SettingWindow(root_path, sampID) + + # 初始化画框 + self.fig = plt.figure(figsize=(12, 9), dpi=100) + self.canvas = FigureCanvasQTAgg(self.fig) + self.figToolbar = CustomNavigationToolbar(self.canvas, self) + self.figToolbar.action_Label_Artifact.setEnabled(False) + for action in self.figToolbar._actions.values(): + action.setEnabled(False) + for action in self.figToolbar.actions(): + if action.text() == "Subplots" or action.text() == "Customize": + self.figToolbar.removeAction(action) + self.figToolbar._actions['home'].triggered.connect(self.toggle_home) + self.figToolbar._actions['zoom'].triggered.connect(self.toggle_zoom) + self.figToolbar._actions['pan'].triggered.connect(self.toggle_pan) + self.figToolbar.action_Label_Artifact.triggered.connect(self.toggle_label_artifact) + self.ui.verticalLayout_canvas.addWidget(self.canvas) + self.ui.verticalLayout_canvas.addWidget(self.figToolbar) + self.gs = gridspec.GridSpec(2, 1, height_ratios=[1, 1]) + self.fig.subplots_adjust(top=0.98, bottom=0.05, right=0.98, left=0.1, hspace=0, wspace=0) + self.ax0 = self.fig.add_subplot(self.gs[0]) + self.ax0.grid(True) + self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax0.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) + self.ax1 = self.fig.add_subplot(self.gs[1], sharex=self.ax0, sharey=self.ax0) + self.ax1.grid(True) + self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + + PublicFunc.__resetAllButton__(self, ButtonState) + + self.ui.spinBox_moveLength.setValue(Config["CustomAutoplayArgs"]["MoveLength"]) + self.ui.spinBox_maxRange.setValue(Config["CustomAutoplayArgs"]["MaxRange"]) + self.ui.spinBox_moveSpeed.setValue(Config["CustomAutoplayArgs"]["MoveSpeed"]) + + self.ui.tableWidget_type_1.setHorizontalHeaderLabels(['序号', '起始时间', '终止时间']) + self.ui.tableWidget_type_2.setHorizontalHeaderLabels(['序号', '起始时间', '终止时间']) + self.ui.tableWidget_type_3.setHorizontalHeaderLabels(['序号', '起始时间', '终止时间']) + self.ui.tableWidget_type_4.setHorizontalHeaderLabels(['序号', '起始时间', '终止时间']) + self.ui.tableWidget_type_5.setHorizontalHeaderLabels(['序号', '起始时间', '终止时间']) + self.ui.tableWidget_type_1.setEditTriggers(QTableWidget.NoEditTriggers) + self.ui.tableWidget_type_2.setEditTriggers(QTableWidget.NoEditTriggers) + self.ui.tableWidget_type_3.setEditTriggers(QTableWidget.NoEditTriggers) + self.ui.tableWidget_type_4.setEditTriggers(QTableWidget.NoEditTriggers) + self.ui.tableWidget_type_5.setEditTriggers(QTableWidget.NoEditTriggers) + self.ui.tableWidget_type_1.horizontalHeader().setStretchLastSection(True) + self.ui.tableWidget_type_2.horizontalHeader().setStretchLastSection(True) + self.ui.tableWidget_type_3.horizontalHeader().setStretchLastSection(True) + self.ui.tableWidget_type_4.horizontalHeader().setStretchLastSection(True) + self.ui.tableWidget_type_5.horizontalHeader().setStretchLastSection(True) + + self.ui.pushButton_input.clicked.connect(self.__slot_btn_input__) + self.ui.pushButton_type_1.clicked.connect(self.__slot_btn_label__) + self.ui.pushButton_type_2.clicked.connect(self.__slot_btn_label__) + self.ui.pushButton_type_3.clicked.connect(self.__slot_btn_label__) + self.ui.pushButton_type_4.clicked.connect(self.__slot_btn_label__) + self.ui.pushButton_type_5.clicked.connect(self.__slot_btn_label__) + self.ui.pushButton_save.clicked.connect(self.__slot_btn_save__) + self.ui.pushButton_delete.clicked.connect(self.__slot_btn_delete_label__) + self.ui.pushButton_prev_move.clicked.connect(self.__slot_btn_move__) + self.ui.pushButton_pause.clicked.connect(self.__slot_btn_move__) + self.ui.pushButton_next_move.clicked.connect(self.__slot_btn_move__) + self.ui.radioButton_move_preset_1.toggled.connect(self.__change_autoplay_args__) + self.ui.radioButton_move_preset_2.toggled.connect(self.__change_autoplay_args__) + self.ui.radioButton_move_preset_3.toggled.connect(self.__change_autoplay_args__) + self.ui.radioButton_move_custom.toggled.connect(self.__change_autoplay_args__) + self.ui.tableWidget_type_1.cellDoubleClicked.connect(self.__slot_tableWidget_on_cell_double_clicked__) + self.ui.tableWidget_type_2.cellDoubleClicked.connect(self.__slot_tableWidget_on_cell_double_clicked__) + self.ui.tableWidget_type_3.cellDoubleClicked.connect(self.__slot_tableWidget_on_cell_double_clicked__) + self.ui.tableWidget_type_4.cellDoubleClicked.connect(self.__slot_tableWidget_on_cell_double_clicked__) + self.ui.tableWidget_type_5.cellDoubleClicked.connect(self.__slot_tableWidget_on_cell_double_clicked__) + self.ui.pushButton_input_setting.clicked.connect(self.setting.show) + + @overrides + def closeEvent(self, event): + reply = QMessageBox.question(self, '确认', '确认退出吗?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) + if reply == QMessageBox.Yes: + + PublicFunc.__disableAllButton__(self, ButtonState) + + PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg(Constants.SHUTTING_DOWN)) + QApplication.processEvents() + + # 清空画框 + del self.rectangles_ax0_patches + del self.rectangles_ax1_patches + del self.annotation_tableWidget + self.ax0.clear() + self.ax1.clear() + + # 释放资源 + del self.data + self.fig.clf() + plt.close(self.fig) + self.deleteLater() + collect() + self.canvas = None + event.accept() + else: + event.ignore() + + def __reset__(self): + ButtonState["Current"].update(ButtonState["Default"].copy()) + + def __plot__(self): + # 清空画框 + if self.annotation_tableWidget is not None: + self.annotation_tableWidget.remove() + self.annotation_tableWidget = None + + self.reset_axes() + + sender = self.sender() + + if sender == self.ui.pushButton_input: + try: + self.ax0.plot(self.data.orgBcg, label=Constants.ARTIFACT_LABEL_PLOT_LABEL_ORGBCG_SYNC, + color=Constants.PLOT_COLOR_BLUE) + self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) + self.ax1.plot(self.data.BCG, label=Constants.ARTIFACT_LABEL_PLOT_LABEL_BCG_SYNC, + color=Constants.PLOT_COLOR_BLUE) + self.ax1.legend(loc=Constants.PLOT_UPPER_RIGHT) + self.rect_down = min(self.ax0.get_ylim()[0], self.ax1.get_ylim()[0]) - 1000 + self.rect_up = max(self.ax0.get_ylim()[1], self.ax1.get_ylim()[1]) + 1000 + self.canvas.draw() + self.__plot_artifact__() + self.ax0.autoscale(False) + self.ax1.autoscale(False) + except Exception as e: + return Result().failure(info=Constants.DRAWING_FAILURE + "\n" + format_exc()) + return Result().success(info=Constants.DRAWING_FINISHED) + else: + self.canvas.draw() + self.ax0.autoscale(False) + self.ax1.autoscale(False) + return Result().failure(info=Constants.DRAWING_FAILURE) + + def __plot_artifact__(self): + if len(self.ax0.patches) != 0: + for patch in self.ax0.patches: + if patch in self.rectangles_ax0_patches: + patch.remove() + if len(self.ax1.patches) != 0: + for patch in self.ax1.patches: + if patch in self.rectangles_ax1_patches: + patch.remove() + + self.rectangles_ax0_patches = [] + self.rectangles_ax1_patches = [] + self.ax1.callbacks.connect('xlim_changed', lambda ax: self.on_xlim_change(ax)) + self.canvas.draw() + + # 绘制体动 + for i in range(0, len(self.data.df_Artifact_a)): + if self.data.df_Artifact_a.iloc[i][1] == 1: + # 橙色,剧烈体动 + rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), + width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), + height=self.rect_up - self.rect_down, + fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_DEEP_YELLOW) + self.rectangles_ax0_patches.append(rectangle) + rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), + width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), + height=self.rect_up - self.rect_down, + fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_DEEP_YELLOW) + self.rectangles_ax1_patches.append(rectangle) + elif self.data.df_Artifact_a.iloc[i][1] == 2: + # 黄色,脉冲体动 + rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), + width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), + height=self.rect_up - self.rect_down, + fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_YELLOW) + self.rectangles_ax0_patches.append(rectangle) + rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), + width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), + height=self.rect_up - self.rect_down, + fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_YELLOW) + self.rectangles_ax1_patches.append(rectangle) + elif self.data.df_Artifact_a.iloc[i][1] == 3: + # 青色,常规体动 + rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), + width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), + height=self.rect_up - self.rect_down, + fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_AQUA) + self.rectangles_ax0_patches.append(rectangle) + rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), + width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), + height=self.rect_up - self.rect_down, + fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_AQUA) + self.rectangles_ax1_patches.append(rectangle) + elif self.data.df_Artifact_a.iloc[i][1] == 4: + # 紫色,疑似鼾声 + rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), + width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), + height=self.rect_up - self.rect_down, + fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_PURPLE_PINK) + self.rectangles_ax0_patches.append(rectangle) + rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), + width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), + height=self.rect_up - self.rect_down, + fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_PURPLE_PINK) + self.rectangles_ax1_patches.append(rectangle) + elif self.data.df_Artifact_a.iloc[i][1] == 5: + # 灰色,离床 + rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), + width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), + height=self.rect_up - self.rect_down, + fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_DEEP_GREY) + self.rectangles_ax0_patches.append(rectangle) + rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), + width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), + height=self.rect_up - self.rect_down, + fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_DEEP_GREY) + self.rectangles_ax1_patches.append(rectangle) + for patch in self.rectangles_ax0_patches: + self.ax0.add_patch(patch) + for patch in self.rectangles_ax1_patches: + self.ax1.add_patch(patch) + + self.canvas.draw() + + def update_label_args(self, rect_left, rect_right): + try: + # 计算傅里叶变换 + fft_result = fft(self.data.orgBcg[rect_left:rect_right]) + fft_freqs = fftfreq(len(self.data.orgBcg[rect_left:rect_right]), 1 / Config["InputConfig"]["orgBcgFreq"]) + # 确定频率高于20Hz的成分 + high_freq_indices = abs(fft_freqs) > 20 + high_freq_fft = fft_result[high_freq_indices] + # 计算能量 + total_energy = sum(abs(fft_result) ** 2) + high_freq_energy = sum(abs(high_freq_fft) ** 2) + # 计算能量占比 + energy_ratio_orgData_sync = round((high_freq_energy * 100 / total_energy), 6) + + # 计算傅里叶变换 + fft_result = fft(self.data.orgBcg[rect_left:rect_right]) + fft_freqs = fftfreq(len(self.data.orgBcg[rect_left:rect_right]), + 1 / Config["InputConfig"]["orgBcgFreq"]) + # 确定频率高于20Hz的成分 + high_freq_indices = abs(fft_freqs) > 20 + high_freq_fft = fft_result[high_freq_indices] + # 计算能量 + total_energy = sum(abs(fft_result) ** 2) + high_freq_energy = sum(abs(high_freq_fft) ** 2) + # 计算能量占比 + energy_ratio_BCG_sync = round((high_freq_energy * 100 / total_energy), 6) + + self.ui.lineEdit_energy_percent_orgBcg.setText(str(energy_ratio_orgData_sync) + "%") + self.ui.lineEdit_energy_percent_BCG.setText(str(energy_ratio_BCG_sync) + "%") + self.ui.lineEdit_start_time.setText(str(int(self.rect_left))) + self.ui.lineEdit_end_time.setText(str(int(self.rect_right))) + self.ui.lineEdit_duration.setText(str(int(self.rect_right) - int(self.rect_left))) + except Exception: + self.ui.lineEdit_energy_percent_orgBcg.setText("获取异常") + self.ui.lineEdit_energy_percent_BCG.setText("获取异常") + self.ui.lineEdit_start_time.setText("获取异常") + self.ui.lineEdit_end_time.setText("获取异常") + self.ui.lineEdit_duration.setText("获取异常") + + def update_tableWidget(self): + try: + self.ui.tableWidget_type_1.clearContents() + self.ui.tableWidget_type_2.clearContents() + self.ui.tableWidget_type_3.clearContents() + self.ui.tableWidget_type_4.clearContents() + self.ui.tableWidget_type_5.clearContents() + self.ui.tableWidget_type_1.setRowCount(0) + self.ui.tableWidget_type_2.setRowCount(0) + self.ui.tableWidget_type_3.setRowCount(0) + self.ui.tableWidget_type_4.setRowCount(0) + self.ui.tableWidget_type_5.setRowCount(0) + for row, data in self.data.df_Artifact_a.iterrows(): + if data["type"] == 1: + self.ui.tableWidget_type_1.setRowCount(self.ui.tableWidget_type_1.rowCount() + 1) + self.ui.tableWidget_type_1.setItem(self.ui.tableWidget_type_1.rowCount() - 1, 0, QTableWidgetItem(str(data["number"]))) + self.ui.tableWidget_type_1.setItem(self.ui.tableWidget_type_1.rowCount() - 1, 1, QTableWidgetItem(str(data["startTime"]))) + self.ui.tableWidget_type_1.setItem(self.ui.tableWidget_type_1.rowCount() - 1, 2, QTableWidgetItem(str(data["endTime"]))) + elif data["type"] == 2: + self.ui.tableWidget_type_2.setRowCount(self.ui.tableWidget_type_2.rowCount() + 1) + self.ui.tableWidget_type_2.setItem(self.ui.tableWidget_type_2.rowCount() - 1, 0, QTableWidgetItem(str(data["number"]))) + self.ui.tableWidget_type_2.setItem(self.ui.tableWidget_type_2.rowCount() - 1, 1, QTableWidgetItem(str(data["startTime"]))) + self.ui.tableWidget_type_2.setItem(self.ui.tableWidget_type_2.rowCount() - 1, 2, QTableWidgetItem(str(data["endTime"]))) + elif data["type"] == 3: + self.ui.tableWidget_type_3.setRowCount(self.ui.tableWidget_type_3.rowCount() + 1) + self.ui.tableWidget_type_3.setItem(self.ui.tableWidget_type_3.rowCount() - 1, 0, QTableWidgetItem(str(data["number"]))) + self.ui.tableWidget_type_3.setItem(self.ui.tableWidget_type_3.rowCount() - 1, 1, QTableWidgetItem(str(data["startTime"]))) + self.ui.tableWidget_type_3.setItem(self.ui.tableWidget_type_3.rowCount() - 1, 2, QTableWidgetItem(str(data["endTime"]))) + elif data["type"] == 4: + self.ui.tableWidget_type_4.setRowCount(self.ui.tableWidget_type_4.rowCount() + 1) + self.ui.tableWidget_type_4.setItem(self.ui.tableWidget_type_4.rowCount() - 1, 0, QTableWidgetItem(str(data["number"]))) + self.ui.tableWidget_type_4.setItem(self.ui.tableWidget_type_4.rowCount() - 1, 1, QTableWidgetItem(str(data["startTime"]))) + self.ui.tableWidget_type_4.setItem(self.ui.tableWidget_type_4.rowCount() - 1, 2, QTableWidgetItem(str(data["endTime"]))) + elif data["type"] == 5: + self.ui.tableWidget_type_5.setRowCount(self.ui.tableWidget_type_5.rowCount() + 1) + self.ui.tableWidget_type_5.setItem(self.ui.tableWidget_type_5.rowCount() - 1, 0, QTableWidgetItem(str(data["number"]))) + self.ui.tableWidget_type_5.setItem(self.ui.tableWidget_type_5.rowCount() - 1, 1, QTableWidgetItem(str(data["startTime"]))) + self.ui.tableWidget_type_5.setItem(self.ui.tableWidget_type_5.rowCount() - 1, 2, QTableWidgetItem(str(data["endTime"]))) + except Exception as e: + return Result().failure(info=Constants.ARTIFACT_LABEL_UPDATE_FAILURE + Constants.ARTIFACT_LABEL_FAILURE_REASON["Update_tableWidget_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.ARTIFACT_LABEL_UPDATE_FINISHED) + + def update_Info(self): + try: + artifact_amount = [0, 0, 0, 0, 0] + artifact_total_duration = [0, 0, 0, 0, 0] + tableWidget_list = [self.ui.tableWidget_type_1, + self.ui.tableWidget_type_2, + self.ui.tableWidget_type_3, + self.ui.tableWidget_type_4, + self.ui.tableWidget_type_5] + for index, tableWidget in enumerate(tableWidget_list): + sum_of_differences = 0 + for row in range(tableWidget.rowCount()): + startTime = tableWidget.item(row, 1) + endTime = tableWidget.item(row, 2) + if startTime and endTime: # 确保单元格不为空 + startTime = int(startTime.text()) + endTime = int(endTime.text()) + difference_amount = endTime - startTime + sum_of_differences += difference_amount + artifact_amount[index] = tableWidget.rowCount() + artifact_total_duration[index] = sum_of_differences + self.ui.spinBox_amount_type_1.setValue(artifact_amount[0]) + self.ui.spinBox_amount_type_2.setValue(artifact_amount[1]) + self.ui.spinBox_amount_type_3.setValue(artifact_amount[2]) + self.ui.spinBox_amount_type_4.setValue(artifact_amount[3]) + self.ui.spinBox_amount_type_5.setValue(artifact_amount[4]) + self.ui.spinBox_duration_type_1.setValue(artifact_total_duration[0]) + self.ui.spinBox_duration_type_2.setValue(artifact_total_duration[1]) + self.ui.spinBox_duration_type_3.setValue(artifact_total_duration[2]) + self.ui.spinBox_duration_type_4.setValue(artifact_total_duration[3]) + self.ui.spinBox_duration_type_5.setValue(artifact_total_duration[4]) + except Exception as e: + return Result().failure(info=Constants.ARTIFACT_LABEL_UPDATE_FAILURE + Constants.ARTIFACT_LABEL_FAILURE_REASON["Update_Info_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.ARTIFACT_LABEL_UPDATE_FINISHED) + + def __slot_btn_input__(self): + PublicFunc.__disableAllButton__(self, ButtonState) + + # 清空画框 + # if self.point_peak_original is not None: + # self.point_peak_original.remove() + # self.point_peak_original = None + # if self.point_peak_corrected is not None: + # self.point_peak_corrected.remove() + # self.point_peak_corrected = None + # if self.annotation_tableWidget is not None: + # self.annotation_tableWidget.remove() + # self.annotation_tableWidget = None + + self.reset_axes() + self.canvas.draw() + + self.data = Data() + + # 导入数据 + PublicFunc.progressbar_update(self, 1, 5, Constants.INPUTTING_DATA, 0) + result = self.data.open_file() + if not result.status: + PublicFunc.text_output(self.ui, "(1/5)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(1/5)" + result.info, Constants.TIPS_TYPE_INFO) + + # 获取存档 + PublicFunc.progressbar_update(self, 2, 5, Constants.ARTIFACT_LABEL_LOADING_ARCHIVE, 50) + result = self.data.get_archive() + if not result.status: + PublicFunc.text_output(self.ui, "(2/5)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(2/5)" + result.info, Constants.TIPS_TYPE_INFO) + + # 绘图 + PublicFunc.progressbar_update(self, 3, 5, Constants.DRAWING_DATA, 60) + result = self.__plot__() + if not result.status: + PublicFunc.text_output(self.ui, "(3/5)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(3/5)" + result.info, Constants.TIPS_TYPE_INFO) + + # 更新表格 + PublicFunc.progressbar_update(self, 4, 5, Constants.ARTIFACT_LABEL_UPDATING_TABLE, 90) + result = self.update_tableWidget() + if not result.status: + PublicFunc.text_output(self.ui, "(4/5)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(4/5)" + result.info, Constants.TIPS_TYPE_INFO) + + # 更新信息 + PublicFunc.progressbar_update(self, 5, 5, Constants.ARTIFACT_LABEL_UPDATING_INFO, 95) + result = self.update_Info() + if not result.status: + PublicFunc.text_output(self.ui, "(5/5)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(5/5)" + result.info, Constants.TIPS_TYPE_INFO) + + self.__reset__() + self.figToolbar.action_Label_Artifact.setEnabled(True) + for action in self.figToolbar._actions.values(): + action.setEnabled(True) + ButtonState["Current"]["pushButton_input"] = False + ButtonState["Current"]["pushButton_input_setting"] = False + ButtonState["Current"]["pushButton_prev_move"] = True + ButtonState["Current"]["pushButton_next_move"] = True + ButtonState["Current"]["pushButton_pause"] = True + ButtonState["Current"]["pushButton_save"] = True + ButtonState["Current"]["pushButton_type_1"] = True + ButtonState["Current"]["pushButton_type_2"] = True + ButtonState["Current"]["pushButton_type_3"] = True + ButtonState["Current"]["pushButton_type_4"] = True + ButtonState["Current"]["pushButton_type_5"] = True + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_label__(self): + sender = self.sender() + + if sender == self.ui.pushButton_type_1: + type = 1 + elif sender == self.ui.pushButton_type_2: + type = 2 + elif sender == self.ui.pushButton_type_3: + type = 3 + elif sender == self.ui.pushButton_type_4: + type = 4 + elif sender == self.ui.pushButton_type_5: + type = 5 + else: + raise ValueError() + + if (self.ui.lineEdit_start_time.text() == Constants.STRING_IS_EMPTY or + self.ui.lineEdit_end_time.text() == Constants.STRING_IS_EMPTY): + PublicFunc.msgbox_output(self, Constants.ARTIFACT_LABEL_MISS_ARGS, Constants.MSGBOX_TYPE_ERROR) + return + + for index, row in self.data.df_Artifact_a.iterrows(): + value_startTime = row['startTime'] + value_endTime = row['endTime'] + if value_startTime <= int(self.ui.lineEdit_end_time.text()) and int( + self.ui.lineEdit_start_time.text()) <= value_endTime: + PublicFunc.msgbox_output(self, f"{Constants.ARTIFACT_LABEL_OVERLAPPING}{row['number']}", Constants.MSGBOX_TYPE_ERROR) + return + new_row = {'number': int(len(self.data.df_Artifact_a) + 1), + 'type': int(type), + 'startTime': int(self.ui.lineEdit_start_time.text()), + 'endTime': int(self.ui.lineEdit_end_time.text())} + self.data.df_Artifact_a = concat([self.data.df_Artifact_a, DataFrame([new_row])], ignore_index=True) + sorted_part = self.data.df_Artifact_a[['type', 'startTime', 'endTime']].sort_values(by='startTime').reset_index( + drop=True) + self.data.df_Artifact_a[['type', 'startTime', 'endTime']] = sorted_part + self.update_tableWidget() + self.update_Info() + self.__plot_artifact__() + + target_row = self.data.df_Artifact_a[ + self.data.df_Artifact_a.eq(int(self.ui.lineEdit_start_time.text())).any(axis=1)] + if not target_row.empty: + first_column_value = target_row.iloc[0, 0] # 获取第1列的值 + else: + raise AttributeError() + + PublicFunc.text_output(self.ui, f"新增体动标签{first_column_value}, 类型{new_row['type']},从{int(self.ui.lineEdit_start_time.text())}ms到{int(self.ui.lineEdit_end_time.text())}ms", Constants.TIPS_TYPE_INFO) + + self.__slot_btn_save__() + + def __slot_btn_save__(self): + PublicFunc.__disableAllButton__(self, ButtonState) + + # 保存 + PublicFunc.progressbar_update(self, 1, 1, Constants.SAVING_DATA, 0) + + amount = [ + self.ui.spinBox_amount_type_1.value(), + self.ui.spinBox_amount_type_2.value(), + self.ui.spinBox_amount_type_3.value(), + self.ui.spinBox_amount_type_4.value(), + self.ui.spinBox_amount_type_5.value() + ] + duration = [ + self.ui.spinBox_duration_type_1.value(), + self.ui.spinBox_duration_type_2.value(), + self.ui.spinBox_duration_type_3.value(), + self.ui.spinBox_duration_type_4.value(), + self.ui.spinBox_duration_type_5.value() + ] + + result = self.data.save(amount, duration) + + if not result.status: + PublicFunc.text_output(self.ui, "(1/1)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(1/1)" + result.info, Constants.TIPS_TYPE_INFO) + + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_delete_label__(self): + if self.pressed_number is not None: + self.data.df_Artifact_a = self.data.df_Artifact_a[self.data.df_Artifact_a['number'] != self.pressed_number] + self.data.df_Artifact_a = self.data.df_Artifact_a.reset_index(drop=True) + sorted_part = self.data.df_Artifact_a[['type', 'startTime', 'endTime']].sort_values(by='startTime').reset_index( + drop=True) + self.data.df_Artifact_a[['type', 'startTime', 'endTime']] = sorted_part + self.data.df_Artifact_a['number'] = self.data.df_Artifact_a.index + 1 + try: + if self.annotation_tableWidget: + self.annotation_tableWidget.remove() + except AttributeError: + pass + self.annotation_tableWidget = None + self.reset_labelBtn_color() + self.update_tableWidget() + self.update_Info() + self.__plot_artifact__() + self.__slot_btn_save__() + PublicFunc.text_output(self.ui, f"{self.pressed_number}{Constants.ARTIFACT_LABEL_DELETE_ARTIFACT_SUCCESSFULLY}", Constants.TIPS_TYPE_INFO) + else: + PublicFunc.text_output(self.ui, f"{self.pressed_number}{Constants.ARTIFACT_LABEL_DELETE_ARTIFACT_FAILURE}", Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, f"{self.pressed_number}{Constants.ARTIFACT_LABEL_DELETE_ARTIFACT_FAILURE}", Constants.MSGBOX_TYPE_ERROR) + self.pressed_number = None + + def __slot_btn_move__(self): + if self.data is None: + return + + sender = self.sender() + + if sender == self.ui.pushButton_prev_move: + Config["AutoplayArgs"]["AutoplayMode"] = "prev" + self.autoplay_xlim_start = int(self.ax0.get_xlim()[1] - Config["AutoplayArgs"]["MaxRange"]) + self.autoplay_xlim_end = int(self.ax0.get_xlim()[1]) + if self.autoplay_xlim_end > len(self.data.BCG): + self.autoplay_xlim_start = int(len(self.data.BCG) - Config["AutoplayArgs"]["MaxRange"]) + self.autoplay_xlim_end = int(len(self.data.BCG)) + self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end) + self.canvas.draw() + self.timer_autoplay.start(Config["AutoplayArgs"]["MoveSpeed"]) + PublicFunc.text_output(self.ui, Constants.ARTIFACT_LABEL_PREV_MOVE, Constants.TIPS_TYPE_INFO) + elif sender == self.ui.pushButton_next_move: + Config["AutoplayArgs"]["AutoplayMode"] = "next" + self.autoplay_xlim_start = int(self.ax0.get_xlim()[0]) + self.autoplay_xlim_end = int(self.ax0.get_xlim()[0] + Config["AutoplayArgs"]["MaxRange"]) + if self.autoplay_xlim_start < 0: + self.autoplay_xlim_start = 0 + self.autoplay_xlim_end = 0 + Config["AutoplayArgs"]["MaxRange"] + self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end) + self.canvas.draw() + self.timer_autoplay.start(Config["AutoplayArgs"]["MoveSpeed"]) + PublicFunc.text_output(self.ui, Constants.ARTIFACT_LABEL_NEXT_MOVE, Constants.TIPS_TYPE_INFO) + elif sender == self.ui.pushButton_pause: + Config["AutoplayArgs"]["AutoplayMode"] = "pause" + self.timer_autoplay.stop() + PublicFunc.text_output(self.ui, Constants.ARTIFACT_LABEL_PAUSE, Constants.TIPS_TYPE_INFO) + + def __change_autoplay_args__(self): + sender = self.sender() + + if sender == self.ui.radioButton_move_preset_1 and self.ui.radioButton_move_preset_1.isChecked(): + Config["AutoplayArgs"]["MoveLength"] = int(self.ui.label_moveLength_preset_1.text()) + Config["AutoplayArgs"]["MaxRange"] = int(self.ui.label_maxRange_preset_1.text()) + Config["AutoplayArgs"]["MoveSpeed"] = int(self.ui.label_moveSpeed_preset_1.text()) + PublicFunc.text_output(self.ui, Constants.ARTIFACT_LABEL_SWITCH_PRESET_1, Constants.TIPS_TYPE_INFO) + elif sender == self.ui.radioButton_move_preset_2 and self.ui.radioButton_move_preset_2.isChecked(): + Config["AutoplayArgs"]["MoveLength"] = int(self.ui.label_moveLength_preset_2.text()) + Config["AutoplayArgs"]["MaxRange"] = int(self.ui.label_maxRange_preset_2.text()) + Config["AutoplayArgs"]["MoveSpeed"] = int(self.ui.label_moveSpeed_preset_2.text()) + PublicFunc.text_output(self.ui, Constants.ARTIFACT_LABEL_SWITCH_PRESET_2, Constants.TIPS_TYPE_INFO) + elif sender == self.ui.radioButton_move_preset_3 and self.ui.radioButton_move_preset_3.isChecked(): + Config["AutoplayArgs"]["MoveLength"] = int(self.ui.label_moveLength_preset_3.text()) + Config["AutoplayArgs"]["MaxRange"] = int(self.ui.label_maxRange_preset_3.text()) + Config["AutoplayArgs"]["MoveSpeed"] = int(self.ui.label_moveSpeed_preset_3.text()) + PublicFunc.text_output(self.ui, Constants.ARTIFACT_LABEL_SWITCH_PRESET_3, Constants.TIPS_TYPE_INFO) + elif sender == self.ui.radioButton_move_custom and self.ui.radioButton_move_custom.isChecked(): + Config["AutoplayArgs"]["MoveLength"] = int(self.ui.spinBox_moveLength.value()) + Config["AutoplayArgs"]["MaxRange"] = int(self.ui.spinBox_maxRange.value()) + Config["AutoplayArgs"]["MoveSpeed"] = int(self.ui.spinBox_moveSpeed.value()) + PublicFunc.text_output(self.ui, Constants.ARTIFACT_LABEL_SWITCH_CUSTOM, Constants.TIPS_TYPE_INFO) + if Config["AutoplayArgs"]["AutoplayMode"] == "next": + self.autoplay_xlim_start = int(self.ax0.get_xlim()[0]) + self.autoplay_xlim_end = int(self.ax0.get_xlim()[0] + Config["AutoplayArgs"]["MaxRange"]) + if self.autoplay_xlim_start < 0: + self.autoplay_xlim_start = 0 + self.autoplay_xlim_end = 0 + Config["AutoplayArgs"]["MaxRange"] + self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end) + self.timer_autoplay.start(Config["AutoplayArgs"]["MoveSpeed"]) + elif Config["AutoplayArgs"]["AutoplayMode"] == "prev": + self.autoplay_xlim_start = int(self.ax0.get_xlim()[1] - Config["AutoplayArgs"]["MaxRange"]) + self.autoplay_xlim_end = int(self.ax0.get_xlim()[1]) + if self.autoplay_xlim_end > len(self.data.BCG): + self.autoplay_xlim_start = int(self.data.BCG) - Config["AutoplayArgs"]["MaxRange"] + self.autoplay_xlim_end = int(self.data.BCG) + self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end) + self.timer_autoplay.start(Config["AutoplayArgs"]["MoveSpeed"]) + elif Config["AutoplayArgs"]["AutoplayMode"] == "pause": + self.timer_autoplay.stop() + + def __slot_tableWidget_on_cell_double_clicked__(self, row, col): + if Config["AutoplayArgs"]["AutoplayMode"] != "pause": + self.ui.pushButton_pause.click() + + sender = self.sender() + + if sender == self.ui.tableWidget_type_1: + self.pressed_number = int( + self.ui.tableWidget_type_1.item(row, 0).text()) + startTime = int(self.ui.tableWidget_type_1.item(row, 1).text()) + endTime = int(self.ui.tableWidget_type_1.item(row, 2).text()) + type = 1 + elif sender == self.ui.tableWidget_type_2: + self.pressed_number = int( + self.ui.tableWidget_type_2.item(row, 0).text()) + startTime = int(self.ui.tableWidget_type_2.item(row, 1).text()) + endTime = int(self.ui.tableWidget_type_2.item(row, 2).text()) + type = 2 + elif sender == self.ui.tableWidget_type_3: + self.pressed_number = int( + self.ui.tableWidget_type_3.item(row, 0).text()) + startTime = int(self.ui.tableWidget_type_3.item(row, 1).text()) + endTime = int(self.ui.tableWidget_type_3.item(row, 2).text()) + type = 3 + elif sender == self.ui.tableWidget_type_4: + self.pressed_number = int( + self.ui.tableWidget_type_4.item(row, 0).text()) + startTime = int(self.ui.tableWidget_type_4.item(row, 1).text()) + endTime = int(self.ui.tableWidget_type_4.item(row, 2).text()) + type = 4 + elif sender == self.ui.tableWidget_type_5: + self.pressed_number = int( + self.ui.tableWidget_type_5.item(row, 0).text()) + startTime = int(self.ui.tableWidget_type_5.item(row, 1).text()) + endTime = int(self.ui.tableWidget_type_5.item(row, 2).text()) + type = 5 + else: + raise ValueError() + + self.ax0.set_xlim(startTime - 60000, endTime + 60000) + self.annotation_tableWidget = self.ax0.annotate(f'number={int(self.pressed_number)}, duration={int(endTime - startTime)}ms', + xy=(int(startTime + (endTime - startTime) / 2), self.ax0.get_ylim()[0]), + xytext=( + int(startTime + (endTime - startTime) / 2), self.ax0.get_ylim()[0] + ( + self.ax0.get_ylim()[1] - self.ax0.get_ylim()[ + 0]) * 0.1), + arrowprops=dict(facecolor=Constants.PLOT_COLOR_BLACK, shrink=0.1)) + self.change_labelBtn_color(type) + self.ui.pushButton_delete.setEnabled(True) + self.canvas.draw() + self.rect_left = startTime + self.rect_right = endTime + self.update_label_args(int(self.rect_left), int(self.rect_right)) + PublicFunc.text_output(self.ui, f"{Constants.ARTIFACT_LABEL_JUMP_ARTIFACT}{str(self.pressed_number)}", Constants.TIPS_TYPE_INFO) + + def reset_axes(self): + self.ax0.clear() + self.ax1.clear() + self.ax0.grid(True) + self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax0.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) + self.ax1.grid(True) + self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + + def on_xlim_change(self, event_ax): + try: + if self.annotation_tableWidget: + self.annotation_tableWidget.remove() + except AttributeError: + pass + self.annotation_tableWidget = None + self.reset_labelBtn_color() + ButtonState["Current"]["pushButton_delete"] = False + PublicFunc.__enableAllButton__(self, ButtonState) + + def autoplay_move_xlim(self): + if Config["AutoplayArgs"]["AutoplayMode"] == "prev" and self.autoplay_xlim_start < 0: + Config["AutoplayArgs"]["AutoplayMode"] = "pause" + self.timer_autoplay.stop() + elif Config["AutoplayArgs"]["AutoplayMode"] == "next" and self.autoplay_xlim_end > len(self.data.BCG): + Config["AutoplayArgs"]["AutoplayMode"] = "pause" + self.timer_autoplay.stop() + else: + if Config["AutoplayArgs"]["AutoplayMode"] == "next": + self.autoplay_xlim_start += Config["AutoplayArgs"]["MoveLength"] + self.autoplay_xlim_end += Config["AutoplayArgs"]["MoveLength"] + elif Config["AutoplayArgs"]["AutoplayMode"] == "prev": + self.autoplay_xlim_start -= Config["AutoplayArgs"]["MoveLength"] + self.autoplay_xlim_end -= Config["AutoplayArgs"]["MoveLength"] + self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end) + self.canvas.draw() + + def change_labelBtn_color(self, type): + if type == 1: + self.ui.pushButton_type_1.setStyleSheet( + Constants.ARTIFACT_LABEL_LABELBTN_STYLE_1) + self.ui.pushButton_type_2.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_3.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_4.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_5.setStyleSheet(Constants.STRING_IS_EMPTY) + elif type == 2: + self.ui.pushButton_type_1.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_2.setStyleSheet( + Constants.ARTIFACT_LABEL_LABELBTN_STYLE_2) + self.ui.pushButton_type_3.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_4.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_5.setStyleSheet(Constants.STRING_IS_EMPTY) + elif type == 3: + self.ui.pushButton_type_1.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_2.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_3.setStyleSheet( + Constants.ARTIFACT_LABEL_LABELBTN_STYLE_3) + self.ui.pushButton_type_4.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_5.setStyleSheet(Constants.STRING_IS_EMPTY) + elif type == 4: + self.ui.pushButton_type_1.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_2.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_3.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_4.setStyleSheet( + Constants.ARTIFACT_LABEL_LABELBTN_STYLE_4) + self.ui.pushButton_type_5.setStyleSheet(Constants.STRING_IS_EMPTY) + elif type == 5: + self.ui.pushButton_type_1.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_2.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_3.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_4.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_5.setStyleSheet( + Constants.ARTIFACT_LABEL_LABELBTN_STYLE_5) + + def reset_labelBtn_color(self): + self.ui.pushButton_type_1.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_2.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_3.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_4.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_type_5.setStyleSheet(Constants.STRING_IS_EMPTY) + + def toggle_home(self): + if Config["AutoplayArgs"]["AutoplayMode"] != "pause": + self.ui.pushButton_pause.click() + if self.figToolbar.rect_patch_ax0 is not None and self.figToolbar.rect_patch_ax1 is not None: + self.figToolbar.rect_patch_ax0.remove() + self.figToolbar.rect_patch_ax0 = None + self.figToolbar.rect_patch_ax1.remove() + self.figToolbar.rect_patch_ax1 = None + self.rect_left = None + self.rect_right = None + self.ui.lineEdit_start_time.setText(Constants.STRING_IS_EMPTY) + self.ui.lineEdit_end_time.setText(Constants.STRING_IS_EMPTY) + self.ui.lineEdit_duration.setText(Constants.STRING_IS_EMPTY) + self.ui.lineEdit_energy_percent_orgBcg.setText(Constants.STRING_IS_EMPTY) + self.ui.lineEdit_energy_percent_BCG.setText(Constants.STRING_IS_EMPTY) + self.canvas.draw() + self.ax0.autoscale(True) + self.ax1.autoscale(True) + self.ax1.relim() + self.ax1.autoscale_view() + self.canvas.draw() + self.ax0.autoscale(False) + self.ax1.autoscale(False) + PublicFunc.text_output(self.ui, Constants.ARTIFACT_LABEL_RECOVER_SCALE, Constants.TIPS_TYPE_INFO) + + def toggle_zoom(self): + if self.figToolbar.rect_patch_ax0 is not None and self.figToolbar.rect_patch_ax1 is not None: + self.figToolbar.rect_patch_ax0.remove() + self.figToolbar.rect_patch_ax0 = None + self.figToolbar.rect_patch_ax1.remove() + self.figToolbar.rect_patch_ax1 = None + self.rect_left = None + self.rect_right = None + self.ui.lineEdit_start_time.setText(Constants.STRING_IS_EMPTY) + self.ui.lineEdit_end_time.setText(Constants.STRING_IS_EMPTY) + self.ui.lineEdit_duration.setText(Constants.STRING_IS_EMPTY) + self.ui.lineEdit_energy_percent_orgBcg.setText(Constants.STRING_IS_EMPTY) + self.ui.lineEdit_energy_percent_BCG.setText(Constants.STRING_IS_EMPTY) + self.canvas.draw() + + def toggle_pan(self): + if self.figToolbar.rect_patch_ax0 is not None and self.figToolbar.rect_patch_ax1 is not None: + self.figToolbar.rect_patch_ax0.remove() + self.figToolbar.rect_patch_ax0 = None + self.figToolbar.rect_patch_ax1.remove() + self.figToolbar.rect_patch_ax1 = None + self.rect_left = None + self.rect_right = None + self.ui.lineEdit_start_time.setText(Constants.STRING_IS_EMPTY) + self.ui.lineEdit_end_time.setText(Constants.STRING_IS_EMPTY) + self.ui.lineEdit_duration.setText(Constants.STRING_IS_EMPTY) + self.ui.lineEdit_energy_percent_orgBcg.setText(Constants.STRING_IS_EMPTY) + self.ui.lineEdit_energy_percent_BCG.setText(Constants.STRING_IS_EMPTY) + self.canvas.draw() + + def toggle_label_artifact(self, state): + if state: + self.deactivate_figToolbar_buttons() + self.figToolbar.action_Label_Artifact.setChecked(True) + self.figToolbar.cid_mouse_press = self.canvas.mpl_connect( + "button_press_event", self.on_click) + self.figToolbar.cid_mouse_release = self.canvas.mpl_connect( + "button_release_event", self.on_release) + self.figToolbar.cid_mouse_hold = self.canvas.mpl_connect( + "motion_notify_event", self.on_hold) + else: + if self.figToolbar.rect_patch_ax0 is not None and self.figToolbar.rect_patch_ax1 is not None: + self.figToolbar.rect_patch_ax0.remove() + self.figToolbar.rect_patch_ax0 = None + self.figToolbar.rect_patch_ax1.remove() + self.figToolbar.rect_patch_ax1 = None + self.rect_left = None + self.rect_right = None + self.ui.lineEdit_start_time.setText(Constants.STRING_IS_EMPTY) + self.ui.lineEdit_end_time.setText(Constants.STRING_IS_EMPTY) + self.ui.lineEdit_duration.setText(Constants.STRING_IS_EMPTY) + self.ui.lineEdit_energy_percent_orgBcg.setText(Constants.STRING_IS_EMPTY) + self.ui.lineEdit_energy_percent_BCG.setText(Constants.STRING_IS_EMPTY) + self.canvas.draw() + if self.figToolbar.cid_mouse_press is not None: + self.canvas.mpl_disconnect(self.figToolbar.cid_mouse_press) + self.figToolbar.cid_mouse_press = None + if self.figToolbar.cid_mouse_release is not None: + self.canvas.mpl_disconnect(self.figToolbar.cid_mouse_release) + self.figToolbar.cid_mouse_release = None + if self.figToolbar.cid_mouse_hold: + self.canvas.mpl_disconnect(self.figToolbar.cid_mouse_hold) + self.figToolbar.cid_mouse_hold = None + + def deactivate_figToolbar_buttons(self): + for action in self.figToolbar._actions.values(): + if action.isChecked(): + if action == self.figToolbar._actions['pan']: + self.figToolbar.pan() + if action == self.figToolbar._actions['zoom']: + self.figToolbar.zoom() + + def on_click(self, event): + if self.figToolbar.action_Label_Artifact.isChecked(): + self.reset_labelBtn_color() + ButtonState["Current"]["pushButton_delete"] = False + PublicFunc.__enableAllButton__(self, ButtonState) + if event.button == 1: + self.is_left_button_pressed = True + self.figToolbar.rect_start_x = event.xdata + # 如果矩形patch已存在,先移除 + if self.figToolbar.rect_patch_ax0 is not None and self.figToolbar.rect_patch_ax1 is not None: + self.figToolbar.rect_patch_ax0.remove() + self.figToolbar.rect_patch_ax0 = None + self.figToolbar.rect_patch_ax1.remove() + self.figToolbar.rect_patch_ax1 = None + self.rect_left = None + self.rect_right = None + self.ui.lineEdit_start_time.setText(Constants.STRING_IS_EMPTY) + self.ui.lineEdit_end_time.setText(Constants.STRING_IS_EMPTY) + self.ui.lineEdit_duration.setText(Constants.STRING_IS_EMPTY) + self.canvas.draw() + self.ui.lineEdit_energy_percent_orgBcg.setText(Constants.STRING_IS_EMPTY) + self.ui.lineEdit_energy_percent_BCG.setText(Constants.STRING_IS_EMPTY) + + def on_release(self, event): + if self.figToolbar.rect_start_x is not None: + self.figToolbar.rect_end_x = event.xdata + if self.figToolbar.rect_start_x is not None and self.figToolbar.rect_end_x is not None: + if self.figToolbar.rect_start_x < self.figToolbar.rect_end_x: + self.rect_left = self.figToolbar.rect_start_x + self.rect_right = self.figToolbar.rect_end_x + elif self.figToolbar.rect_start_x > self.figToolbar.rect_end_x: + self.rect_left = self.figToolbar.rect_end_x + self.rect_right = self.figToolbar.rect_start_x + else: + self.rect_left = self.figToolbar.rect_start_x + self.rect_right = self.figToolbar.rect_start_x + else: + self.rect_left = self.figToolbar.rect_start_x + self.rect_right = self.figToolbar.rect_start_x + if event.button == 1 and self.is_left_button_pressed: + self.is_left_button_pressed = False + if self.rect_left < 0: + self.rect_left = 0 + elif self.rect_left >= len(self.data.BCG): + self.rect_left = 0 + self.rect_right = 0 + if self.rect_right >= len(self.data.BCG): + self.rect_right = len(self.data.BCG) - 1 + elif self.rect_right < 0: + self.rect_left = 0 + self.rect_right = 0 + + if int(self.rect_left) != int(self.rect_right): + self.update_label_args(int(self.rect_left), int(self.rect_right)) + + self.figToolbar.rect_start_x = None + self.figToolbar.rect_end_x = None + self.canvas.draw() + + def on_hold(self, event): + if self.figToolbar.rect_start_x is not None and event.xdata is not None: + self.figToolbar.rect_end_x = event.xdata + + # 如果矩形patch不存在,则创建一个新的 + if self.figToolbar.rect_patch_ax0 is None: + if self.is_left_button_pressed: + self.figToolbar.rect_patch_ax0 = patches.Rectangle((0, 0), 1, 1, fill=True, alpha=0.2, color='r') + self.ax0.add_patch(self.figToolbar.rect_patch_ax0) + + # 如果矩形patch不存在,则创建一个新的 + if self.figToolbar.rect_patch_ax1 is None: + if self.is_left_button_pressed: + self.figToolbar.rect_patch_ax1 = patches.Rectangle((0, 0), 1, 1, fill=True, alpha=0.2, color='r') + self.ax1.add_patch(self.figToolbar.rect_patch_ax1) + + # 更新矩形patch的位置和大小 + x_start = self.figToolbar.rect_start_x + x_end = self.figToolbar.rect_end_x + self.figToolbar.rect_patch_ax0.set_xy((min(x_start, x_end), self.rect_down)) + self.figToolbar.rect_patch_ax0.set_width(abs(x_end - x_start)) + self.figToolbar.rect_patch_ax0.set_height(self.rect_up - self.rect_down) + self.figToolbar.rect_patch_ax1.set_xy((min(x_start, x_end), self.rect_down)) + self.figToolbar.rect_patch_ax1.set_width(abs(x_end - x_start)) + self.figToolbar.rect_patch_ax1.set_height(self.rect_up - self.rect_down) + + self.canvas.draw() + + +class Data: + + def __init__(self): + self.orgBcg = None + self.BCG = None + self.Artifact_a = None + self.df_Artifact_a = DataFrame(columns=["number", "type", "startTime", "endTime"]) + + def open_file(self): + if (not Path(Config["Path"]["Input_orgBcg"]).exists()) or (not Path(Config["Path"]["Input_BCG"]).exists()): + return Result().failure(info=Constants.INPUT_FAILURE + Constants.ARTIFACT_LABEL_FAILURE_REASON["Data_Path_Not_Exist"]) + + try: + self.orgBcg = read_csv(Config["Path"]["Input_orgBcg"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + self.BCG = read_csv(Config["Path"]["Input_BCG"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + except Exception as e: + return Result().failure(info=Constants.INPUT_FAILURE + Constants.ARTIFACT_LABEL_FAILURE_REASON["Read_Data_Exception"] + "\n" + format_exc()) + + # 检查同步后的orgBcg信号和同步后的BCG信号长度是否相同 + if len(self.orgBcg) != len(self.BCG): + return Result().failure(info=Constants.INPUT_FAILURE + Constants.ARTIFACT_LABEL_FAILURE_REASON["Data_Length_not_Correct"]) + + return Result().success(info=Constants.INPUT_FINISHED) + + def get_archive(self): + if not Path(Config["Path"]["Save_a"]).exists(): + self.Artifact_a = [] + return Result().success(info=Constants.ARTIFACT_LABEL_ARCHIVE_NOT_EXIST) + else: + self.Artifact_a = read_csv(Config["Path"]["Save_a"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + try: + # 检查体动标签正确性,长度 + if len(self.Artifact_a) % 4 != 0: + return Result().failure(info=Constants.INPUT_FAILURE + Constants.ARTIFACT_LABEL_FAILURE_REASON[ + "Artifact_Format_Not_Correct"]) + for i in range(0, len(self.Artifact_a), 4): + unit_data = self.Artifact_a[i:i + 4] + if len(unit_data) < 4: + break + self.df_Artifact_a.loc[len(self.df_Artifact_a)] = [int(unit_data[j]) for j in range(4)] + except Exception as e: + return Result().failure(info=Constants.INPUT_FAILURE + Constants.ARTIFACT_LABEL_FAILURE_REASON[ + "Get_Artifact_Format_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.ARTIFACT_LABEL_ARCHIVE_EXIST) + + def save(self, amount, duration): + try: + # Artifact_a.txt和Artifact_c.csv的内容遍历 + output_lines = [] + for row_index in range(len(self.df_Artifact_a)): + for col in self.df_Artifact_a.columns: + value = self.df_Artifact_a.at[row_index, col] + output_lines.append(str(value)) + + # Artifact_b.txt的内容遍历 + dict = { + 'type': [1, 2, 3, 4, 5], + 'amount': [int(amount[0]), int(amount[1]), int(amount[2]), int(amount[3]), int(amount[4])], + 'duration': [int(duration[0]), int(duration[1]), int(duration[2]), int(duration[3]), int(duration[4])] + } + df_Artifact_b = DataFrame(dict) + + # 写入文件并保存 + self.df_Artifact_a.to_csv(Path(Config["Path"]["Save_a"]), header=False, index=False, sep='\n') + df_Artifact_b.to_csv(Path(Config["Path"]["Save_b"]), header=False, index=False, sep='\n') + self.df_Artifact_a.to_csv(Path(Config["Path"]["Save_c"]), index=False, + encoding=ConfigParams.GBK_ENCODING) + except Exception as e: + return Result().failure(info=Constants.SAVING_FAILURE + Constants.ARTIFACT_LABEL_FAILURE_REASON[ + "Save_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.SAVING_FINISHED) + + +class CustomNavigationToolbar(NavigationToolbar2QT): + + def __init__(self, canvas, parent): + super().__init__(canvas, parent) + # 初始化画框工具栏 + self.action_Label_Artifact = QAction(Constants.ARTIFACT_LABEL_ACTION_LABEL, self) + self.action_Label_Artifact.setFont(QFont(ConfigParams.FONT, 14)) + self.action_Label_Artifact.setCheckable(True) + self.action_Label_Artifact.setShortcut(QCoreApplication.translate( + "MainWindow", + ConfigParams.ARTIFACT_LABEL_ACTION_LABEL_ARTIFACT_SHORTCUT_KEY)) + self.insertAction(self._actions['pan'], self.action_Label_Artifact) + + self._actions['pan'].setShortcut(QCoreApplication.translate( + "MainWindow", + ConfigParams.ACTION_PAN_SHORTCUT_KEY)) + self._actions['zoom'].setShortcut(QCoreApplication.translate( + "MainWindow", + ConfigParams.ACTION_ZOOM_SHORTCUT_KEY)) + + # 用于存储事件连接ID + self.cid_mouse_press = None + self.cid_mouse_release = None + self.cid_mouse_hold = None + + # 初始化矩形选择区域 + self.rect_start_x = None + self.rect_end_x = None + self.rect_patch_ax0 = None # 用于绘制矩形的patch + self.rect_patch_ax1 = None # 用于绘制矩形的patch + + def home(self, *args): + pass + + def zoom(self, *args): + super().zoom(*args) + self.deactivate_figToorbar_label_artifact() + + def pan(self, *args): + super().pan(*args) + self.deactivate_figToorbar_label_artifact() + + def deactivate_figToorbar_label_artifact(self): + if self.action_Label_Artifact.isChecked(): + self.action_Label_Artifact.setChecked(False) + if self.cid_mouse_press is not None: + self.canvas.mpl_disconnect(self.cid_mouse_press) + self.cid_mouse_press = None + if self.cid_mouse_release is not None: + self.canvas.mpl_disconnect(self.cid_mouse_release) + self.cid_mouse_release = None \ No newline at end of file diff --git a/func/Module_mainwindow.py b/func/Module_mainwindow.py index 3fe6963..f6ba025 100644 --- a/func/Module_mainwindow.py +++ b/func/Module_mainwindow.py @@ -14,6 +14,7 @@ from func.Module_detect_Rpeak import MainWindow_detect_Rpeak from func.Module_label_check import MainWindow_label_check from func.Module_precisely_align import MainWindow_precisely_align from func.Module_cut_PSG import MainWindow_cut_PSG +from func.Module_artifact_label import MainWindow_artifact_label from func.utils.Constants import Constants, ConfigParams @@ -50,6 +51,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.label_check = None self.precisely_align = None self.cut_PSG = None + self.artifact_label = None # 绑定槽函数 self.ui.pushButton_open.clicked.connect(self.__slot_btn_open__) @@ -62,6 +64,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.ui.pushButton_label_check_ECG.clicked.connect(self.__slot_btn_label_check__) self.ui.pushButton_precisely_align.clicked.connect(self.__slot_btn_precisely_align__) self.ui.pushButton_cut_PSG.clicked.connect(self.__slot_btn_cut_PSG__) + self.ui.pushButton_artifact_label.clicked.connect(self.__slot_btn_artifact_label__) @staticmethod def __read_config__(): @@ -181,6 +184,16 @@ class MainWindow(QMainWindow, Ui_Signal_Label): return self.cut_PSG.show(root_path, int(sampID)) + def __slot_btn_artifact_label__(self): + self.artifact_label = MainWindow_artifact_label() + root_path = self.ui.plainTextEdit_root_path.toPlainText() + sampID = self.ui.comboBox_sampID.currentText() + if not self.check_root_path(): + return + if not self.check_sampID(): + return + self.artifact_label.show(root_path, int(sampID)) + def seek_sampID(self, path): if not Path(path).exists(): PublicFunc.msgbox_output(self, Constants.MAINWINDOW_ROOT_PATH_NOT_EXIST, Constants.MSGBOX_TYPE_ERROR) diff --git a/func/utils/ConfigParams.py b/func/utils/ConfigParams.py index 1f607e5..bad17a1 100644 --- a/func/utils/ConfigParams.py +++ b/func/utils/ConfigParams.py @@ -216,31 +216,35 @@ class ConfigParams: # 体动标注 + ARTIFACT_LABEL_CONFIG_FILE_PATH: str = "./config/Config_artifact_label.yaml" + ARTIFACT_LABEL_CONFIG_NEW_CONTENT: dict = { + "InputConfig": { + "orgBcgFreq": 1000, + "BCGFreq": 1000 + }, + "CustomAutoplayArgs": { + "MoveLength": 15000, + "MaxRange": 60000, + "MoveSpeed": 1000 + } + } + ARTIFACT_LABEL_INPUT_ORGBCG_FILENAME: str = "orgBcg_Sync_" + ARTIFACT_LABEL_INPUT_BCG_FILENAME: str = "BCG_Sync_" + ARTIFACT_LABEL_SAVE_FILENAME_A: str = "Artifact_a" + ARTIFACT_LABEL_SAVE_FILENAME_B: str = "Artifact_b" + ARTIFACT_LABEL_SAVE_FILENAME_C: str = "Artifact_c" + ARTIFACT_LABEL_LABEL_TRANSPARENCY: float = 0.3 + ARTIFACT_LABEL_ACTION_LABEL_ARTIFACT_SHORTCUT_KEY: str = "Z" + + + + # TODO:弃用 # 通用 VALIDATOR_INTEGER = QIntValidator(-2**31, 2**31 - 1) VALIDATOR_DOUBLE = QDoubleValidator(-1e100, 1e100, 10) - # 体动打标 - ARTIFACT_LABEL_INPUT_BCG_FILENAME: str = "BCG_sync_" - ARTIFACT_LABEL_INPUT_XINXIAO_FILENAME: str = "orgBcg_sync_" - ARTIFACT_LABEL_SAVE_TXT_ARTIFACT_FILENAME: str = "Artifact_a" - ARTIFACT_LABEL_SAVE_TXT_ARTIFACT_AMOUNT_FILENAME: str = "Artifact_b" - ARTIFACT_LABEL_SAVE_CSV_ARTIFACT_FILENAME: str = "Artifact_c" - - ARTIFACT_LABEL_INPUT_XINXIAO_DEFAULT_FS: int = 1000 - ARTIFACT_LABEL_INPUT_BCG_DEFAULT_FS: int = 1000 - - ARTIFACT_LABEL_MOVELENGTH_DEFAULT: int = 15000 - ARTIFACT_LABEL_MAXRANGE_DEFAULT: int = 60000 - ARTIFACT_LABEL_MOVESPEED_DEFAULT: int = 1000 - - ARTIFACT_LABEL_LABEL_TRANSPARENCY: float = 0.3 - - ARTIFACT_LABEL_ACTION_LABEL_ARTIFACT_SHORTCUT_KEY: str = "Z" - - # 质量打标 BCG_QUALITY_LABEL_INPUT_BCG_FILENAME: str = "BCG_sync_" BCG_QUALITY_LABEL_INPUT_ARTIFACT_FILENAME: str = "Artifact_a" diff --git a/func/utils/Constants.py b/func/utils/Constants.py index 131175a..eae3f26 100644 --- a/func/utils/Constants.py +++ b/func/utils/Constants.py @@ -357,40 +357,45 @@ class Constants: } # 体动标注 + ARTIFACT_LABEL_LOADING_ARCHIVE: str = "正在获取历史存档" + ARTIFACT_LABEL_ARCHIVE_EXIST: str = "找到历史存档,成功读取" + ARTIFACT_LABEL_ARCHIVE_NOT_EXIST: str = "未找到历史存档,创建新存档" - # TODO:弃用 - # 体动打标 - ARTIFACT_LABEL_FILES_NOT_FOUND: str = f"无法找到{ConfigParams.ARTIFACT_LABEL_INPUT_BCG_FILENAME}{ConfigParams.ENDSWITH_TXT}或{ConfigParams.ARTIFACT_LABEL_INPUT_XINXIAO_FILENAME}{ConfigParams.ENDSWITH_TXT},无法执行<体动标注>" - ARTIFACT_LABEL_FILES_FOUND: str = f"找到{ConfigParams.ARTIFACT_LABEL_INPUT_BCG_FILENAME}{ConfigParams.ENDSWITH_TXT}和{ConfigParams.ARTIFACT_LABEL_INPUT_XINXIAO_FILENAME}{ConfigParams.ENDSWITH_TXT}" - ARTIFACT_LABEL_HISTORICAL_SAVE_FOUND: str = "找到历史存档文件,已成功读取" + ARTIFACT_LABEL_UPDATING_TABLE: str = "正在更新表格" + ARTIFACT_LABEL_UPDATING_INFO: str = "正在更新信息" + ARTIFACT_LABEL_UPDATE_FINISHED: str = "更新完成" + ARTIFACT_LABEL_UPDATE_FAILURE: str = "更新失败" - ARTIFACT_LABEL_RUNNING: str = "开始执行任务<体动标注>" - ARTIFACT_LABEL_INPUT_FAILURE_LENGTH: str = "导入失败,两个输入信号的长度不相等" - ARTIFACT_LABEL_INPUT_ARTIFACT_FAILURE_FORMAT: str = "导入体动失败,请检查体动标签格式" - ARTIFACT_LABEL_INPUT_ARTIFACT_FAILURE_LENGTH: str = "导入体动失败,请检查体动长度是否为4的倍数" - ARTIFACT_LABEL_DELETE_ARTIFACT_SUCCESSFULLY: str = "体动被删除" - ARTIFACT_LABEL_DELETE_ARTIFACT_FAILURE: str = "需要被删除的体动不存在" + ARTIFACT_LABEL_FAILURE_REASON: str = { + "Data_Path_Not_Exist": "(数据路径不存在)", + "Read_Data_Exception": "(读取数据异常)", + "File_not_Exist": "(需要处理的文件不存在)", + "Data_Length_not_Correct": "(orgBcg和BCG长度不匹配)", + "Artifact_Format_Not_Correct": "(体动长度或格式不正确)", + "Get_Artifact_Format_Exception": "(获取体动长度或格式异常)", + "Update_tableWidget_Exception": "(更新表格异常)", + "Update_Info_Exception": "(更新信息异常)", + "Save_Data_not_Exist": "(需要保存的数据不存在)", + "Save_Exception": "(保存异常)" + } + + ARTIFACT_LABEL_PLOT_LABEL_ORGBCG_SYNC: str = "orgBcg_sync" + ARTIFACT_LABEL_PLOT_LABEL_BCG_SYNC: str = "BCG_sync" + ARTIFACT_LABEL_PREV_MOVE: str = "向前移动" + ARTIFACT_LABEL_NEXT_MOVE: str = "向后移动" + ARTIFACT_LABEL_PAUSE: str = "暂停移动" + ARTIFACT_LABEL_SWITCH_PRESET_1: str = "变更为预设1" + ARTIFACT_LABEL_SWITCH_PRESET_2: str = "变更为预设2" + ARTIFACT_LABEL_SWITCH_PRESET_3: str = "变更为预设3" + ARTIFACT_LABEL_SWITCH_CUSTOM: str = "变更为自定义,请注意,自定义的参数未经校验,过大或过小的参数可能导致程序异常" ARTIFACT_LABEL_JUMP_ARTIFACT: str = "跳转到体动" + ARTIFACT_LABEL_RECOVER_SCALE: str = "尺度恢复" ARTIFACT_LABEL_MISS_ARGS: str = "打标参数未填写" ARTIFACT_LABEL_OVERLAPPING: str = "当前所打标的片段存在重合,重合片段序号:" - ARTIFACT_LABEL_COLUMN_ORGBCG_SYNC: str = "orgBcg_sync" - ARTIFACT_LABEL_COLUMN_BCG_SYNC: str = "BCG_sync" - ARTIFACT_LABEL_AUTOPLAY_LEFT: str = "LEFT" - ARTIFACT_LABEL_AUTOPLAY_PAUSE: str = "PAUSE" - ARTIFACT_LABEL_AUTOPLAY_RIGHT: str = "RIGHT" - ARTIFACT_LABEL_AUTOPLAY_LEFT_INFO: str = "开始自动播放-向左" - ARTIFACT_LABEL_AUTOPLAY_PAUSE_INFO: str = "暂停自动播放" - ARTIFACT_LABEL_AUTOPLAY_RIGHT_INFO: str = "开始自动播放-向右" - ARTIFACT_LABEL_RECOVER_SCALE: str = "尺度恢复" - ARTIFACT_LABEL_BUTTON_PRESS_EVENT: str = "button_press_event" - ARTIFACT_LABEL_BUTTON_RELEASE_EVENT: str = "button_release_event" - ARTIFACT_LABEL_MOTION_NOTIFY_EVENT: str = "motion_notify_event" - ARTIFACT_LABEL_AUTOPLAY_PRESET1_INFO: str = "切换到自动播放-预设1" - ARTIFACT_LABEL_AUTOPLAY_PRESET2_INFO: str = "切换到自动播放-预设2" - ARTIFACT_LABEL_AUTOPLAY_PRESET3_INFO: str = "切换到自动播放-预设3" - ARTIFACT_LABEL_AUTOPLAY_PRESET_CUSTOM_INFO: str = "切换到自动播放-自定义" - ARTIFACT_LABEL_CUSTOM_NAVIGATIONTOOLBAR_WIDGET_NAME: str = "MainWindow" - ARTIFACT_LABEL_ACTION_LABEL_ARTIFACT_NAME: str = f"标注体动({ConfigParams.ARTIFACT_LABEL_ACTION_LABEL_ARTIFACT_SHORTCUT_KEY})" + ARTIFACT_LABEL_DELETE_ARTIFACT_SUCCESSFULLY: str = "体动被删除" + ARTIFACT_LABEL_DELETE_ARTIFACT_FAILURE: str = "需要被删除的体动不存在" + ARTIFACT_LABEL_ACTION_LABEL: str = f"标注体动({ConfigParams.ARTIFACT_LABEL_ACTION_LABEL_ARTIFACT_SHORTCUT_KEY})" + ARTIFACT_LABEL_LABELBTN_STYLE_1: str = """ QPushButton { background-color: #ffa500; /* 设置背景颜色 */ @@ -443,6 +448,12 @@ class Constants: }""" + + + + + + # TODO:弃用 # 质量打标 BCG_QUALITY_LABEL_FILES_NOT_FOUND: str = f"无法找到{ConfigParams.BCG_QUALITY_LABEL_INPUT_BCG_FILENAME}{ConfigParams.ENDSWITH_TXT}或{ConfigParams.BCG_QUALITY_LABEL_INPUT_ARTIFACT_FILENAME}{ConfigParams.ENDSWITH_TXT},无法执行" BCG_QUALITY_LABEL_FILES_FOUND: str = f"找到{ConfigParams.BCG_QUALITY_LABEL_INPUT_BCG_FILENAME}{ConfigParams.ENDSWITH_TXT}和{ConfigParams.BCG_QUALITY_LABEL_INPUT_ARTIFACT_FILENAME}{ConfigParams.ENDSWITH_TXT}" diff --git a/ui/MainWindow/MainWindow_artifact_label.py b/ui/MainWindow/MainWindow_artifact_label.py index b2e25ee..588cb13 100644 --- a/ui/MainWindow/MainWindow_artifact_label.py +++ b/ui/MainWindow/MainWindow_artifact_label.py @@ -389,13 +389,13 @@ class Ui_MainWindow_artifact_label(object): self.verticalLayout_2.addItem(self.verticalSpacer_3) - self.pushButton = QPushButton(self.groupBox_left) - self.pushButton.setObjectName(u"pushButton") - sizePolicy.setHeightForWidth(self.pushButton.sizePolicy().hasHeightForWidth()) - self.pushButton.setSizePolicy(sizePolicy) - self.pushButton.setFont(font1) + self.pushButton_save = QPushButton(self.groupBox_left) + self.pushButton_save.setObjectName(u"pushButton_save") + sizePolicy.setHeightForWidth(self.pushButton_save.sizePolicy().hasHeightForWidth()) + self.pushButton_save.setSizePolicy(sizePolicy) + self.pushButton_save.setFont(font1) - self.verticalLayout_2.addWidget(self.pushButton) + self.verticalLayout_2.addWidget(self.pushButton_save) self.groupBox_4 = QGroupBox(self.groupBox_left) self.groupBox_4.setObjectName(u"groupBox_4") @@ -426,6 +426,7 @@ class Ui_MainWindow_artifact_label(object): self.gridLayout_4.setObjectName(u"gridLayout_4") self.spinBox_duration_type_3 = QSpinBox(self.groupBox_right) self.spinBox_duration_type_3.setObjectName(u"spinBox_duration_type_3") + self.spinBox_duration_type_3.setEnabled(False) self.spinBox_duration_type_3.setFont(font1) self.spinBox_duration_type_3.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) self.spinBox_duration_type_3.setMaximum(1000000000) @@ -434,6 +435,7 @@ class Ui_MainWindow_artifact_label(object): self.spinBox_duration_type_4 = QSpinBox(self.groupBox_right) self.spinBox_duration_type_4.setObjectName(u"spinBox_duration_type_4") + self.spinBox_duration_type_4.setEnabled(False) self.spinBox_duration_type_4.setFont(font1) self.spinBox_duration_type_4.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) self.spinBox_duration_type_4.setMaximum(1000000000) @@ -446,6 +448,7 @@ class Ui_MainWindow_artifact_label(object): self.spinBox_duration_type_2 = QSpinBox(self.groupBox_right) self.spinBox_duration_type_2.setObjectName(u"spinBox_duration_type_2") + self.spinBox_duration_type_2.setEnabled(False) self.spinBox_duration_type_2.setFont(font1) self.spinBox_duration_type_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) self.spinBox_duration_type_2.setMaximum(1000000000) @@ -478,6 +481,7 @@ class Ui_MainWindow_artifact_label(object): self.spinBox_amount_type_3 = QSpinBox(self.groupBox_right) self.spinBox_amount_type_3.setObjectName(u"spinBox_amount_type_3") + self.spinBox_amount_type_3.setEnabled(False) self.spinBox_amount_type_3.setFont(font1) self.spinBox_amount_type_3.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) self.spinBox_amount_type_3.setMaximum(1000000000) @@ -486,6 +490,7 @@ class Ui_MainWindow_artifact_label(object): self.spinBox_duration_type_5 = QSpinBox(self.groupBox_right) self.spinBox_duration_type_5.setObjectName(u"spinBox_duration_type_5") + self.spinBox_duration_type_5.setEnabled(False) self.spinBox_duration_type_5.setFont(font1) self.spinBox_duration_type_5.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) self.spinBox_duration_type_5.setMaximum(1000000000) @@ -494,6 +499,7 @@ class Ui_MainWindow_artifact_label(object): self.spinBox_amount_type_1 = QSpinBox(self.groupBox_right) self.spinBox_amount_type_1.setObjectName(u"spinBox_amount_type_1") + self.spinBox_amount_type_1.setEnabled(False) self.spinBox_amount_type_1.setFont(font1) self.spinBox_amount_type_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) self.spinBox_amount_type_1.setMaximum(1000000000) @@ -547,6 +553,7 @@ class Ui_MainWindow_artifact_label(object): self.spinBox_amount_type_2 = QSpinBox(self.groupBox_right) self.spinBox_amount_type_2.setObjectName(u"spinBox_amount_type_2") + self.spinBox_amount_type_2.setEnabled(False) self.spinBox_amount_type_2.setFont(font1) self.spinBox_amount_type_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) self.spinBox_amount_type_2.setMaximum(1000000000) @@ -563,6 +570,7 @@ class Ui_MainWindow_artifact_label(object): self.spinBox_amount_type_4 = QSpinBox(self.groupBox_right) self.spinBox_amount_type_4.setObjectName(u"spinBox_amount_type_4") + self.spinBox_amount_type_4.setEnabled(False) self.spinBox_amount_type_4.setFont(font1) self.spinBox_amount_type_4.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) self.spinBox_amount_type_4.setMaximum(1000000000) @@ -577,6 +585,7 @@ class Ui_MainWindow_artifact_label(object): self.spinBox_duration_type_1 = QSpinBox(self.groupBox_right) self.spinBox_duration_type_1.setObjectName(u"spinBox_duration_type_1") + self.spinBox_duration_type_1.setEnabled(False) self.spinBox_duration_type_1.setFont(font1) self.spinBox_duration_type_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) self.spinBox_duration_type_1.setMaximum(1000000000) @@ -585,6 +594,7 @@ class Ui_MainWindow_artifact_label(object): self.spinBox_amount_type_5 = QSpinBox(self.groupBox_right) self.spinBox_amount_type_5.setObjectName(u"spinBox_amount_type_5") + self.spinBox_amount_type_5.setEnabled(False) self.spinBox_amount_type_5.setFont(font1) self.spinBox_amount_type_5.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) self.spinBox_amount_type_5.setMaximum(1000000000) @@ -707,7 +717,7 @@ class Ui_MainWindow_artifact_label(object): self.label_7.setText(QCoreApplication.translate("MainWindow_artifact_label", u"\u79fb\u52a8\u8ddd\u79bb", None)) self.label_6.setText(QCoreApplication.translate("MainWindow_artifact_label", u"\u6700\u5927\u8303\u56f4", None)) self.label_8.setText(QCoreApplication.translate("MainWindow_artifact_label", u"\u79fb\u52a8\u95f4\u9694(ms)", None)) - self.pushButton.setText(QCoreApplication.translate("MainWindow_artifact_label", u"\u5bfc\u51fa\u6807\u7b7e", None)) + self.pushButton_save.setText(QCoreApplication.translate("MainWindow_artifact_label", u"\u5bfc\u51fa\u6807\u7b7e", None)) self.groupBox_4.setTitle(QCoreApplication.translate("MainWindow_artifact_label", u"\u65e5\u5fd7", None)) self.groupBox_right.setTitle(QCoreApplication.translate("MainWindow_artifact_label", u"\u6807\u6ce8\u64cd\u4f5c\u548c\u4fe1\u606f", None)) self.pushButton_type_1.setText(QCoreApplication.translate("MainWindow_artifact_label", u"\u5267\u70c8\u4f53\u52a8", None)) diff --git a/ui/MainWindow/MainWindow_artifact_label.ui b/ui/MainWindow/MainWindow_artifact_label.ui index 9814a36..76ccb60 100644 --- a/ui/MainWindow/MainWindow_artifact_label.ui +++ b/ui/MainWindow/MainWindow_artifact_label.ui @@ -677,7 +677,7 @@ - + 0 @@ -722,6 +722,9 @@ + + false + 12 @@ -737,6 +740,9 @@ + + false + 12 @@ -765,6 +771,9 @@ + + false + 12 @@ -819,6 +828,9 @@ + + false + 12 @@ -834,6 +846,9 @@ + + false + 12 @@ -849,6 +864,9 @@ + + false + 12 @@ -951,6 +969,9 @@ + + false + 12 @@ -984,6 +1005,9 @@ + + false + 12 @@ -1011,6 +1035,9 @@ + + false + 12 @@ -1026,6 +1053,9 @@ + + false + 12