Unet心电信号分割方法(Pytorch)

news2025/2/25 1:25:56

心血管疾病是一种常见病,严重影响人们的健康及日常生活。 近年来随着人们生活习惯的不断变化,心血管疾病对人们影响愈加明显,发病率呈现出逐年攀升的趋势,心血管疾病是中国城乡居民死亡的首要原因。心电图ECG已被广泛用于研究心跳活动。作为一种无创的方法,ECG的相关研究为了解心脏的功能提供了便利。对心电图进行有效分析可以为心血管疾病的诊断和防治提供丰富的信息,进而大大减缓心血管疾病对人们生活的影响。

心电信号分割是心电图解读的第一步,通过心电信号分割,有助于进一步对运动员心脏健康状况进行分析,进而减少运动员受伤、致病及运动中猝死的风险。

from typing import Union,List, Tuple
# get signal with wfdb library# using an indexdef get_signal(index:int, as_p_signal:bool=True) -> Union[wfdb.Record, np.ndarray]:    record = wfdb.rdrecord(DATA_FOLDER + "/" +  str(index))    assert type(record) is wfdb.Record
    if as_p_signal:        assert type(record.p_signal) is np.ndarray        return record.p_signal            return record
# get annotations given the ecg leaddef get_annotations(index:int, lead, as_sample=True) -> Union[wfdb.Annotation, np.ndarray]:    annotations = wfdb.rdann(DATA_FOLDER +"/" + str(index), extension = lead)    if as_sample:        return np.array(annotations.sample)    return annotations
# get a full EGC with 12 leadsdef get_full_ecg(index:int):    signal = get_signal(index)    annotations = [        get_annotations(index, lead) for lead in LEADS    ]    return signal, annotations

def get_single_lead_ecg(index, lead) -> Tuple[np.ndarray, np.ndarray]:    """    return and ecg signal and its annotations    both as ndarray    """    signal = get_signal(index)    assert type(signal) is np.ndarray    signal = signal[:, LEADS.index(lead)]
    samples = get_annotations(index, lead)    assert type(samples) is np.ndarray        return signal, samples

def get_annotations_symbols(index, lead):    ann = get_annotations(index, lead, as_sample=False)    return ann.symbol
def paired_annotation_sample_and_symbol(index, lead):    annotations_symbols = get_annotations_symbols(index, lead)    annotations_sample = get_annotations(index, lead)    return zip(annotations_sample, annotations_symbols)

def get_single_lead_ecg_with_symbols(index, lead):    """    return and ecg signal and its annotations    both as ndarray    """    signal = get_signal(index)    assert type(signal) is np.ndarray    signal = signal[:, LEADS.index(lead)]
    data = paired_annotation_sample_and_symbol(index, lead)        return signal, np.array(list(data))
# plot single lead ecg with annotationsdef plot_single_lead_ecg(index, lead):    signal, samples = get_single_lead_ecg(index, lead)
    fig, ax = plt.subplots(figsize = (28, 3))
    ax.plot(signal)    ax.scatter(samples, signal[samples], c = 'r', marker = 'o')

# now plot every lead with annotationsdef plot_signal_with_annotation(index):    signal, samples = get_full_ecg(index)    # extract sample from annotations    wfdb.plot_items(signal, samples )
plot_signal_with_annotation(index = 199)

图片

class EGCSignal:    """    This class has 4 main purposes:    1. To store the signal and its annotations    2. To cut the signal once at the beginning and once at the end    3. To plot the ECG in different ways    4. To convert the annotation in a one hot encoding
    Note that doesn't store the entire ECG, but only one lead
    Also has a method to initialize the class without explicitly passing the signal and annotations    but with the index and lead of the record    """    def __init__(self, signal, time_points, symbol, categories = None):        self.signal:np.ndarray = signal        self.time_points:np.ndarray = time_points        self.symbols:list[str] = symbol        self.symbol_to_category = {            'N': 0,            't': 1,            'p': 2        }        self.category_to_symbol = {            0: 'N',            1: 't',            2: 'p'        }        self.categories = categories if categories is not None else self.symbols_to_category()        self._cut_beginning( 550)        self._cut_end( 3500)
    def __getitem__(self, key):        return self.signal[key]
    def __len__(self):        return len(self.signal)
    def _cut_beginning(self, start_point):        self.signal = self.signal[start_point:]        self.categories = self.categories[start_point:]
        # now have to check if time_points and symbols are also to cut        if start_point > self.time_points[0]:            # get the index of the first time point greater than start_point            index = np.argmax(self.time_points > start_point)                            self.time_points = self.time_points[index:]            self.symbols = self.symbols[index:]
        self.time_points = self.time_points - start_point
        # check the cut point        if self.categories[0] != -1:            # if the first symbol is a ')' then i have to prepend a '(' and a letter from self.category_to_symbol            if self.symbols[0] == ')':                self.symbols = ['('] + [self.category_to_symbol[self.categories[0]]] + self.symbols                self.time_points = np.concatenate(([0,1], self.time_points))            elif self.symbols[0] in self.symbol_to_category:                # just prepend '('                self.symbols = ['('] + self.symbols                self.time_points = np.concatenate(([0], self.time_points))
    def _cut_end(self, end_point):        self.signal = self.signal[:end_point]        self.categories = self.categories[:end_point]
        index = self.time_points[self.time_points < self.signal.size].size        self.time_points = self.time_points[:index]        self.symbols = self.symbols[:index]
        # check the cut point        if self.categories[-1] != -1:            # if the last symbol is a '(' then i have to append a ')' and a letter from self.category_to_symbol            if self.symbols[-1] == '(':                self.symbols = self.symbols +  [self.category_to_symbol[self.categories[-1]]] + [')']                self.time_points = np.concatenate((self.time_points, [self.signal.size - 1, self.signal.size ]))            elif self.symbols[-1] in self.symbol_to_category:                # just append ')'                self.symbols = self.symbols + [')']                self.time_points = np.concatenate((self.time_points, [self.signal.size]))     def plot(self, ax=None):        if ax is None:            fig, ax = plt.subplots(figsize = (28, 3))        ax.plot(self.signal)
    def plot_with_time_point(self):        fig, ax = plt.subplots(figsize = (28, 3))        self.plot(ax)        ax.scatter(self.time_points, self.signal[self.time_points], c = 'r', marker = 'o')
    def plot_with_segments(self):        fig, ax = plt.subplots(figsize = (28, 3))        self.plot(ax)
        for start, symbol, end in grouped(self.time_points, 3):                        i = np.nonzero(self.time_points == symbol)[0][0]            current_symbol = self.symbols[i]            color = SEGMENT_TO_COLOR[current_symbol]            ax.axvspan(start, end, color=color, alpha=0.4)
    def symbols_to_category(self):        """        converts the symbols list in a numpy array of integers        same length as the signal        """
        # first instantiate an array of -1 same length as the signal        category = np.full(len(self.signal), -1)        # now fill the array with the known category        for section in grouped(self.time_points):            # unpack the section            start, peak, end = section                                    # get the category given the peak            i = np.nonzero(self.time_points == peak)[0][0]            current_symbol = self.symbols[i]
            category[start:end] = self.symbol_to_category[current_symbol]
        return category
    @staticmethod    def from_index_and_lead(index, lead):        return EGCSignal(        get_signal(index)[:, LEADS.index(lead)],        get_annotations(index, lead),        get_annotations_symbols(index, lead) )


EGCSignal.from_index_and_lead(1, LEADS[0]).plot_with_segments()

图片

# plot categories on ecgsignal = X_test[ecg_index]categories = np.argmax(Y_test[ecg_index], axis=1)predicted_categories = np.argmax(Y_test_pred[ecg_index], axis=1)
# get time point where category changestime_points = np.where(categories[:-1] != categories[1:])[0]
# chek if category was at beginning or endif categories[0] != 0:    # if category was at beginning, add first time point    time_points = np.append(0, time_points)if categories[-1] != 0:    # if category was at end, add last time point    time_points = np.append(time_points, len(categories))
# plot the signalplt.figure(figsize=(10, 4))plt.plot(signal)for b,e in grouped(time_points, 2):    plt.axvspan(b, e, facecolor='0.5', alpha=0.5)

图片

signal = X_test[ecg_index]categories = np.argmax(Y_test[ecg_index], axis=1)predicted_categories = np.argmax(Y_test_pred[ecg_index], axis=1)
# get time point where category changestime_points = np.where(predicted_categories[:-1] != predicted_categories[1:])[0]

# chek if category was at beginning or endif predicted_categories[0] != 0:    # if category was at beginning, add first time point    time_points = np.append(0, time_points)if predicted_categories[-1] != 0:    # if category was at end, add last time point    time_points = np.append(time_points, len(predicted_categories))
# plot the signalplt.figure(figsize=(10, 4))plt.plot(signal)for b,e in grouped(time_points, 2):    plt.axvspan(b, e, facecolor='0.5', alpha=0.5)

图片

plt.figure(figsize=(10, 4))
plt.plot(signal, color = "gray")plt.plot(pred[:,0]*signal, alpha=0.5) # predicted not interesting
plt.plot(pred[:,3]*signal, alpha=0.9, label= "p", c=SEGMENT_TO_COLOR['p']) # predicted p
plt.plot(pred[:,1]*signal, alpha=0.9, label= "qrs", c=SEGMENT_TO_COLOR['N']) # predicted qrsplt.plot(pred[:,2]*signal, alpha=0.9, label= "t", c=SEGMENT_TO_COLOR['t']) # predicted t
plt.legend(    loc='upper right',    ncol=1,
)

图片

from matplotlib.collections import LineCollectionfrom matplotlib.colors import ListedColormap
x   = np.arange(len(signal)) t = np.linspace(0,1,x.shape[0]) # your "time" variable
lightblue  = [(0.3, 0.5, 0.9, 0.99 * p) for p in pred[:,1]]lightred   = [(0.99, 0.6, 0.5, 0.99 * p) for p in pred[:,2]]lightgreen = [(0.55, 0.99, 0.66, 0.99 * p) for p in pred[:,3]]

# set up a list of (x,y) pointspoints = np.array([x,signal]).transpose().reshape(-1,1,2)segs = np.concatenate([points[:-1],points[1:]],axis=1)
# make the collection of segmentslcblue = LineCollection(segs, cmap=ListedColormap( lightblue))lcblue.set_array(t)lcred = LineCollection(segs, cmap=ListedColormap( lightred))lcred.set_array(t)lcgreen = LineCollection(segs, cmap=ListedColormap( lightgreen))lcgreen.set_array(t)

# plot the collectionplt.figure(figsize=(15, 5))plt.plot(signal, alpha = 0.4, linewidth = 2, color='gray')plt.gca().add_collection(lcblue) # add the collection to the plotplt.gca().add_collection(lcred) # add the collection to the plotplt.gca().add_collection(lcgreen) # add the collection to the plotplt.xlim(x.min(), x.max()) # line collections don't auto-scale the plotplt.ylim(signal.min(), signal.max())

图片

工学博士,担任《Mechanical System and Signal Processing》《中国电机工程学报》《控制与决策》等期刊审稿专家,擅长领域:现代信号处理,机器学习,深度学习,数字孪生,时间序列分析,设备缺陷检测、设备异常检测、设备智能故障诊断与健康管理PHM等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1824132.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

跨境电商卖家入驻美国线下商超困难吗?

对于跨境电商卖家来说&#xff0c;入驻美国线下商超确实具有一定的挑战性&#xff0c;但并非不可能。成功的关键在于卖家是否具备必要的条件和资质&#xff0c;以及是否能够有效应对美国市场的挑战。 1、卖家需要满足美国相关法律法规的要求 需要拥有合法的经营执照、提供准确…

AI绘画入门教程(非常详细)从零基础入门到精通Midjourney提示词,咒语

Microorganisms infiltrating through brain-machine interfaces --v 6.0 Microorganisms infiltrating through brain-machine interfaces ,redpupil --v 6.0 Microorganisms infiltrating through brain-machine interfaces,billion girls dream --v 6.0 --niji 6 “动漫风”…

Kafka性能优化策略综述:提升吞吐量与可靠性

Kafka性能优化策略综述&#xff1a;提升吞吐量与可靠性 优化 Kafka 的性能可以从多个方面入手&#xff0c;包括配置调优、架构设计和硬件资源优化。下面详细介绍一些常用的优化策略&#xff1a; 1. 分区设计 增加分区数量&#xff1a;更多的分区意味着更高的并行处理能力&a…

德国欧洲杯观战掌中宝

点击标题下「蓝色微信名」可快速关注 今天03:00&#xff0c;德国欧洲杯即将拉开帷幕&#xff0c;首战德国对阵苏格兰&#xff0c;24支欧洲国家队&#xff0c;分为6个小组&#xff0c;你是谁的拥趸&#xff1f; 本届欧洲杯的比赛时间有三个&#xff0c;分别是零点、凌晨三点和晚…

Ollama在MacOS、Linux本地部署千问大模型及实现WEB UI访问

一、前言 阿里通义千问发布了Qwen2&#xff0c;提供了0.5B&#xff5e;72B的量级模型&#xff0c;在​​Ollama官网​​可以搜索qwen2查看&#xff0c;本文提供了Ollama的下载&#xff08;在线/离线安装&#xff09;、Ollama运行模型、使用WebUI连接模型以及页面简单配置。 …

Real3D:利用真实世界图像扩展3D重建模型

原理&#xff1a; 在3D重建领域&#xff0c;单视图重建任务由于其固有的不确定性而充满挑战。为了克服这一难题&#xff0c;研究者们一直在探索如何利用大型数据集训练模型以学习形状和纹理的通用先验知识。然而&#xff0c;现有训练方法依赖于合成数据或多视图捕获&#xff0c…

【实例分享】银河麒麟高级服务器操作系统环境资源占用异常-情况分析及处理方法

1.情况描述 使用vsftp进行文件传输&#xff0c;发现sshd进程cpu占用异常&#xff0c;并且su和ssh登录相比正常机器会慢2秒左右。 图&#xff11; 2.问题分析 通过strace跟踪su和sshd进程&#xff0c;有大量ssh:notty信息。 图2 配置ssh绕过pam模块认证后&#xff0c;ssh连接速…

【计算机视觉】人脸算法之图像处理基础知识(二)

图像处理基础知识&#xff08;二&#xff09; 1.图像的颜色空间转换 我们常见的图像通常由R&#xff08;红色&#xff09;、G&#xff08;绿色&#xff09;、B&#xff08;蓝色&#xff09;组成。但是在很多时候我们会将彩色图像转换成灰度图像进行处理。此时会用到cv2.cvtCo…

EasyGBS服务器和终端配置

服务器配置 修改easygbs.ini sip/host为本机IP&#xff0c;否则终端能登录&#xff0c;无法视频。 [sip] host192.168.3.190 终端用于登录的用户名和密码 default_usertest default_passwordtest1234 default_guest_userguest default_guest_passwordtest1234终端配置 关…

【Quartus 13.0】EP1C3144I7 部署4*6矩阵键盘

仿照 正点原子 的 Sample 修改 V2手册 P266 没有用这个 给出的手动按键控制的矩阵模块 为 4*6 矩阵键盘外接模块 每一个按键自带led&#xff0c;所以对应的接口是合并在一起的一个引脚 按下后 LED 亮&#xff0c;vice versa 底部 LED*8 目前不清楚有什么用 或许可以变成 16进…

使用sherpa-ncnn进行中文语音识别(ubuntu22)

获取该开源项目的渠道&#xff0c;是我在b站上&#xff0c;看到了由csukuangfj制作的一套语音识别视频。以下地址均为csukuangfj在视频中提供&#xff0c;感谢分享&#xff01; 新一代Kaldi RISC-V: VisionFive2 上的实时中英文语音识别_哔哩哔哩_bilibili 开源项目地址&…

Vue41-vc实例与vm实例

一、 vc实例与vm实例的区别 vc实例与vm实例&#xff0c;99%结构都是类似的&#xff0c;仅2点不同&#xff1a; el属性data的书写格式 1-1、 el属性 vc有的功能vm都有&#xff0c;但是vm能通过el决定为哪个容器服务&#xff0c;但是vc却不行&#xff01; 1-2、data的书写格式

利用Cesium和JS实现地点点聚合功能

引言 在实现基于地图的业务场景时&#xff0c;当地图上需要展示过多的标记点时&#xff0c;大量的分散点会使地图上显得杂乱无章&#xff0c;导致标记点对地图上的其他重要信息造成遮挡和混淆&#xff0c;降低地图整体的可读性。 标记点的聚合就很好的解决了这些痛点的同时&a…

理解Es的DSL语法(二):聚合

前一篇已经系统介绍过查询语法&#xff0c;详细可直接看上一篇文章&#xff08;理解DSL语法&#xff08;一&#xff09;&#xff09;&#xff0c;本篇主要介绍DSL中的另一部分&#xff1a;聚合 理解Es中的聚合 虽然Elasticsearch 是一个基于 Lucene 的搜索引擎&#xff0c;但…

单通道触摸感应开关RH6016

1.简介 SOT23-6 RH6016 封装和丝印 RH6016 是一款内置稳压模块的单通道电容式触摸感应控制开关IC&#xff0c;可以替代传统的机械式开关。 RH6016可在有介质(如玻璃、亚克力、塑料、陶瓷等)隔离保护的情况下实现触摸功能&#xff0c;安全性高。 RH6016内置高精度稳压、上电复…

C++17并行算法与HIPSTDPAR

C17 parallel algorithms and HIPSTDPAR — ROCm Blogs (amd.com) C17标准在原有的C标准库中引入了并行算法的概念。像std::transform这样的并行版本算法保持了与常规串行版本相同的签名&#xff0c;只是增加了一个额外的参数来指定使用的执行策略。这种灵活性使得已经使用C标准…

数据采集项目2-业务数据同步

全量同步 每天都将业务数据库中的全部数据同步一份到数据仓库 全量同步采用DataX datax datax使用 执行 python /opt/module/datax/bin/datax.py /opt/module/datax/job/job.json 更多job.json配置文件在&#xff1a; 生成的DataX配置文件 java -jar datax-config-genera…

【RabbitMQ】RabbitMQ 的 6 种工作模式

RabbitMQ 的 6 种工作模式 1.简单模式2.工作队列模式3.交换机模式4.Routing 转发模式5.主题转发模式6.RPC 模式6.1 消息属性6.2 关联标识6.3 工作流程 7.小结 1.简单模式 生产者把消息放入队列&#xff0c;消费者获得消息&#xff0c;如下图所示。这个模式只有 一个消费者、一…

【python】python指南(三):使用正则表达式re提取文本中的http链接

一、引言 对于算法工程师来说&#xff0c;语言从来都不是关键&#xff0c;关键是快速学习以及解决问题的能力。大学的时候参加ACM/ICPC一直使用的是C语言&#xff0c;实习的时候做一个算法策略后台用的是php&#xff0c;毕业后做策略算法开发&#xff0c;因为要用spark&#x…

LeetCode | 520.检测大写字母

这道题直接分3种情况讨论&#xff1a;1、全部都为大写&#xff1b;2、全部都为小写&#xff1b;3、首字母大写其余小写。这里我借用了一个全是大写字母的串和一个全为小写字母的串进行比较 class Solution(object):def detectCapitalUse(self, word):""":type …