1、将原本的<预定位>步骤中的append.py的功能整合入此界面中的<片段合并>按钮中

2、优化了部分功能
This commit is contained in:
Yorusora 2025-02-21 16:00:31 +08:00
parent bbe6abc57f
commit d7195feff5
2 changed files with 117 additions and 17 deletions

52
append.py Normal file
View File

@ -0,0 +1,52 @@
import pandas as pd
import numpy as np
from pathlib import Path
def find_TPeak(data,peaks,th=50):
"""
找出真实的J峰或R峰
:param data: BCG或ECG数据
:param peaks: 初步峰值从label中导出的location_R
:param th: 范围阈值
:return: 真实峰值
"""
return_peak = []
for peak in peaks:
if peak>len(data):continue
min_win,max_win = max(0,int(peak-th)),min(len(data),int(peak+th))
return_peak.append(np.argmax(data[min_win:max_win])+min_win)
return np.array(return_peak)
def Rpeak_Detection(input_dir, fs, th1):
raw_ecg = pd.read_csv(Path(input_dir) / "filter_ecg.txt").to_numpy().reshape(-1)
# raw_ecg = raw_ecg[200*sample_rate:]
#######################限制幅值处理############################################
# for i in range(len(raw_ecg)):
# if raw_ecg[i] > 300 or raw_ecg[i] < -300:
# raw_ecg[i] = 0
##############################################################################
all_R_peak = np.array([])
##############################切割处理##########################################
for file_num in range(1, len(list((Path(input_dir) / "label").rglob("*location_J.txt"))) + 1):
R_peak_dir = Path(input_dir) / "label" / (str(file_num) + 'location_J.txt')
R_peak = np.array(pd.read_csv(R_peak_dir, header=None)).reshape(-1)
R_peak = R_peak + fs * 3600 * (file_num - 1)
all_R_peak = np.append(all_R_peak, R_peak)
##############################################################################
all_R_peak = find_TPeak(raw_ecg, all_R_peak, th=int(th1 * fs / 1000))
RR_Interval = np.full(len(all_R_peak) - 1, np.nan)
for i in range(len(all_R_peak) - 1):
RR_Interval[i] = all_R_peak[i + 1] - all_R_peak[i]
RRIV = np.full(len(RR_Interval) - 1, np.nan)
for i in range(len(RR_Interval) - 1):
RRIV[i] = RR_Interval[i + 1] - RR_Interval[i]
Interval = np.full(len(raw_ecg), np.nan)
for i in range(len(all_R_peak) - 1):
Interval[all_R_peak[i]: all_R_peak[i + 1]] = all_R_peak[i + 1] - all_R_peak[i]
return all_R_peak.reshape(-1)

View File

@ -9,7 +9,9 @@ import sys
from logging import NOTSET, getLogger, FileHandler, Formatter, StreamHandler, info, error, debug
from time import time, strftime, localtime
import pandas as pd
import numpy as np
from PyQt5 import QtGui
from PyQt5.QtGui import QFont, QDoubleValidator, QIntValidator
from matplotlib.ticker import FuncFormatter
from numpy import load, nan, zeros, append, linspace, place
@ -20,9 +22,10 @@ from datetime import datetime
from pathlib import Path
from PyQt5.QtCore import QCoreApplication, QTimer
from PyQt5.QtWidgets import QFileDialog, QMainWindow, QMessageBox, QButtonGroup, QApplication, QTableWidgetItem, \
QLineEdit, QAction, QTableWidget
QLineEdit, QAction, QTableWidget, QDialog, QVBoxLayout, QLabel, QPushButton, QDialogButtonBox
from scipy.signal import butter, filtfilt, find_peaks
import append
from MainWindow import Ui_MainWindow
use("Qt5Agg") # 声明使用QT5
@ -153,7 +156,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.radioButton_data1_fillterMode.setChecked(True)
self.radioButton_data2_fillterMode.setChecked(True)
self.radioButton_move_preset_1.setChecked(True)
self.pushButton_append.setEnabled(False)
self.pushButton_outputLabel.setEnabled(False)
self.figToolbar.action_Label_Single.setEnabled(False)
self.figToolbar.action_Label_Multiple.setEnabled(False)
@ -362,7 +364,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# 更新界面
self.groupBox_inputSetting.setEnabled(False)
self.groupBox_autoplay.setEnabled(True)
self.pushButton_append.setEnabled(True)
self.pushButton_outputLabel.setEnabled(True)
self.figToolbar.action_Label_Single.setEnabled(True)
self.figToolbar.action_Label_Multiple.setEnabled(True)
@ -388,6 +389,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# 保存路径文件是否存在的检查
if not Path(self.lineEdit_savepath.text()).exists():
Path(self.lineEdit_savepath.text()).touch()
np.savetxt(Path(self.lineEdit_savepath.text()), self.label2, fmt='%d', newline='\n')
info("Finished Input Data.")
self.textBrowser_update("提示:导入数据完成")
@ -574,22 +576,25 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.textBrowser_update(f"操作跳转到x坐标: {str(int(x))}")
def slot_btn_append(self):
# TODO
reply = QMessageBox.question(self, "警告:确认操作", f"你正在执行<片段合并>,请确保需要被合并的片段已完成标注工作。你确定要将片段合并,并将结果保存到{self.lineEdit_resample1000Hz_save_path.text()}", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
for idx in range(len(self.ecg_seq)):
DataFrame(self.ecg_seq[idx].reshape(-1)).to_csv(
str(Path(self.lineEdit_detect_Rpeaks_save_path.text()) / f"{idx + 1}ecg.txt"), index=False,
header=None)
DataFrame(self.R_peak_seq[idx].reshape(-1)).to_csv(
str(Path(self.lineEdit_detect_Rpeaks_save_path.text()) / f"{idx + 1}Rpeak.txt"), index=False,
header=None)
info(f"Saved Data {idx + 1} to Directory {self.lineEdit_detect_Rpeaks_save_path.text()}.")
self.textBrowser_update(
f"提示:保存片段{idx + 1}成功至文件夹{self.lineEdit_detect_Rpeaks_save_path.text()}")
self.msgBox.setText(f"保存成功至{self.lineEdit_detect_Rpeaks_save_path.text()}")
dialog = CustomMessageBox(self)
reply = dialog.exec_()
if reply == QDialog.Accepted:
if self.lineEdit_rootpath.text() == "" or len(list((Path(self.lineEdit_rootpath.text()) / "label").rglob("*location_J.txt"))) == 0:
info(f"*location_J.txt Files not Exist in the Directory.")
self.textBrowser_update(f"错误:无法进行<片段合并>")
self.msgBox.setText(f"目录下不存在*location_J.txt文件")
self.msgBox.setIcon(QMessageBox.Warning)
self.msgBox.exec()
return
final_Rpeak = append.Rpeak_Detection(self.lineEdit_rootpath.text(), int(dialog.lineEdit_fs.text()), int(dialog.lineEdit_th1.text()))
pd.DataFrame(final_Rpeak).to_csv(Path(self.lineEdit_rootpath.text()) / "final_Rpeak.txt", index=False, header=None)
info(f"Saved final_Rpeak to Directory {self.lineEdit_rootpath.text()}.")
self.textBrowser_update(f"提示保存final_Rpeak.txt成功至文件夹{self.lineEdit_rootpath.text()}")
self.msgBox.setText(f"保存成功至{self.lineEdit_rootpath.text()}")
self.msgBox.setIcon(QMessageBox.Information)
self.msgBox.exec()
else:
self.textBrowser_update("提示:操作取消")
def slot_btn_outputLabel(self):
np.savetxt(Path(self.lineEdit_savepath.text()), self.label2, fmt='%d', newline='\n')
@ -973,6 +978,49 @@ class CustomNavigationToolbar(NavigationToolbar2QT):
self.canvas.mpl_disconnect(self.cid_mouse_hold)
self.cid_mouse_hold = None
class CustomMessageBox(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.resize(300, 300)
self.setWindowTitle("警告:确认操作")
layout = QVBoxLayout()
self.label = QLabel("是否执行<片段合并>?请在执行前确保此份数据的所有片段都已被打标!请输入相应参数后执行任务。")
self.label1 = QLabel(" ")
self.label_fs = QLabel("信号采样率(Hz)")
self.label_th1 = QLabel("寻峰阈值(个)")
self.lineEdit_fs = QLineEdit()
self.lineEdit_th1 = QLineEdit()
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.label.setFont(font)
self.label1.setFont(font)
self.label_fs.setFont(font)
self.label_th1.setFont(font)
self.lineEdit_fs.setFont(font)
self.lineEdit_th1.setFont(font)
self.label.setWordWrap(True)
self.label.setFixedWidth(300)
self.lineEdit_fs.setText("1000")
self.lineEdit_th1.setText("130")
layout.addWidget(self.label)
layout.addWidget(self.label1)
layout.addWidget(self.label_fs)
layout.addWidget(self.lineEdit_fs)
layout.addWidget(self.label_th1)
layout.addWidget(self.lineEdit_th1)
self.button_box = QDialogButtonBox(QDialogButtonBox.Yes | QDialogButtonBox.No)
self.button_box.setFont(font)
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.reject)
layout.addWidget(self.button_box)
self.setLayout(layout)
# 主函数
if __name__ == '__main__':
app = QApplication(sys.argv)