基于Unet的BraTS 3d 脑肿瘤医学图像分割,从nii.gz文件中切分出2D图片数据

news2025/1/16 6:55:54

1、前言

3D图像分割一直是医疗领域的难题,在这方面nnunet已经成为了标杆,不过nnunet教程较少,本人之前跑了好久,一直目录报错、格式报错,反正哪里都是报错等等。并且,nnunet对于硬件的要求很高,一般的电脑配置或者低配置的服务器完全带不起来

或者定义conv.3D的unet网络模型,但对显卡的要求也很高...

之前实现了unet的自适应多类别分割任务,博文如下

Unet 实战分割项目、多尺度训练、多类别分割_unet进行多类分割-CSDN博客

代码根据数据集的mask,可以自动计算出mask前景的类别,这样就能为unet的输出自动调整,不需要更改别的操作。

而3d的图像其实就是2d拼接起来的,或许可以将nii格式的3d图片切分,这样根据上文的代码就可以实现医疗图像3d的分割

提示:这里切分的2d分割,效果肯定不如3d图像的分割

就比如线性回归对图像的分类,忽略了像素点的空间信息。那么3D切割出2D,其实也是忽略了图像的空间信息,效果肯定不如3d的直接分割

2、 nii 文件的切分

import SimpleITK as sitk 

这里用itk 对3d数据进行读取

2.1 数据集

这里的3d数据是 BRATS 脑肿瘤分割数据(brain tumor segmentation challenge,BraTS Chanllenge),这里只对训练集进行操作

需要注意的是,一般的nii图像都是3D的,这里数据是4D的,好像是每个3D图像的模态,类似于官方的增强?

T1 成像,利于观察解剖结构,病灶显示不够清晰

T1gd 在受试者做磁共振之前向血液内注射造影剂,使成像中血流活跃的区域更加明显,是增强肿瘤的重要判据

T2 成像,病灶显示较为清晰,判断整颗肿瘤

FLAIR(抑制脑脊液的高信号),含水量大则更亮眼,可以判断瘤周水肿区域

mask模板是四分类的:

2.2 slice 切片代码

代码放在这里:

这里参考之前的博文:nii 文件的相关操作(SimpleITK)_如何使用nii文件做深度学习-CSDN博客

import SimpleITK as sitk
import numpy as np
import os
from tqdm import tqdm
import shutil
import cv2


# 新建目录
def mkdir(rt):
    ret_path = rt + '_ret2D'
    if os.path.exists(ret_path):        # 删除之前的切片目录
        shutil.rmtree(ret_path)

    os.mkdir(ret_path)
    os.mkdir(os.path.join(ret_path,'images'))
    os.mkdir(os.path.join(ret_path,'labels'))


def get_image_from_nii(x,y,name,thre):  # 传入nii文件,对nii进行切片
    img = sitk.ReadImage(x)
    img_array = sitk.GetArrayFromImage(img)  # nii-->array

    label = sitk.ReadImage(y)
    label_array = sitk.GetArrayFromImage(label)  # nii-->array

    for index,i in enumerate(range(img_array.shape[1])):    # TODO 需要根据img维度更改,4D设定为1,3D设置为0
        img_select = img_array[0,i, :, :]       # TODO 需要根据img维度更改,从x轴切分,[:,i,:]从y轴切分
        label_select = label_array[i, :, :]

        # 图片保存目录
        img_save_name = os.path.join(root+'_ret2D','images',name+'_'+str(index)+'.png')
        label_save_name = os.path.join(root+'_ret2D','labels',name+'_'+str(index)+'.png')

        h,w = label_select.shape
        total_pixel = h*w           # 总的像素点个数

        if label_select.max() == 0:     # 没有前景的像素点不保存
            continue

        else:
            # 归一化
            img_select = (img_select - img_select.min()) / (img_select.max() - img_select.min())*255

            img_select = img_select.astype(np.uint8)
            label_select = label_select.astype(np.uint8)

            if (np.sum(label_select !=0 ) / total_pixel) > thre:
                cv2.imwrite(img_save_name,img_select)
                cv2.imwrite(label_save_name,label_select)


# 切片函数
def sliceMain(rt,imgf,labf,thre):
    # 删除之前的切片目录,建立新的目录
    mkdir(rt)

    nii_list = [i for i in os.listdir(os.path.join(rt,imgf))]

    for image_nii in tqdm(nii_list):      # 遍历所有的nii文件
        name = image_nii.split('.nii.gz')[0]

        image_nii = os.path.join(rt,imgf,image_nii)
        label_nii = image_nii.replace(imgf,labf)       # 自动获取nii 的标签

        get_image_from_nii(image_nii,label_nii,name,thre)


if __name__ == '__main__':

    root = 'BRATS'          # 待切分nii文件的父目录
    images_folder = 'imagesTr'      # 3d nii的数据
    labels_folder = 'labelsTr'       # 3d nii 的标签数据
    threshold = 0.03               # 分割的比例不超过阈值的数据删除

    # 切片函数
    sliceMain(
        rt=root,
        imgf=images_folder,
        labf=labels_folder,
        thre=threshold
    )

这里简单介绍一下:目录结构如下

具体数据的名称和后缀要严格对应!!!

 

threshold 是阈值处理,如果mask前景的像素点个数没有达到整个图片像素点的阈值,就不会被保存。这里默认是0.03

切分的时候,因为这里是4D的,所以img_array是四维的,我们默认取第一个维度的3D图像

同时,3D图像可以用x,y,z三个坐标表示,这里的shape1就是沿着x轴进行2D的切分

因为医学图像的灰度动态范围很多,可能到上千,因此这里将灰度值重新映射,变成np的uint8格式,再用cv保存

2.3 保存格式

图像的保存,这里搞了好久,要么格式问题,要么灰度有问题。这里做下总结

首先,png格式可以完整的保存2D切分的信息,而不会因为图像压缩导致mask灰度值改变。说人话就是,这里切分的2d像素值只有0 100 255,如果保存为其他格式,可能读取的时候,会产生0 1 2 3....等等灰度图像,而分割的mask是阈值图像!!

其次,plt保存的时候,会将图像重新映射,我们只想要0 1 2这种格式,但是他可能会把0变成0,1变成128.2变成255这样。虽说,这样看mask确实方便,不至于变成全黑的,但是本人测试的时候,总会莫名多出一个灰度。说人话就是,本来这里是四分类的,plt保存的时候,np.unique读取的时候,会变成5个类别

这里搞了半天,本人电脑太差,测试半天,只有这个代码是符合的。至于问题到底是不是我说的那样,可以自己测试

代码如下:

import os
from tqdm import tqdm
import numpy as np
import cv2


root = './BRATS_ret2D/labels'             # 训练 mask的路径
masks_path = [os.path.join(root ,i) for i in os.listdir(root)]
gray = []           # 前景像素点
for i in tqdm(masks_path,desc="gray compute"):
    img = cv2.imread(i,0)
    img_uni = np.unique(img)        # 获取mask的灰度值

    for j in img_uni:
        if j not in gray:
            gray.append(j)
print(gray)

2.4 切分好的数据

上述代码,切分后会生成root的返回目录

这里的mask并不是全黑的,只是0 1 2 3这样导致很黑而已。这里的目录名称按照切分索引,而没有从0开始,这样就能看出来BRATS_001 里面,49之前的要么没有mask前景,要么前景的区域不足我们设定的阈值!

 

3、划分数据集

参考之前的代码:关于图像分割任务中按照比例将数据集随机划分成训练集和测试集_图像分割数据集怎么划分-CSDN博客

 

这里可以可视化一下:关于图像分割项目的可视化脚本-CSDN博客

4、训练

unet训练如下:

训练时间太长了, 这里只简单训练了10个epoch用作测试,结果如下:

代码是这篇的代码:Unet 实战分割项目、多尺度训练、多类别分割_unet进行多类分割-CSDN博客

训练日志里面,有每个类别的指标:

推理结果:

4、项目总结

1、准备好3D的nii.gz数据,然后根据本章第二节摆放好数据切分。根据项目的实际要求设定好阈值或者沿着哪个轴切分

2、划分数据很简单

3、训练的 train 脚本

4、推理的时候,把待推理的数据放在inference目录下即可

5、说点废话

对于项目的改进的思考,项目下载:

深度学习Unet实战分割项目:BraTS3d脑肿瘤图像切分的2D图片分割项目(4分类)资源-CSDN文库

因为医学图像的灰度值都很低,往往图像会很暗,这样图像的梯度信息啊、边缘信息啊都很模糊,效果不太好,可以利用医学图像常用的windowing方法,其实就是对比度拉伸

医学图像处理的windowing 方法_医学图像常用windowing和histogram equalization-CSDN博客

而且,不同于正常的分类图像,这里的normalize可能直接 - 0.5 在除以 2效果不太好,这可以手动计算好图像的mean和std,可以有效提升网络的性能

怎么计算数据的均值和方差_计算数据集均值和方差-CSDN博客

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

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

相关文章

基于51单片机电子钟闹钟设计

基于51单片机电子钟闹钟设计 (仿真+程序+原理图) 功能介绍 具体功能: 1.LCD1602实时显示时间和闹钟时间; 2.可整点报时。 3.按键设置时间、闹钟。 4.使用蜂鸣器报时和响闹钟; ​演示视频&…

CCIE-14-MPLS_and_BGP

目录 实验条件网络拓朴 环境配置开始配置配置MPLSR1访问R6检测结果R6访问R1检测结果 实验条件 网络拓朴 环境配置 在我的资源里可以下载&#xff08;就在这篇文章的开头也可以下载&#xff09; 开始配置 R1<->R2&#xff1a;EBGP R2<->R5&#xff1a;IBGP&…

Azkaban集群模式部署详细教程

序言 Azkaban是一个用于工作流程调度和任务调度的开源工具&#xff0c;它可以帮助用户轻松地管理和监控复杂的工作流程。Azkaban的架构设计旨在提供高度可扩展性和可靠性&#xff0c;同时保持易用性和灵活性。 Azkaban的架构可以分为三个主要组件:Executor、Web Server和db数据…

FebHost:什么是土耳其.TR域名?

当前互联网高速发展,一个国家的顶级域名已成为其网络形象的重要标识。近期,土耳其国家顶级域名”.TR”引起了广泛关注,成为业界热议的话题。 作为代表土耳其共和国的国家顶级域名(ccTLD),.TR域名于1991年首次引入,由土耳其科技和信息技术部负责管理。除了常见的”.com.tr”、”…

JavaEE 初阶篇-生产者与消费者模型(线程通信)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 生产者与消费者模型概述 2.0 在生产者与消费者模型中涉及的关键概念 2.1 缓冲区 2.2 生产者 2.3 消费者 2.4 同步机制 2.5 线程间通信 3.0 实现生产者与消费者模…

【大数据存储】spark-编程

实验8-spark编程 实验&#xff1a;编写Spark应用程序&#xff08;掌握Spark应用程序的编写、编译打包和运行方法&#xff09; 1、对于两个输入文件A和B&#xff0c;编写Spark独立应用程序&#xff0c;对两个文件进行合并&#xff0c;并剔除其中重复的内容&#xff0c;得到一个…

IMU参数辨识及标定

IMU参数辨识及标定 一、标定参数分析 标定的本质是参数辨识。首先明确哪些参数可辨识&#xff0c;其次弄清怎样辨识。 参数包括陀螺仪和加速度计各自的零偏、标度因数、安装误差。 IMU需要标定的参数主要是确定性误差和随机误差&#xff0c;确定性误差主要标定bias&#xff0…

多线程学习-线程池

目录 1.线程池的作用 2.线程池的实现 3.自定义创建线程池 1.线程池的作用 当我们使用Thread的实现类来创建线程并调用start运行线程时&#xff0c;这个线程只会使用一次并且执行的任务是固定的&#xff0c;等run方法中的代码执行完之后这个线程就会变成垃圾等待被回收掉。如…

AcWing2069.网格分析

【题目链接】2069. 网络分析 - AcWing题库 输入样例1&#xff1a; 4 8 1 1 2 2 1 10 2 3 5 1 4 1 2 2 2 1 1 2 1 2 4 2 2 1输出样例1&#xff1a; 13 13 5 3 【代码及详细注释】 #include<bits/stdc.h> using namespace std; const int N1e510; int n,m,p[N],d[N]; /…

数据结构初阶:顺序表和链表

线性表 线性表 ( linear list ) 是 n 个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使 用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串 ... 线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的, 线性…

阿里巴巴蔡崇信:中国AI追赶神速,制造业霸主地位无可撼动!

快科技4月5日讯&#xff0c;阿里巴巴集团创始人兼董事长蔡崇信近日就AI技术领域及全球制造业形势发表看法。他认为&#xff0c;尽管中国在AI技术方面与美国有一定差距&#xff0c;但中国的追赶速度非常快。 AI-321 | 专注于AI工具分享的网站 AI工具集 | 人工智能工具箱 | 全球…

xss.pwnfunction-Jefff

在eval中可以直接执行命令所以直接把"直接闭合在结尾再加上一个"因为后面的"没闭和会报错 ?jeffa";alert(1);" 或 ?jeffa"-alert(1)-" -是分隔符

C++从入门到精通——类的定义及类的访问限定符和封装

类的定义及类的访问限定符和封装 前言一、类的定义类的两种定义方式成员变量命名规则的建议示例 二、类的访问限定符和封装访问限定符访问限定符说明C为什么要出现访问限定符例题 封装例题 前言 类的定义是面向对象编程中的基本概念&#xff0c;它描述了一类具有相同属性和方法…

【精品教程】护网HVV实战教程资料合集(持续更新,共20节)

以下是资料目录&#xff0c;如需下载&#xff0c;请前往星球获取&#xff1a; 01-HW介绍.zip 02-HTTP&Burp课程资料.zip 03-信息收集_3.zip 04-SQL注入漏洞_2.zip 05-命令执行漏洞.zip 06-XSS漏洞.zip 07-CSRF.zip 08-中间件漏洞.zip 09-SSRF.zip 10-XXE.zip 11-Java反序列…

Seata(分布式事务集成测试和总结)

文章目录 1.集成测试1.集成测试正常下单1.步骤2.浏览器访问 http://localhost:10008/order/save?userId666&productId1&nums1&money1003.注意事项和细节 2.集成测试模拟异常1.步骤1.com/sun/springcloud/controller/StorageController.java 休眠12s&#xff0c;模…

【项目新功能开发篇】需求分析和开发设计

作者介绍&#xff1a;本人笔名姑苏老陈&#xff0c;从事JAVA开发工作十多年了&#xff0c;带过大学刚毕业的实习生&#xff0c;也带过技术团队。最近有个朋友的表弟&#xff0c;马上要大学毕业了&#xff0c;想从事JAVA开发工作&#xff0c;但不知道从何处入手。于是&#xff0…

揭秘rmallox病毒:防范、清除、恢复一步到位!

引言&#xff1a; 随着信息技术的快速发展&#xff0c;计算机病毒已成为网络安全领域的一大难题。其中&#xff0c;rmallox病毒是近年来备受关注的一种恶意软件。本文将深入探讨rmallox病毒的特性、传播途径、防范措施、清除方法以及数据恢复技巧&#xff0c;帮助读者全面了解这…

Mac苹果电脑air/pro包含m1~m3打开app显示弹框“xxx”已损坏,无法打开。您应该将它移到废纸篓

应该是保姆级教程了&#xff1a; Mac苹果电脑air/pro包含m1~m3打开app显示弹框“xxx”已损坏&#xff0c;无法打开。您应该将它移到废纸篓。 我下载的是 Sublime Text 3 for Mac中文直装版&#xff0c;https://www.32r.com/soft/38404.html 安装后打开就gg了&#xff1a; 表现…

【图论】【分类讨论】LeetCode3017按距离统计房屋对数目

本文涉及的知识点 图论 分类讨论 本题同解 【差分数组】【图论】【分类讨论】【整除以2】3017按距离统计房屋对数目 LeetCode3017按距离统计房屋对数目 给你三个 正整数 n 、x 和 y 。 在城市中&#xff0c;存在编号从 1 到 n 的房屋&#xff0c;由 n 条街道相连。对所有 …

2024最新Notepad++下载安装教程图文步骤演示

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 文章目录 &#x1f42f;2024最新Notepad下载安装教程图文步骤演示&#x1f4dd;摘要引言正文&#x1f4d8;Notepad简介&#x1f4e5;下载Notepad&#x1f4e6;安装教程1. 获取安装…