1、将原本的<预定位>步骤中的append.py的功能整合入此界面中的<片段合并>按钮中
2、优化了部分功能
This commit is contained in:
parent
bbe6abc57f
commit
d7195feff5
52
append.py
Normal file
52
append.py
Normal 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)
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user