def get_data_for_patient(patient): signal, fields = wfdb.rdsamp(f'{DATA_DIR}/data/{patient}') fs = fields['fs'] r_peaks_ix = processing.gqrs_detect(signal[:, 0], fs=fs, threshold=1.0) features = feature_selection(signal, fs, r_peaks_ix) return features
def get_rr_peaks_indices(record, max_bpm=230): """ :param record_name: :param database: :param max_bpm: :return: list of timestamps for """ qrs_inds = processing.gqrs_detect(sig=record.p_signal[:, 0], fs=record.fs) search_radius = int(record.fs * 60 / max_bpm) corrected_peak_inds = processing.correct_peaks( record.p_signal[:, 0], peak_inds=qrs_inds, search_radius=search_radius, smooth_window_size=150) result = [] discarded_count = 0 prev_pi = -1 for pi in corrected_peak_inds: if pi != prev_pi: result.append(pi) else: discarded_count += 1 prev_pi = pi # returns r-r peaks timestamps result = np.array(result) / record.fs return result, discarded_count
def test_pure_prediction(self): record_name = self.mitdb + "100" sig, fields = wfdb.rdsamp(record_name, channels=[0]) res = processing.gqrs_detect(sig, fs=fields['fs']) wfdb.wrann("100", 'atr', res, write_dir="data", symbol=(['N'] * len(res))) print(res) self.assertIsNotNone(res)
def getQRSLocations(file_path): ''' get numpy list of QRS Locations Returns: qrs_locs (numpy list): list of QRS locations in the signal ''' record = wfdb.rdrecord(file_path, channels=[0]) qrs_locs = processing.gqrs_detect(record.p_signal[:, 0], fs=record.fs) return qrs_locs
def filter_ecg(ecg, fs, get_heart_rate=False, cutoff_frequencies=[0.5, 100.0]): nyq_f = fs / 2 w_low = cutoff_frequencies[0] / (math.pi * nyq_f) w_high = cutoff_frequencies[1] / (math.pi * nyq_f) filt_order = 4 b, a = scipy.signal.butter(filt_order, [w_low, w_high], btype='bandpass') processed_ecg = scipy.signal.filtfilt(b, a, ecg) if get_heart_rate: qrs_inds = processing.gqrs_detect(sig=ecg, fs=fs) hr = processing.compute_hr(sig_len=len(ecg), qrs_inds=qrs_inds, fs=fs) return (processed_ecg, hr) else: return (processed_ecg)
def get_data(age_start, age_stop, limit=1): """ Получение данных пациентов в промежутке возраста от age_start до age_stop (limit по количеству пациентов) :return: dict """ data_for_age_range = df.loc[(age_start < df['Age']) & (df['Age'] < age_stop)] result = {'data': []} for i in range(0, limit): try: pdf = data_for_age_range.iloc[i] fid = pdf['ID'] signal, fields = wfdb.rdsamp(f'{DATA_DIR}/data/{fid}') qrs_locs = processing.gqrs_detect(signal[:, 0], fs=fields['fs']) # result['data'].append({'ecg_data': signal.tolist(), 'qrs_ix': qrs_locs.tolist(), 'fields': fields}) patient_data = { 'avatar': f'require("~/assets/images/users/avatar-{randint(1, 4)}.jpg")', 'name': choice(["Смирнов", "Кузнецов", "Попов", "Васильев", "Петров", "Соколов", "Михайлов", "Фролов", "Журавлёв", "Николаев", "Крылов", "Максимов", "Сидоров", "Осипов", "Белоусов", "Федотов", "Дорофеев", "Егоров", "Матвеев", "Бобров", "Дмитриев","Калинин", 'Петров', "Васильев", "Тылык", "Иванов", "Пушкин", "Лермонтов", "Данилин", "Ванилин", "Герц", "Тесла", "Улец", "Кершин", "Ким"])+' '+choice(['И.', "А.", "В.", "Д.", "К."])+choice(['И.', "А.", "В.", "Д."]), 'age': str(pdf['Age']), 'id': str(pdf['ID']), 'diagnose': pdf['Rhythms'], 'state': 'Отклонение от нормы' if pdf['Rhythms'] != 'Sinus rhythm' else 'В норме', 'last_visit': f"{randint(1, 31)}/{randint(1, 12)}/2020", 'last_data_update': f"{randint(1, 31)}/{randint(1, 12)}/2021", 'tmt_online': choice(['Online', 'Offline']), 'link': '/dashboard/diagnosis/index2' if pdf['Rhythms'] != 'Sinus rhythm' else '/dashboard/diagnosis', }, print('{', end='') for key, value in patient_data[0].items(): if key == 'avatar': print(f"{key}: {value}", end=', ') else: print(f"{key}: '{value}'", end=', ') print('},') result['data'].append(patient_data) except Exception as e: print('Error (getting ecg data): {}'.format(e)) print(result) result = json.dumps(result) return result
def test_gqrs(self): record = wfdb.rdrecord('sample-data/100', channels=[0], sampfrom=9998, sampto=19998, physical=False) expected_peaks = [271, 580, 884, 1181, 1469, 1770, 2055, 2339, 2634, 2939, 3255, 3551, 3831, 4120, 4412, 4700, 5000, 5299, 5596, 5889, 6172, 6454, 6744, 7047, 7347, 7646, 7936, 8216, 8503, 8785, 9070, 9377, 9682] peaks = processing.gqrs_detect(d_sig=record.d_signal[:,0], fs=record.fs, adc_gain=record.adc_gain[0], adc_zero=record.adc_zero[0], threshold=1.0) assert np.array_equal(peaks, expected_peaks)
def test_gqrs(self): record = wfdb.rdrecord('sample-data/100', channels=[0], sampfrom=9998, sampto=19998, physical=False) expected_peaks = [271, 580, 884, 1181, 1469, 1770, 2055, 2339, 2634, 2939, 3255, 3551, 3831, 4120, 4412, 4700, 5000, 5299, 5596, 5889, 6172, 6454, 6744, 7047, 7347, 7646, 7936, 8216, 8503, 8785, 9070, 9377, 9682] peaks = processing.gqrs_detect(d_sig=record.d_signal[:,0], fs=record.fs, adc_gain=record.adc_gain[0], adc_zero=record.adc_zero[0], threshold=1.0) assert np.array_equal(peaks, expected_peaks)
def gqrs_algorithm(filename, sampfrom=None, sampto=None, channel=0, r_peak_inds=None, fig=None, pic_index=1, pic_size=1, skip_flag=False): sig, fields = wfdb.rdsamp(filename, channels=[channel], sampfrom=sampfrom, sampto=sampto) qrs_inds = processing.gqrs_detect(sig=sig[:, 0], fs=fields['fs']) # 标记位置减去采样点开始位置得到相对位置 r_peak_inds -= sampfrom if len(qrs_inds) < 1: qrs_inds = np.array([-100]) if skip_flag: return draw_graph(r_peak_inds, sig, fields, 'GQRS', qrs_inds, fig=fig, pic_index=pic_index, pic_size=pic_size, skip_flag=skip_flag) summary, fig = draw_graph(r_peak_inds, sig, fields, 'GQRS', qrs_inds, fig=fig, pic_index=pic_index, pic_size=pic_size) return summary, fig
def rpeak_gqrs(ecg, fs): rr_min = 0.25 rr_max = 1.5 res = processing.gqrs_detect(sig=ecg, fs=fs, RRmin=rr_min, RRmax=rr_max) return res
def ExtractFeatures(dataset, size, minThreshold): # Features qAmplitudes = [] rAmplitudes = [] qrsDurations = [] rrIntervals = [] heartRatesDuringHeartBeat = [] minSize = sys.maxsize signals = dataset['signal'] labels = dataset['label'] for i, sig in enumerate(signals[:size]): print(str(i) + "/" + str(len(signals)) + " ...") qrsInds = processing.gqrs_detect(sig=sig.astype('float64'), fs=300) heartRates = processing.compute_hr(sig_len=sig.shape[0], fs=300, qrs_inds=sorted(qrsInds)) rPoints, sPoints, qPoints = QRS_util.ECG_QRS_detect( sig, 300, True, False) lenHb = sys.maxsize lenSigQrs = sys.maxsize lenHr = sys.maxsize lenQ = sys.maxsize lenR = sys.maxsize if (len(heartRates) > 0 and len(rPoints) > 0): # Adding features for each signal. heartRatesDuringHeartBeat.append(np.array(heartRates[rPoints])) lenHr = len(heartRates[rPoints]) if (len(qPoints) > 0): qAmplitudes.append(np.array(sig[qPoints])) lenQ = len(sig[qPoints]) if (len(rPoints) > 0): rAmplitudes.append(np.array(sig[rPoints])) lenR = len(sig[rPoints]) if (len(qPoints) > 0 and len(rPoints) > 0): sigQrsDuration = [ sPoints[i] - qPoints[i] for i in range(len(qPoints) - 1) ] qrsDurations.append(np.array(sigQrsDuration)) lenSigQrs = len(sigQrsDuration) hbIntervals = [ rPoints[i + 1] - rPoints[i] for i in range(len(rPoints) - 1) ] rrIntervals.append(np.array(hbIntervals)) lenHb = len(hbIntervals) minIter = min(lenHb, lenQ, lenR, lenSigQrs, lenHr) if minIter < minThreshold: # Rollback del heartRatesDuringHeartBeat[-1] del qAmplitudes[-1] del rAmplitudes[-1] del qrsDurations[-1] del rrIntervals[-1] elif minIter < minSize: minSize = minIter qAmplitudes = np.array( [np.array(x[:minSize], dtype='int64') for x in qAmplitudes]) rAmplitudes = np.array( [np.array(x[:minSize], dtype='int64') for x in rAmplitudes]) rrIntervals = np.array( [np.array(x[:minSize], dtype='int64') for x in rrIntervals]) qrsDurations = np.array( [np.array(x[:minSize], dtype='int64') for x in qrsDurations]) heartRatesDuringHeartBeat = np.array([ np.array(x[:minSize], dtype='int64') for x in heartRatesDuringHeartBeat ]) qAmplitudes = np.stack(qAmplitudes, axis=0) rAmplitudes = np.stack(rAmplitudes, axis=0) heartRatesDuringHeartBeat = np.stack(heartRatesDuringHeartBeat, axis=0) rrIntervals = np.stack(rrIntervals, axis=0) qrsDurations = np.stack(qrsDurations, axis=0) return qAmplitudes, rAmplitudes, heartRatesDuringHeartBeat, rrIntervals, qrsDurations, labels[: size], minSize
from imutils.video import VideoStream from imutils import face_utils from threading import Thread import numpy as np import pyglet import argparse import imutils import time import dlib import cv2 # 1. Read signal record = wfdb.rdrecord('mit-bih-arrhythmia-database-1.0.0/108', channels=[0]) # 2. Detect QRS locations qrs_locs = processing.gqrs_detect(record.p_signal[:, 0], fs=record.fs) # 5. Length of signal len = record.sig_len # 6. Compute heart rate heart_rate = processing.compute_hr(len, qrs_locs, fs=record.fs) # 7. Remove Nan values from array heart_rate = heart_rate[~np.isnan(heart_rate)] # 8. Calculate RR from heart rate # RR-interval is shorter and wider for awake subject than drowsy subject. RR = 60 / heart_rate # From hrv analysis get frequency features
def gqrs_single(fields, record, save_path, sig, save=True): r_peaks = processing.gqrs_detect(sig[:, 0], fs=fields['fs']) if save: save_prediction(r_peaks, record, save_path) else: return r_peaks
import wfdb from wfdb import processing import numpy as np DATA_PATH = "/data/" SAVE_PATH = "/pred/" with open(DATA_PATH + "RECORDS", 'r') as f: records = f.readlines() records = list(map(lambda r: r.strip("\n"), records)) for record in records: sig, fields = wfdb.rdsamp(DATA_PATH + record, channels=[0]) res = processing.gqrs_detect(sig[:, 0], fs=fields['fs']) if len(res) > 0: wfdb.wrann(record, 'atr', res, write_dir=SAVE_PATH, symbol=(['N'] * len(res)))
def detect(self, records): return [ processing.gqrs_detect(sig=record.p_signal.T[0], fs=record.fs) for record in records ]
ax_left.set_title(title) ax_left.set_xlabel('Time (ms)') ax_left.set_ylabel('ECG (mV)', color='#3979f0') ax_right.set_ylabel('Heart rate (bpm)', color='m') #设置颜色使得和线条颜色一致 ax_left.tick_params('y', colors='#3979f0') ax_right.tick_params('y', colors='m') if saveto is not None: plt.savefig(saveto, dpi=600) plt.show() #加载ECG信号 record=wfdb.rdrecord('./2') #.hea .dat文件名称 #help(wfdb.rdrecord) #使用gqrs算法定位qrs波位置 qrs_inds=processing.gqrs_detect(sig=record.p_signal[:, 0], fs=record.fs) #未矫正位置 #画出结果 #peaks_hr(sig=record.p_signal, peak_inds=qrs_inds, fs=record.fs, title='GQRS peak detection on record 100') #修正峰值,将其设置为局部最大值 min_bpm=20 max_bpm=230 #使用可能最大的bpm作为搜索半径 search_radius=int(record.fs*60/max_bpm) corrected_peak_inds=processing.correct_peaks(record.p_signal[:, 0], peak_inds=qrs_inds, search_radius=search_radius, smooth_window_size=150) #输出矫正后的QRS波峰位置 print('Corrected gqrs detected peak indices:', sorted(corrected_peak_inds)) # Feature 1: 计算R波波峰
def dataGeneration(data_path, csv_path, record_path): # initialize dataset dataset = pd.DataFrame(columns=['label', 'record']) if record_path == None: # a loop for each patient detail_path = data_path + '/' record_files = [ i.split('.')[0] for i in os.listdir(detail_path) if (not i.startswith('.') and i.endswith('.hea')) ] Bar.check_tty = False bar = Bar('Processing', max=len(record_files), fill='#', suffix='%(percent)d%%') # a loop for each record for record_name in record_files: # load record signal, info = wfdb.rdsamp(detail_path + record_name) fs = 200 signal = processing.resample_sig(signal[:, 0], info['fs'], fs)[0] # set some parameters window_size_half = int(fs * 0.125 / 2) max_bpm = 230 # detect QRS peaks qrs_inds = processing.gqrs_detect(signal, fs=fs) search_radius = int(fs * 60 / max_bpm) corrected_qrs_inds = processing.correct_peaks( signal, peak_inds=qrs_inds, search_radius=search_radius, smooth_window_size=150) average_qrs = 0 count = 0 for i in range(1, len(corrected_qrs_inds) - 1): start_ind = corrected_qrs_inds[i] - window_size_half end_ind = corrected_qrs_inds[i] + window_size_half + 1 if start_ind < corrected_qrs_inds[ i - 1] or end_ind > corrected_qrs_inds[i + 1]: continue average_qrs = average_qrs + signal[start_ind:end_ind] count = count + 1 # remove outliers if count < 8: print('\noutlier detected, discard ' + record_name) continue average_qrs = average_qrs / count corrcoefs = [] for i in range(1, len(corrected_qrs_inds) - 1): start_ind = corrected_qrs_inds[i] - window_size_half end_ind = corrected_qrs_inds[i] + window_size_half + 1 if start_ind < corrected_qrs_inds[ i - 1] or end_ind > corrected_qrs_inds[i + 1]: corrcoefs.append(-100) continue corrcoef = pearsonr(signal[start_ind:end_ind], average_qrs)[0] corrcoefs.append(corrcoef) max_corr = list(map(corrcoefs.index, heapq.nlargest(8, corrcoefs))) index_corr = random.sample( list(itertools.permutations(max_corr, 8)), 100) for index in index_corr: # a temp dataframe to store one record record_temp = pd.DataFrame() signal_temp = [] for i in index: start_ind = corrected_qrs_inds[i + 1] - window_size_half end_ind = corrected_qrs_inds[i + 1] + window_size_half + 1 sig = processing.normalize_bound(signal[start_ind:end_ind], -1, 1) signal_temp = np.concatenate((signal_temp, sig)) record_temp = record_temp.append(pd.DataFrame( signal_temp.reshape(-1, signal_temp.shape[0])), ignore_index=True, sort=False) record_temp['label'] = record_name record_temp['record'] = record_name # add it to final dataset dataset = dataset.append(record_temp, ignore_index=True, sort=False) bar.next() bar.finish() else: patient_folders = [ i for i in os.listdir(data_path) if (not i.startswith('.') and i.startswith(record_path)) ] Bar.check_tty = False bar = Bar('Processing', max=len(patient_folders), fill='#', suffix='%(percent)d%%') # a loop for each patient for patient_name in patient_folders: detail_path = data_path + patient_name + '/' record_files = [ i.split('.')[0] for i in os.listdir(detail_path) if i.endswith('.hea') ] # a loop for each record for record_name in record_files: # load record signal, info = wfdb.rdsamp(detail_path + record_name) fs = 200 signal = processing.resample_sig(signal[:, 0], info['fs'], fs)[0] # set some parameters window_size_half = int(fs * 0.125 / 2) max_bpm = 230 # detect QRS peaks qrs_inds = processing.gqrs_detect(signal, fs=fs) search_radius = int(fs * 60 / max_bpm) corrected_qrs_inds = processing.correct_peaks( signal, peak_inds=qrs_inds, search_radius=search_radius, smooth_window_size=150) average_qrs = 0 count = 0 for i in range(1, len(corrected_qrs_inds) - 1): start_ind = corrected_qrs_inds[i] - window_size_half end_ind = corrected_qrs_inds[i] + window_size_half + 1 if start_ind < corrected_qrs_inds[ i - 1] or end_ind > corrected_qrs_inds[i + 1]: continue average_qrs = average_qrs + signal[start_ind:end_ind] count = count + 1 # remove outliers if count < 8: print('\noutlier detected, discard ' + record_name + ' of ' + patient_name) continue average_qrs = average_qrs / count corrcoefs = [] for i in range(1, len(corrected_qrs_inds) - 1): start_ind = corrected_qrs_inds[i] - window_size_half end_ind = corrected_qrs_inds[i] + window_size_half + 1 if start_ind < corrected_qrs_inds[ i - 1] or end_ind > corrected_qrs_inds[i + 1]: corrcoefs.append(-100) continue corrcoef = pearsonr(signal[start_ind:end_ind], average_qrs)[0] corrcoefs.append(corrcoef) max_corr = list( map(corrcoefs.index, heapq.nlargest(8, corrcoefs))) index_corr = random.sample( list(itertools.permutations(max_corr, 8)), 100) for index in index_corr: # a temp dataframe to store one record record_temp = pd.DataFrame() signal_temp = [] for i in index: start_ind = corrected_qrs_inds[i + 1] - window_size_half end_ind = corrected_qrs_inds[i + 1] + window_size_half + 1 sig = processing.normalize_bound( signal[start_ind:end_ind], -1, 1) signal_temp = np.concatenate((signal_temp, sig)) record_temp = record_temp.append(pd.DataFrame( signal_temp.reshape(-1, signal_temp.shape[0])), ignore_index=True, sort=False) record_temp['label'] = patient_name record_temp['record'] = record_name # add it to final dataset dataset = dataset.append(record_temp, ignore_index=True, sort=False) bar.next() bar.finish() # save for further use dataset.to_csv(csv_path, index=False) print('processing completed')