深度学习落地实战:基于UNet实现血管瘤超声图像分割

前言

大家好,我是机长

本专栏将持续收集整理市场上深度学习的相关项目,旨在为准备从事深度学习工作或相关科研活动的伙伴,储备、提升更多的实际开发经验,每个项目实例都可作为实际开发项目写入简历,且都附带完整的代码与数据集。可通过百度云盘进行获取,实现开箱即用

正在跟新中~

项目背景

(基于UNet实现血管瘤超声图像分割)

血管瘤是一种常见的血管异常疾病,尤其在婴幼儿中具有较高的发病率。超声检查作为一种无创的诊断手段,能够为临床提供血管瘤的位置、形状及累及范围等重要信息,对指导医生进一步治疗至关重要。然而,目前血管瘤病灶的分割主要依赖于专家的人工勾画,这不仅耗时耗力,还容易受到临床经验水平的影响,导致分割结果存在人为误差。因此,利用深度学习技术实现血管瘤超声图像的自动精准分割,成为了一个医学应用与研究的热点方向方向。

项目环境

  • 平台:windows 10
  • 语言环境:python 3.8
  • 编辑器:PyCharm
  • PyThorch版本:1.8

1.创建并跳转到虚拟环境

python -m venv myenvmyenv\Scripts\activate.bat

2. 虚拟环境pip命令安装其他工具包

pip install torch torchvision torchaudio

注:此处只示范安装pytorch,其他工具包安装类似,可通过运行代码查看所确实包提示进行安装

3.pycharm 运行环境配置

进入pytcharm =》点击file =》点击settings=》点击Project:...=》点击 Python Interpreter,进入如下界面

点击add =》点击Existing environment  =》 点击 ... =》选择第一步1创建虚拟环境目录myenv\Scripts\下的python.exe文件点击ok完成环境配置

数据集介绍

数据集分分训练数据集与标签数据集

                

       训练数据样式                                                               标注数据样式

训练数据获取:

私信博主获取

UNet网络介绍

U-Net网络的以其独特的U型结构著称,这种结构由编码器(Encoder)和解码器(Decoder)两大部分组成,非常适合于医学图像分割等任务。下面我将进一步解释您提到的关键点,并补充一些细节。

Encoder(编码器)
  • 结构:编码器的左半部分主要负责特征提取。它通过多个卷积层(通常是3x3的卷积核)和ReLU激活函数来逐层提取图像的特征。在每个卷积层组合之后,通常会添加一个2x2的最大池化层(Max Pooling)来降低特征图的分辨率,并增加感受野。这种下采样操作有助于捕获图像中的全局信息。
  • 作用:编码器通过逐层提取和抽象化图像特征,为后续的分割任务提供丰富的信息。
Decoder(解码器)
  • 结构:解码器的右半部分则负责将编码器提取的特征图恢复到原始图像的分辨率,以便进行像素级别的分类。它首先通过上采样(通常是转置卷积或双线性插值)来增加特征图的尺寸,然后通过特征拼接(Concatenation)将上采样后的特征图与编码器对应层级的特征图进行融合。之后,再通过卷积层和ReLU激活函数进一步处理融合后的特征图。
  • 特征拼接:与FCN(全卷积网络)的逐点相加不同,U-Net使用特征拼接来融合不同层级的特征图。这种拼接方式能够保留更多的特征信息,形成更“厚”的特征图,但同时也需要更多的显存来存储这些特征。
  • 作用:解码器通过逐步上采样和特征融合,将编码器提取的高级特征与低级特征相结合,恢复出精细的图像分割结果。
优点与挑战
  • 优点:U-Net网络结构简洁,但性能强大,特别适用于医学图像分割等任务。其独特的U型结构和特征拼接方式使得网络能够同时捕获全局和局部特征,从而实现高精度的分割。
  • 挑战:尽管U-Net在性能上表现出色,但其对显存的需求也相对较高。特别是当处理高分辨率图像或进行大规模训练时,显存消耗可能会成为限制因素。此外,网络的设计和训练也需要大量的专业知识和经验。

综上所述,U-Net网络通过其独特的编码器-解码器结构和特征拼接方式,在医学图像分割等领域取得了显著成效。然而,在实际应用中仍需注意显存消耗等挑战,并不断探索更高效的优化方法。

pytorch实现UNet网络

class double_conv2d_bn(nn.Module):def __init__(self, in_channels, out_channels, kernel_size=3, strides=1, padding=1):super(double_conv2d_bn, self).__init__()self.conv1 = nn.Conv2d(in_channels, out_channels,kernel_size=kernel_size,stride=strides, padding=padding, bias=True)self.conv2 = nn.Conv2d(out_channels, out_channels,kernel_size=kernel_size,stride=strides, padding=padding, bias=True)self.bn1 = nn.BatchNorm2d(out_channels)self.bn2 = nn.BatchNorm2d(out_channels)def forward(self, x):out = F.relu(self.bn1(self.conv1(x)))out = F.relu(self.bn2(self.conv2(out)))return outclass deconv2d_bn(nn.Module):def __init__(self, in_channels, out_channels, kernel_size=2, strides=2):super(deconv2d_bn, self).__init__()self.conv1 = nn.ConvTranspose2d(in_channels, out_channels,kernel_size=kernel_size,stride=strides, bias=True)self.bn1 = nn.BatchNorm2d(out_channels)def forward(self, x):out = F.relu(self.bn1(self.conv1(x)))return outclass Unet(nn.Module):def __init__(self):super(Unet, self).__init__()self.layer1_conv = double_conv2d_bn(1, 8)self.layer2_conv = double_conv2d_bn(8, 16)self.layer3_conv = double_conv2d_bn(16, 32)self.layer4_conv = double_conv2d_bn(32, 64)self.layer5_conv = double_conv2d_bn(64, 128)self.layer6_conv = double_conv2d_bn(128, 64)self.layer7_conv = double_conv2d_bn(64, 32)self.layer8_conv = double_conv2d_bn(32, 16)self.layer9_conv = double_conv2d_bn(16, 8)self.layer10_conv = nn.Conv2d(8, 1, kernel_size=3,stride=1, padding=1, bias=True)self.deconv1 = deconv2d_bn(128, 64)self.deconv2 = deconv2d_bn(64, 32)self.deconv3 = deconv2d_bn(32, 16)self.deconv4 = deconv2d_bn(16, 8)self.sigmoid = nn.Sigmoid()def forward(self, x):conv1 = self.layer1_conv(x)pool1 = F.max_pool2d(conv1, 2)conv2 = self.layer2_conv(pool1)pool2 = F.max_pool2d(conv2, 2)conv3 = self.layer3_conv(pool2)pool3 = F.max_pool2d(conv3, 2)conv4 = self.layer4_conv(pool3)pool4 = F.max_pool2d(conv4, 2)conv5 = self.layer5_conv(pool4)convt1 = self.deconv1(conv5)concat1 = torch.cat([convt1, conv4], dim=1)conv6 = self.layer6_conv(concat1)convt2 = self.deconv2(conv6)concat2 = torch.cat([convt2, conv3], dim=1)conv7 = self.layer7_conv(concat2)convt3 = self.deconv3(conv7)concat3 = torch.cat([convt3, conv2], dim=1)conv8 = self.layer8_conv(concat3)convt4 = self.deconv4(conv8)concat4 = torch.cat([convt4, conv1], dim=1)conv9 = self.layer9_conv(concat4)outp = self.layer10_conv(conv9)outp = self.sigmoid(outp)return outp

自定义加载数据集

class LiverDataset(data.Dataset):def __init__(self, root, transform=None, target_transform=None, mode='train'):n = len(os.listdir(root + '/images'))imgs = []if mode == 'train':for i in range(n):img = os.path.join(root, 'images',"%d.png" % (i + 1))mask = os.path.join(root, 'mask', "%d.png" % (i + 1))imgs.append([img, mask])else:for i in range(n):img = os.path.join(root, 'images',"%d.png" % (i + 1))mask = os.path.join(root, 'mask', "%d.png" % (i + 1))imgs.append([img, mask])self.imgs = imgsself.transform = transformself.target_transform = target_transformdef __getitem__(self, index):x_path, y_path = self.imgs[index]img_x = Image.open(x_path)img_y = Image.open(y_path)if self.transform is not None:img_x = self.transform(img_x)if self.target_transform is not None:img_y = self.target_transform(img_y)return img_x, img_ydef __len__(self):return len(self.imgs)

完整代码

import osimport PIL.Image as Image
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use('TkAgg')
#module 'backend_interagg' has no attribute 'FigureCanvas',报错执行pip install matplotlib==3.5.0
import numpy as np
#关于numpy 报错时执行 pip install numpy==1.23.5
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.utils.data as data
from torchvision import transforms
from tqdm import tqdmepochs = 1
batch_size = 32
device = 'cpu'
best_model = None
best_loss = 999
save_path = './checkpoints/best_model.pkl'
directory_path = './checkpoints'# 检查目录是否存在
if not os.path.exists(directory_path):# 如果目录不存在,则创建它os.makedirs(directory_path)class double_conv2d_bn(nn.Module):def __init__(self, in_channels, out_channels, kernel_size=3, strides=1, padding=1):super(double_conv2d_bn, self).__init__()self.conv1 = nn.Conv2d(in_channels, out_channels,kernel_size=kernel_size,stride=strides, padding=padding, bias=True)self.conv2 = nn.Conv2d(out_channels, out_channels,kernel_size=kernel_size,stride=strides, padding=padding, bias=True)self.bn1 = nn.BatchNorm2d(out_channels)self.bn2 = nn.BatchNorm2d(out_channels)def forward(self, x):out = F.relu(self.bn1(self.conv1(x)))out = F.relu(self.bn2(self.conv2(out)))return outclass deconv2d_bn(nn.Module):def __init__(self, in_channels, out_channels, kernel_size=2, strides=2):super(deconv2d_bn, self).__init__()self.conv1 = nn.ConvTranspose2d(in_channels, out_channels,kernel_size=kernel_size,stride=strides, bias=True)self.bn1 = nn.BatchNorm2d(out_channels)def forward(self, x):out = F.relu(self.bn1(self.conv1(x)))return outclass Unet(nn.Module):def __init__(self):super(Unet, self).__init__()self.layer1_conv = double_conv2d_bn(1, 8)self.layer2_conv = double_conv2d_bn(8, 16)self.layer3_conv = double_conv2d_bn(16, 32)self.layer4_conv = double_conv2d_bn(32, 64)self.layer5_conv = double_conv2d_bn(64, 128)self.layer6_conv = double_conv2d_bn(128, 64)self.layer7_conv = double_conv2d_bn(64, 32)self.layer8_conv = double_conv2d_bn(32, 16)self.layer9_conv = double_conv2d_bn(16, 8)self.layer10_conv = nn.Conv2d(8, 1, kernel_size=3,stride=1, padding=1, bias=True)self.deconv1 = deconv2d_bn(128, 64)self.deconv2 = deconv2d_bn(64, 32)self.deconv3 = deconv2d_bn(32, 16)self.deconv4 = deconv2d_bn(16, 8)self.sigmoid = nn.Sigmoid()def forward(self, x):conv1 = self.layer1_conv(x)pool1 = F.max_pool2d(conv1, 2)conv2 = self.layer2_conv(pool1)pool2 = F.max_pool2d(conv2, 2)conv3 = self.layer3_conv(pool2)pool3 = F.max_pool2d(conv3, 2)conv4 = self.layer4_conv(pool3)pool4 = F.max_pool2d(conv4, 2)conv5 = self.layer5_conv(pool4)convt1 = self.deconv1(conv5)concat1 = torch.cat([convt1, conv4], dim=1)conv6 = self.layer6_conv(concat1)convt2 = self.deconv2(conv6)concat2 = torch.cat([convt2, conv3], dim=1)conv7 = self.layer7_conv(concat2)convt3 = self.deconv3(conv7)concat3 = torch.cat([convt3, conv2], dim=1)conv8 = self.layer8_conv(concat3)convt4 = self.deconv4(conv8)concat4 = torch.cat([convt4, conv1], dim=1)conv9 = self.layer9_conv(concat4)outp = self.layer10_conv(conv9)outp = self.sigmoid(outp)return outpclass LiverDataset(data.Dataset):def __init__(self, root, transform=None, target_transform=None, mode='train'):n = len(os.listdir(root + '/images'))imgs = []if mode == 'train':for i in range(n):img = os.path.join(root, 'images',"%d.png" % (i + 1))mask = os.path.join(root, 'mask', "%d.png" % (i + 1))imgs.append([img, mask])else:for i in range(n):img = os.path.join(root, 'images',"%d.png" % (i + 1))mask = os.path.join(root, 'mask', "%d.png" % (i + 1))imgs.append([img, mask])self.imgs = imgsself.transform = transformself.target_transform = target_transformdef __getitem__(self, index):x_path, y_path = self.imgs[index]img_x = Image.open(x_path)img_y = Image.open(y_path)if self.transform is not None:img_x = self.transform(img_x)if self.target_transform is not None:img_y = self.target_transform(img_y)return img_x, img_ydef __len__(self):return len(self.imgs)x_transform = transforms.Compose([transforms.ToTensor(),transforms.RandomResizedCrop(224),transforms.Grayscale(num_output_channels=1)
])y_transform = transforms.Compose([transforms.ToTensor(),transforms.RandomResizedCrop(224)
])liver_dataset = LiverDataset("./data/train", transform=x_transform, target_transform=y_transform)
dataloader = torch.utils.data.DataLoader(liver_dataset, batch_size=batch_size, shuffle=True)model = Unet()
criterion = torch.nn.BCELoss()
#criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters())for epoch in range(epochs):model.train()epoch_loss = 0train_bar = tqdm(dataloader)for x, y in train_bar:optimizer.zero_grad()inputs = x.to(device)labels = y.to(device)outputs = model(inputs)labels=labels.bool().float()loss = criterion(outputs, labels)loss.backward()optimizer.step()epoch_loss += loss.item()print("【EPOCH: 】%s" % str(epoch + 1))print("训练损失为%s" % str(epoch_loss))if epoch_loss < best_loss:best_loss = epoch_lossbest_model = model.state_dict()# 在训练结束保存最优的模型参数if epoch == epochs - 1:# 保存模型torch.save(best_model, save_path)print('Finished Training')plt.figure('测试一张图片')
pil_img = Image.open('./data/train/images/1.png')
np_img = np.array(pil_img)
plt.imshow(np_img)
plt.show()plt.figure('测试一张蒙版图片')
pil_img = Image.open('./data/train/mask/1.png')
np_img = np.array(pil_img)
plt.imshow(np_img)
plt.show()

开启训练

训练结果展示

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

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

相关文章

类和对象(补充)

1.static成员 1>静态成员变量在类外进行初始化 2>静态成员变量为所有类对象所共享&#xff0c;不属于任何具体对象&#xff0c;存放在静态区中 3>静态成员函数没有this指针&#xff0c;可访问其他静态成员&#xff0c;但不可访问非静态的 4>非静态成员函数可以…

jmeter做接口压力测试_jmeter接口性能测试

jmeter是apache公司基于java开发的一款开源压力测试工具&#xff0c;体积小&#xff0c;功能全&#xff0c;使用方便&#xff0c;是一个比较轻量级的测试工具&#xff0c;使用起来非常简单。因为jmeter是java开发的&#xff0c;所以运行的时候必须先要安装jdk才可以。jmeter是免…

SQL Server 使用 OPTION (RECOMPILE) 和查询存储的查询

设置 我们正在使用 WideWorldImporters 数据库&#xff0c;您可以从 Github 下载【sql-server-samples/samples/databases/wide-world-importers at master microsoft/sql-server-samples GitHub】。我正在运行SQL Server 2017 的最新 CU【https://sqlserverbuilds.b…

[Vulnhub] digitalworld.local-JOY snmp+ProFTPD权限提升

信息收集 IP AddressOpening Ports192.168.101.150TCP:21,22,25,80,110,139,143,445,465,587,993,995 $ nmap -p- 192.168.101.150 --21,22,25,min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 21/tcp open ftp ProFTPD | ftp-anon: Anonymous FTP logi…

基于Java中的SSM框架实现求职招聘网站系统项目【项目源码】

基于Java中的SSM框架实现线求职招聘网站系统演示 研究方法 本文的研究方法主要有&#xff1a; &#xff08;1&#xff09;调查法 调查法就是在系统的构思阶段&#xff0c;设计者对系统的功能和系统的现状有些不了解&#xff0c;需要去实地的去和本系统相关的区域进行调查&am…

数据结构——单链表详解(超详细)(2)

前言&#xff1a; 上一篇文章小编简单的介绍了单链表的概念和一些函数的实现&#xff0c;不过为了保证文章的简洁&#xff0c;小编把它分成了两篇来写&#xff0c;这一篇小编紧接上一篇文章继续写单链表函数功能的实现&#xff1a; 目录&#xff1a; 1.单链表剩余函数的编写 1.…

Idea如何快速高效的修改项目的包名

文章目录 前言一、全局替换的快捷键二、弹出如下的界面 前言 当我们有时候在做项目迁移的时候&#xff0c;需要快速的修改项目的包名&#xff01;那么如何快速高效的修改项目的报名呢&#xff1f; 经过尝试了很多方法&#xff01;最简单的方法就是利用全局替换来直接替换报名&…

微服务到底是个什么东东?

微服务架构是一种架构模式&#xff0c;它提倡将单一应用程序划分成一组小的服务&#xff0c;服务之间互相协调、互相配合&#xff0c;为用户提供最终价值。 每个服务运行在其独立的进程中&#xff0c;服务和服务间采用轻量级的通信机制互相沟通&#xff08;通常是基于 HTTP 的…

通过反射机制给已知属性赋值

最近在看spring&#xff0c;在手写spring框架之前&#xff0c;需要巩固一下反射。 反射有这样一个简单的例子&#xff0c;记录一下。 假如你知道age这个属性名&#xff0c;但是不知道属性类型&#xff0c;也可以写&#xff1a; 可以获取到属性的类型

设计模式-领域逻辑模式-事务脚本(Transaction Script)

事务脚本的特点 多数应用可看成由多个事务组成事务脚本将多个业务逻辑组织成单个过程事务间相互修改各自产生的数据 事务脚本的运行机制 使用事务脚本时&#xff0c;领域逻辑主要通过系统所执行的事务来组织。例如&#xff1a;预定酒店过程。 事务脚本的组织 将整个事务脚本放…

【BUG】已解决:IndexError: list index out of range

已解决&#xff1a;IndexError: list index out of range 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市开发者社区…

对服务器进行基本了解(二)

目录 一. 云服务器数据库 1.查看MYSQL版本 2.查看mysql的运行状态 3.运行mysql 4. 进入mysql的用户 5. 更改用户密码 6. 查找mysql端口号 7. 创建一个数据库 8. 查看用户 9. 查看数据库 10. 显示数据库的表 11. 修改用户的host 12. 对用户赋权 13. 开放指定端…

【学习笔记】无人机系统(UAS)的连接、识别和跟踪(一)-3GPP TS 23.256 技术规范概述

3GPP TS 23.256 技术规范&#xff0c;主要定义了3GPP系统对无人机&#xff08;UAV&#xff09;的连接性、身份识别、跟踪及A2X&#xff08;Aircraft-to-Everything&#xff09;服务的支持。 3GPP TS 23.256 技术规范&#xff1a; 以下是文档的核心内容总结&#xff1a; UAV系…

nginx的access.log日志输出请求数

适用格式 #log_format main $remote_addr - $remote_user [$time_local] "$request" # $status $body_bytes_sent "$http_referer" # "$http_user_agent" "$http_x_forwarded_for"; 形如&#…

【JVM实战篇】内存调优:内存问题诊断+案例实战

文章目录 诊断内存快照在内存溢出时生成内存快照MAT分析内存快照MAT内存泄漏检测的原理支配树介绍如何在不内存溢出情况下生成堆内存快照&#xff1f;MAT查看支配树MAT如何根据支配树发现内存泄漏 运行程序的内存快照导出和分析快照**大文件的处理** 案例实战案例1&#xff1a;…

CH390H+STM32F1+LWIP

文章目录 1、CH390芯片介绍2、电路部分3、LWIP调试3.1修改点13.2 修改点2 4、结果展示参考 1、CH390芯片介绍 官网地址&#xff1a; 南京沁恒微电子股份有限公司 特点&#xff1a; 2、电路部分 CH390及接口&#xff1a; STM32F1引脚&#xff1a; 不含LWIP的demo及LWIP…

【数据结构】二叉树全攻略,从实现到应用详解

​ &#x1f48e;所属专栏&#xff1a;数据结构与算法学习 &#x1f48e; 欢迎大家互三&#xff1a;2的n次方_ ​ &#x1f341;1. 树形结构的介绍 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做…

Qt纯代码绘制一个等待提示Ui控件

等待样式控件是我们在做UI时出场率还挺高的控件之一&#xff0c;通常情况下有如下的几种实现方式&#xff1a;1、自定义绘图&#xff0c;然后重写paintEvent函数&#xff0c;在paintEvent中绘制等待图标&#xff0c;通过QTimer更新绘制达到转圈圈的效果。2、 获取一张gif的资源…

SpringBoot下的定时魔法:揭秘@Scheduled注解的无限可能

在这个快节奏的时代&#xff0c;自动化与定时任务成为了提升效率的不二法门。而在Java的Spring Boot框架中&#xff0c;Scheduled注解就像是一位精通时间魔法的巫师&#xff0c;悄无声息地让你的应用按部就班地执行着各种定时任务。今天&#xff0c;就让我们一起揭开它的神秘面…

Ubuntu上安装配置samba服务

Ubuntu上安装配置samba服务 在Ubuntu中安装配置samba共享服务&#xff0c;可以让你在网络上共享文件和打印机。以下是一个相对详细的步骤指南&#xff0c;介绍如何在Ubuntu上安装和配置Samba。 1. 安装Samba 首先&#xff0c;需要安装Samba软件包。打开终端并运行以下命令&a…