使用 MONAI 加载和保存各种格式的医学图像

本教程属于实战,手把手教你加载各种医学图像数据(nii.gz, .dcm, .png等)。并学会查看医学图像数据的元数据(shape, affine, orientation)。学会使用monai全方位了解你的数据,并把它用于之后的深度学习训练。以及学会保存transform处理后的图像以及分割结果。干货很多,动手跟着一起来。

查看本教程前,请自行下载参考代码,边跑代码边看教程,学习效率更高哦

使用默认 image reader 加载 Nifti 图像

monai 根据文件后缀选择默认阅读器:

  • nii、nii.gz -> NibabelReader
  • png、jpg、bmp -> PILReader
  • npz、npy -> NumpyReader
  • 其他 -> ITKReader

开始实验前准备你的 nifti 格式图像,

filename = '/Users/Downloads/WORD-V0.1.0/imagesTr/word_0002.nii.gz'

如果没有,可以下载monai的示例

# download a test image
tempdir = tempfile.mkdtemp()
test_url = "https://github.com/Project-MONAI/MONAI-extra-test-data/releases/download/0.8.1/avg152T1_RL_nifti.nii.gz"
filename = os.path.join(tempdir, "avg152T1_RL_nifti.nii.gz")
monai.apps.download_url(test_url, filepath=filename)

接下来使用LoadImage加载图像

data = LoadImage(image_only=True, ensure_channel_first=True, simple_keys=True)(filename)
print(f"image data shape: {data.shape}")
print(f"meta data: {data.meta.keys()}")

参数解析

  • image_only: 默认为True,只返回图像;if False, 返回的data就是tuple, image=data[0], metadata(元数据)=data[1]
  • ensure_channel_first:默认为False, if True, 会给图像加一个channel,假如图像shape=[512, 512, 64], 加了channel就变成[1, 512, 512, 64]. 这在深度学习训练中基本都是要设为True, 向本教程的目的是加载图像的话,就不必设为True
    其余参数可以在pycharm源代码里查看

接下来,重点解释一下元数据,这是医学图像独有的信息。可以使用data.meta获取所有的元数据。包括

打勾的几个数据就是我平时用的比较多的,比如做图像分割的时候,要保存图像和分割结果,就需要知道affine信息。分割结果命名想同图像命名对应的时候,就需要知道filename_or_obj.

加载进来的3D图像如何展示出来呢?可以使用monai.visualize.matshow3d功能。

data1 = monai.transforms.Orientation("IPL")(data) # (Left, Right), (Posterior, Anterior), (Inferior, Superior).
fig = monai.visualize.matshow3d(volume=data1, 
                                # title='abdomen CT', 
                                figsize=(20,20),
                                frames_per_row=6, 
                                frame_dim=-3,
                                channel_dim=0,
                                every_n=5,
                                vmin=-300, vmax=600,
                                cmap='gray',
                                fill_value=255)

关于matshow3d函数的更多使用技巧,参考这篇文章【添加文章地址】

加载3D DICOM 图像

LoadImage同样支持加载DICOM图像和DICOM文件夹

filenames = ['/Users/Downloads/CBA60D87FAB145C3A9EB31A1C371C07E/0F9B3029D79B4B7DBE18776D284BB713.dcm',
            '/Users/Downloads/CBA60D87FAB145C3A9EB31A1C371C07E/0F9B3029D79B4B7DBE18776D284BB713.dcm']

folder_path = '/Users/Downloads/CBA60D87FAB145C3A9EB31A1C371C07E'

# load single image
# data = LoadImage(image_only=True)(filenames)

# load  DICOM series
data = LoadImage(image_only=True, ensure_channel_first=True)(folder_path)
print(f"image data shape: {data.shape}")

使用data.meta也可以查看元数据

加载 2D PNG图像

# 下载png图像
tempdir = tempfile.mkdtemp()
filename = os.path.join(tempdir, "MONAI-logo_color.png")
monai.apps.download_url("https://monai.io/assets/img/MONAI-logo_color.png", filepath=filename)

data, meta = LoadImage(image_only=False, reader="PILReader", reverse_indexing=False)(filename)
fig = monai.visualize.matshow3d(data, frame_dim=-1)
print(f"image data shape: {data.shape}")
print(f"meta data: {meta}")

保存图像

例如在图像分割中,想保存分割结果或者预处理后的图像。可以使用SaveImage方法。代码以Nifti图像格式为例

假设加载图像并进行了一些transform

# 假设加载图像并进行了一些transform
filenames = '/Users/Downloads/WORD-V0.1.0/imagesTr/word_0002.nii.gz'
transform = Compose(
    [
        LoadImaged(keys="image", image_only=True, ensure_channel_first=True),
        Resized(keys="image", spatial_size=[256, 256, 240])
    ]
)
test_data = {"image": filenames}
result = transform(test_data)
print(f"image data shape:{result['image'].shape}")
print(result["image"].affine)

保存处理后的图像

img = result["image"]
saver = SaveImage(
    output_dir='./output',
    output_ext=".nii.gz",
    output_postfix="trans",
    # output_dtype=np.uint8, # type改变,保存出来的图像变化大,慎重选择type
    resample=False,
    squeeze_end_dims=True,
    writer="NibabelWriter",
)
img = saver(img)

SaveImage将图像(可以是torch tensor或numpy ndarray的形式)和元数据字典保存到文件中。

保存的文件名将为{input_image_name}_{output_postfix}{output_ext},其中input_image_name是从提供的元数据字典中提取的。如果没有提供元数据,将使用从0开始的递增索引作为文件名前缀。

重要参数解析

  • output_ext:输出扩展名
  • output_postfix:输出后缀,默认为trans,如果输出是分割结果,可以设为seg, 最后文件名就是:{input_image_name}_seg.nii.gz
  • resample: 布尔值。if True, 就会重采样到原始图像大小。适用于在transform中对image做了采样后,保存分割结果又重新采样回去。使得分割结果同原始图像一样大小。此操作会利用原始图像元数据信息的spatail_shape以及original_affine.
  • squeeze_end_dims:if True, 去掉为1的维度,比如chanenl维度一般为1,保存的时候【C,H,W,D】-> 【H, W, D】
  • writer: 可以设置为 None,自动根据 output_ext 来选择合适的读写器。也可以是[“NibabelWriter”、“ITKWriter”、“PILWriter”]

当然,你也可以手动指定 metadata, 以及 filename

saver(img, meta_data=img.meta, filename='img_trans.nii.gz')

注意:这个要看版本,1.3版本没有filename

总结:图像的输出非常依赖于元数据(metadata), 对医学图像不是很熟悉的,重点关注本次内容中关于元数据的部分。monai的好处是加载图像后,图像的元数据(image dir, affine, spatial shape等信息全部都保存下来了,只需要img.meta就可以调出来)。

文章持续更新,可以关注微公【医学图像人工智能实战营】获取最新动态,一个关注于医学图像处理领域前沿科技的公众号。坚持以实践为主,手把手带你做项目,打比赛,写论文。凡原创文章皆提供理论讲解,实验代码,实验数据。只有实践才能成长的更快,关注我们,一起学习进步~

我是Tina, 我们下篇博客见~

白天工作晚上写文,呕心沥血

觉得写的不错的话最后,求点赞,评论,收藏。或者一键三连
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IO进程线程day

1.实现互斥机制 #include <head.h>char buf[128]; //全局数组&#xff0c;临界资源//1、创建一个互斥锁 pthread_mutex_t mutex;//定义分支线程 void *task(void *arg) {while(1){//3、获取锁资源pthread_mutex_lock(&mutex);printf("分支线程中&…

字节跳动机器人研究团队:用大规模视频数据训练GR-1,机器人轻松应对复杂任务

最近 GPT 模型在 NLP 领域取得了巨大成功。GPT 模型首先在大规模的数据上预训练&#xff0c;然后在特定的下游任务的数据上微调。大规模的预训练能够帮助模型学习可泛化的特征&#xff0c;进而让其轻松迁移到下游的任务上。 但相比自然语言数据&#xff0c;机器人数据是十分稀…

【学习笔记】1、数字逻辑概论

1.1 数字信号 数字信号&#xff0c;在时间和数值上均是离散的。数字信号的表达方式&#xff1a;二值数字逻辑和逻辑电平描述的数字波形。 &#xff08;1&#xff09; 数字波形的两种类型 数值信号又称为“二值信号”。数字波形又称为“二值位形图”。 什么是一拍 一定的时…

最新ChatGPT网站系统源码+详细搭建部署教程+Midjourney绘画AI绘画

一、前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作Ch…

Java学习苦旅(二十三)——二叉搜索树

本篇博客将详细讲解二叉搜索树。 文章目录 二叉搜索树概念操作查找插入删除 性能分析 结尾 二叉搜索树 概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根…

uniapp微信小程序投票系统实战 (SpringBoot2+vue3.2+element plus ) -全局异常统一处理实现

锋哥原创的uniapp微信小程序投票系统实战&#xff1a; uniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )_哔哩哔哩_bilibiliuniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )共计21条视频…

Packet Tracer - Configure AAA Authentication on Cisco Routers

Packet Tracer - 在思科路由器上配置 AAA 认证 地址表 目标 在R1上配置本地用户账户&#xff0c;并使用本地AAA进行控制台和vty线路的身份验证。从R1控制台和PC-A客户端验证本地AAA身份验证功能。配置基于服务器的AAA身份验证&#xff0c;采用TACACS协议。从PC-B客户端验证基…

LeetCode 2807. 在链表中插入最大公约数【链表,迭代,递归】1279

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…

Java多线程技术11——ThreadPoolExecutor类的使用1

1 概述 ThreadPoolExecutor类可以非常方便的创建线程池对象&#xff0c;而不需要程序员设计大量的new实例化Thread相关的代码。 2 队列LinkedBlockingQueue的使用 public class Test1 {public static void main(String[] args) {LinkedBlockingQueue queue new LinkedBlocki…

LeetCode-移动零(283)

题目描述&#xff1a; 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 思路&#xff1a; 这里的思路跟以前做过的去重复数字的思路有点像&…

字符输入输出 C语言xdoj16

问题描述&#xff1a; 通过键盘输入5个大写字母&#xff0c;输出其对应的小写字母&#xff0c;并在末尾加上“&#xff01;”。 输入说明&#xff1a; 5个大写字母通过键盘输入&#xff0c;字母之间以竖线“|”分隔。 输出说明&#xff1a; 输出5个大写字母对应的小写字母&…

多线程模板应用实现(实践学习笔记)

出处&#xff1a;B站码出名企路 个人笔记&#xff1a;因为是跟着b站的教学视频以及文档初步学习&#xff0c;可能存在诸多的理解有误&#xff0c;对大家仅供借鉴&#xff0c;参考&#xff0c;然后是B站up阳哥的视频&#xff0c;我是跟着他学。大家有兴趣的可以到b站搜索。加油…

webpack的性能优化(一)——分包优化

1.什么是分包&#xff1f;为什么要分包&#xff1f; 默认情况下&#xff0c;Webpack 会将所有代码构建成一个单独的包&#xff0c;这在小型项目通常不会有明显的性能问题&#xff0c;但伴随着项目的推进&#xff0c;包体积逐步增长可能会导致应用的响应耗时越来越长。归根结底这…

【Linux】进程信号——进程信号的概念和介绍、产生信号、四种产生信号方式、阻塞信号、捕捉信号、阻塞和捕捉信号的函数

文章目录 进程信号1.进程信号的概念和介绍2.产生信号2.1通过终端按键产生信号2.2 调用系统函数向进程发信号2.3 由软件条件产生信号2.4硬件异常产生信号 3.阻塞信号3.1信号在内核中的表示3.2信号集操作函数3.3sigprocmask 4.捕捉信号4.1内核如何实现信号的捕捉4.2 sigaction 进…

【AI视野·今日Robot 机器人论文速览 第七十一期】Fri, 5 Jan 2024

AI视野今日CS.Robotics 机器人学论文速览 Fri, 5 Jan 2024 Totally 11 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Robotics Papers Machine Learning in Robotic Ultrasound Imaging: Challenges and Perspectives Authors Yuan Bi, Zhongliang Jiang, Felix D…

线性代数 --- 矩阵行列式的性质

Determinant det A|A| 矩阵的行列式是一个数&#xff0c;这个数能够反应一些关于矩阵的信息。行列式只对方阵有效。 若矩阵A为&#xff1a; 则A的行列式为&#xff1a; 性质1&#xff1a; 单位矩阵的行列式等于1 性质2&#xff1a;行与行之间的交换会改变det的正负号 以2x2单位…

Mybatis入门源码二:sql执行

后面开始分析sql执行的源码流程也就是这一部分 一、factory.openSession() 重点关注configuration.newExecutor这个方法&#xff0c;获取事务处理器比较简单&#xff0c;就是获取一个jdbc的事务管理器。 这个方法通过传入的执行器类型来创建不同的执行器&#xff0c;有simp…

x-cmd pkg | trdsql - 能对 CSV、LTSV、JSON 和 TBLN 执行 SQL 查询的工具

目录 简介首次用户技术特点竞品和相关作品进一步阅读 简介 trdsql 是一个使用 sql 作为 DSL 的强大工具: 采用 SQL 对 CSV、LTSV、JSON 和 TBLN 文件执行查询与 MySQL&#xff0c;Postgresql&#xff0c;Sqlite 的 Driver 协同&#xff0c;可以实现对应数据库的表与文件的 JO…

安全基础~信息搜集3

文章目录 知识补充APP信息搜集php开发学习理解漏洞 知识补充 端口渗透总结 python Crypto报错&#xff1a;https://blog.csdn.net/five3/article/details/86160683 APP信息搜集 1. AppInfoScanner 移动端(Android、iOS、WEB、H5、静态网站)信息收集扫描工具 使用教程 演示&…

超维空间M1无人机使用说明书——21、基于opencv的人脸识别

引言&#xff1a;M1型号无人机不仅提供了yolo进行物体识别&#xff0c;也增加了基于opencv的人脸识别功能包&#xff0c;仅需要启动摄像头和识别节点即可 链接: 源码链接 一、一键启动摄像头和人脸识别节点 roslaunch robot_bringup bringup_face_detect.launch无报错&#…