Compare commits

..

24 Commits

Author SHA1 Message Date
0935aefeb2 新增粗对齐重采样功能,优化相关异常处理和UI元素,更新常量定义 2026-01-22 21:46:39 +08:00
a0254d8e66 修正低通滤波器通道名称,从"0.7lowpass_resp"更改为"0.5lowpass_resp",确保一致性 2026-01-20 15:44:51 +08:00
1285789b56 优化数据处理逻辑,新增sanitize_data方法以转换NumPy类型为原生Python类型,修正数据保存格式 2025-12-28 20:11:00 +08:00
986188cf9d 优化异常处理,新增traceback打印以便于调试,调整低通滤波器参数 2025-12-27 14:02:55 +08:00
df0df6ad4f 修正remark获取逻辑,优化待讨论状态判断条件 2025-12-23 16:58:51 +08:00
ee45d1d351 优化文件路径检查逻辑,修正路径引用方式以确保文件存在性验证 2025-12-20 13:20:55 +08:00
800c68655f 优化BCG和ECG信号对齐逻辑,修正前后信号计算方式,简化剩余长度计算 2025-12-19 11:11:23 +08:00
e7583fdb8d 新增删除历史粗对齐文件功能,优化相关常量和UI组件名称 2025-12-19 10:37:53 +08:00
b11fe50419 优化文件路径配置,新增同步路径参数,增强输入文件检查逻辑 2025-12-18 21:20:43 +08:00
af59f9d257 新增OrgBCG偏移微调功能,优化粗对齐信息获取和计算逻辑,调整UI布局和组件名称 2025-12-18 21:20:35 +08:00
6c688f26cf 重构数据切割和标签映射模块,新增OrgBCG和ECG通道支持,优化文件路径和异常处理逻辑,调整UI组件名称和布局 2025-12-18 20:00:45 +08:00
860bddf0a3 优化界面布局,新增偏移量调整功能,支持x轴解绑,手动获取偏移位置,调整控件大小和字体,增强X轴同步处理逻辑 2025-12-18 10:34:48 +08:00
2166a5827c 优化X轴联动功能,增强同步处理逻辑,避免回调冲突 2025-12-17 15:45:21 +08:00
02fe64012c 优化绘图逻辑,增强X轴联动功能,调整刻度格式化 2025-12-17 15:33:24 +08:00
6845626fe9 新增偏移格式化函数,优化BCG提前模式下的X轴刻度显示 2025-12-17 15:00:05 +08:00
ea024eafbc 优化文件路径读取逻辑,增强异常处理,调整信号处理流程 2025-12-17 01:38:22 +08:00
c6161e7dd5 优化J峰和R峰的绘制逻辑,调整BCG提前模式下的峰值位置计算 2025-12-17 01:38:07 +08:00
17eb1b34be 新增更新状态按钮及其快捷键,优化用户操作体验 2025-12-17 00:24:39 +08:00
334106006e 更新界面文本,优化幅值放缩设置的描述 2025-12-16 17:00:08 +08:00
1d791320eb 新增批量大小和幅值放缩设置,优化J峰预测功能 2025-12-16 16:57:30 +08:00
cbf871ca8c 新增快捷键设置功能,优化用户操作体验 2025-12-16 15:49:26 +08:00
347fe0dbac 重构重采样函数调用,使用别名以提高代码可读性 2025-12-16 13:46:52 +08:00
7237188b7d Revert "修正重采样函数调用错误与命名错误"
This reverts commit a3f2f04219.
2025-12-16 13:45:33 +08:00
a3f2f04219 修正重采样函数调用错误与命名错误 2025-12-16 13:43:23 +08:00
20 changed files with 2109 additions and 686 deletions

View File

@ -1,3 +1,4 @@
import traceback
from gc import collect
from pathlib import Path
from traceback import format_exc
@ -128,7 +129,9 @@ class SettingWindow(QMainWindow):
self.params.update({
"Path": {
"psg_path": sync_psg_path,
"bcg_path": sync_bcg_path,
"label_path": label_path,
"Input_OrgBCG": sync_bcg_path,
"Input_Tho": sync_psg_path,
"Input_Abd": sync_psg_path,
@ -149,7 +152,7 @@ class SettingWindow(QMainWindow):
def __write_config__(self):
# 从界面写入配置
self.params["Path"]["Input_Stage"] = self.ui.plainTextEdit_file_path_input_signal_Stage().toPlainText()
self.params["Path"]["Input_Stage"] = self.ui.plainTextEdit_file_path_input_signal_Stage.toPlainText()
self.params["Path"]["Input_OrgBCG"] = self.ui.plainTextEdit_file_path_input_signal_OrgBCG.toPlainText()
self.params["Path"]["Input_Tho"] = self.ui.plainTextEdit_file_path_input_signal_Tho.toPlainText()
self.params["Path"]["Input_Abd"] = self.ui.plainTextEdit_file_path_input_signal_Abd.toPlainText()
@ -195,7 +198,8 @@ class SettingWindow(QMainWindow):
# self.ui.plainTextEdit_file_path_save_2.setPlainText(str(self.params["Path"]["Save_2"]))
def __auto_find_file__(self):
check_signal_type_list = ["Input_OrgBCG", "Input_Tho", "Input_Abd", "Input_FlowT", "Input_FlowP", "Input_SpO2", "Input_Stage"]
check_signal_type_list = ["Input_OrgBCG", "Input_Tho", "Input_Abd", "Input_FlowT", "Input_FlowP", "Input_SpO2",
"Input_Stage"]
def find_file(file_path: Path, _type, endswith):
if file_path.is_file():
@ -203,6 +207,13 @@ class SettingWindow(QMainWindow):
filename_start = getattr(Filename, f"{_type.upper()}_SYNC")
result = PublicFunc.examine_file(file_path, filename_start, endswith)
if result.status:
self.params["Path"][f"Input_{_type}"] = result.data["path"]
self.params["Config"]["InputConfig"][f"{_type}Freq"] = result.data["freq"]
else:
filename_start = filename_start.replace("Sync", "RoughCut")
result = PublicFunc.examine_file(file_path, filename_start, endswith)
if result.status:
self.params["Path"][f"Input_{_type}"] = result.data["path"]
@ -258,7 +269,7 @@ class Data:
self.channel = {
"Stage": None,
"orgdata": None,
"0.7lowpass_resp": None,
"0.5lowpass_resp": None,
"Effort Tho": None,
"Effort Abd": None,
"Flow T": None,
@ -298,9 +309,9 @@ class Data:
"Input_SA_Label", "Input_Stage"]
for file_key in check_file_list:
if (not self.config["Path"][file_key].is_file()) or (not self.config["Path"][file_key].exists()):
if (not Path(self.config["Path"][file_key]).is_file()) or (not Path(self.config["Path"][file_key]).exists()):
return Result().failure(info=Constants.INPUT_FAILURE + "\n" +
str(self.config["Path"][file_key]) +
str(self.config["Path"][file_key]) + file_key +
Constants.FAILURE_REASON["Path_Not_Exist"])
try:
@ -319,7 +330,6 @@ class Data:
self.SpO2 = read_csv(self.config["Path"]["Input_SpO2"], encoding=Params.UTF8_ENCODING,
header=None).to_numpy().reshape(-1)
if self.config["Path"]["Input_Artifact_A"].exists() and self.config["Path"]["Input_Artifact_A"].is_file():
self.Artifact = read_csv(self.config["Path"]["Input_Artifact_A"],
encoding=Params.UTF8_ENCODING,
@ -329,6 +339,7 @@ class Data:
except Exception as e:
traceback.print_exc()
return Result().failure(info=Constants.INPUT_FAILURE +
Constants.FAILURE_REASON["Open_Data_Exception"] + "\n" + format_exc())
@ -337,6 +348,7 @@ class Data:
PublicFunc.examine_artifact(self.Artifact)
self.Artifact = self.Artifact.reshape(-1, 4)
except Exception as e:
traceback.print_exc()
return Result().failure(info=Constants.INPUT_FAILURE +
Constants.FAILURE_REASON[
"Get_Artifact_Format_Exception"] + "\n" + format_exc())
@ -345,7 +357,6 @@ class Data:
"SignalSecond": int(len(self.OrgBCG) // self.config["Config"]["InputConfig"]["OrgBCGFreq"])
})
# 批量将睡眠分期按照映射转换为数字
for stage_str, stage_val in self.stage_to_value.items():
place(self.Stage, self.Stage == stage_str, stage_val)
@ -360,7 +371,6 @@ class Data:
self.SpO2 = self.SpO2[:self.config["SignalSecond"] * self.config["Config"]["InputConfig"]["SpO2Freq"]]
self.Stage = self.Stage[:self.config["SignalSecond"]]
plot_freq = self.config["Config"]["InputConfig"]["PlotFreq"]
self.event_label_origin = zeros(self.config["SignalSecond"] * plot_freq)
self.event_label_revised = zeros(self.config["SignalSecond"] * plot_freq)
@ -440,6 +450,7 @@ class Data:
self.event_index_revised[start:end] = one_data["Index"]
except Exception as e:
traceback.print_exc()
return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON[
"Label_Format_Exception"] + "\n" + format_exc())
@ -448,7 +459,10 @@ class Data:
def preprocess(self):
if self.OrgBCG is None:
return Result().failure(info=Constants.PREPROCESS_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"])
if self.Tho is None:
return Result().failure(info=Constants.PREPROCESS_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"])
if self.Abd is None:
return Result().failure(info=Constants.PREPROCESS_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"])
try:
plot_freq = self.config["Config"]["InputConfig"]["PlotFreq"]
orgbcg_freq = self.config["Config"]["InputConfig"]["OrgBCGFreq"]
@ -458,7 +472,8 @@ class Data:
'lowpass', low_cut=20, order=3)
self.lowPassResp = Butterworth_for_ECG_PreProcess(self.OrgBCG,
orgbcg_freq,
'lowpass', low_cut=0.7, order=3)
'lowpass', low_cut=0.5, order=3)
self.artifact_label = zeros(len(self.event_label_origin))
for i, artifact_type, start, end in self.Artifact:
@ -473,6 +488,7 @@ class Data:
self.artifact_label[start:end] = artifact_type
except Exception as e:
traceback.print_exc()
return Result().failure(info=Constants.PREPROCESS_FAILURE +
Constants.FAILURE_REASON["Preprocess_Exception"] + "\n" + format_exc())
@ -508,7 +524,7 @@ class Data:
self.Stage_Resampled = _resample_signal(self.Stage, 1, plot_freq)
self.channel["orgdata"] = self.lowPass20Hz_Resampled
self.channel["0.7lowpass_resp"] = self.lowPassResp_Resampled
self.channel["0.5lowpass_resp"] = self.lowPassResp_Resampled
self.channel["Effort Tho"] = self.Tho_Resampled
self.channel["Effort Abd"] = self.Abd_Resampled
self.channel["Flow T"] = self.FlowT_Resampled
@ -526,6 +542,7 @@ class Data:
del self.Stage
except Exception as e:
traceback.print_exc()
return Result().failure(info=Constants.RESAMPLE_FAILURE +
Constants.FAILURE_REASON["Resample_Exception"] + "\n" + format_exc())
@ -538,10 +555,13 @@ class Data:
try:
self.df_revised.to_csv(self.config["Path"]["SA_Label_Revised"], mode='w', index=None, encoding="gbk")
except PermissionError as e:
traceback.print_exc()
return Result().failure(info=Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Save_Permission_Denied"])
except FileNotFoundError as e:
traceback.print_exc()
return Result().failure(info=Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Save_File_Not_Found"])
except Exception as e:
traceback.print_exc()
return Result().failure(info=Constants.SAVE_FAILURE +
Constants.FAILURE_REASON["Save_Exception"] + "\n" + format_exc())
@ -589,9 +609,9 @@ class DataFrameModel(QAbstractTableModel):
# remark 返回蓝色 score 1 返回绿色, 2返回橙色 3返回灰色 -1返回红色
# 获取此行的remark
remark = not self._dataframe[self._dataframe["Index"] == event_index]["remark"].values[0]
remark = self._dataframe[self._dataframe["Index"] == event_index]["remark"].values[0]
score = self._dataframe[self._dataframe["Index"] == event_index]["score"].values[0]
if str(remark).startswith("待讨论"):
if "待讨论" in str(remark):
return QColor(0, 0, 255)
elif score == 1:
return QColor(0, 255, 0)
@ -606,6 +626,7 @@ class DataFrameModel(QAbstractTableModel):
return QColor(0, 0, 0)
except Exception as e:
traceback.print_exc()
return None
return None
@ -799,7 +820,7 @@ class MainWindow_SA_label(QMainWindow):
"Flow P": self.ax2,
"Effort Tho": self.ax3,
"Effort Abd": self.ax4,
"0.7lowpass_resp": self.ax5,
"0.5lowpass_resp": self.ax5,
"orgdata": self.ax6,
"Stage": self.ax7,
}
@ -811,7 +832,7 @@ class MainWindow_SA_label(QMainWindow):
"Flow P": self.ui.checkBox_best_flow,
"Effort Tho": self.ui.checkBox_best_effort,
"Effort Abd": self.ui.checkBox_best_effort,
"0.7lowpass_resp": self.ui.checkBox_best_resp,
"0.5lowpass_resp": self.ui.checkBox_best_resp,
"orgdata": self.ui.checkBox_best_raw,
}
@ -863,8 +884,10 @@ class MainWindow_SA_label(QMainWindow):
self.ui.pushButton_confirmLabel.clicked.connect(self.__slot_btn_confirmLabel__)
self.ui.pushButton_reset_event.clicked.connect(self.__reset_event__)
self.ui.pushButton_next_half.setProperty("offset", int(self.ui.comboBox_window_signal_length.lineEdit().text()) // 2)
self.ui.pushButton_previous_half.setProperty("offset", -int(self.ui.comboBox_window_signal_length.lineEdit().text()) // 2)
self.ui.pushButton_next_half.setProperty("offset",
int(self.ui.comboBox_window_signal_length.lineEdit().text()) // 2)
self.ui.pushButton_previous_half.setProperty("offset",
-int(self.ui.comboBox_window_signal_length.lineEdit().text()) // 2)
# 输入防抖
self.debounce_timer1 = QTimer()
@ -944,6 +967,7 @@ class MainWindow_SA_label(QMainWindow):
self.set_tableview_column_width_by_ratio(self.ui.tableView_label_revised, [1, 3, 1, 2, 2])
except Exception as e:
traceback.print_exc()
return Result().failure(info=Constants.UPDATE_FAILURE +
Constants.FAILURE_REASON["Update_tableWidget_Exception"] + "\n" + format_exc())
@ -965,8 +989,6 @@ class MainWindow_SA_label(QMainWindow):
not self.channel_to_best_fit_checkbox[channel].isChecked()):
continue
signal_max = self.data.channel[channel][start_point: end_point].max()
signal_min = self.data.channel[channel][start_point: end_point].min()
if channel == "SpO2":
@ -1370,6 +1392,7 @@ class MainWindow_SA_label(QMainWindow):
self.data.df_revised = self.data.df_revised[~mask].reset_index(drop=True)
self.data.df_revised.to_csv(self.config["Path"]["SA_Label_Revised"], index=False, encoding="gbk")
except Exception as e:
traceback.print_exc()
return Result().failure(info=Constants.SAVE_FAILURE +
Constants.FAILURE_REASON["Save_revised_csv_Exception"] + "\n" + format_exc())
return Result().success(info=Constants.SAVE_FINISHED)
@ -2000,8 +2023,8 @@ class MainWindow_SA_label(QMainWindow):
label_list=self.data.event_label_origin, event_code=[1, 2, 3, 4])
self.plt_channel(channel="Effort Abd", start=0, end=self.config["SignalSecond"],
label_list=self.data.event_label_origin, event_code=[1, 2, 3, 4])
self.plt_channel(channel="0.7lowpass_resp", start=0, end=self.config["SignalSecond"])
self.plt_interactive_event(channel="0.7lowpass_resp", label_df=self.data.df_revised)
self.plt_channel(channel="0.5lowpass_resp", start=0, end=self.config["SignalSecond"])
self.plt_interactive_event(channel="0.5lowpass_resp", label_df=self.data.df_revised)
self.plt_channel(channel="orgdata", start=0, end=self.config["SignalSecond"],
label_list=self.data.artifact_label, event_code=[6, 7, 8, 9, 10])
self.plt_channel(channel="Stage", start=0, end=self.config["SignalSecond"])
@ -2009,6 +2032,7 @@ class MainWindow_SA_label(QMainWindow):
self.ax0.set_xlim(self.check_start_end(self.config["WindowStartSecond"], 0))
self.canvas.draw()
except Exception as e:
traceback.print_exc()
return Result().failure(info=Constants.DRAW_FAILURE + "\n" + format_exc())
return Result().success(info=Constants.DRAW_FINISHED)

View File

@ -1472,7 +1472,14 @@ class Data:
theilsen = TheilSenRegressor()
theilsen.fit(X, y)
slope = theilsen.coef_[0]
frequency = 1 - slope / epoch_second / temp_freq if slope != 0 else float('inf')
# frequency = 1 - slope / epoch_second / temp_freq if slope != 0 else float('inf')
if slope != 0:
drift_rate = slope / epoch_second
# frequency = temp_freq * (1 - drift_rate)
frequency = 1 - drift_rate
else:
# frequency = float(temp_freq)
frequency = 1
theilsen_y = theilsen.predict(X)

View File

@ -1,358 +0,0 @@
from ast import literal_eval
from gc import collect
from math import floor
from pathlib import Path
from traceback import format_exc
from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication
from numpy import array
from overrides import overrides
from pandas import read_csv, DataFrame
from yaml import dump, load, FullLoader
from func.utils.ConfigParams import Filename, Params
from func.utils.PublicFunc import PublicFunc
from func.utils.Constants import Constants
from func.utils.Result import Result
from ui.MainWindow.MainWindow_cut_PSG import Ui_MainWindow_cut_PSG
Config = {
}
ButtonState = {
"Default": {
"pushButton_execute": True
},
"Current": {
"pushButton_execute": True
}
}
class MainWindow_cut_PSG(QMainWindow):
def __init__(self):
super(MainWindow_cut_PSG, self).__init__()
self.ui = Ui_MainWindow_cut_PSG()
self.ui.setupUi(self)
self.root_path = None
self.sampID = None
self.__read_config__()
self.data = None
self.ui.textBrowser_info.setStyleSheet("QTextBrowser { background-color: rgb(255, 255, 200); }")
PublicFunc.__styleAllButton__(self, ButtonState)
# 初始化进度条
self.ui.progressbar.setStyleSheet(Constants.PROGRESSBAR_STYLE)
self.progressbar = self.ui.progressbar
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
PublicFunc.__resetAllButton__(self, ButtonState)
Config.update({
"Path": {
"InputFolder": str(Path(self.root_path) / Filename.PATH_PSG_TEXT / Path(str(self.sampID))),
"SaveFolder": str(Path(self.root_path) / Filename.PATH_PSG_ALIGNED / Path(str(self.sampID))),
"InputAlignInfo": str(Path(self.root_path) / Filename.PATH_LABEL / Path(str(self.sampID)))
}
})
self.ui.plainTextEdit_channel.setPlainText(', '.join(Config["ChannelInput"].keys()))
self.ui.plainTextEdit_label.setPlainText(', '.join(Config["LabelInput"].keys()))
self.ui.pushButton_execute.clicked.connect(self.__slot_btn_execute__)
@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.data
self.deleteLater()
collect()
event.accept()
else:
event.ignore()
def __reset__(self):
ButtonState["Current"].update(ButtonState["Default"].copy())
def __read_config__(self):
if not Path(Params.CUT_PSG_CONFIG_FILE_PATH).exists():
with open(Params.CUT_PSG_CONFIG_FILE_PATH, "w") as f:
dump(Params.CUT_PSG_CONFIG_NEW_CONTENT, f)
with open(Params.CUT_PSG_CONFIG_FILE_PATH, "r") as f:
file_config = load(f.read(), Loader=FullLoader)
Config.update(file_config)
# 数据回显
self.ui.spinBox_ECGFreq.setValue(Config["ECGFreq"])
def __slot_btn_execute__(self):
PublicFunc.__disableAllButton__(self, ButtonState)
self.data = Data(self.root_path, self.sampID)
Config["ECGFreq"] = self.ui.spinBox_ECGFreq.value()
# 检查文件是否存在并获取其数据采样率
PublicFunc.progressbar_update(self, 1, 5, Constants.CUT_PSG_GETTING_FILE_AND_FREQ, 0)
result = self.data.get_file_and_freq()
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.finish_operation(self, ButtonState)
# 导入数据
PublicFunc.progressbar_update(self, 2, 5, Constants.INPUTTING_DATA, 10)
result = self.data.open_file()
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.finish_operation(self, ButtonState)
# 切割数据
PublicFunc.progressbar_update(self, 3, 5, Constants.CUT_PSG_CUTTING_DATA, 40)
result = self.data.cut_data()
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.finish_operation(self, ButtonState)
# 标签映射
PublicFunc.progressbar_update(self, 4, 5, Constants.CUT_PSG_ALIGNING_LABEL, 60)
result = self.data.align_label()
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.finish_operation(self, ButtonState)
# 保存数据
PublicFunc.progressbar_update(self, 5, 5, Constants.SAVING_DATA, 70)
result = self.data.save()
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)
for key, raw in self.data.raw.items():
info = "保存{}的长度为{},采样率为{}Hz".format(key, str(len(raw)), str(self.data.freq[key]))
PublicFunc.text_output(self.ui, info, Constants.TIPS_TYPE_INFO)
QApplication.processEvents()
PublicFunc.msgbox_output(self, result.info, Constants.TIPS_TYPE_INFO)
PublicFunc.finish_operation(self, ButtonState)
class Data:
def __init__(self, root_path, sampID):
self.alignInfo = None
self.raw = {key: array([]) for key in Config["ChannelInput"]}
self.freq = {key: 0 for key in Config["ChannelInput"]}
self.SALabel = None
self.startTime = None
self.root_path = root_path
self.sampID = sampID
def get_file_and_freq(self):
try:
for file_path in Path(Config["Path"]["InputFolder"]).glob('*'):
if file_path.is_file():
file_stem = Path(file_path).stem
for key, prefix in Config["ChannelInput"].items():
if file_stem.startswith(prefix):
freq_str = file_stem.rsplit('_', 1)[1]
try:
freq = int(freq_str)
self.freq[key] = freq
except ValueError:
return Result().failure(info=Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE +
Constants.FAILURE_REASON["Filename_Format_not_Correct"] + f"\n{Config['ChannelInput']}")
for value in self.freq.values():
if value == 0:
return Result().failure(info=Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE +
Constants.FAILURE_REASON["Filename_Format_not_Correct"] + f"\n{Config['ChannelInput']}")
if not any((Config["LabelInput"]["SA Label"] + Config["EndWith"]["SA Label"]) in str(file) for file in Path(Config["Path"]["InputFolder"]).glob('*')):
return Result().failure(info=Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE +
Constants.FAILURE_REASON["File_Not_Exist"])
if not any((Config["StartTime"] + Config["EndWith"]["StartTime"]) in str(file) for file in Path(Config["Path"]["InputFolder"]).glob('*')):
return Result().failure(info=Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE +
Constants.FAILURE_REASON["File_Not_Exist"])
if not Path(Config["Path"]["InputAlignInfo"]).exists():
return Result().failure(info=Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE +
Constants.FAILURE_REASON["File_Not_Exist"])
except Exception as e:
return Result().failure(info=Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE +
Constants.FAILURE_REASON["Get_File_and_Freq_Excepetion"] + "\n" + format_exc())
return Result().success(info=Constants.CUT_PSG_GET_FILE_AND_FREQ_FINISHED)
def open_file(self):
path = str(Path(self.root_path) / Filename.PATH_PSG_TEXT / Path(str(self.sampID)))
for value in Config["ChannelInput"].values():
result = PublicFunc.examine_file(path, value, Params.ENDSWITH_TXT)
if not result.status:
return result
if Path(Config["Path"]["InputAlignInfo"]).is_file():
Config["Path"]["InputAlignInfo"] = str(Path(Config["Path"]["InputAlignInfo"]).parent)
Config["Path"]["InputAlignInfo"] = str(
Path(Config["Path"]["InputAlignInfo"]) / Path(
Filename.PRECISELY_ALIGN_INFO + Params.ENDSWITH_TXT))
try:
for key in Config["ChannelInput"].keys():
self.raw[key] = read_csv(Path(Config["Path"]["InputFolder"]) / Path((Config["ChannelInput"][key] + str(self.freq[key]) + Config["EndWith"][key])),
encoding=Params.UTF8_ENCODING,
header=None).to_numpy().reshape(-1)
self.SALabel = read_csv(Path(Config["Path"]["InputFolder"]) / Path((Config["LabelInput"]["SA Label"] + Config["EndWith"]["SA Label"])),
encoding=Params.GBK_ENCODING)
self.startTime = read_csv(Path(Config["Path"]["InputFolder"]) / Path((Config["StartTime"] + Config["EndWith"]["StartTime"])),
encoding=Params.UTF8_ENCODING,
header=None).to_numpy().reshape(-1)
self.alignInfo = read_csv(Path(Config["Path"]["InputAlignInfo"]),
encoding=Params.UTF8_ENCODING,
header=None).to_numpy().reshape(-1)
self.alignInfo = literal_eval(self.alignInfo[0])
except Exception as e:
return Result().failure(info=Constants.INPUT_FAILURE +
Constants.FAILURE_REASON["Open_Data_Exception"] + "\n" + format_exc())
return Result().success(info=Constants.INPUT_FINISHED)
def cut_data(self):
try:
for key, raw in self.raw.items():
# 转换切割点
ECG_freq = Config["ECGFreq"]
raw_freq = self.freq[key]
duration_second = ((self.alignInfo["cut_index"]["back_ECG"] - self.alignInfo["cut_index"]["front_ECG"]) // ECG_freq) + 1
start_index_cut = floor(self.alignInfo["cut_index"]["front_ECG"] * (raw_freq / ECG_freq))
end_index_cut = start_index_cut + (duration_second * raw_freq)
try:
# 切割信号
self.raw[key] = self.raw[key][start_index_cut:end_index_cut]
except Exception:
return Result().failure(info=Constants.CUT_PSG_CUT_DATA_FAILURE +
Constants.FAILURE_REASON["Cut_Data_Length_not_Correct"])
except Exception as e:
return Result().failure(info=Constants.CUT_PSG_CUT_DATA_FAILURE +
Constants.FAILURE_REASON["Cut_Data_Exception"] + "\n" + format_exc())
return Result().success(info=Constants.CUT_PSG_CUT_DATA_FINISHED)
def align_label(self):
try:
# 读取SA标签
self.SALabel = self.SALabel.loc[:, ~self.SALabel.columns.str.contains("^Unnamed")]
self.SALabel = self.SALabel[self.SALabel["Event type"].isin(Params.CUT_PSG_SALABEL_EVENT)]
self.SALabel["Duration"] = self.SALabel["Duration"].astype(str)
self.SALabel["Duration"] = self.SALabel["Duration"].str.replace(r' \(.*?\)', '', regex=True)
except Exception:
return Result().failure(info=Constants.CUT_PSG_ALIGN_LABEL_FAILURE +
Constants.FAILURE_REASON["Align_Label_SALabel_Format_not_Correct"])
try:
# 获取记录开始时间
start_time = str(self.startTime[0]).split(" ")[1]
start_time = Data.get_time_to_seconds(start_time)
# 计算起始时间秒数和终止时间秒数
self.SALabel["Start"] = (self.SALabel["Time"].apply(self.get_time_to_seconds) - start_time).apply(
lambda x: x + 24 * 3600 if x < 0 else x).astype(int)
self.SALabel["End"] = self.SALabel["Start"] + self.SALabel["Duration"].astype(float).round(0).astype(int)
# 标签映射
ECG_length = self.alignInfo["cut_index"]["back_ECG"] - self.alignInfo["cut_index"]["front_ECG"]
self.SALabel["Start"] = self.SALabel["Start"] - round((self.alignInfo["cut_index"]["front_ECG"] / 1000))
self.SALabel["End"] = self.SALabel["End"] - round((self.alignInfo["cut_index"]["front_ECG"] / 1000))
self.SALabel = self.SALabel[self.SALabel["End"] >= 0]
self.SALabel.loc[self.SALabel["Start"] < 0, "Start"] = 0
self.SALabel = self.SALabel[self.SALabel["Start"] < ECG_length]
self.SALabel.loc[self.SALabel["End"] >= ECG_length, "End"] = ECG_length - 1
except Exception as e:
return Result().failure(info=Constants.CUT_PSG_ALIGN_LABEL_FAILURE +
Constants.FAILURE_REASON["Align_Label_Exception"] + "\n" + format_exc())
return Result().success(info=Constants.CUT_PSG_ALIGN_LABEL_FINISHED)
def save(self):
for raw in self.raw.values():
if len(raw) == 0:
return Result().failure(info=Constants.SAVE_FAILURE +
Constants.FAILURE_REASON["Data_not_Exist"])
try:
for key, raw in self.raw.items():
DataFrame(raw.reshape(-1)).to_csv(Path(Config["Path"]["SaveFolder"]) / Path((Config["ChannelSave"][key] + str(self.freq[key]) + Config["EndWith"][key])),
index=False, header=False)
# 重排index从1开始并给index命名
self.SALabel.sort_values(by=["Start"], inplace=True)
self.SALabel.reset_index(drop=True, inplace=True)
self.SALabel.index = self.SALabel.index + 1
self.SALabel.index.name = "Index"
self.SALabel.to_csv(Path(Config["Path"]["SaveFolder"]) / Path((Config["LabelSave"]["SA Label"] + Config["EndWith"]["SA Label"])),
encoding="gbk")
except PermissionError as e:
return Result().failure(info=Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Save_Permission_Denied"])
except FileNotFoundError as e:
return Result().failure(info=Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Save_File_Not_Found"])
except Exception as e:
return Result().failure(info=Constants.SAVE_FAILURE +
Constants.FAILURE_REASON["Save_Exception"] + "\n" + format_exc())
return Result().success(info=Constants.SAVE_FINISHED)
@staticmethod
def get_time_to_seconds(time_str):
h, m, s = map(int, time_str.split(":"))
return h * 3600 + m * 60 + s

View File

@ -0,0 +1,656 @@
import re
import traceback
from ast import literal_eval
from gc import collect
from math import floor, ceil
from pathlib import Path
from traceback import format_exc
import soxr
from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication
from numpy import array
from overrides import overrides
from pandas import read_csv, DataFrame
from yaml import dump, load, FullLoader
import numpy as np
from func.utils.ConfigParams import Filename, Params
from func.utils.PublicFunc import PublicFunc
from func.utils.Constants import Constants
from func.utils.Result import Result
from numpy import float32
from ui.MainWindow.MainWindow_cut_PAIR_FILE import Ui_MainWindow_cut_PAIR_FILE
Config = {
}
ButtonState = {
"Default": {
"checkBox_roughCut": True,
"checkBox_roughResample": False,
"pushButton_deleteRoughCut": False,
"pushButton_execute": True,
"spinBox_OrgBCGShift": False
},
"Current": {
"checkBox_roughCut": True,
"checkBox_roughResample": False,
"pushButton_deleteRoughCut": False,
"pushButton_execute": True,
"spinBox_OrgBCGShift": False
}
}
class MainWindow_cut_PAIR_FILE(QMainWindow):
def __init__(self):
super(MainWindow_cut_PAIR_FILE, self).__init__()
self.ui = Ui_MainWindow_cut_PAIR_FILE()
self.ui.setupUi(self)
self.root_path = None
self.sampID = None
self.__read_config__()
self.data = None
self.ui.textBrowser_info.setStyleSheet("QTextBrowser { background-color: rgb(255, 255, 200); }")
PublicFunc.__styleAllButton__(self, ButtonState)
# 初始化进度条
self.ui.progressbar.setStyleSheet(Constants.PROGRESSBAR_STYLE)
self.progressbar = self.ui.progressbar
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
PublicFunc.__resetAllButton__(self, ButtonState)
Config.update({
"Path": {
"InputPSGFolder": str(Path(self.root_path) / Filename.PATH_PSG_TEXT / Path(str(self.sampID))),
"SavePSGFolder": str(Path(self.root_path) / Filename.PATH_PSG_ALIGNED / Path(str(self.sampID))),
"InputAlignInfo": str(Path(self.root_path) / Filename.PATH_LABEL / Path(str(self.sampID))),
"InputOrgBCGFolder": str(Path(self.root_path) / Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID))),
"SaveOrgBCGFolder": str(Path(self.root_path) / Filename.PATH_ORGBCG_ALIGNED / Path(str(self.sampID)))
}
})
self.ui.plainTextEdit_channel.setPlainText(', '.join(Config["ChannelInput"].keys()))
self.ui.plainTextEdit_label.setPlainText(', '.join(Config["LabelInput"].keys()))
self.ui.pushButton_execute.clicked.connect(self.__slot_btn_execute__)
self.ui.checkBox_roughCut.stateChanged.connect(self.__change_approximate_align_mode__)
self.ui.pushButton_deleteRoughCut.clicked.connect(self.__delete_rough_cut_file__)
self.ui.spinBox_OrgBCGShift.setEnabled(False)
@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.data
self.deleteLater()
collect()
event.accept()
else:
event.ignore()
def __reset__(self):
ButtonState["Current"].update(ButtonState["Default"].copy())
def __read_config__(self):
if not Path(Params.CUT_PAIR_FILE_CONFIG_FILE_PATH).exists():
with open(Params.CUT_PAIR_FILE_CONFIG_FILE_PATH, "w") as f:
dump(Params.CUT_PAIR_FILE_CONFIG_NEW_CONTENT, f)
with open(Params.CUT_PAIR_FILE_CONFIG_FILE_PATH, "r") as f:
file_config = load(f.read(), Loader=FullLoader)
Config.update(file_config)
# 数据回显
self.ui.spinBox_ECGFreq.setValue(Config["ECGFreq"])
def __change_approximate_align_mode__(self):
# ChannelInput 添加OrgBCGCHannelInput
if self.ui.checkBox_roughCut.isChecked():
Config["ChannelInput"].update(Config["OrgBCGChannelInput"])
Config["ChannelInput"].update(Config["ECGChannelInput"])
# 修改ChannelSave中的Sync为RoughCut
for key in Config["ChannelSave"].keys():
if "Sync" in Config["ChannelSave"][key]:
Config["ChannelSave"][key] = Config["ChannelSave"][key].replace("Sync", "RoughCut")
ButtonState["Default"]["pushButton_deleteRoughCut"] = True
ButtonState["Default"]["checkBox_roughResample"] = True
self.ui.plainTextEdit_channel.setPlainText(', '.join(Config["ChannelInput"].keys()))
self.ui.spinBox_OrgBCGShift.setEnabled(True)
ButtonState["Current"]["pushButton_deleteRoughCut"] = True
ButtonState["Current"]["checkBox_roughResample"] = True
PublicFunc.finish_operation(self, ButtonState)
else:
# ChannelInput 移除OrgBCGCHannelInput
for key in Config["OrgBCGChannelInput"].keys():
if key in Config["ChannelInput"]:
Config["ChannelInput"].pop(key)
for key in Config["ECGChannelInput"].keys():
if key in Config["ChannelInput"]:
Config["ChannelInput"].pop(key)
# print(Config["ChannelInput"])
# 修改ChannelSave中的RoughCut为Sync
for key in Config["ChannelSave"].keys():
if "RoughCut" in Config["ChannelSave"][key]:
Config["ChannelSave"][key] = Config["ChannelSave"][key].replace("RoughCut", "Sync")
ButtonState["Default"]["pushButton_deleteRoughCut"] = False
ButtonState["Default"]["checkBox_roughResample"] = False
self.ui.plainTextEdit_channel.setPlainText(', '.join(Config["ChannelInput"].keys()))
self.ui.spinBox_OrgBCGShift.setEnabled(False)
ButtonState["Current"]["pushButton_deleteRoughCut"] = False
ButtonState["Current"]["checkBox_roughResample"] = False
PublicFunc.finish_operation(self, ButtonState)
def __slot_btn_execute__(self):
PublicFunc.__disableAllButton__(self, ButtonState)
self.data = Data(self.root_path, self.sampID)
Config["ECGFreq"] = self.ui.spinBox_ECGFreq.value()
# 检查文件是否存在并获取其数据采样率
PublicFunc.progressbar_update(self, 1, 5, Constants.CUT_PAIR_FILE_GETTING_FILE_AND_FREQ, 0)
result = self.data.get_file_and_freq()
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:
if self.ui.checkBox_roughCut.isChecked():
Config["BCGFreq"] = self.data.freq["OrgBCG"]
Config["ECGFreq"] = self.data.freq["ECG"]
PublicFunc.text_output(self.ui, "(1/5)" + result.info, Constants.TIPS_TYPE_INFO)
PublicFunc.finish_operation(self, ButtonState)
# 导入数据
PublicFunc.progressbar_update(self, 2, 5, Constants.INPUTTING_DATA, 10)
result = self.data.open_file()
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.finish_operation(self, ButtonState)
if self.ui.checkBox_roughCut.isChecked():
# 获取或计算粗对齐信息
PublicFunc.progressbar_update(self, 3, 5, Constants.CUT_PAIR_FILE_GETTING_APPROXIMATE_ALIGN_INFO, 20)
result_approximate = self.data.get_approximately_align_info()
if not result_approximate:
PublicFunc.msgbox_output(self, Constants.CUT_PAIR_FILE_GETTING_APPROXIMATE_ALIGN_INFO_FAILURE, Constants.MSGBOX_TYPE_ERROR)
PublicFunc.finish_operation(self, ButtonState)
return
else:
PublicFunc.text_output(self.ui, "(3/5)" + Constants.CUT_PAIR_FILE_GETTING_APPROXIMATE_ALIGN_INFO_FINISHED, Constants.TIPS_TYPE_INFO)
if self.ui.checkBox_roughResample.isChecked():
result_resample = self.data.resample_BCG()
if not result_resample.status:
PublicFunc.text_output(self.ui, "(3/5)" + result_resample.info, Constants.TIPS_TYPE_ERROR)
PublicFunc.msgbox_output(self, result_resample.info, Constants.MSGBOX_TYPE_ERROR)
PublicFunc.finish_operation(self, ButtonState)
return
else:
PublicFunc.text_output(self.ui, "(3/5)" + result_resample.info, Constants.TIPS_TYPE_INFO)
result_approximate = self.data.calc_approximately_align_info(int(self.ui.spinBox_OrgBCGShift.value()))
if not result_approximate.status:
PublicFunc.text_output(self.ui, "(3/5)" + result_approximate.info, Constants.TIPS_TYPE_ERROR)
PublicFunc.msgbox_output(self, result_approximate.info, Constants.MSGBOX_TYPE_ERROR)
PublicFunc.finish_operation(self, ButtonState)
return
else:
PublicFunc.text_output(self.ui, "(3/5)" + result_approximate.info, Constants.TIPS_TYPE_INFO)
PublicFunc.finish_operation(self, ButtonState)
# 切割数据
PublicFunc.progressbar_update(self, 3, 5, Constants.CUT_PAIR_FILE_CUTTING_DATA, 40)
PublicFunc.text_output(self.ui, "(3/5)" + str(self.data.alignInfo["cut_index"]), Constants.TIPS_TYPE_INFO)
result = self.data.cut_data()
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.finish_operation(self, ButtonState)
# 标签映射
PublicFunc.progressbar_update(self, 4, 5, Constants.CUT_PAIR_FILE_ALIGNING_LABEL, 60)
result = self.data.align_label()
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.finish_operation(self, ButtonState)
# 保存数据
PublicFunc.progressbar_update(self, 5, 5, Constants.SAVING_DATA, 70)
result = self.data.save()
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)
for key, raw in self.data.raw.items():
info = "保存{}的长度为{},采样率为{}Hz".format(key, str(len(raw)), str(self.data.freq[key]))
PublicFunc.text_output(self.ui, info, Constants.TIPS_TYPE_INFO)
QApplication.processEvents()
PublicFunc.msgbox_output(self, result.info, Constants.TIPS_TYPE_INFO)
PublicFunc.finish_operation(self, ButtonState)
def __delete_rough_cut_file__(self):
PublicFunc.__disableAllButton__(self, ButtonState)
self.data = Data(self.root_path, self.sampID)
# 删除粗切割文件
PublicFunc.progressbar_update(self, 1, 1, Constants.CUT_PAIR_FILE_DELETING_ROUGH_CUT_FILE, 50)
result = self.data.delete_rough_cut_file()
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.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_INFO)
PublicFunc.finish_operation(self, ButtonState)
class Data:
def __init__(self, root_path, sampID):
self.actualBCGFreq = None
self.TimeBiasSecond = None
self.alignInfo = None
self.raw = {key: array([]) for key in Config["ChannelInput"]}
self.freq = {key: 0 for key in Config["ChannelInput"]}
self.SALabel = None
self.startTime = None
self.root_path = root_path
self.sampID = sampID
def get_file_and_freq(self):
try:
for file_path in Path(Config["Path"]["InputPSGFolder"]).glob('*'):
if file_path.is_file():
file_stem = Path(file_path).stem
for key, prefix in Config["ChannelInput"].items():
if not prefix.startswith("PSG:"):
continue
prefix = prefix[len("PSG:"):]
if file_stem.startswith(prefix):
freq_str = file_stem.rsplit('_', 1)[1]
try:
freq = int(freq_str)
self.freq[key] = freq
except ValueError:
return Result().failure(info=Constants.CUT_PAIR_FILE_GET_FILE_AND_FREQ_FAILURE +
Constants.FAILURE_REASON["Filename_Format_not_Correct"] + f"\n{Config['ChannelInput']}")
for file_path in Path(Config["Path"]["InputOrgBCGFolder"]).glob('*'):
if file_path.is_file():
file_stem = Path(file_path).stem
for key, prefix in Config["ChannelInput"].items():
if not prefix.startswith("OrgBCG:"):
continue
prefix = prefix[len("OrgBCG:"):]
if file_stem.startswith(prefix):
freq_str = file_stem.rsplit('_', 1)[1]
try:
freq = int(freq_str)
self.freq[key] = freq
except ValueError:
return Result().failure(info=Constants.CUT_PAIR_FILE_GET_FILE_AND_FREQ_FAILURE +
Constants.FAILURE_REASON["Filename_Format_not_Correct"] + f"\n{Config['ChannelInput']}")
for value in self.freq.values():
if value == 0:
return Result().failure(info=Constants.CUT_PAIR_FILE_GET_FILE_AND_FREQ_FAILURE +
Constants.FAILURE_REASON["Filename_Format_not_Correct"] + f"\n{Config['ChannelInput']}")
if not any((Config["LabelInput"]["SA Label"] + Config["EndWith"]["SA Label"]) in str(file) for file in Path(Config["Path"]["InputPSGFolder"]).glob('*')):
return Result().failure(info=Constants.CUT_PAIR_FILE_GET_FILE_AND_FREQ_FAILURE +
Constants.FAILURE_REASON["File_Not_Exist"])
if not any((Config["StartTime"] + Config["EndWith"]["StartTime"]) in str(file) for file in Path(Config["Path"]["InputPSGFolder"]).glob('*')):
return Result().failure(info=Constants.CUT_PAIR_FILE_GET_FILE_AND_FREQ_FAILURE +
Constants.FAILURE_REASON["File_Not_Exist"])
if not Path(Config["Path"]["InputAlignInfo"]).exists():
return Result().failure(info=Constants.CUT_PAIR_FILE_GET_FILE_AND_FREQ_FAILURE +
Constants.FAILURE_REASON["File_Not_Exist"])
except Exception as e:
return Result().failure(info=Constants.CUT_PAIR_FILE_GET_FILE_AND_FREQ_FAILURE +
Constants.FAILURE_REASON["Get_File_and_Freq_Excepetion"] + "\n" + format_exc())
return Result().success(info=Constants.CUT_PAIR_FILE_GET_FILE_AND_FREQ_FINISHED)
def open_file(self):
psg_path = str(Path(self.root_path) / Filename.PATH_PSG_TEXT / Path(str(self.sampID)))
bcg_path = str(Path(self.root_path) / Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID)))
for value in Config["ChannelInput"].values():
if value.startswith("PSG:"):
value = value[len("PSG:"):]
result = PublicFunc.examine_file(psg_path, value, Params.ENDSWITH_TXT)
if not result.status:
return result
elif value.startswith("OrgBCG:"):
value = value[len("OrgBCG:"):]
result = PublicFunc.examine_file(bcg_path, value, Params.ENDSWITH_TXT)
if not result.status:
return result
if Path(Config["Path"]["InputAlignInfo"]).is_file():
Config["Path"]["InputAlignInfo"] = str(Path(Config["Path"]["InputAlignInfo"]).parent)
Config["Path"]["Input_Approximately_Align"] = str(
Path(Config["Path"]["InputAlignInfo"]) / Path(
Filename.APPROXIMATELY_ALIGN_INFO + Params.ENDSWITH_CSV))
Config["Path"]["InputAlignInfo"] = str(
Path(Config["Path"]["InputAlignInfo"]) / Path(
Filename.PRECISELY_ALIGN_INFO + Params.ENDSWITH_TXT))
try:
for key in Config["ChannelInput"].keys():
if not Config["ChannelInput"][key].startswith("OrgBCG"):
self.raw[key] = read_csv(Path(Config["Path"]["InputPSGFolder"]) / Path((Config["ChannelInput"][key][len("PSG:"):] + str(self.freq[key]) + Config["EndWith"][key])),
encoding=Params.UTF8_ENCODING,
header=None).to_numpy().reshape(-1)
elif Config["ChannelInput"][key].startswith("OrgBCG"):
self.raw[key] = read_csv(Path(Config["Path"]["InputOrgBCGFolder"]) / Path((Config["ChannelInput"][key][len("OrgBCG:"):] + str(self.freq[key]) + Config["EndWith"][key])),
encoding=Params.UTF8_ENCODING,
header=None).to_numpy().reshape(-1)
self.SALabel = read_csv(Path(Config["Path"]["InputPSGFolder"]) / Path((Config["LabelInput"]["SA Label"] + Config["EndWith"]["SA Label"])),
encoding=Params.GBK_ENCODING)
self.startTime = read_csv(Path(Config["Path"]["InputPSGFolder"]) / Path((Config["StartTime"] + Config["EndWith"]["StartTime"])),
encoding=Params.UTF8_ENCODING,
header=None).to_numpy().reshape(-1)
if Path(Config["Path"]["InputAlignInfo"]).exists():
self.alignInfo = read_csv(Path(Config["Path"]["InputAlignInfo"]),
encoding=Params.UTF8_ENCODING,
header=None).to_numpy().reshape(-1)
cleaned_str = re.sub(r'np\.(int64|float64|float32|int32)\((.*?)\)', r'\2', self.alignInfo[0])
self.alignInfo = literal_eval(cleaned_str)
except Exception as e:
return Result().failure(info=Constants.INPUT_FAILURE +
Constants.FAILURE_REASON["Open_Data_Exception"] + "\n" + format_exc())
return Result().success(info=Constants.INPUT_FINISHED)
def get_approximately_align_info(self):
try:
df = read_csv(Config["Path"]["Input_Approximately_Align"])
pos = df["pos"].values[-1]
ApplyFrequency = df["ApplyFrequency"].values[-1]
self.TimeBiasSecond = pos / ApplyFrequency
self.actualBCGFreq = df["estimate_freq"].values[-1] * Config["BCGFreq"]
return Result().success(info=Constants.INPUT_FINISHED)
except Exception as e:
self.TimeBiasSecond = 0
self.actualBCGFreq = Config["BCGFreq"]
traceback.print_exc()
return Result().failure(info=Constants.INPUT_FAILURE
+ Constants.FAILURE_REASON["Get_Approximately_Align_Info_Exception"]
+ "\n" + format_exc())
def resample_BCG(self):
try:
for key in self.raw.keys():
if Config["ChannelInput"][key].startswith("OrgBCG:"):
# data = self.raw[key]
# n_samples = len(data)
# duration = n_samples / self.actualBCGFreq
#
# t_old = np.linspace(0, duration, n_samples, endpoint=False)
# n_new = int(np.round(duration * Config["BCGFreq"]))
# t_new = np.linspace(0, duration, n_new, endpoint=False)
# self.raw[key] = np.interp(t_new, t_old, data)
resample_signal = soxr.resample(
x=self.raw[key].astype(np.float64),
in_rate=self.actualBCGFreq,
out_rate=Config["BCGFreq"],
quality='VHQ'
)
print(f"Resampled BCG from {self.actualBCGFreq}Hz to {Config['BCGFreq']}Hz, original length: {len(self.raw[key])}, new length: {len(resample_signal)}")
self.raw[key] = resample_signal.astype(self.raw[key].dtype)
self.TimeBiasSecond = int(self.TimeBiasSecond * (self.actualBCGFreq / Config["BCGFreq"]))
return Result().success(info=Constants.CUT_PAIR_FILE_ROUGH_RESAMPLE_BCG_FINISHED)
except Exception as e:
traceback.print_exc()
print(e)
return Result().failure(info=Constants.CUT_PAIR_FILE_ROUGH_RESAMPLE_BCG_FAILURE +
Constants.FAILURE_REASON["Resample_BCG_Exception"] + "\n" + format_exc())
def calc_approximately_align_info(self, OrgBCGShift=0):
try:
# 获取BCG长度
BCG_freq = Config["BCGFreq"]
BCG_second = len(self.raw["OrgBCG"]) // BCG_freq
# 计算ECG长度
ECG_freq = Config["ECGFreq"]
ECG_second = len(self.raw["ECG"]) // ECG_freq
pos = self.TimeBiasSecond
# 如果pos<0表示BCG信号比ECG信号提前需要在开头去除掉一部分BCG信号
if pos < 0:
front_BCG = ceil(-pos) - OrgBCGShift
front_ECG = 0
else:
front_BCG = 0
front_ECG = ceil(pos) + OrgBCGShift
# 计算剩余长度
remain_BCG_second = BCG_second - front_BCG
remain_ECG_second = ECG_second - front_ECG
remain_second = min(remain_BCG_second, remain_ECG_second)
back_BCG = front_BCG + remain_second - 1
back_ECG = front_ECG + remain_second - 1
self.alignInfo = {
"cut_index": {
"front_BCG": front_BCG * BCG_freq,
"back_BCG": back_BCG * BCG_freq,
"front_ECG": front_ECG * ECG_freq,
"back_ECG": back_ECG * ECG_freq,
}
}
return Result().success(info=Constants.CUT_PAIR_FILE_GETTING_APPROXIMATE_ALIGN_INFO_CALC_FINISHED)
except Exception as e:
traceback.print_exc()
print(e)
Result().failure(info=Constants.CUT_PAIR_FILE_GETTING_APPROXIMATE_ALIGN_INFO_FAILURE +
Constants.FAILURE_REASON["Calculate_Approximately_Align_Info_Exception"] + "\n" + format_exc())
def delete_rough_cut_file(self):
# 在保存路径中删除RoughCut文件
try:
for key in Config["ChannelInput"].keys():
if Config["ChannelInput"][key].startswith("OrgBCG:"):
file_path = Path(Config["Path"]["SaveOrgBCGFolder"]).glob(f"{Config['ChannelSave'][key][len('OrgBCG:'):]}*{Config['EndWith'][key]}")
for file in file_path:
file.unlink()
if Config["ChannelInput"][key].startswith("PSG:"):
file_path = Path(Config["Path"]["SavePSGFolder"]).glob(f"{Config['ChannelSave'][key][len('PSG:'):]}*{Config['EndWith'][key]}")
for file in file_path:
file.unlink()
return Result().success(info=Constants.CUT_PAIR_FILE_DELETE_ROUGH_CUT_FILE_FINISHED)
except Exception as e:
return Result().failure(info=Constants.CUT_PAIR_FILE_DELETE_ROUGH_CUT_FILE_FAILURE +
Constants.FAILURE_REASON["Delete_Rough_Cut_File_Exception"] + "\n" + format_exc())
def cut_data(self):
try:
for key, raw in self.raw.items():
if Config["ChannelInput"][key].startswith("PSG:"):
# 转换切割点
ECG_freq = Config["ECGFreq"]
raw_freq = self.freq[key]
duration_second = ((self.alignInfo["cut_index"]["back_ECG"] - self.alignInfo["cut_index"]["front_ECG"]) // ECG_freq) + 1
start_index_cut = floor(self.alignInfo["cut_index"]["front_ECG"] * (raw_freq / ECG_freq))
end_index_cut = start_index_cut + (duration_second * raw_freq)
try:
# 切割信号
self.raw[key] = self.raw[key][start_index_cut:end_index_cut]
except Exception:
return Result().failure(info=Constants.CUT_PAIR_FILE_CUT_DATA_FAILURE +
Constants.FAILURE_REASON["Cut_Data_Length_not_Correct"])
elif Config["ChannelInput"][key].startswith("OrgBCG:"):
# 转换切割点
BCG_freq = Config["BCGFreq"]
raw_freq = self.freq[key]
duration_second = ((self.alignInfo["cut_index"]["back_BCG"] - self.alignInfo["cut_index"]["front_BCG"]) // BCG_freq) + 1
start_index_cut = floor(self.alignInfo["cut_index"]["front_BCG"] * (raw_freq / BCG_freq))
end_index_cut = start_index_cut + (duration_second * raw_freq)
try:
# 切割信号
self.raw[key] = self.raw[key][start_index_cut:end_index_cut]
except Exception:
return Result().failure(info=Constants.CUT_PAIR_FILE_CUT_DATA_FAILURE +
Constants.FAILURE_REASON["Cut_Data_Length_not_Correct"])
except Exception as e:
return Result().failure(info=Constants.CUT_PAIR_FILE_CUT_DATA_FAILURE +
Constants.FAILURE_REASON["Cut_Data_Exception"] + "\n" + format_exc())
return Result().success(info=Constants.CUT_PAIR_FILE_CUT_DATA_FINISHED)
def align_label(self):
try:
# 读取SA标签
self.SALabel = self.SALabel.loc[:, ~self.SALabel.columns.str.contains("^Unnamed")]
self.SALabel = self.SALabel[self.SALabel["Event type"].isin(Params.CUT_PAIR_FILE_SALABEL_EVENT)]
self.SALabel["Duration"] = self.SALabel["Duration"].astype(str)
self.SALabel["Duration"] = self.SALabel["Duration"].str.replace(r' \(.*?\)', '', regex=True)
except Exception:
return Result().failure(info=Constants.CUT_PAIR_FILE_ALIGN_LABEL_FAILURE +
Constants.FAILURE_REASON["Align_Label_SALabel_Format_not_Correct"])
try:
# 获取记录开始时间
start_time = str(self.startTime[0]).split(" ")[1]
start_time = Data.get_time_to_seconds(start_time)
ECG_freq = Config["ECGFreq"]
# 计算起始时间秒数和终止时间秒数
self.SALabel["Start"] = (self.SALabel["Time"].apply(self.get_time_to_seconds) - start_time).apply(
lambda x: x + 24 * 3600 if x < 0 else x).astype(int)
self.SALabel["End"] = self.SALabel["Start"] + self.SALabel["Duration"].astype(float).round(0).astype(int)
# 标签映射
ECG_length = self.alignInfo["cut_index"]["back_ECG"] - self.alignInfo["cut_index"]["front_ECG"]
self.SALabel["Start"] = self.SALabel["Start"] - round((self.alignInfo["cut_index"]["front_ECG"] / ECG_freq))
self.SALabel["End"] = self.SALabel["End"] - round((self.alignInfo["cut_index"]["front_ECG"] / ECG_freq))
self.SALabel = self.SALabel[self.SALabel["End"] >= 0]
self.SALabel.loc[self.SALabel["Start"] < 0, "Start"] = 0
self.SALabel = self.SALabel[self.SALabel["Start"] < ECG_length]
self.SALabel.loc[self.SALabel["End"] >= ECG_length, "End"] = ECG_length - 1
except Exception as e:
return Result().failure(info=Constants.CUT_PAIR_FILE_ALIGN_LABEL_FAILURE +
Constants.FAILURE_REASON["Align_Label_Exception"] + "\n" + format_exc())
return Result().success(info=Constants.CUT_PAIR_FILE_ALIGN_LABEL_FINISHED)
def save(self):
for raw in self.raw.values():
if len(raw) == 0:
return Result().failure(info=Constants.SAVE_FAILURE +
Constants.FAILURE_REASON["Data_not_Exist"])
try:
for key, raw in self.raw.items():
if Config["ChannelInput"][key].startswith("PSG:"):
# print(f"Saving PSG channel: {key} to {Config['Path']['SavePSGFolder']} / {Config['ChannelSave'][key] + str(self.freq[key]) + Config['EndWith'][key]}")
DataFrame(raw.reshape(-1)).to_csv(Path(Config["Path"]["SavePSGFolder"]) / Path((Config["ChannelSave"][key][len("PSG:"):] + str(self.freq[key]) + Config["EndWith"][key])),
index=False, header=False)
elif Config["ChannelInput"][key].startswith("OrgBCG:"):
# print(f"Saving OrgBCG channel: {key} to {Config['Path']['SaveOrgBCGFolder']} / {Config['ChannelSave'][key] + str(self.freq[key]) + Config['EndWith'][key]}")
DataFrame(raw.reshape(-1)).to_csv(Path(Config["Path"]["SaveOrgBCGFolder"]) / Path((Config["ChannelSave"][key][len("OrgBCG:"):] + str(self.freq[key]) + Config["EndWith"][key])),
index=False, header=False)
# 重排index从1开始并给index命名
self.SALabel.sort_values(by=["Start"], inplace=True)
self.SALabel.reset_index(drop=True, inplace=True)
self.SALabel.index = self.SALabel.index + 1
self.SALabel.index.name = "Index"
self.SALabel.to_csv(Path(Config["Path"]["SavePSGFolder"]) / Path((Config["LabelSave"]["SA Label"] + Config["EndWith"]["SA Label"])),
encoding="gbk")
except PermissionError as e:
return Result().failure(info=Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Save_Permission_Denied"])
except FileNotFoundError as e:
return Result().failure(info=Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Save_File_Not_Found"])
except Exception as e:
return Result().failure(info=Constants.SAVE_FAILURE +
Constants.FAILURE_REASON["Save_Exception"] + "\n" + format_exc())
return Result().success(info=Constants.SAVE_FINISHED)
@staticmethod
def get_time_to_seconds(time_str):
h, m, s = map(int, time_str.split(":"))
return h * 3600 + m * 60 + s

View File

@ -338,7 +338,8 @@ class MainWindow_detect_Jpeak(QMainWindow):
# 预测峰值
PublicFunc.progressbar_update(self, 2, 3, Constants.DETECT_JPEAK_PREDICTING_PEAK, 10)
self.model.selected_model = Config["DetectMethod"]
result = self.data.predict_Jpeak(self.model)
scale = self.ui.spinBox_scaleValue.value() if self.ui.checkBox_scaleEnable.isChecked() else 0
result = self.data.predict_Jpeak(self.model, batch_size=int(self.ui.comboBox_batchSize.currentText()), scale=scale)
if not result.status:
PublicFunc.text_output(self.ui, "(2/3)" + result.info, Constants.TIPS_TYPE_ERROR)
PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR)
@ -469,7 +470,7 @@ class Data:
return Result().failure(info=Constants.PREPROCESS_FAILURE +
Constants.FAILURE_REASON["Preprocess_Exception"] + "\n" + format_exc())
def predict_Jpeak(self, model):
def predict_Jpeak(self, model, batch_size=0, scale=0):
if not (Path(model.model_folder_path) / Path(model.selected_model)).exists():
return Result().failure(info=Constants.DETECT_JPEAK_PREDICT_FAILURE +
Constants.FAILURE_REASON["Model_File_Not_Exist"])
@ -489,7 +490,9 @@ class Data:
Config["IntervalHigh"],
Config["IntervalLow"],
Config["PeaksValue"],
Config["UseCPU"])
Config["UseCPU"],
batch_size,
scale)
except Exception as e:
return Result().failure(info=Constants.DETECT_JPEAK_PREDICT_FAILURE +
Constants.FAILURE_REASON["Predict_Exception"] + "\n" + format_exc())

View File

@ -36,7 +36,8 @@ ButtonState = {
"pushButton_save": False,
"pushButton_prev_move": False,
"pushButton_pause": False,
"pushButton_next_move": False
"pushButton_next_move": False,
"pushButton_update_state": False
},
"Current": {
"pushButton_input_setting": True,
@ -44,7 +45,8 @@ ButtonState = {
"pushButton_save": False,
"pushButton_prev_move": False,
"pushButton_pause": False,
"pushButton_next_move": False
"pushButton_next_move": False,
"pushButton_update_state": False
}
}
@ -257,6 +259,9 @@ class MainWindow_label_check(QMainWindow):
self.point_peak_corrected = None
self.annotation_tableWidget = None
self.move_state = None
self.last_move_state = None
self.ui.textBrowser_info.setStyleSheet("QTextBrowser { background-color: rgb(255, 255, 200); }")
PublicFunc.__styleAllButton__(self, ButtonState)
@ -332,6 +337,7 @@ class MainWindow_label_check(QMainWindow):
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.pushButton_update_state.clicked.connect(self.__update_state__)
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__)
@ -347,6 +353,20 @@ class MainWindow_label_check(QMainWindow):
self.ui.spinBox_maxRange.editingFinished.connect(self.__update_config__)
self.ui.spinBox_moveSpeed.editingFinished.connect(self.__update_config__)
self.ui.pushButton_prev_move.setShortcut(
QCoreApplication.translate("MainWindow", Params.LABEL_CHECK_BTN_PREV_MOVE_SHORTCUT_KEY))
self.ui.pushButton_next_move.setShortcut(
QCoreApplication.translate("MainWindow", Params.LABEL_CHECK_BTN_NEXT_MOVE_SHORTCUT_KEY))
self.ui.pushButton_pause.setShortcut(
QCoreApplication.translate("MainWindow", Params.LABEL_CHECK_BTN_PAUSE_SHORTCUT_KEY)
)
self.ui.pushButton_update_state.setShortcut(
QCoreApplication.translate("MainWindow", Params.LABEL_CHECK_BTN_UPDATE_STATE_SHORTCUT_KEY)
)
@overrides
def closeEvent(self, event):
reply = QMessageBox.question(self, '确认', '确认退出吗?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
@ -576,6 +596,8 @@ class MainWindow_label_check(QMainWindow):
ButtonState["Current"]["pushButton_prev_move"] = True
ButtonState["Current"]["pushButton_next_move"] = True
ButtonState["Current"]["pushButton_pause"] = True
ButtonState["Current"]["pushButton_update_state"] = True
PublicFunc.finish_operation(self, ButtonState)
def __slot_btn_save__(self):
@ -595,6 +617,20 @@ class MainWindow_label_check(QMainWindow):
PublicFunc.msgbox_output(self, result.info, Constants.TIPS_TYPE_INFO)
PublicFunc.finish_operation(self, ButtonState)
def __update_state__(self):
if self.move_state == "moving":
self.ui.pushButton_pause.click()
self.move_state = "pause"
else:
if self.last_move_state == "prev":
self.ui.pushButton_prev_move.click()
elif self.last_move_state == "next":
self.ui.pushButton_next_move.click()
else:
self.ui.pushButton_next_move.click()
self.move_state = "moving"
def __slot_btn_move__(self):
if self.data is None:
return
@ -602,6 +638,8 @@ class MainWindow_label_check(QMainWindow):
sender = self.sender()
if sender == self.ui.pushButton_prev_move:
self.last_move_state = "prev"
self.move_state = "moving"
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])
@ -613,6 +651,8 @@ class MainWindow_label_check(QMainWindow):
self.timer_autoplay.start(Config["AutoplayArgs"]["MoveSpeed"])
PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_PREV_MOVE, Constants.TIPS_TYPE_INFO)
elif sender == self.ui.pushButton_next_move:
self.last_move_state = "next"
self.move_state = "moving"
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"])

View File

@ -16,7 +16,7 @@ from func.Module_detect_Jpeak import MainWindow_detect_Jpeak
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_cut_pair_file import MainWindow_cut_PAIR_FILE
from func.Module_artifact_label import MainWindow_artifact_label
from func.Module_bcg_quality_label import MainWindow_bcg_quality_label
from func.Module_resp_quality_label import MainWindow_resp_quality_label
@ -266,7 +266,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label):
self.check_save_path_and_mkdir(root_path, sampID)
def __slot_btn_cut_PSG__(self):
self.cut_PSG = MainWindow_cut_PSG()
self.cut_PSG = MainWindow_cut_PAIR_FILE()
root_path = self.ui.plainTextEdit_root_path.toPlainText()
sampID = self.ui.comboBox_sampID.currentText()
if not self.check_root_path():

View File

@ -9,12 +9,13 @@ from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication, QButtonGro
from matplotlib import gridspec, patches
from matplotlib.backends.backend_qt import NavigationToolbar2QT
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg
from matplotlib.ticker import FuncFormatter, ScalarFormatter
from numpy import (diff, where, correlate, corrcoef, searchsorted, sum as np_sum, max as np_max, min as np_min, arange,
array,
append, delete, abs as np_abs, argmin as np_argmin, argmax as np_argmax, asarray)
from overrides import overrides
from pandas import read_csv, DataFrame
# from resampy import resample
from resampy import resample as rspy_resample
from scipy.signal import find_peaks, resample as ss_resample
from yaml import dump, load, FullLoader
@ -38,7 +39,10 @@ ButtonState = {
"pushButton_calculate_correlation": False,
"pushButton_correlation_align": False,
"pushButton_view_align": False,
"pushButton_save": False
"pushButton_save": False,
"checkBox_sync_xlim": False,
"pushButton_getPos": False,
"pushButton_resetPos": False
},
"Current": {
"pushButton_input_setting": True,
@ -46,7 +50,10 @@ ButtonState = {
"pushButton_calculate_correlation": False,
"pushButton_correlation_align": False,
"pushButton_view_align": False,
"pushButton_save": False
"pushButton_save": False,
"checkBox_sync_xlim": False,
"pushButton_getPos": False,
"pushButton_resetPos": False
},
"Statue_1": {
"pushButton_input_setting": False,
@ -54,7 +61,10 @@ ButtonState = {
"pushButton_calculate_correlation": True,
"pushButton_correlation_align": False,
"pushButton_view_align": False,
"pushButton_save": False
"pushButton_save": False,
"checkBox_sync_xlim": True,
"pushButton_getPos": False,
"pushButton_resetPos": False
},
"Statue_2": {
"pushButton_input_setting": False,
@ -62,7 +72,10 @@ ButtonState = {
"pushButton_calculate_correlation": True,
"pushButton_correlation_align": True,
"pushButton_view_align": False,
"pushButton_save": False
"pushButton_save": False,
"checkBox_sync_xlim": False,
"pushButton_getPos": False,
"pushButton_resetPos": False
},
"Statue_3": {
"pushButton_input_setting": False,
@ -70,7 +83,10 @@ ButtonState = {
"pushButton_calculate_correlation": False,
"pushButton_correlation_align": False,
"pushButton_view_align": True,
"pushButton_save": False
"pushButton_save": False,
"checkBox_sync_xlim": False,
"pushButton_getPos": False,
"pushButton_resetPos": False
},
"Statue_4": {
"pushButton_input_setting": False,
@ -78,7 +94,10 @@ ButtonState = {
"pushButton_calculate_correlation": False,
"pushButton_correlation_align": False,
"pushButton_view_align": False,
"pushButton_save": True
"pushButton_save": True,
"checkBox_sync_xlim": False,
"pushButton_getPos": False,
"pushButton_resetPos": False
},
}
@ -393,8 +412,12 @@ class MainWindow_precisely_align(QMainWindow):
self.ui.pushButton_correlation_align.clicked.connect(self.__slot_btn_correlation_align__)
self.ui.pushButton_view_align.clicked.connect(self.__slot_btn_view_align__)
self.ui.pushButton_save.clicked.connect(self.__slot_btn_save__)
self.ui.pushButton_getPos.clicked.connect(self.__get_current_pos__)
self.ui.pushButton_resetPos.clicked.connect(self.__reset_pos__)
self.canvas.mpl_connect('pick_event', self.on_pick)
self.ui.checkBox_sync_xlim.checkStateChanged.connect(self.__checkBox_sync_xlim_changed__)
self.ui.spinBox_BCG_front_JJIV_1.editingFinished.connect(self.__update_coordinate__)
self.ui.spinBox_BCG_front_JJIV_2.editingFinished.connect(self.__update_coordinate__)
self.ui.spinBox_BCG_back_JJIV_1.editingFinished.connect(self.__update_coordinate__)
@ -404,6 +427,8 @@ class MainWindow_precisely_align(QMainWindow):
self.ui.spinBox_ECG_back_RRIV_1.editingFinished.connect(self.__update_coordinate__)
self.ui.spinBox_ECG_back_RRIV_2.editingFinished.connect(self.__update_coordinate__)
self.ui.label_sampno.setText(str(self.sampID))
@overrides
def closeEvent(self, event):
reply = QMessageBox.question(self, '确认', '确认退出吗?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
@ -470,39 +495,105 @@ class MainWindow_precisely_align(QMainWindow):
sender = self.sender()
def offset_formatter(x, pos):
if self.data.BCG_early:
return f"{int(x + self.data.approximately_align_pos)}"
else:
return f"{int(x - self.data.approximately_align_pos)}"
if sender == self.ui.pushButton_input:
self.gs = gridspec.GridSpec(2, 1, height_ratios=[1, 1])
self.fig.subplots_adjust(top=0.95, bottom=0.05, right=0.98, left=0.05, hspace=0.15, wspace=0)
self.ax0 = self.fig.add_subplot(self.gs[0])
self.ax0.grid(True)
self.ax0.xaxis.set_major_formatter(Params.FORMATTER)
self.ax1 = self.fig.add_subplot(self.gs[1], sharex=self.ax0, sharey=self.ax0)
# self.ax0.xaxis.set_major_formatter(Params.FORMATTER)
self.ax1 = self.fig.add_subplot(self.gs[1], sharey=self.ax0)
self.ax1.grid(True)
self.ax1.xaxis.set_major_formatter(Params.FORMATTER)
# self.ax1.xaxis.set_major_formatter(Params.FORMATTER)
Jpeak = self.data.Jpeak[:-2]
Rpeak = self.data.Rpeak[:-2]
self.ax0.set_title("JJIV")
self.ax1.set_title("RRIV")
self._syncing_xlim_change = False
def on_ax0_xlim_changed(ax):
if self.ui.checkBox_sync_xlim.isChecked() is False:
return
if self._syncing_xlim_change:
return
if ax is self.ax0:
self._syncing_xlim_change = True
x0, x1 = ax.get_xlim()
self.ax1.set_xlim(x0, x1)
self._syncing_xlim_change = False
def on_ax1_xlim_changed(ax):
if self.ui.checkBox_sync_xlim.isChecked() is False:
return
if self._syncing_xlim_change:
return
if ax is self.ax1:
self._syncing_xlim_change = True
x0, x1 = ax.get_xlim()
self.ax0.set_xlim(x0, x1)
self._syncing_xlim_change = False
if self.data.BCG_early:
Jpeak = Jpeak - self.data.approximately_align_pos
else:
Jpeak = Jpeak + self.data.approximately_align_pos
# if self.data.BCG_early is True:
# self.ax0.stem(Jpeak, plot_element["JJIVs"],
# markerfmt="C0.", linefmt=Constants.PLOT_COLOR_GREEN,
# label=Constants.PRECISELY_ALIGN_PLOT_LABEL_JJIV)
# self.ax1.stem(Rpeak, plot_element["RRIVs"],
# markerfmt="C0.", linefmt=Constants.PLOT_COLOR_ORANGE,
# label=Constants.PRECISELY_ALIGN_PLOT_LABEL_RRIV)
# self.ax0.axvline(x=self.data.approximately_align_pos, color=Constants.PLOT_COLOR_BLACK, linestyle="--",
# label="Start Line")
# self.ax1.axvline(x=0, color=Constants.PLOT_COLOR_BLACK, linestyle="--", label="Start Line")
# elif self.data.BCG_early is False:
# Jpeak = Jpeak + self.data.approximately_align_pos
# self.ax0.stem(Jpeak, plot_element["JJIVs"],
# markerfmt="C0.", linefmt=Constants.PLOT_COLOR_GREEN,
# label=Constants.PRECISELY_ALIGN_PLOT_LABEL_JJIV)
# self.ax1.stem(Rpeak, plot_element["RRIVs"],
# markerfmt="C0.", linefmt=Constants.PLOT_COLOR_ORANGE,
# label=Constants.PRECISELY_ALIGN_PLOT_LABEL_RRIV)
# self.ax0.axvline(x=0, color=Constants.PLOT_COLOR_BLACK, linestyle="--", label="Start Line")
# self.ax1.axvline(x=self.data.approximately_align_pos, color=Constants.PLOT_COLOR_BLACK, linestyle="--",
# label="Start Line")
# else:
# self.ax0.stem(Jpeak, plot_element["JJIVs"],
# markerfmt="C0.", linefmt=Constants.PLOT_COLOR_GREEN,
# label=Constants.PRECISELY_ALIGN_PLOT_LABEL_JJIV)
# self.ax1.stem(Rpeak, plot_element["RRIVs"],
# markerfmt="C0.", linefmt=Constants.PLOT_COLOR_ORANGE,
# label=Constants.PRECISELY_ALIGN_PLOT_LABEL_RRIV)
# self.ax0.axvline(x=self.data.approximately_align_pos, color=Constants.PLOT_COLOR_BLACK, linestyle="--",
# label="Start Line")
# self.ax1.axvline(x=self.data.approximately_align_pos, color=Constants.PLOT_COLOR_BLACK, linestyle="--",
# label="Start Line")
self.ax0.stem(Jpeak, plot_element["JJIVs"],
markerfmt="C0.", linefmt=Constants.PLOT_COLOR_GREEN,
label=Constants.PRECISELY_ALIGN_PLOT_LABEL_JJIV)
self.ax1.set_title("RRIV")
self.ax0.xaxis.set_major_formatter(FuncFormatter(offset_formatter))
self.ax1.stem(Rpeak, plot_element["RRIVs"],
markerfmt="C0.", linefmt=Constants.PLOT_COLOR_ORANGE,
label=Constants.PRECISELY_ALIGN_PLOT_LABEL_RRIV)
if self.data.BCG_early is True:
self.ax0.axvline(x=self.data.approximately_align_pos, color=Constants.PLOT_COLOR_BLACK, linestyle="--",
label="Start Line")
self.ax1.axvline(x=0, color=Constants.PLOT_COLOR_BLACK, linestyle="--", label="Start Line")
elif self.data.BCG_early is False:
self.ax0.axvline(x=0, color=Constants.PLOT_COLOR_BLACK, linestyle="--", label="Start Line")
self.ax1.axvline(x=self.data.approximately_align_pos, color=Constants.PLOT_COLOR_BLACK, linestyle="--",
label="Start Line")
else:
self.ax0.axvline(x=self.data.approximately_align_pos, color=Constants.PLOT_COLOR_BLACK, linestyle="--",
label="Start Line")
self.ax1.axvline(x=self.data.approximately_align_pos, color=Constants.PLOT_COLOR_BLACK, linestyle="--",
label="Start Line")
self.ax1.xaxis.set_major_formatter(Params.FORMATTER)
self.ax0.callbacks.connect('xlim_changed', on_ax0_xlim_changed)
self.ax1.callbacks.connect('xlim_changed', on_ax1_xlim_changed)
self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT)
self.ax1.legend(loc=Constants.PLOT_UPPER_RIGHT)
@ -632,6 +723,55 @@ class MainWindow_precisely_align(QMainWindow):
self.canvas.draw()
return Result().failure(info=Constants.DRAW_FAILURE)
def __checkBox_sync_xlim_changed__(self):
if not self.ui.checkBox_sync_xlim.isChecked():
self.ui.pushButton_getPos.setEnabled(True)
self.ui.pushButton_resetPos.setEnabled(True)
else:
self.ui.pushButton_getPos.setEnabled(False)
self.ui.pushButton_resetPos.setEnabled(False)
def __get_current_pos__(self):
if self.ui.checkBox_sync_xlim.isChecked():
return
# 获取当前两子图的x轴起始点
ax0_x0, _ = self.ax0.get_xlim()
ax1_x0, _ = self.ax1.get_xlim()
# 获取ax0的trick位置
# if self.data.BCG_early:
# ax1_x0 += self.data.approximately_align_pos
# else:
# ax0_x0 -= self.data.approximately_align_pos
print(ax0_x0, ax1_x0)
actual_pos = -1 * self.data.approximately_align_pos if self.data.BCG_early else self.data.approximately_align_pos
actual_ax0_x0 = ax0_x0 - actual_pos
new_pos = actual_ax0_x0 - ax1_x0
print(actual_ax0_x0, ax1_x0)
if new_pos > 0:
self.data.BCG_early = True
else:
self.data.BCG_early = False
self.data.approximately_align_pos = abs(new_pos)
print(self.data.BCG_early, self.data.approximately_align_pos)
self.ui.label_pos.setText(str(int(self.data.approximately_align_pos) * (-1 if self.data.BCG_early else 1)))
self.ui.pushButton_input.click()
def __reset_pos__(self):
if self.data.TimeBiasSecond > 0:
self.data.BCG_early = True
else:
self.data.BCG_early = False
self.data.approximately_align_pos = abs(self.data.TimeBiasSecond)
self.ui.label_pos.setText(str(int(self.data.approximately_align_pos) * (-1 if self.data.BCG_early else 1)))
def __update_info__(self):
self.ui.spinBox_BCG_front_JJIV_1.setValue(Config["IV_Coordinate"]["BCG_front_1"])
self.ui.spinBox_BCG_front_JJIV_2.setValue(Config["IV_Coordinate"]["BCG_front_2"])
@ -711,6 +851,9 @@ class MainWindow_precisely_align(QMainWindow):
action.setEnabled(True)
ButtonState["Current"].update(ButtonState["Statue_1"].copy())
PublicFunc.finish_operation(self, ButtonState)
self.ui.label_pos.setText(str(int(self.data.approximately_align_pos) * (-1 if self.data.BCG_early else 1)))
self.ui.pushButton_input.clicked.disconnect()
self.ui.pushButton_input.clicked.connect(self.__slot_btn_repick__)
self.ui.pushButton_input.setText("重新选取")
@ -1392,6 +1535,14 @@ class MainWindow_precisely_align(QMainWindow):
elif rect_right < 0:
rect_left = 0
rect_right = 0
if self.data.BCG_early:
# 如果是提前BCG模式J峰位置需要加上offset
rect_left += self.data.approximately_align_pos
rect_right += self.data.approximately_align_pos
else:
rect_left -= self.data.approximately_align_pos
rect_right -= self.data.approximately_align_pos
indices = where((self.data.Jpeak[:-2] >= rect_left) & (self.data.Jpeak[:-2] <= rect_right))[0]
if indices is None or len(indices) <= 0:
if self.ui.radioButton_BCG_front.isChecked():
@ -1622,6 +1773,7 @@ class Data:
self.approximately_align_slope = None
self.approximately_align_intercept = None
self.BCG_early = None
self.TimeBiasSecond = None
self.res_orgBcg = None
self.res_BCG = None
@ -1660,6 +1812,13 @@ class Data:
if Path(Config["Path"]["Input_Approximately_Align"]).is_file():
Config["Path"]["Input_Approximately_Align"] = str(Path(Config["Path"]["Input_Approximately_Align"]).parent)
result = PublicFunc.get_machine_start_time_bias(Config["Path"]["Input_ECG"], Config["Path"]["Input_OrgBCG"])
if result.status:
self.TimeBiasSecond = result.data["time_bias"] * Config["InputConfig"]["UseFreq"]
else:
self.TimeBiasSecond = 0
result = PublicFunc.examine_file(Config["Path"]["Input_OrgBCG"], Filename.ORGBCG_RAW, Params.ENDSWITH_TXT)
if result.status:
Config["Path"]["Input_OrgBCG"] = result.data["path"]
@ -1674,7 +1833,7 @@ class Data:
Filename.PRECISELY_ALIGN_INFO + Params.ENDSWITH_TXT))
Config["Path"]["Save_OrgBCG"] = str(
Path(Config["Path"]["Save_OrgBCG"]) / Path(
Filename.ORGBCG_SYNC + str(Config["InputConfig"]["orgBcgFreq"]) + Params.ENDSWITH_TXT))
Filename.ORGBCG_SYNC + str(Config["InputConfig"]["UseFreq"]) + Params.ENDSWITH_TXT))
result = PublicFunc.examine_file(Config["Path"]["Input_BCG"], Filename.BCG_FILTER, Params.ENDSWITH_TXT)
if result.status:
Config["Path"]["Input_BCG"] = result.data["path"]
@ -1716,11 +1875,11 @@ class Data:
Filename.RPEAK_FINAL_CORRECTED + "" +
Config["Path"]["Input_Rpeak"] +
Constants.FAILURE_REASON["Path_Not_Exist"])
if not Path(Config["Path"]["Input_Approximately_Align"]).exists():
return Result().failure(info=Constants.INPUT_FAILURE + "\n" +
Filename.APPROXIMATELY_ALIGN_INFO + "" +
Config["Path"]["Input_Approximately_Align"] +
Constants.FAILURE_REASON["Path_Not_Exist"])
# if not Path(Config["Path"]["Input_Approximately_Align"]).exists():
# return Result().failure(info=Constants.INPUT_FAILURE + "\n" +
# Filename.APPROXIMATELY_ALIGN_INFO + "" +
# Config["Path"]["Input_Approximately_Align"] +
# Constants.FAILURE_REASON["Path_Not_Exist"])
try:
self.raw_orgBcg = read_csv(Config["Path"]["Input_OrgBCG"],
@ -1760,9 +1919,21 @@ class Data:
self.approximately_align_slope = df["estimate_slope"].values[-1] / \
Params.APPROXIMATELY_ALIGN_CONFIG_NEW_CONTENT["Second_PerEpoch"]
self.approximately_align_intercept = df["estimate_intercept"].values[-1] * Config["InputConfig"]["UseFreq"]
self.TimeBiasSecond = self.approximately_align_pos
except Exception:
self.approximately_align_pos = 0
self.approximately_align_pos = abs(self.TimeBiasSecond)
if self.approximately_align_pos > 0:
if self.TimeBiasSecond > 0:
self.BCG_early = True
else:
self.BCG_early = False
else:
self.BCG_early = None
return Result().success(info=Constants.INPUT_FINISHED)
@ -1970,8 +2141,8 @@ class Data:
Config["back"]["anchor_J"] = Config["back"]["anchor_J"] + Config["offset_anchor"]
Config["frontcut_index_BCG"] -= Config["offset_anchor"]
self.res_BCG = resample(self.res_BCG, Config["orgfs"], Config["InputConfig"]["UseFreq"])
self.res_orgBcg = resample(self.res_orgBcg, Config["orgfs"], Config["InputConfig"]["UseFreq"])
self.res_BCG = rspy_resample(self.res_BCG, Config["orgfs"], Config["InputConfig"]["UseFreq"])
self.res_orgBcg = rspy_resample(self.res_orgBcg, Config["orgfs"], Config["InputConfig"]["UseFreq"])
Config["front"]["anchor_J"] = round(int(Config["front"]["anchor_J"]) * Config["InputConfig"]["UseFreq"] / Config["orgfs"])
Config["back"]["anchor_J"] = round(int(Config["back"]["anchor_J"]) * Config["InputConfig"]["UseFreq"] / Config["orgfs"])
@ -1992,6 +2163,7 @@ class Data:
Config["frontcut_index_BCG"] -= Config["offset_anchor"] * Config["orgfs"] / Config["InputConfig"]["UseFreq"]
datalen = np_min([len(self.cut_ECG), len(self.res_BCG)])
print(f"datalen: {datalen} len cut_ECG: {len(self.cut_ECG)} len res_BCG: {len(self.res_BCG)}")
self.cut_ECG = self.cut_ECG[:datalen]
self.res_BCG = self.res_BCG[:datalen]
self.res_orgBcg = self.res_orgBcg[:datalen]
@ -2120,7 +2292,7 @@ class Data:
"back_ECG": Config["backcut_index_ECG"]
}
}
save_data = [str(save_data)]
save_data = [str(PublicFunc.sanitize_data(save_data))]
DataFrame(save_data).to_csv(Config["Path"]["Save_AlignInfo"], index=False, header=False)
except PermissionError as e:
return Result().failure(info=Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Save_Permission_Denied"])
@ -2135,10 +2307,10 @@ class Data:
not Path(Config["Path"]["Save_OrgBCG"]).parent.is_dir()):
Path(Config["Path"]["Save_OrgBCG"]).parent.mkdir(parents=True, exist_ok=True)
if Config["InputConfig"]["orgBcgFreq"] != Config["InputConfig"]["UseFreq"]:
self.res_orgBcg = resample(self.res_orgBcg,
int(len(self.res_orgBcg) *
(Config["InputConfig"]["orgBcgFreq"] / Config["InputConfig"]["UseFreq"])))
# if Config["InputConfig"]["orgBcgFreq"] != Config["InputConfig"]["UseFreq"]:
# self.res_orgBcg = ss_resample(self.res_orgBcg,
# int(len(self.res_orgBcg) *
# (Config["InputConfig"]["orgBcgFreq"] / Config["InputConfig"]["UseFreq"])))
if self.res_orgBcg is None:
return Result().failure(info=Constants.PRECISELY_ALIGN_SAVING_RES_ORGBCG_FAILURE +

View File

@ -199,6 +199,11 @@ class Params:
LABEL_CHECK_LABEL_TRANSPARENCY: float = 0.2
LABEL_CHECK_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY: str = "Z"
LABEL_CHECK_BTN_PREV_MOVE_SHORTCUT_KEY = "A"
LABEL_CHECK_BTN_NEXT_MOVE_SHORTCUT_KEY = "D"
LABEL_CHECK_BTN_PAUSE_SHORTCUT_KEY = "S"
LABEL_CHECK_BTN_UPDATE_STATE_SHORTCUT_KEY = "Space"
# 数据精同步
PRECISELY_ALIGN_CONFIG_FILE_PATH: str = "./config/Config_precisely_align.yaml"
PRECISELY_ALIGN_CONFIG_NEW_CONTENT: dict = {
@ -215,30 +220,39 @@ class Params:
PRECISELY_ALIGN_LABEL_TRANSPARENCY: float = 0.2
# 冗余数据切割和标签映射
CUT_PSG_CONFIG_FILE_PATH: str = "./config/Config_cut_PSG.yaml"
CUT_PSG_CONFIG_NEW_CONTENT: dict = {
CUT_PAIR_FILE_CONFIG_FILE_PATH: str = "./config/Config_cut_PAIR_FILE.yaml"
CUT_PAIR_FILE_CONFIG_NEW_CONTENT: dict = {
"ECGFreq": 1000,
"BCGFreq": 1000,
"ChannelInput": {
"Effort Tho": Filename.THO_RAW,
"Effort Abd": Filename.ABD_RAW,
"Flow T": Filename.FLOWT_RAW,
"Flow P": Filename.FLOWP_RAW,
"Snore": Filename.SNORE_RAW,
"SpO2": Filename.SPO2_RAW,
"5_class": Filename.FIVE_CLASS_RAW
"Effort Tho": "PSG:" + Filename.THO_RAW,
"Effort Abd": "PSG:" + Filename.ABD_RAW,
"Flow T": "PSG:" + Filename.FLOWT_RAW,
"Flow P": "PSG:" + Filename.FLOWP_RAW,
"Snore": "PSG:" + Filename.SNORE_RAW,
"SpO2": "PSG:" + Filename.SPO2_RAW,
"5_class": "PSG:" + Filename.FIVE_CLASS_RAW
},
"OrgBCGChannelInput":{
"OrgBCG": "OrgBCG:OrgBCG_Raw_"
},
"ECGChannelInput": {
"ECG": "PSG:" + Filename.ECG_RAW
},
"LabelInput": {
"SA Label": Filename.SA_LABEL_RAW
},
"StartTime": Filename.STARTTIME_RAW,
"ChannelSave": {
"Effort Tho": Filename.THO_SYNC,
"Effort Abd": Filename.ABD_SYNC,
"Flow T": Filename.FLOWT_SYNC,
"Flow P": Filename.FLOWP_SYNC,
"Snore": Filename.SNORE_SYNC,
"SpO2": Filename.SPO2_SYNC,
"5_class": Filename.FIVE_CLASS_SYNC
"Effort Tho": "PSG:" + Filename.THO_SYNC,
"Effort Abd": "PSG:" + Filename.ABD_SYNC,
"Flow T": "PSG:" + Filename.FLOWT_SYNC,
"Flow P": "PSG:" + Filename.FLOWP_SYNC,
"Snore": "PSG:" + Filename.SNORE_SYNC,
"SpO2": "PSG:" + Filename.SPO2_SYNC,
"5_class": "PSG:" + Filename.FIVE_CLASS_SYNC,
"OrgBCG": "OrgBCG:" + Filename.ORGBCG_SYNC,
"ECG": "PSG:" + Filename.ECG_SYNC
},
"LabelSave": {
"SA Label": Filename.SA_LABEL_SYNC
@ -253,10 +267,12 @@ class Params:
"SpO2": ENDSWITH_TXT,
"5_class": ENDSWITH_TXT,
"SA Label": ENDSWITH_CSV,
"StartTime": ENDSWITH_TXT
"StartTime": ENDSWITH_TXT,
"OrgBCG": ENDSWITH_TXT,
"ECG": ENDSWITH_TXT
},
}
CUT_PSG_SALABEL_EVENT: list = ["Hypopnea", "Central apnea", "Obstructive apnea", "Mixed apnea"]
CUT_PAIR_FILE_SALABEL_EVENT: list = ["Hypopnea", "Central apnea", "Obstructive apnea", "Mixed apnea"]
# 体动标注
ARTIFACT_LABEL_CONFIG_FILE_PATH: str = "./config/Config_artifact_label.yaml"

View File

@ -5,6 +5,7 @@ class Constants:
# 公共
TIPS_TYPE_INFO: str = "Info"
TIPS_TYPE_WARNING: str = "Warning"
TIPS_TYPE_ERROR: str = "Error"
MSGBOX_TYPE_INFO: str = "Info"
MSGBOX_TYPE_WARNING: str = "Warning"
@ -182,7 +183,11 @@ class Constants:
"res_BCG_Not_Exist": "切割后BCG不存在",
"cut_ECG_Not_Exist": "切割后ECG不存在",
"cut_Jpeak_Not_Exist": "切割后J峰不存在",
"cut_Rpeak_Not_Exist": "切割后R峰不存在"
"cut_Rpeak_Not_Exist": "切割后R峰不存在",
"Get_Approximately_Align_Info_Exception": "(获取粗对齐信息异常)",
"Calculate_Approximately_Align_Info_Exception": "(计算粗对齐信息异常)",
"Delete_Rough_Cut_File_Exception": "(删除历史粗对齐文件异常)",
"Resample_BCG_Exception": "粗对齐重采样BCG异常",
}
# 数据粗同步
@ -352,17 +357,31 @@ class Constants:
PRECISELY_ALIGN_ACTION_GET_RANGE_NAME: str = f"设置范围({Params.PRECISELY_ALIGN_ACTION_GET_RANGE_SHORTCUT_KEY})"
# 冗余数据切割和标签映射
CUT_PSG_GETTING_FILE_AND_FREQ: str = "正在获取文件及其采样率"
CUT_PSG_GET_FILE_AND_FREQ_FINISHED: str = "获取文件及其采样率完成"
CUT_PSG_GET_FILE_AND_FREQ_FAILURE: str = "获取文件及其采样率失败"
CUT_PAIR_FILE_GETTING_FILE_AND_FREQ: str = "正在获取文件及其采样率"
CUT_PAIR_FILE_GET_FILE_AND_FREQ_FINISHED: str = "获取文件及其采样率完成"
CUT_PAIR_FILE_GET_FILE_AND_FREQ_FAILURE: str = "获取文件及其采样率失败"
CUT_PSG_CUTTING_DATA: str = "正在切割数据"
CUT_PSG_CUT_DATA_FINISHED: str = "切割数据完成"
CUT_PSG_CUT_DATA_FAILURE: str = "切割数据失败"
CUT_PAIR_FILE_CUTTING_DATA: str = "正在切割数据"
CUT_PAIR_FILE_CUT_DATA_FINISHED: str = "切割数据完成"
CUT_PAIR_FILE_CUT_DATA_FAILURE: str = "切割数据失败"
CUT_PAIR_FILE_ALIGNING_LABEL: str = "正在映射标签"
CUT_PAIR_FILE_ALIGN_LABEL_FINISHED: str = "映射标签完成"
CUT_PAIR_FILE_ALIGN_LABEL_FAILURE: str = "映射标签失败"
CUT_PAIR_FILE_GETTING_APPROXIMATE_ALIGN_INFO: str = "正在获取粗对齐信息"
CUT_PAIR_FILE_GETTING_APPROXIMATE_ALIGN_INFO_FAILURE: str = "获取粗对齐信息失败"
CUT_PAIR_FILE_GETTING_APPROXIMATE_ALIGN_INFO_FINISHED: str = "获取粗对齐信息完成"
CUT_PAIR_FILE_GETTING_APPROXIMATE_ALIGN_INFO_CALC_FINISHED: str = "计算粗对齐信息完成"
CUT_PAIR_FILE_DELETING_ROUGH_CUT_FILE: str = "正在删除历史粗对齐文件"
CUT_PAIR_FILE_DELETE_ROUGH_CUT_FILE_FINISHED: str = "删除历史粗对齐文件完成"
CUT_PAIR_FILE_DELETE_ROUGH_CUT_FILE_FAILURE: str = "删除历史粗对齐文件失败"
CUT_PAIR_FILE_ROUGH_RESAMPLE_BCG: str = "正在粗对齐重采样BCG"
CUT_PAIR_FILE_ROUGH_RESAMPLE_BCG_FINISHED: str = "粗对齐重采样BCG完成"
CUT_PAIR_FILE_ROUGH_RESAMPLE_BCG_FAILURE: str = "粗对齐重采样BCG失败"
CUT_PSG_ALIGNING_LABEL: str = "正在映射标签"
CUT_PSG_ALIGN_LABEL_FINISHED: str = "映射标签完成"
CUT_PSG_ALIGN_LABEL_FAILURE: str = "映射标签失败"
# 体动标注
ARTIFACT_LABEL_PLOT_LABEL_ORGBCG_SYNC: str = "OrgBCG_Sync"

View File

@ -8,7 +8,7 @@ from PySide6.QtWidgets import QMessageBox, QWidget, QPushButton, QProgressBar, Q
from func.utils.Constants import Constants
from func.utils.CustomException import TipsTypeValueNotExistError, MsgBoxTypeValueNotExistError
from func.utils.Result import Result
import numpy as np
class PublicFunc:
@ -113,6 +113,10 @@ class PublicFunc:
if widget.objectName() in buttonState["Current"].keys():
widget.setEnabled(False)
if isinstance(widget, QCheckBox):
if widget.objectName() in buttonState["Current"].keys():
widget.setEnabled(False)
@staticmethod
def __enableAllButton__(mainWindow, buttonState):
# 启用按钮
@ -128,6 +132,10 @@ class PublicFunc:
if widget.objectName() in buttonState["Current"].keys():
widget.setEnabled(buttonState["Current"][widget.objectName()])
if isinstance(widget, QCheckBox):
if widget.objectName() in buttonState["Current"].keys():
widget.setEnabled(buttonState["Current"][widget.objectName()])
@staticmethod
def __resetAllButton__(mainWindow, buttonState):
# 启用按钮
@ -143,6 +151,10 @@ class PublicFunc:
if widget.objectName() in buttonState["Default"].keys():
widget.setEnabled(buttonState["Default"][widget.objectName()])
if isinstance(widget, QCheckBox):
if widget.objectName() in buttonState["Default"].keys():
widget.setEnabled(buttonState["Default"][widget.objectName()])
@staticmethod
def __styleAllButton__(mainWindow, buttonState):
# 启用按钮
@ -308,3 +320,21 @@ class PublicFunc:
unit_data = artifact[i:i + 4]
if len(unit_data) < 4:
break
@staticmethod
def sanitize_data(obj):
"""
递归将对象中的 NumPy 类型转换为 Python 原生类型
"""
if isinstance(obj, dict):
return {k: PublicFunc._sanitize_data(v) for k, v in obj.items()}
elif isinstance(obj, (list, tuple)):
return [PublicFunc._sanitize_data(i) for i in obj]
elif isinstance(obj, (np.integer, np.int64)):
return int(obj)
elif isinstance(obj, (np.floating, np.float64)):
return float(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
else:
return obj

View File

@ -1,3 +1,4 @@
import torch
from numpy import diff, argwhere, argmax, where, delete, insert, mean, array, full, nan
from numpy import min as np_min
from numpy import max as np_max
@ -5,11 +6,12 @@ from torch import FloatTensor, no_grad, load
from torch import device as torch_device
from torch.cuda import is_available, empty_cache
from torch.nn.functional import sigmoid
from torch.utils.data import TensorDataset, DataLoader
from func.BCGDataset import BCG_Operation
from func.Deep_Model import Unet,Fivelayer_Lstm_Unet,Fivelayer_Unet,Sixlayer_Unet
def evaluate(test_data, model,fs,useCPU):
def evaluate(test_data, model,fs,useCPU, batch_size=0, scale=0):
orgBCG = test_data
operation = BCG_Operation()
# 降采样
@ -17,7 +19,12 @@ def evaluate(test_data, model,fs,useCPU):
# plt.figure()
# plt.plot(orgBCG)
# plt.show()
if scale != 0:
orgBCG_std = orgBCG.std()
orgBCG = orgBCG * scale / orgBCG_std
orgBCG = orgBCG.reshape(-1, 1000)
# test dataset
orgData = FloatTensor(orgBCG).unsqueeze(1)
# predict
@ -30,12 +37,32 @@ def evaluate(test_data, model,fs,useCPU):
# if gpu:
# orgData = orgData.cuda()
# model.cuda()
orgData = orgData.to(device)
model = model.to(device)
model.to(device)
orgData_tensor = FloatTensor(orgBCG).unsqueeze(1)
test_dataset = TensorDataset(orgData_tensor)
batch_size = len(test_dataset) if batch_size == 0 else batch_size
#全部数据放在一个batch里评估
test_loader = DataLoader(
dataset=test_dataset,
batch_size=batch_size,
shuffle=False,
num_workers=0 # 简单评估时设为 0
)
all_y_prob = []
with no_grad():
y_hat = model(orgData)
y_prob = sigmoid(y_hat)
for i, data_batch in enumerate(test_loader):
# data_batch 是一个包含 (batch_size, 1, 1000) 数据的列表
inputs = data_batch[0].to(device)
# 预测
y_hat_batch = model(inputs)
y_prob_batch = sigmoid(y_hat_batch)
# 收集结果,移回 CPU
all_y_prob.append(y_prob_batch.cpu())
y_prob = torch.cat(all_y_prob, dim=0).view(-1)
beat = (y_prob>0.5).float().view(-1).cpu().data.numpy()
beat_diff = diff(beat)
up_index = argwhere(beat_diff==1)
@ -250,7 +277,7 @@ def preprocess(raw_bcg, fs, low_cut, high_cut, amp_value):
bcg = preprocessing.Butterworth(bcg_data, "bandpass", low_cut=low_cut, high_cut=high_cut, order=3) * amp_value
return bcg
def Jpeak_Detection(model_name, model_path, bcg_data, fs, interval_high, interval_low, peaks_value, useCPU):
def Jpeak_Detection(model_name, model_path, bcg_data, fs, interval_high, interval_low, peaks_value, useCPU, batch_size=0, scale=0):
model_name = get_model_name(str(model_name))
if model_name == "Fivelayer_Unet":
@ -267,7 +294,7 @@ def Jpeak_Detection(model_name, model_path, bcg_data, fs, interval_high, interva
model.eval()
# J峰预测
beat, up_index, down_index, y_prob = evaluate(bcg_data, model=model, fs=fs, useCPU=useCPU)
beat, up_index, down_index, y_prob = evaluate(bcg_data, model=model, fs=fs, useCPU=useCPU, batch_size=batch_size, scale=scale)
y_prob = y_prob.cpu().reshape(-1).data.numpy()
predict_J = new_calculate_beat(y_prob, 1, th=0.6, up=fs // 100, th1=interval_high, th2=interval_low)

View File

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'MainWindow_cut_PSG.ui'
## Form generated from reading UI file 'MainWindow_cut_PAIR_FILE.ui'
##
## Created by: Qt User Interface Compiler version 6.8.2
## Created by: Qt User Interface Compiler version 6.9.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
@ -16,35 +16,36 @@ from PySide6.QtGui import (QAction, QBrush, QColor, QConicalGradient,
QIcon, QImage, QKeySequence, QLinearGradient,
QPainter, QPalette, QPixmap, QRadialGradient,
QTransform)
from PySide6.QtWidgets import (QApplication, QGridLayout, QGroupBox, QHBoxLayout,
QLabel, QMainWindow, QPlainTextEdit, QProgressBar,
QPushButton, QSizePolicy, QSpacerItem, QSpinBox,
QStatusBar, QTextBrowser, QVBoxLayout, QWidget)
from PySide6.QtWidgets import (QApplication, QCheckBox, QGridLayout, QGroupBox,
QHBoxLayout, QLabel, QMainWindow, QPlainTextEdit,
QProgressBar, QPushButton, QSizePolicy, QSpacerItem,
QSpinBox, QStatusBar, QTextBrowser, QVBoxLayout,
QWidget)
class Ui_MainWindow_cut_PSG(object):
def setupUi(self, MainWindow_cut_PSG):
if not MainWindow_cut_PSG.objectName():
MainWindow_cut_PSG.setObjectName(u"MainWindow_cut_PSG")
MainWindow_cut_PSG.setEnabled(True)
MainWindow_cut_PSG.resize(540, 720)
class Ui_MainWindow_cut_PAIR_FILE(object):
def setupUi(self, MainWindow_cut_PAIR_FILE):
if not MainWindow_cut_PAIR_FILE.objectName():
MainWindow_cut_PAIR_FILE.setObjectName(u"MainWindow_cut_PAIR_FILE")
MainWindow_cut_PAIR_FILE.setEnabled(True)
MainWindow_cut_PAIR_FILE.resize(548, 739)
sizePolicy = QSizePolicy(QSizePolicy.Policy.Ignored, QSizePolicy.Policy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(MainWindow_cut_PSG.sizePolicy().hasHeightForWidth())
MainWindow_cut_PSG.setSizePolicy(sizePolicy)
sizePolicy.setHeightForWidth(MainWindow_cut_PAIR_FILE.sizePolicy().hasHeightForWidth())
MainWindow_cut_PAIR_FILE.setSizePolicy(sizePolicy)
font = QFont()
font.setPointSize(12)
MainWindow_cut_PSG.setFont(font)
self.action_selectPath = QAction(MainWindow_cut_PSG)
MainWindow_cut_PAIR_FILE.setFont(font)
self.action_selectPath = QAction(MainWindow_cut_PAIR_FILE)
self.action_selectPath.setObjectName(u"action_selectPath")
font1 = QFont()
font1.setFamilies([u"\u9ed1\u4f53"])
font1.setPointSize(14)
self.action_selectPath.setFont(font1)
self.action = QAction(MainWindow_cut_PSG)
self.action = QAction(MainWindow_cut_PAIR_FILE)
self.action.setObjectName(u"action")
self.action.setFont(font1)
self.centralwidget = QWidget(MainWindow_cut_PSG)
self.centralwidget = QWidget(MainWindow_cut_PAIR_FILE)
self.centralwidget.setObjectName(u"centralwidget")
self.gridLayout = QGridLayout(self.centralwidget)
self.gridLayout.setObjectName(u"gridLayout")
@ -55,22 +56,33 @@ class Ui_MainWindow_cut_PSG(object):
self.groupBox_3.setFont(font2)
self.gridLayout_2 = QGridLayout(self.groupBox_3)
self.gridLayout_2.setObjectName(u"gridLayout_2")
self.groupBox = QGroupBox(self.groupBox_3)
self.groupBox.setObjectName(u"groupBox")
self.verticalLayout_6 = QVBoxLayout(self.groupBox)
self.verticalLayout_6.setObjectName(u"verticalLayout_6")
self.textBrowser_info = QTextBrowser(self.groupBox)
self.textBrowser_info.setObjectName(u"textBrowser_info")
self.verticalLayout_6.addWidget(self.textBrowser_info)
self.gridLayout_2.addWidget(self.groupBox, 1, 0, 1, 1)
self.groupBox_2 = QGroupBox(self.groupBox_3)
self.groupBox_2.setObjectName(u"groupBox_2")
self.verticalLayout_5 = QVBoxLayout(self.groupBox_2)
self.verticalLayout_5.setObjectName(u"verticalLayout_5")
self.horizontalLayout_3 = QHBoxLayout()
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
self.checkBox_roughCut = QCheckBox(self.groupBox_2)
self.checkBox_roughCut.setObjectName(u"checkBox_roughCut")
self.checkBox_roughCut.setFont(font)
self.horizontalLayout_3.addWidget(self.checkBox_roughCut)
self.checkBox_roughResample = QCheckBox(self.groupBox_2)
self.checkBox_roughResample.setObjectName(u"checkBox_roughResample")
self.checkBox_roughResample.setFont(font)
self.horizontalLayout_3.addWidget(self.checkBox_roughResample)
self.pushButton_deleteRoughCut = QPushButton(self.groupBox_2)
self.pushButton_deleteRoughCut.setObjectName(u"pushButton_deleteRoughCut")
self.pushButton_deleteRoughCut.setFont(font)
self.horizontalLayout_3.addWidget(self.pushButton_deleteRoughCut)
self.verticalLayout_5.addLayout(self.horizontalLayout_3)
self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.label_2 = QLabel(self.groupBox_2)
@ -110,13 +122,23 @@ class Ui_MainWindow_cut_PSG(object):
self.verticalLayout_5.addLayout(self.horizontalLayout_6)
self.horizontalLayout_7 = QHBoxLayout()
self.horizontalLayout_7.setObjectName(u"horizontalLayout_7")
self.label_7 = QLabel(self.groupBox_2)
self.label_7.setObjectName(u"label_7")
self.label_7.setFont(font)
self.gridLayout_3 = QGridLayout()
self.gridLayout_3.setObjectName(u"gridLayout_3")
self.label = QLabel(self.groupBox_2)
self.label.setObjectName(u"label")
self.label.setEnabled(False)
self.label.setFont(font)
self.horizontalLayout_7.addWidget(self.label_7)
self.gridLayout_3.addWidget(self.label, 1, 0, 1, 1)
self.spinBox = QSpinBox(self.groupBox_2)
self.spinBox.setObjectName(u"spinBox")
self.spinBox.setEnabled(False)
self.spinBox.setFont(font)
self.spinBox.setMinimum(1)
self.spinBox.setMaximum(1000000)
self.gridLayout_3.addWidget(self.spinBox, 1, 1, 1, 1)
self.spinBox_ECGFreq = QSpinBox(self.groupBox_2)
self.spinBox_ECGFreq.setObjectName(u"spinBox_ECGFreq")
@ -124,12 +146,30 @@ class Ui_MainWindow_cut_PSG(object):
self.spinBox_ECGFreq.setMinimum(1)
self.spinBox_ECGFreq.setMaximum(1000000)
self.horizontalLayout_7.addWidget(self.spinBox_ECGFreq)
self.gridLayout_3.addWidget(self.spinBox_ECGFreq, 0, 1, 1, 1)
self.horizontalLayout_7.setStretch(0, 1)
self.horizontalLayout_7.setStretch(1, 1)
self.label_7 = QLabel(self.groupBox_2)
self.label_7.setObjectName(u"label_7")
self.label_7.setFont(font)
self.verticalLayout_5.addLayout(self.horizontalLayout_7)
self.gridLayout_3.addWidget(self.label_7, 0, 0, 1, 1)
self.label_3 = QLabel(self.groupBox_2)
self.label_3.setObjectName(u"label_3")
self.label_3.setFont(font2)
self.gridLayout_3.addWidget(self.label_3, 2, 0, 1, 1)
self.spinBox_OrgBCGShift = QSpinBox(self.groupBox_2)
self.spinBox_OrgBCGShift.setObjectName(u"spinBox_OrgBCGShift")
self.spinBox_OrgBCGShift.setFont(font)
self.spinBox_OrgBCGShift.setMinimum(-10000000)
self.spinBox_OrgBCGShift.setMaximum(10000000)
self.gridLayout_3.addWidget(self.spinBox_OrgBCGShift, 2, 1, 1, 1)
self.verticalLayout_5.addLayout(self.gridLayout_3)
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
@ -159,15 +199,28 @@ class Ui_MainWindow_cut_PSG(object):
self.verticalLayout_5.addWidget(self.progressbar)
self.verticalLayout_5.setStretch(0, 2)
self.verticalLayout_5.setStretch(0, 1)
self.verticalLayout_5.setStretch(1, 2)
self.verticalLayout_5.setStretch(2, 1)
self.verticalLayout_5.setStretch(3, 2)
self.verticalLayout_5.setStretch(4, 1)
self.verticalLayout_5.setStretch(2, 2)
self.verticalLayout_5.setStretch(3, 1)
self.verticalLayout_5.setStretch(4, 2)
self.verticalLayout_5.setStretch(5, 1)
self.verticalLayout_5.setStretch(6, 1)
self.gridLayout_2.addWidget(self.groupBox_2, 0, 0, 1, 2)
self.groupBox = QGroupBox(self.groupBox_3)
self.groupBox.setObjectName(u"groupBox")
self.verticalLayout_6 = QVBoxLayout(self.groupBox)
self.verticalLayout_6.setObjectName(u"verticalLayout_6")
self.textBrowser_info = QTextBrowser(self.groupBox)
self.textBrowser_info.setObjectName(u"textBrowser_info")
self.verticalLayout_6.addWidget(self.textBrowser_info)
self.gridLayout_2.addWidget(self.groupBox, 1, 0, 1, 1)
self.pushButton_execute = QPushButton(self.groupBox_3)
self.pushButton_execute.setObjectName(u"pushButton_execute")
sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Preferred)
@ -180,34 +233,37 @@ class Ui_MainWindow_cut_PSG(object):
self.gridLayout_2.addWidget(self.pushButton_execute, 1, 1, 1, 1)
self.gridLayout_2.setRowStretch(0, 7)
self.gridLayout_2.setRowStretch(1, 3)
self.gridLayout_2.setColumnStretch(0, 4)
self.gridLayout_2.setColumnStretch(1, 1)
self.gridLayout.addWidget(self.groupBox_3, 0, 0, 1, 1)
self.gridLayout.setColumnStretch(0, 2)
MainWindow_cut_PSG.setCentralWidget(self.centralwidget)
self.statusbar = QStatusBar(MainWindow_cut_PSG)
MainWindow_cut_PAIR_FILE.setCentralWidget(self.centralwidget)
self.statusbar = QStatusBar(MainWindow_cut_PAIR_FILE)
self.statusbar.setObjectName(u"statusbar")
MainWindow_cut_PSG.setStatusBar(self.statusbar)
MainWindow_cut_PAIR_FILE.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow_cut_PSG)
self.retranslateUi(MainWindow_cut_PAIR_FILE)
QMetaObject.connectSlotsByName(MainWindow_cut_PSG)
QMetaObject.connectSlotsByName(MainWindow_cut_PAIR_FILE)
# setupUi
def retranslateUi(self, MainWindow_cut_PSG):
MainWindow_cut_PSG.setWindowTitle(QCoreApplication.translate("MainWindow_cut_PSG", u"\u5197\u4f59\u6570\u636e\u5207\u5272\u548c\u6807\u7b7e\u6620\u5c04", None))
self.action_selectPath.setText(QCoreApplication.translate("MainWindow_cut_PSG", u"\u6570\u636e\u8def\u5f84\u9009\u62e9", None))
self.action.setText(QCoreApplication.translate("MainWindow_cut_PSG", u"\u52a0\u8f7d\u5b58\u6863", None))
self.groupBox_3.setTitle(QCoreApplication.translate("MainWindow_cut_PSG", u"\u5197\u4f59\u6570\u636e\u5207\u5272\u548c\u6807\u7b7e\u6620\u5c04", None))
self.groupBox.setTitle(QCoreApplication.translate("MainWindow_cut_PSG", u"\u65e5\u5fd7", None))
self.groupBox_2.setTitle(QCoreApplication.translate("MainWindow_cut_PSG", u"\u786e\u5b9a\u6570\u636e", None))
self.label_2.setText(QCoreApplication.translate("MainWindow_cut_PSG", u"\u9700\u8981\u5207\u5272\u7684\u901a\u9053\u540d\uff1a", None))
self.label_6.setText(QCoreApplication.translate("MainWindow_cut_PSG", u"\u9700\u8981\u6620\u5c04\u7684\u6807\u7b7e\uff1a", None))
self.label_7.setText(QCoreApplication.translate("MainWindow_cut_PSG", u"\u6570\u636e\u7cbe\u540c\u6b65\u65f6ECG\u7684\u91c7\u6837\u7387\uff1a", None))
self.label_show.setText(QCoreApplication.translate("MainWindow_cut_PSG", u"\u70b9\u51fb\u6267\u884c\u4ee5\u5f00\u59cb...", None))
self.pushButton_execute.setText(QCoreApplication.translate("MainWindow_cut_PSG", u"\u6267\u884c", None))
def retranslateUi(self, MainWindow_cut_PAIR_FILE):
MainWindow_cut_PAIR_FILE.setWindowTitle(QCoreApplication.translate("MainWindow_cut_PAIR_FILE", u"\u5197\u4f59\u6570\u636e\u5207\u5272\u548c\u6807\u7b7e\u6620\u5c04", None))
self.action_selectPath.setText(QCoreApplication.translate("MainWindow_cut_PAIR_FILE", u"\u6570\u636e\u8def\u5f84\u9009\u62e9", None))
self.action.setText(QCoreApplication.translate("MainWindow_cut_PAIR_FILE", u"\u52a0\u8f7d\u5b58\u6863", None))
self.groupBox_3.setTitle(QCoreApplication.translate("MainWindow_cut_PAIR_FILE", u"\u5197\u4f59\u6570\u636e\u5207\u5272\u548c\u6807\u7b7e\u6620\u5c04", None))
self.groupBox_2.setTitle(QCoreApplication.translate("MainWindow_cut_PAIR_FILE", u"\u786e\u5b9a\u6570\u636e", None))
self.checkBox_roughCut.setText(QCoreApplication.translate("MainWindow_cut_PAIR_FILE", u"\u7c97\u5bf9\u9f50\u7ed3\u679c\u5207\u5272\u6a21\u5f0f", None))
self.checkBox_roughResample.setText(QCoreApplication.translate("MainWindow_cut_PAIR_FILE", u"\u7c97\u5bf9\u9f50\u91cd\u91c7\u6837", None))
self.pushButton_deleteRoughCut.setText(QCoreApplication.translate("MainWindow_cut_PAIR_FILE", u"\u5220\u9664\u7c97\u5bf9\u9f50\u5207\u5272\u6587\u4ef6", None))
self.label_2.setText(QCoreApplication.translate("MainWindow_cut_PAIR_FILE", u"\u9700\u8981\u5207\u5272\u7684\u901a\u9053\u540d\uff1a", None))
self.label_6.setText(QCoreApplication.translate("MainWindow_cut_PAIR_FILE", u"\u9700\u8981\u6620\u5c04\u7684\u6807\u7b7e\uff1a", None))
self.label.setText(QCoreApplication.translate("MainWindow_cut_PAIR_FILE", u"BCG\u539f\u59cb\u91c7\u6837\u7387\uff1a", None))
self.label_7.setText(QCoreApplication.translate("MainWindow_cut_PAIR_FILE", u"\u6570\u636e\u7cbe\u540c\u6b65\u65f6ECG\u7684\u91c7\u6837\u7387\uff1a", None))
self.label_3.setText(QCoreApplication.translate("MainWindow_cut_PAIR_FILE", u"\u7c97\u5bf9\u9f50\u5fae\u8c03\u79d2\u6570(-\uff1a\u538b\u7535\u5de6\u79fb +\uff1a\u538b\u7535\u53f3\u79fb)", None))
self.label_show.setText(QCoreApplication.translate("MainWindow_cut_PAIR_FILE", u"\u70b9\u51fb\u6267\u884c\u4ee5\u5f00\u59cb...", None))
self.groupBox.setTitle(QCoreApplication.translate("MainWindow_cut_PAIR_FILE", u"\u65e5\u5fd7", None))
self.pushButton_execute.setText(QCoreApplication.translate("MainWindow_cut_PAIR_FILE", u"\u6267\u884c", None))
# retranslateUi

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow_cut_PSG</class>
<widget class="QMainWindow" name="MainWindow_cut_PSG">
<class>MainWindow_cut_PAIR_FILE</class>
<widget class="QMainWindow" name="MainWindow_cut_PAIR_FILE">
<property name="enabled">
<bool>true</bool>
</property>
@ -9,8 +9,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>540</width>
<height>720</height>
<width>548</width>
<height>739</height>
</rect>
</property>
<property name="sizePolicy">
@ -39,25 +39,53 @@
<property name="title">
<string>冗余数据切割和标签映射</string>
</property>
<layout class="QGridLayout" name="gridLayout_2" rowstretch="7,3" columnstretch="4,1">
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>日志</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QTextBrowser" name="textBrowser_info"/>
</item>
</layout>
</widget>
</item>
<layout class="QGridLayout" name="gridLayout_2" rowstretch="7,0" columnstretch="4,0">
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>确定数据</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5" stretch="2,2,1,2,1,1">
<layout class="QVBoxLayout" name="verticalLayout_5" stretch="1,2,2,1,2,1,1">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QCheckBox" name="checkBox_roughCut">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>粗对齐结果切割模式</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_roughResample">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>粗对齐重采样</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_deleteRoughCut">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>删除粗对齐切割文件</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1">
<item>
@ -108,20 +136,41 @@
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7" stretch="1,1">
<item>
<widget class="QLabel" name="label_7">
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="enabled">
<bool>false</bool>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>数据精同步时ECG的采样率:</string>
<string>BCG原始采样率:</string>
</property>
</widget>
</item>
<item>
<item row="1" column="1">
<widget class="QSpinBox" name="spinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000000</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spinBox_ECGFreq">
<property name="font">
<font>
@ -136,6 +185,45 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_7">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>数据精同步时ECG的采样率</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>粗对齐微调秒数(-:压电左移 +:压电右移)</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spinBox_OrgBCGShift">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="minimum">
<number>-10000000</number>
</property>
<property name="maximum">
<number>10000000</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
@ -189,6 +277,18 @@
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>日志</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QTextBrowser" name="textBrowser_info"/>
</item>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="pushButton_execute">
<property name="sizePolicy">

View File

@ -3,7 +3,7 @@
################################################################################
## Form generated from reading UI file 'MainWindow_detect_Jpeak.ui'
##
## Created by: Qt User Interface Compiler version 6.8.2
## Created by: Qt User Interface Compiler version 6.9.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
@ -16,10 +16,10 @@ from PySide6.QtGui import (QAction, QBrush, QColor, QConicalGradient,
QIcon, QImage, QKeySequence, QLinearGradient,
QPainter, QPalette, QPixmap, QRadialGradient,
QTransform)
from PySide6.QtWidgets import (QApplication, QCheckBox, QComboBox, QDoubleSpinBox,
QGridLayout, QGroupBox, QHBoxLayout, QLabel,
QMainWindow, QPushButton, QRadioButton, QSizePolicy,
QSpacerItem, QSpinBox, QStatusBar, QTextBrowser,
from PySide6.QtWidgets import (QAbstractSpinBox, QApplication, QCheckBox, QComboBox,
QDoubleSpinBox, QGridLayout, QGroupBox, QHBoxLayout,
QLabel, QMainWindow, QPushButton, QRadioButton,
QSizePolicy, QSpinBox, QStatusBar, QTextBrowser,
QVBoxLayout, QWidget)
class Ui_MainWindow_detect_Jpeak(object):
@ -221,26 +221,77 @@ class Ui_MainWindow_detect_Jpeak(object):
self.groupBox_3 = QGroupBox(self.groupBox_args)
self.groupBox_3.setObjectName(u"groupBox_3")
self.verticalLayout_2 = QVBoxLayout(self.groupBox_3)
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
self.gridLayout_3 = QGridLayout(self.groupBox_3)
self.gridLayout_3.setObjectName(u"gridLayout_3")
self.spinBox_scaleValue = QSpinBox(self.groupBox_3)
self.spinBox_scaleValue.setObjectName(u"spinBox_scaleValue")
self.spinBox_scaleValue.setFont(font)
self.spinBox_scaleValue.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
self.spinBox_scaleValue.setMinimum(10)
self.spinBox_scaleValue.setMaximum(1000)
self.spinBox_scaleValue.setValue(100)
self.gridLayout_3.addWidget(self.spinBox_scaleValue, 1, 1, 1, 1)
self.checkBox_useCPU = QCheckBox(self.groupBox_3)
self.checkBox_useCPU.setObjectName(u"checkBox_useCPU")
self.checkBox_useCPU.setFont(font)
self.verticalLayout_2.addWidget(self.checkBox_useCPU)
self.label_7 = QLabel(self.groupBox_3)
self.label_7.setObjectName(u"label_7")
self.label_7.setFont(font)
self.label_7.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.verticalLayout_2.addWidget(self.label_7)
self.gridLayout_3.addWidget(self.checkBox_useCPU, 0, 0, 1, 1)
self.comboBox_model = QComboBox(self.groupBox_3)
self.comboBox_model.setObjectName(u"comboBox_model")
sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
sizePolicy2.setHorizontalStretch(0)
sizePolicy2.setVerticalStretch(0)
sizePolicy2.setHeightForWidth(self.comboBox_model.sizePolicy().hasHeightForWidth())
self.comboBox_model.setSizePolicy(sizePolicy2)
self.comboBox_model.setFont(font)
self.verticalLayout_2.addWidget(self.comboBox_model)
self.gridLayout_3.addWidget(self.comboBox_model, 4, 1, 1, 1)
self.checkBox_scaleEnable = QCheckBox(self.groupBox_3)
self.checkBox_scaleEnable.setObjectName(u"checkBox_scaleEnable")
self.checkBox_scaleEnable.setFont(font)
self.gridLayout_3.addWidget(self.checkBox_scaleEnable, 1, 0, 1, 1)
self.label_8 = QLabel(self.groupBox_3)
self.label_8.setObjectName(u"label_8")
sizePolicy3 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Preferred)
sizePolicy3.setHorizontalStretch(0)
sizePolicy3.setVerticalStretch(0)
sizePolicy3.setHeightForWidth(self.label_8.sizePolicy().hasHeightForWidth())
self.label_8.setSizePolicy(sizePolicy3)
self.label_8.setFont(font)
self.label_8.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.gridLayout_3.addWidget(self.label_8, 2, 0, 1, 1)
self.comboBox_batchSize = QComboBox(self.groupBox_3)
self.comboBox_batchSize.addItem("")
self.comboBox_batchSize.addItem("")
self.comboBox_batchSize.addItem("")
self.comboBox_batchSize.addItem("")
self.comboBox_batchSize.addItem("")
self.comboBox_batchSize.addItem("")
self.comboBox_batchSize.addItem("")
self.comboBox_batchSize.setObjectName(u"comboBox_batchSize")
self.comboBox_batchSize.setFont(font)
self.gridLayout_3.addWidget(self.comboBox_batchSize, 2, 1, 1, 1)
self.label_7 = QLabel(self.groupBox_3)
self.label_7.setObjectName(u"label_7")
sizePolicy4 = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Preferred)
sizePolicy4.setHorizontalStretch(0)
sizePolicy4.setVerticalStretch(0)
sizePolicy4.setHeightForWidth(self.label_7.sizePolicy().hasHeightForWidth())
self.label_7.setSizePolicy(sizePolicy4)
self.label_7.setFont(font)
self.label_7.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.gridLayout_3.addWidget(self.label_7, 4, 0, 1, 1)
self.verticalLayout_5.addWidget(self.groupBox_3)
@ -253,10 +304,6 @@ class Ui_MainWindow_detect_Jpeak(object):
self.verticalLayout.addWidget(self.groupBox_args)
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
self.verticalLayout.addItem(self.verticalSpacer)
self.horizontalLayout_3 = QHBoxLayout()
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
self.pushButton_view = QPushButton(self.groupBox_left)
@ -292,9 +339,8 @@ class Ui_MainWindow_detect_Jpeak(object):
self.verticalLayout.setStretch(0, 1)
self.verticalLayout.setStretch(1, 7)
self.verticalLayout.setStretch(2, 4)
self.verticalLayout.setStretch(3, 1)
self.verticalLayout.setStretch(4, 5)
self.verticalLayout.setStretch(2, 1)
self.verticalLayout.setStretch(3, 5)
self.gridLayout.addWidget(self.groupBox_left, 0, 0, 1, 1)
@ -330,7 +376,17 @@ class Ui_MainWindow_detect_Jpeak(object):
self.label_4.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"~", None))
self.groupBox_3.setTitle(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u6a21\u578b\u8bbe\u7f6e", None))
self.checkBox_useCPU.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u5f3a\u5236\u4f7f\u7528CPU", None))
self.label_7.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u68c0\u6d4b\u6a21\u578b\u9009\u62e9", None))
self.checkBox_scaleEnable.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u5b9a\u4f4d\u65f6\u5e45\u503c\u653e\u7f29", None))
self.label_8.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"Batch Size:", None))
self.comboBox_batchSize.setItemText(0, QCoreApplication.translate("MainWindow_detect_Jpeak", u"0", None))
self.comboBox_batchSize.setItemText(1, QCoreApplication.translate("MainWindow_detect_Jpeak", u"64", None))
self.comboBox_batchSize.setItemText(2, QCoreApplication.translate("MainWindow_detect_Jpeak", u"128", None))
self.comboBox_batchSize.setItemText(3, QCoreApplication.translate("MainWindow_detect_Jpeak", u"256", None))
self.comboBox_batchSize.setItemText(4, QCoreApplication.translate("MainWindow_detect_Jpeak", u"512", None))
self.comboBox_batchSize.setItemText(5, QCoreApplication.translate("MainWindow_detect_Jpeak", u"1024", None))
self.comboBox_batchSize.setItemText(6, QCoreApplication.translate("MainWindow_detect_Jpeak", u"2048", None))
self.label_7.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u68c0\u6d4b\u6a21\u578b\u9009\u62e9\uff1a", None))
self.pushButton_view.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u67e5\u770b\u7ed3\u679c", None))
self.pushButton_save.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u4fdd\u5b58\u7ed3\u679c", None))
self.groupBox.setTitle(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u65e5\u5fd7", None))

View File

@ -56,7 +56,7 @@
<property name="title">
<string>BCG的J峰算法定位</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="1,7,4,1,5">
<layout class="QVBoxLayout" name="verticalLayout" stretch="1,7,1,5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
@ -321,8 +321,29 @@
<property name="title">
<string>模型设置</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="1">
<widget class="QSpinBox" name="spinBox_scaleValue">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
</property>
<property name="minimum">
<number>10</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>100</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="checkBox_useCPU">
<property name="font">
<font>
@ -334,48 +355,124 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_7">
<item row="4" column="1">
<widget class="QComboBox" name="comboBox_model">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkBox_scaleEnable">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>检测模型选择</string>
<string>定位时幅值放缩</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_8">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>Batch Size:</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_model">
<item row="2" column="1">
<widget class="QComboBox" name="comboBox_batchSize">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<item>
<property name="text">
<string>0</string>
</property>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
<property name="text">
<string>64</string>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</item>
<item>
<property name="text">
<string>128</string>
</property>
</spacer>
</item>
<item>
<property name="text">
<string>256</string>
</property>
</item>
<item>
<property name="text">
<string>512</string>
</property>
</item>
<item>
<property name="text">
<string>1024</string>
</property>
</item>
<item>
<property name="text">
<string>2048</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_7">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>检测模型选择:</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">

View File

@ -3,7 +3,7 @@
################################################################################
## Form generated from reading UI file 'MainWindow_label_check.ui'
##
## Created by: Qt User Interface Compiler version 6.8.2
## Created by: Qt User Interface Compiler version 6.9.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
@ -156,6 +156,14 @@ class Ui_MainWindow_label_check(object):
self.horizontalLayout_2.addWidget(self.pushButton_pause)
self.pushButton_update_state = QPushButton(self.groupBox_2)
self.pushButton_update_state.setObjectName(u"pushButton_update_state")
sizePolicy.setHeightForWidth(self.pushButton_update_state.sizePolicy().hasHeightForWidth())
self.pushButton_update_state.setSizePolicy(sizePolicy)
self.pushButton_update_state.setFont(font1)
self.horizontalLayout_2.addWidget(self.pushButton_update_state)
self.pushButton_next_move = QPushButton(self.groupBox_2)
self.pushButton_next_move.setObjectName(u"pushButton_next_move")
sizePolicy.setHeightForWidth(self.pushButton_next_move.sizePolicy().hasHeightForWidth())
@ -505,6 +513,13 @@ class Ui_MainWindow_label_check(object):
self.groupBox_2.setTitle(QCoreApplication.translate("MainWindow_label_check", u"\u81ea\u52a8\u64ad\u653e", None))
self.pushButton_prev_move.setText(QCoreApplication.translate("MainWindow_label_check", u"< <(A)", None))
self.pushButton_pause.setText(QCoreApplication.translate("MainWindow_label_check", u"| |(S)", None))
#if QT_CONFIG(tooltip)
self.pushButton_update_state.setToolTip(QCoreApplication.translate("MainWindow_label_check", u"\u6309\u4e0b\u540e\u6062\u590d\u4e0a\u6b21\u72b6\u6001", None))
#endif // QT_CONFIG(tooltip)
#if QT_CONFIG(whatsthis)
self.pushButton_update_state.setWhatsThis("")
#endif // QT_CONFIG(whatsthis)
self.pushButton_update_state.setText(QCoreApplication.translate("MainWindow_label_check", u"\u26aa( )", None))
self.pushButton_next_move.setText(QCoreApplication.translate("MainWindow_label_check", u"> >(D)", None))
self.groupBox_3.setTitle(QCoreApplication.translate("MainWindow_label_check", u"\u8bbe\u7f6e", None))
self.label_moveLength_preset_1.setText(QCoreApplication.translate("MainWindow_label_check", u"10000", None))

View File

@ -237,6 +237,30 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_update_state">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="toolTip">
<string>按下后恢复上次状态</string>
</property>
<property name="whatsThis">
<string/>
</property>
<property name="text">
<string>⚪( )</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_next_move">
<property name="sizePolicy">

View File

@ -3,7 +3,7 @@
################################################################################
## Form generated from reading UI file 'MainWindow_precisely_align.ui'
##
## Created by: Qt User Interface Compiler version 6.7.0
## Created by: Qt User Interface Compiler version 6.9.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
@ -27,7 +27,7 @@ class Ui_MainWindow_precisely_align(object):
if not MainWindow_precisely_align.objectName():
MainWindow_precisely_align.setObjectName(u"MainWindow_precisely_align")
MainWindow_precisely_align.setEnabled(True)
MainWindow_precisely_align.resize(1920, 1080)
MainWindow_precisely_align.resize(1912, 1061)
sizePolicy = QSizePolicy(QSizePolicy.Policy.Ignored, QSizePolicy.Policy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@ -69,6 +69,37 @@ class Ui_MainWindow_precisely_align(object):
self.groupBox_left.setFont(font2)
self.verticalLayout = QVBoxLayout(self.groupBox_left)
self.verticalLayout.setObjectName(u"verticalLayout")
self.horizontalLayout_7 = QHBoxLayout()
self.horizontalLayout_7.setObjectName(u"horizontalLayout_7")
self.label_18 = QLabel(self.groupBox_left)
self.label_18.setObjectName(u"label_18")
self.label_18.setFont(font)
self.label_18.setAlignment(Qt.AlignmentFlag.AlignRight|Qt.AlignmentFlag.AlignTrailing|Qt.AlignmentFlag.AlignVCenter)
self.horizontalLayout_7.addWidget(self.label_18)
self.label_sampno = QLabel(self.groupBox_left)
self.label_sampno.setObjectName(u"label_sampno")
self.label_sampno.setFont(font)
self.horizontalLayout_7.addWidget(self.label_sampno)
self.label_20 = QLabel(self.groupBox_left)
self.label_20.setObjectName(u"label_20")
self.label_20.setFont(font)
self.label_20.setAlignment(Qt.AlignmentFlag.AlignRight|Qt.AlignmentFlag.AlignTrailing|Qt.AlignmentFlag.AlignVCenter)
self.horizontalLayout_7.addWidget(self.label_20)
self.label_pos = QLabel(self.groupBox_left)
self.label_pos.setObjectName(u"label_pos")
self.label_pos.setFont(font)
self.horizontalLayout_7.addWidget(self.label_pos)
self.verticalLayout.addLayout(self.horizontalLayout_7)
self.horizontalLayout_4 = QHBoxLayout()
self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
self.pushButton_input_setting = QPushButton(self.groupBox_left)
@ -138,7 +169,12 @@ class Ui_MainWindow_precisely_align(object):
self.spinBox_BCG_front_Signal_2 = QSpinBox(self.groupBox_2)
self.spinBox_BCG_front_Signal_2.setObjectName(u"spinBox_BCG_front_Signal_2")
self.spinBox_BCG_front_Signal_2.setEnabled(False)
self.spinBox_BCG_front_Signal_2.setFont(font)
sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Preferred)
sizePolicy2.setHorizontalStretch(0)
sizePolicy2.setVerticalStretch(0)
sizePolicy2.setHeightForWidth(self.spinBox_BCG_front_Signal_2.sizePolicy().hasHeightForWidth())
self.spinBox_BCG_front_Signal_2.setSizePolicy(sizePolicy2)
self.spinBox_BCG_front_Signal_2.setFont(font2)
self.spinBox_BCG_front_Signal_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
self.spinBox_BCG_front_Signal_2.setMinimum(0)
self.spinBox_BCG_front_Signal_2.setMaximum(1000000000)
@ -147,7 +183,9 @@ class Ui_MainWindow_precisely_align(object):
self.spinBox_BCG_front_JJIV_1 = QSpinBox(self.groupBox_2)
self.spinBox_BCG_front_JJIV_1.setObjectName(u"spinBox_BCG_front_JJIV_1")
self.spinBox_BCG_front_JJIV_1.setFont(font)
sizePolicy2.setHeightForWidth(self.spinBox_BCG_front_JJIV_1.sizePolicy().hasHeightForWidth())
self.spinBox_BCG_front_JJIV_1.setSizePolicy(sizePolicy2)
self.spinBox_BCG_front_JJIV_1.setFont(font2)
self.spinBox_BCG_front_JJIV_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
self.spinBox_BCG_front_JJIV_1.setMinimum(0)
self.spinBox_BCG_front_JJIV_1.setMaximum(1000000000)
@ -163,7 +201,12 @@ class Ui_MainWindow_precisely_align(object):
self.label_4 = QLabel(self.groupBox_2)
self.label_4.setObjectName(u"label_4")
self.label_4.setFont(font)
sizePolicy3 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)
sizePolicy3.setHorizontalStretch(0)
sizePolicy3.setVerticalStretch(0)
sizePolicy3.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth())
self.label_4.setSizePolicy(sizePolicy3)
self.label_4.setFont(font2)
self.label_4.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.gridLayout_2.addWidget(self.label_4, 0, 3, 1, 1)
@ -171,7 +214,9 @@ class Ui_MainWindow_precisely_align(object):
self.spinBox_BCG_front_Signal_1 = QSpinBox(self.groupBox_2)
self.spinBox_BCG_front_Signal_1.setObjectName(u"spinBox_BCG_front_Signal_1")
self.spinBox_BCG_front_Signal_1.setEnabled(False)
self.spinBox_BCG_front_Signal_1.setFont(font)
sizePolicy2.setHeightForWidth(self.spinBox_BCG_front_Signal_1.sizePolicy().hasHeightForWidth())
self.spinBox_BCG_front_Signal_1.setSizePolicy(sizePolicy2)
self.spinBox_BCG_front_Signal_1.setFont(font2)
self.spinBox_BCG_front_Signal_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
self.spinBox_BCG_front_Signal_1.setMinimum(0)
self.spinBox_BCG_front_Signal_1.setMaximum(1000000000)
@ -180,7 +225,9 @@ class Ui_MainWindow_precisely_align(object):
self.spinBox_BCG_front_JJIV_2 = QSpinBox(self.groupBox_2)
self.spinBox_BCG_front_JJIV_2.setObjectName(u"spinBox_BCG_front_JJIV_2")
self.spinBox_BCG_front_JJIV_2.setFont(font)
sizePolicy2.setHeightForWidth(self.spinBox_BCG_front_JJIV_2.sizePolicy().hasHeightForWidth())
self.spinBox_BCG_front_JJIV_2.setSizePolicy(sizePolicy2)
self.spinBox_BCG_front_JJIV_2.setFont(font2)
self.spinBox_BCG_front_JJIV_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
self.spinBox_BCG_front_JJIV_2.setMinimum(0)
self.spinBox_BCG_front_JJIV_2.setMaximum(1000000000)
@ -189,20 +236,26 @@ class Ui_MainWindow_precisely_align(object):
self.label_6 = QLabel(self.groupBox_2)
self.label_6.setObjectName(u"label_6")
self.label_6.setFont(font)
sizePolicy3.setHeightForWidth(self.label_6.sizePolicy().hasHeightForWidth())
self.label_6.setSizePolicy(sizePolicy3)
self.label_6.setFont(font2)
self.label_6.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.gridLayout_2.addWidget(self.label_6, 1, 3, 1, 1)
self.label = QLabel(self.groupBox_2)
self.label.setObjectName(u"label")
self.label.setFont(font)
sizePolicy3.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
self.label.setSizePolicy(sizePolicy3)
self.label.setFont(font2)
self.gridLayout_2.addWidget(self.label, 0, 1, 1, 1)
self.label_2 = QLabel(self.groupBox_2)
self.label_2.setObjectName(u"label_2")
self.label_2.setFont(font)
sizePolicy3.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth())
self.label_2.setSizePolicy(sizePolicy3)
self.label_2.setFont(font2)
self.gridLayout_2.addWidget(self.label_2, 1, 1, 1, 1)
@ -221,7 +274,9 @@ class Ui_MainWindow_precisely_align(object):
self.spinBox_BCG_back_Signal_2 = QSpinBox(self.groupBox_4)
self.spinBox_BCG_back_Signal_2.setObjectName(u"spinBox_BCG_back_Signal_2")
self.spinBox_BCG_back_Signal_2.setEnabled(False)
self.spinBox_BCG_back_Signal_2.setFont(font)
sizePolicy2.setHeightForWidth(self.spinBox_BCG_back_Signal_2.sizePolicy().hasHeightForWidth())
self.spinBox_BCG_back_Signal_2.setSizePolicy(sizePolicy2)
self.spinBox_BCG_back_Signal_2.setFont(font2)
self.spinBox_BCG_back_Signal_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
self.spinBox_BCG_back_Signal_2.setMinimum(0)
self.spinBox_BCG_back_Signal_2.setMaximum(1000000000)
@ -231,7 +286,9 @@ class Ui_MainWindow_precisely_align(object):
self.spinBox_BCG_back_Signal_1 = QSpinBox(self.groupBox_4)
self.spinBox_BCG_back_Signal_1.setObjectName(u"spinBox_BCG_back_Signal_1")
self.spinBox_BCG_back_Signal_1.setEnabled(False)
self.spinBox_BCG_back_Signal_1.setFont(font)
sizePolicy2.setHeightForWidth(self.spinBox_BCG_back_Signal_1.sizePolicy().hasHeightForWidth())
self.spinBox_BCG_back_Signal_1.setSizePolicy(sizePolicy2)
self.spinBox_BCG_back_Signal_1.setFont(font2)
self.spinBox_BCG_back_Signal_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
self.spinBox_BCG_back_Signal_1.setMinimum(0)
self.spinBox_BCG_back_Signal_1.setMaximum(1000000000)
@ -240,7 +297,9 @@ class Ui_MainWindow_precisely_align(object):
self.spinBox_BCG_back_JJIV_2 = QSpinBox(self.groupBox_4)
self.spinBox_BCG_back_JJIV_2.setObjectName(u"spinBox_BCG_back_JJIV_2")
self.spinBox_BCG_back_JJIV_2.setFont(font)
sizePolicy2.setHeightForWidth(self.spinBox_BCG_back_JJIV_2.sizePolicy().hasHeightForWidth())
self.spinBox_BCG_back_JJIV_2.setSizePolicy(sizePolicy2)
self.spinBox_BCG_back_JJIV_2.setFont(font2)
self.spinBox_BCG_back_JJIV_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
self.spinBox_BCG_back_JJIV_2.setMinimum(0)
self.spinBox_BCG_back_JJIV_2.setMaximum(1000000000)
@ -256,7 +315,9 @@ class Ui_MainWindow_precisely_align(object):
self.spinBox_BCG_back_JJIV_1 = QSpinBox(self.groupBox_4)
self.spinBox_BCG_back_JJIV_1.setObjectName(u"spinBox_BCG_back_JJIV_1")
self.spinBox_BCG_back_JJIV_1.setFont(font)
sizePolicy2.setHeightForWidth(self.spinBox_BCG_back_JJIV_1.sizePolicy().hasHeightForWidth())
self.spinBox_BCG_back_JJIV_1.setSizePolicy(sizePolicy2)
self.spinBox_BCG_back_JJIV_1.setFont(font2)
self.spinBox_BCG_back_JJIV_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
self.spinBox_BCG_back_JJIV_1.setMinimum(0)
self.spinBox_BCG_back_JJIV_1.setMaximum(1000000000)
@ -265,27 +326,35 @@ class Ui_MainWindow_precisely_align(object):
self.label_7 = QLabel(self.groupBox_4)
self.label_7.setObjectName(u"label_7")
self.label_7.setFont(font)
sizePolicy3.setHeightForWidth(self.label_7.sizePolicy().hasHeightForWidth())
self.label_7.setSizePolicy(sizePolicy3)
self.label_7.setFont(font2)
self.label_7.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.gridLayout_3.addWidget(self.label_7, 1, 3, 1, 1)
self.label_5 = QLabel(self.groupBox_4)
self.label_5.setObjectName(u"label_5")
self.label_5.setFont(font)
sizePolicy3.setHeightForWidth(self.label_5.sizePolicy().hasHeightForWidth())
self.label_5.setSizePolicy(sizePolicy3)
self.label_5.setFont(font2)
self.label_5.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.gridLayout_3.addWidget(self.label_5, 0, 3, 1, 1)
self.label_3 = QLabel(self.groupBox_4)
self.label_3.setObjectName(u"label_3")
self.label_3.setFont(font)
sizePolicy3.setHeightForWidth(self.label_3.sizePolicy().hasHeightForWidth())
self.label_3.setSizePolicy(sizePolicy3)
self.label_3.setFont(font2)
self.gridLayout_3.addWidget(self.label_3, 0, 1, 1, 1)
self.label_12 = QLabel(self.groupBox_4)
self.label_12.setObjectName(u"label_12")
self.label_12.setFont(font)
sizePolicy3.setHeightForWidth(self.label_12.sizePolicy().hasHeightForWidth())
self.label_12.setSizePolicy(sizePolicy3)
self.label_12.setFont(font2)
self.gridLayout_3.addWidget(self.label_12, 1, 1, 1, 1)
@ -303,7 +372,9 @@ class Ui_MainWindow_precisely_align(object):
self.gridLayout_4.setObjectName(u"gridLayout_4")
self.spinBox_ECG_front_RRIV_2 = QSpinBox(self.groupBox_3)
self.spinBox_ECG_front_RRIV_2.setObjectName(u"spinBox_ECG_front_RRIV_2")
self.spinBox_ECG_front_RRIV_2.setFont(font)
sizePolicy2.setHeightForWidth(self.spinBox_ECG_front_RRIV_2.sizePolicy().hasHeightForWidth())
self.spinBox_ECG_front_RRIV_2.setSizePolicy(sizePolicy2)
self.spinBox_ECG_front_RRIV_2.setFont(font2)
self.spinBox_ECG_front_RRIV_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
self.spinBox_ECG_front_RRIV_2.setMinimum(0)
self.spinBox_ECG_front_RRIV_2.setMaximum(1000000000)
@ -312,7 +383,9 @@ class Ui_MainWindow_precisely_align(object):
self.label_10 = QLabel(self.groupBox_3)
self.label_10.setObjectName(u"label_10")
self.label_10.setFont(font)
sizePolicy3.setHeightForWidth(self.label_10.sizePolicy().hasHeightForWidth())
self.label_10.setSizePolicy(sizePolicy3)
self.label_10.setFont(font2)
self.label_10.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.gridLayout_4.addWidget(self.label_10, 1, 3, 1, 1)
@ -326,7 +399,9 @@ class Ui_MainWindow_precisely_align(object):
self.spinBox_ECG_front_Signal_2 = QSpinBox(self.groupBox_3)
self.spinBox_ECG_front_Signal_2.setObjectName(u"spinBox_ECG_front_Signal_2")
self.spinBox_ECG_front_Signal_2.setEnabled(False)
self.spinBox_ECG_front_Signal_2.setFont(font)
sizePolicy2.setHeightForWidth(self.spinBox_ECG_front_Signal_2.sizePolicy().hasHeightForWidth())
self.spinBox_ECG_front_Signal_2.setSizePolicy(sizePolicy2)
self.spinBox_ECG_front_Signal_2.setFont(font2)
self.spinBox_ECG_front_Signal_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
self.spinBox_ECG_front_Signal_2.setMinimum(0)
self.spinBox_ECG_front_Signal_2.setMaximum(1000000000)
@ -336,7 +411,9 @@ class Ui_MainWindow_precisely_align(object):
self.spinBox_ECG_front_Signal_1 = QSpinBox(self.groupBox_3)
self.spinBox_ECG_front_Signal_1.setObjectName(u"spinBox_ECG_front_Signal_1")
self.spinBox_ECG_front_Signal_1.setEnabled(False)
self.spinBox_ECG_front_Signal_1.setFont(font)
sizePolicy2.setHeightForWidth(self.spinBox_ECG_front_Signal_1.sizePolicy().hasHeightForWidth())
self.spinBox_ECG_front_Signal_1.setSizePolicy(sizePolicy2)
self.spinBox_ECG_front_Signal_1.setFont(font2)
self.spinBox_ECG_front_Signal_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
self.spinBox_ECG_front_Signal_1.setMinimum(0)
self.spinBox_ECG_front_Signal_1.setMaximum(1000000000)
@ -345,7 +422,9 @@ class Ui_MainWindow_precisely_align(object):
self.spinBox_ECG_front_RRIV_1 = QSpinBox(self.groupBox_3)
self.spinBox_ECG_front_RRIV_1.setObjectName(u"spinBox_ECG_front_RRIV_1")
self.spinBox_ECG_front_RRIV_1.setFont(font)
sizePolicy2.setHeightForWidth(self.spinBox_ECG_front_RRIV_1.sizePolicy().hasHeightForWidth())
self.spinBox_ECG_front_RRIV_1.setSizePolicy(sizePolicy2)
self.spinBox_ECG_front_RRIV_1.setFont(font2)
self.spinBox_ECG_front_RRIV_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
self.spinBox_ECG_front_RRIV_1.setMinimum(0)
self.spinBox_ECG_front_RRIV_1.setMaximum(1000000000)
@ -354,20 +433,26 @@ class Ui_MainWindow_precisely_align(object):
self.label_8 = QLabel(self.groupBox_3)
self.label_8.setObjectName(u"label_8")
self.label_8.setFont(font)
sizePolicy3.setHeightForWidth(self.label_8.sizePolicy().hasHeightForWidth())
self.label_8.setSizePolicy(sizePolicy3)
self.label_8.setFont(font2)
self.label_8.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.gridLayout_4.addWidget(self.label_8, 0, 3, 1, 1)
self.label_13 = QLabel(self.groupBox_3)
self.label_13.setObjectName(u"label_13")
self.label_13.setFont(font)
sizePolicy3.setHeightForWidth(self.label_13.sizePolicy().hasHeightForWidth())
self.label_13.setSizePolicy(sizePolicy3)
self.label_13.setFont(font2)
self.gridLayout_4.addWidget(self.label_13, 0, 1, 1, 1)
self.label_14 = QLabel(self.groupBox_3)
self.label_14.setObjectName(u"label_14")
self.label_14.setFont(font)
sizePolicy3.setHeightForWidth(self.label_14.sizePolicy().hasHeightForWidth())
self.label_14.setSizePolicy(sizePolicy3)
self.label_14.setFont(font2)
self.gridLayout_4.addWidget(self.label_14, 1, 1, 1, 1)
@ -391,14 +476,18 @@ class Ui_MainWindow_precisely_align(object):
self.label_11 = QLabel(self.groupBox_5)
self.label_11.setObjectName(u"label_11")
self.label_11.setFont(font)
sizePolicy3.setHeightForWidth(self.label_11.sizePolicy().hasHeightForWidth())
self.label_11.setSizePolicy(sizePolicy3)
self.label_11.setFont(font2)
self.label_11.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.gridLayout_5.addWidget(self.label_11, 1, 3, 1, 1)
self.spinBox_ECG_back_RRIV_2 = QSpinBox(self.groupBox_5)
self.spinBox_ECG_back_RRIV_2.setObjectName(u"spinBox_ECG_back_RRIV_2")
self.spinBox_ECG_back_RRIV_2.setFont(font)
sizePolicy2.setHeightForWidth(self.spinBox_ECG_back_RRIV_2.sizePolicy().hasHeightForWidth())
self.spinBox_ECG_back_RRIV_2.setSizePolicy(sizePolicy2)
self.spinBox_ECG_back_RRIV_2.setFont(font2)
self.spinBox_ECG_back_RRIV_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
self.spinBox_ECG_back_RRIV_2.setMinimum(0)
self.spinBox_ECG_back_RRIV_2.setMaximum(1000000000)
@ -408,7 +497,9 @@ class Ui_MainWindow_precisely_align(object):
self.spinBox_ECG_back_Signal_2 = QSpinBox(self.groupBox_5)
self.spinBox_ECG_back_Signal_2.setObjectName(u"spinBox_ECG_back_Signal_2")
self.spinBox_ECG_back_Signal_2.setEnabled(False)
self.spinBox_ECG_back_Signal_2.setFont(font)
sizePolicy2.setHeightForWidth(self.spinBox_ECG_back_Signal_2.sizePolicy().hasHeightForWidth())
self.spinBox_ECG_back_Signal_2.setSizePolicy(sizePolicy2)
self.spinBox_ECG_back_Signal_2.setFont(font2)
self.spinBox_ECG_back_Signal_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
self.spinBox_ECG_back_Signal_2.setMinimum(0)
self.spinBox_ECG_back_Signal_2.setMaximum(1000000000)
@ -417,7 +508,9 @@ class Ui_MainWindow_precisely_align(object):
self.spinBox_ECG_back_RRIV_1 = QSpinBox(self.groupBox_5)
self.spinBox_ECG_back_RRIV_1.setObjectName(u"spinBox_ECG_back_RRIV_1")
self.spinBox_ECG_back_RRIV_1.setFont(font)
sizePolicy2.setHeightForWidth(self.spinBox_ECG_back_RRIV_1.sizePolicy().hasHeightForWidth())
self.spinBox_ECG_back_RRIV_1.setSizePolicy(sizePolicy2)
self.spinBox_ECG_back_RRIV_1.setFont(font2)
self.spinBox_ECG_back_RRIV_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
self.spinBox_ECG_back_RRIV_1.setMinimum(0)
self.spinBox_ECG_back_RRIV_1.setMaximum(1000000000)
@ -427,7 +520,9 @@ class Ui_MainWindow_precisely_align(object):
self.spinBox_ECG_back_Signal_1 = QSpinBox(self.groupBox_5)
self.spinBox_ECG_back_Signal_1.setObjectName(u"spinBox_ECG_back_Signal_1")
self.spinBox_ECG_back_Signal_1.setEnabled(False)
self.spinBox_ECG_back_Signal_1.setFont(font)
sizePolicy2.setHeightForWidth(self.spinBox_ECG_back_Signal_1.sizePolicy().hasHeightForWidth())
self.spinBox_ECG_back_Signal_1.setSizePolicy(sizePolicy2)
self.spinBox_ECG_back_Signal_1.setFont(font2)
self.spinBox_ECG_back_Signal_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
self.spinBox_ECG_back_Signal_1.setMinimum(0)
self.spinBox_ECG_back_Signal_1.setMaximum(1000000000)
@ -436,20 +531,26 @@ class Ui_MainWindow_precisely_align(object):
self.label_9 = QLabel(self.groupBox_5)
self.label_9.setObjectName(u"label_9")
self.label_9.setFont(font)
sizePolicy3.setHeightForWidth(self.label_9.sizePolicy().hasHeightForWidth())
self.label_9.setSizePolicy(sizePolicy3)
self.label_9.setFont(font2)
self.label_9.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.gridLayout_5.addWidget(self.label_9, 0, 3, 1, 1)
self.label_15 = QLabel(self.groupBox_5)
self.label_15.setObjectName(u"label_15")
self.label_15.setFont(font)
sizePolicy3.setHeightForWidth(self.label_15.sizePolicy().hasHeightForWidth())
self.label_15.setSizePolicy(sizePolicy3)
self.label_15.setFont(font2)
self.gridLayout_5.addWidget(self.label_15, 0, 1, 1, 1)
self.label_16 = QLabel(self.groupBox_5)
self.label_16.setObjectName(u"label_16")
self.label_16.setFont(font)
sizePolicy3.setHeightForWidth(self.label_16.sizePolicy().hasHeightForWidth())
self.label_16.setSizePolicy(sizePolicy3)
self.label_16.setFont(font2)
self.gridLayout_5.addWidget(self.label_16, 1, 1, 1, 1)
@ -459,6 +560,42 @@ class Ui_MainWindow_precisely_align(object):
self.verticalLayout_5.addWidget(self.groupBox_5)
self.groupBox_7 = QGroupBox(self.groupBox_args)
self.groupBox_7.setObjectName(u"groupBox_7")
self.horizontalLayout_6 = QHBoxLayout(self.groupBox_7)
self.horizontalLayout_6.setObjectName(u"horizontalLayout_6")
self.gridLayout_6 = QGridLayout()
self.gridLayout_6.setObjectName(u"gridLayout_6")
self.pushButton_getPos = QPushButton(self.groupBox_7)
self.pushButton_getPos.setObjectName(u"pushButton_getPos")
self.pushButton_getPos.setFont(font)
self.gridLayout_6.addWidget(self.pushButton_getPos, 2, 0, 1, 1)
self.pushButton_resetPos = QPushButton(self.groupBox_7)
self.pushButton_resetPos.setObjectName(u"pushButton_resetPos")
self.pushButton_resetPos.setFont(font)
self.gridLayout_6.addWidget(self.pushButton_resetPos, 2, 1, 1, 1)
self.checkBox_sync_xlim = QCheckBox(self.groupBox_7)
self.checkBox_sync_xlim.setObjectName(u"checkBox_sync_xlim")
self.checkBox_sync_xlim.setFont(font)
self.checkBox_sync_xlim.setChecked(True)
self.gridLayout_6.addWidget(self.checkBox_sync_xlim, 0, 0, 1, 2)
self.label_19 = QLabel(self.groupBox_7)
self.label_19.setObjectName(u"label_19")
self.gridLayout_6.addWidget(self.label_19, 1, 0, 1, 2)
self.horizontalLayout_6.addLayout(self.gridLayout_6)
self.verticalLayout_5.addWidget(self.groupBox_7)
self.verticalLayout_5.setStretch(0, 2)
self.verticalLayout_5.setStretch(1, 2)
self.verticalLayout_5.setStretch(2, 2)
@ -467,10 +604,6 @@ class Ui_MainWindow_precisely_align(object):
self.verticalLayout.addWidget(self.groupBox_args)
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
self.verticalLayout.addItem(self.verticalSpacer)
self.horizontalLayout_8 = QHBoxLayout()
self.horizontalLayout_8.setObjectName(u"horizontalLayout_8")
self.pushButton_calculate_correlation = QPushButton(self.groupBox_left)
@ -526,7 +659,8 @@ class Ui_MainWindow_precisely_align(object):
self.verticalLayout.addWidget(self.groupBox)
self.verticalLayout.setStretch(0, 1)
self.verticalLayout.setStretch(1, 7)
self.verticalLayout.setStretch(1, 1)
self.verticalLayout.setStretch(2, 6)
self.verticalLayout.setStretch(3, 1)
self.verticalLayout.setStretch(4, 1)
self.verticalLayout.setStretch(5, 5)
@ -551,6 +685,10 @@ class Ui_MainWindow_precisely_align(object):
self.action.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u52a0\u8f7d\u5b58\u6863", None))
self.groupBox_canvas.setTitle(QCoreApplication.translate("MainWindow_precisely_align", u"\u7ed8\u56fe\u533a", None))
self.groupBox_left.setTitle(QCoreApplication.translate("MainWindow_precisely_align", u"\u6570\u636e\u7cbe\u540c\u6b65", None))
self.label_18.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u7f16\u53f7\uff1a", None))
self.label_sampno.setText(QCoreApplication.translate("MainWindow_precisely_align", u"None", None))
self.label_20.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u504f\u79fb\u91cf\uff1a", None))
self.label_pos.setText(QCoreApplication.translate("MainWindow_precisely_align", u"0", None))
self.pushButton_input_setting.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u5bfc\u5165\u8bbe\u7f6e", None))
self.pushButton_input.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u5f00\u59cb\u5bfc\u5165", None))
self.groupBox_args.setTitle(QCoreApplication.translate("MainWindow_precisely_align", u"\u53c2\u6570\u8f93\u5165", None))
@ -581,6 +719,11 @@ class Ui_MainWindow_precisely_align(object):
self.label_9.setText(QCoreApplication.translate("MainWindow_precisely_align", u"~", None))
self.label_15.setText(QCoreApplication.translate("MainWindow_precisely_align", u"RRIV\u5e8f\u53f7", None))
self.label_16.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u4fe1\u53f7\u5750\u6807", None))
self.groupBox_7.setTitle(QCoreApplication.translate("MainWindow_precisely_align", u"\u504f\u79fb\u91cf\u8c03\u6574", None))
self.pushButton_getPos.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u6355\u83b7\u5f53\u524d\u504f\u79fb\u91cf", None))
self.pushButton_resetPos.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u6062\u590d\u9ed8\u8ba4\u504f\u79fb\u91cf", None))
self.checkBox_sync_xlim.setText(QCoreApplication.translate("MainWindow_precisely_align", u"X\u8f74\u540c\u6b65\uff08\u4ec5\u5728\u9009\u5b9a\u533a\u95f4\u65f6\u6709\u6548\uff09", None))
self.label_19.setText(QCoreApplication.translate("MainWindow_precisely_align", u"Tips: \u91cd\u65b0\u6355\u83b7\u65f6\u5c06\u5bf9\u9f50\u70b9\u7f6e\u4e8ex\u8f74\u5de6\u4fa7\uff0c\u8ba1\u7b97x\u8f74\u8d77\u70b9\u5dee\u503c", None))
self.pushButton_calculate_correlation.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u8ba1\u7b97\u76f8\u5173\u6027", None))
self.pushButton_correlation_align.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u76f8\u5173\u5bf9\u9f50", None))
self.pushButton_view_align.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u67e5\u770b\u5bf9\u9f50\u7ed3\u679c", None))

View File

@ -9,8 +9,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>1920</width>
<height>1080</height>
<width>1912</width>
<height>1061</height>
</rect>
</property>
<property name="sizePolicy">
@ -56,7 +56,65 @@
<property name="title">
<string>数据精同步</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="1,7,0,1,1,5">
<layout class="QVBoxLayout" name="verticalLayout" stretch="1,1,6,1,1,5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QLabel" name="label_18">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>编号:</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_sampno">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>None</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_20">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>偏移量:</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_pos">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
@ -102,7 +160,7 @@
<property name="title">
<string>参数输入</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5" stretch="2,2,2,2,2">
<layout class="QVBoxLayout" name="verticalLayout_5" stretch="2,2,2,2,2,0">
<item>
<widget class="QGroupBox" name="groupBox_6">
<property name="title">
@ -177,9 +235,15 @@
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="buttonSymbols">
@ -195,9 +259,15 @@
</item>
<item row="0" column="2">
<widget class="QSpinBox" name="spinBox_BCG_front_JJIV_1">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="buttonSymbols">
@ -228,9 +298,15 @@
</item>
<item row="0" column="3">
<widget class="QLabel" name="label_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
@ -246,9 +322,15 @@
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="buttonSymbols">
@ -264,9 +346,15 @@
</item>
<item row="0" column="4">
<widget class="QSpinBox" name="spinBox_BCG_front_JJIV_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="buttonSymbols">
@ -282,9 +370,15 @@
</item>
<item row="1" column="3">
<widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
@ -297,9 +391,15 @@
</item>
<item row="0" column="1">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
@ -309,9 +409,15 @@
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
@ -337,9 +443,15 @@
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="buttonSymbols">
@ -358,9 +470,15 @@
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="buttonSymbols">
@ -376,9 +494,15 @@
</item>
<item row="0" column="4">
<widget class="QSpinBox" name="spinBox_BCG_back_JJIV_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="buttonSymbols">
@ -409,9 +533,15 @@
</item>
<item row="0" column="2">
<widget class="QSpinBox" name="spinBox_BCG_back_JJIV_1">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="buttonSymbols">
@ -427,9 +557,15 @@
</item>
<item row="1" column="3">
<widget class="QLabel" name="label_7">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
@ -442,9 +578,15 @@
</item>
<item row="0" column="3">
<widget class="QLabel" name="label_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
@ -457,9 +599,15 @@
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
@ -469,9 +617,15 @@
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_12">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
@ -494,9 +648,15 @@
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="4">
<widget class="QSpinBox" name="spinBox_ECG_front_RRIV_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="buttonSymbols">
@ -512,9 +672,15 @@
</item>
<item row="1" column="3">
<widget class="QLabel" name="label_10">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
@ -542,9 +708,15 @@
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="buttonSymbols">
@ -563,9 +735,15 @@
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="buttonSymbols">
@ -581,9 +759,15 @@
</item>
<item row="0" column="2">
<widget class="QSpinBox" name="spinBox_ECG_front_RRIV_1">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="buttonSymbols">
@ -599,9 +783,15 @@
</item>
<item row="0" column="3">
<widget class="QLabel" name="label_8">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
@ -614,9 +804,15 @@
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_13">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
@ -626,9 +822,15 @@
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_14">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
@ -663,9 +865,15 @@
</item>
<item row="1" column="3">
<widget class="QLabel" name="label_11">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
@ -678,9 +886,15 @@
</item>
<item row="0" column="4">
<widget class="QSpinBox" name="spinBox_ECG_back_RRIV_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="buttonSymbols">
@ -699,9 +913,15 @@
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="buttonSymbols">
@ -717,9 +937,15 @@
</item>
<item row="0" column="2">
<widget class="QSpinBox" name="spinBox_ECG_back_RRIV_1">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="buttonSymbols">
@ -738,9 +964,15 @@
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="buttonSymbols">
@ -756,9 +988,15 @@
</item>
<item row="0" column="3">
<widget class="QLabel" name="label_9">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
@ -771,9 +1009,15 @@
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_15">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
@ -783,9 +1027,15 @@
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_16">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
@ -798,21 +1048,67 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_7">
<property name="title">
<string>偏移量调整</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<layout class="QGridLayout" name="gridLayout_6">
<item row="2" column="0">
<widget class="QPushButton" name="pushButton_getPos">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>捕获当前偏移量</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="pushButton_resetPos">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>恢复默认偏移量</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QCheckBox" name="checkBox_sync_xlim">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>X轴同步仅在选定区间时有效</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Tips: 重新捕获时将对齐点置于x轴左侧计算x轴起点差值</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">