目录

  • 前言
  • nii格式
  • 读取nii成numpy格式
  • 将numpy格式保存成nii
  • 什么是origin、Direction、Spacing,以及如何设置它们
  • 示例
  • 重采样
    • 重采样代码
  • 参考链接

前言

nii.gz格式是保存医学图像非常重要一种格式,下面来介绍一下如何使用SimpleITK这个包来处理nii文件。我们首先会介绍最简单的读取、保存、以及如何转为numpy数组;然后再来介绍一些高级操作,什么是DirectionOriginSpacing重采样

nii格式

首先nii格式就是后缀名为.nii.nii.gz的文件,该格式又叫NIfTI-1MRI图像或者CT图像通常会以这种格式保存。

至于这种格式的作用,简单来理解就是将索引坐标映射到体素坐标。我们知道计算机中的数据都是离散的,比如一个数组可以按照索引取对应的值,但是在显示生活中,距离都是连续的,那如何给计算机中离散的点(索引坐标)赋予一个连续的坐标(即体素坐标)呢?

在nii格式中,为了将索引坐标(数组下标)映射到体素坐标(空间坐标),除了保存图像的数据外,即那一个个离散的像素,还保存了一些额外信息,比如每个像素间的距离原点坐标方向等等,这样根据像素间的距离就可以计算某一像素在空间中真正的坐标了。

更为详细的解释在这里可以看到。

那我们做深度学习需要空间坐标干嘛呢,确实,在训练过程中我们并不关心空间坐标,只需要把nii文件中保存的像素值拿出来转化为numpytensor输入网络就可以了,空间距离对我们也没什么用。但还是想写给大家,因为当我们做对比实验时,你会发现将不同网络输出的预测结果保存为nii文件,然后用3DSlicer打开后,二者的预测结果可能完全不一样,这是因为起始坐标原始label是对不上的,所以需要设置成一样的,这个问题我们后面再说。

读取nii成numpy格式

这个非常容易,只需要使用SimpleITK先读取图像,然后从图像中获取数组就可以了。
最后image就是一个numpy数组,但是需要注意的是nii文件默认保存数据的顺序是[x, y, z],但是numpy数组保存数据的顺序是[z, y, x],刚好是反过来的.。因为在训练时一般是[x, y, z],所以我们在dataset中需要将图像的坐标轴转换一下,即做一个transpose(2, 1, 0)操作。

import SimpleITK as sitk
image_path = ''
image = sitk.ReadImage(image_path)
image = sitk.GetArrayFromImage(image)

将numpy格式保存成nii

代码也是非常简单,仍然需要注意的是,可能从网络中输出预测结果的坐标顺序为[x, y, z],但是保存时numpy数组轴的顺序一定要是[z, y, x ],做一下transpose(2, 1, 0)permute(2, 1, 0)操作,这样才是正确的。当然,这一步操作取决于你的dataset类是否交换了维度,如果交换了维度,网络输出后自然需要交换回来。不知道我讲清楚了没有

# image是一个三维numpy数组,image_path是要保存的路径
sitk.WriteImage(image, image_path)

什么是origin、Direction、Spacing,以及如何设置它们

origin就是原点的坐标,direction我还不太清楚,大概是轴的方向吧,spacing就是每个像素间所代表的真实世界的距离,下面的这个图比较容易理解

对这些有一个大概的认识后,实际使用中,我们只需要以原图为基准,将不同网络输出预测结果的元数据属性设置成和原图一样就可以了,这样用3D Slicer打开时位置就能对应起来~,代码如下:
需要注意的是保存前的numpy轴的顺序必须得是[z, y, x],否则需要先交换再设置元数据属性,这样才是正确的!!!

# 读取原图像
origin_path = ''
origin = sitk.ReadImage(origin_path)# 读取预测图像
pred_path = ''
pred = sitk.ReadImage(pred_path)# 将预测结果的元数据属性设置成和原图像一样
pred.SetDirection(origin.GetDirection())
pred.SetOrigin(origin.GetOrigin())
pred.SetSpacing(origin.GetSpacing())# 保存处理后的
sitk.WriteImage(pred, pred_path)

示例

把自己的代码保存在这里吧,我做了四个对比试验,nnunet,nnformer,unetr,our,根据nii的ID来依次处理,将他们的元数据都设成和原始image的元数据一样,应该比较好理解吧~

import SimpleITK as sitkdef setMetaMessage(target, origin):target.SetDirection(origin.GetDirection())target.SetOrigin(origin.GetOrigin())target.SetSpacing(origin.GetSpacing())return targetdef process(id):image_path = 'C:/Users/hejianfei/Desktop/vessel result/result'image = sitk.ReadImage(os.path.join(image_path, str(id) + '_image.nii.gz'))print('image size:', image.GetSize())sitk.WriteImage(image, os.path.join('C:/Users/hejianfei/Desktop/vessel result/process result', str(id) + '_image.nii.gz'))label = sitk.ReadImage(os.path.join(image_path, str(id) + '_label.nii.gz'))print('label size:', label.GetSize())label = setMetaMessage(label, image)sitk.WriteImage(label, os.path.join('C:/Users/hejianfei/Desktop/vessel result/process result', str(id) + '_label.nii.gz'))nnunet = sitk.ReadImage(os.path.join(image_path, str(id) + '_nnunet.nii.gz'))print('nnunet size:', nnunet.GetSize())nnunet = setMetaMessage(nnunet, image)sitk.WriteImage(nnunet, os.path.join('C:/Users/hejianfei/Desktop/vessel result/process result', str(id) + '_nnunet.nii.gz'))nnformer = sitk.ReadImage(os.path.join(image_path, str(id) + '_nnformer.nii.gz'))print('nnformer size:', nnformer.GetSize())nnformer = setMetaMessage(nnformer, image)sitk.WriteImage(nnformer, os.path.join('C:/Users/hejianfei/Desktop/vessel result/process result', str(id) + '_nnformer.nii.gz'))unetr = sitk.ReadImage(os.path.join(image_path, str(id) + '_unetr.nii.gz'))unetr = sitk.GetArrayFromImage(unetr)unetr = unetr.transpose(2, 1, 0)  # 换轴unetr = sitk.GetImageFromArray(unetr)print('unetr size:', unetr.GetSize())unetr = setMetaMessage(unetr, image)sitk.WriteImage(unetr, os.path.join('C:/Users/hejianfei/Desktop/vessel result/process result', str(id) + '_unetr.nii.gz'))our = sitk.ReadImage(os.path.join(image_path, str(id) + '_our.nii.gz'))our = sitk.GetArrayFromImage(our)our = our.transpose(2, 1, 0)  # 换轴our = sitk.GetImageFromArray(our)print('our size:', our.GetSize())our = setMetaMessage(our, image)sitk.WriteImage(our, os.path.join('C:/Users/hejianfei/Desktop/vessel result/process result', str(id) + '_our.nii.gz'))if __name__ == '__main__':process(447)

重采样

重采样可以这样理解,现在我们有一个2m*2m*2m的正方体,它的像素分辨率为100*100*100,即每个方向都存了100个离散的像素点,现在我们保持正方体的尺寸不变,还是2m*2m*2m,但是像素分辨率插值变为150*150*150,这样就缩小了每个像素间的space。所以这个函数也是需要我们传入一个目标space。大家先简单理解一下,相当于体积不变,密度增大了,类比二维的resize操作,等用到的时候去查一下文档~
这里说一下我对重采样的简单理解,重采样改变的是每个像素间所代表的物理距离,在重采样代码中,我们是重采样前像素个数为x,每个像素间的距离(即Spacing)为y;重采样后的像素个数为z,每个像素间的距离为m;我们为了保持物理体积不变(即x*y = z*m),所以当改变m(即Spacing)后,相应的像素个数z也会通过插值改变。
在神经网络中,我们除了通过重采样改变像素个数外,还可以通过Resize操作来改变像素点。只不过为了最终可视化和原label大小一样,最好先把两者的Spacing调整为一样的。
否则会出现如下情况,可以看到长宽比发生了变形:
原图

预测label:

重采样代码

def resampleVolume(outspacing, vol, type):"""将体数据重采样的指定的spacing大小\nparas:outpacing:指定的spacing,例如[1,1,1]vol:sitk读取的image信息,这里是体数据type:指定插值方法,一般对image采取线性插值,对label采用最近邻插值return:重采样后的数据"""outsize = [0, 0, 0]# 读取文件的size和spacing信息inputsize = vol.GetSize()inputspacing = vol.GetSpacing()transform = sitk.Transform()transform.SetIdentity()# 计算改变spacing后的size,用物理尺寸/体素的大小outsize[0] = round(inputsize[0] * inputspacing[0] / outspacing[0])outsize[1] = round(inputsize[1] * inputspacing[1] / outspacing[1])outsize[2] = round(inputsize[2] * inputspacing[2] / outspacing[2])# 设定重采样的一些参数resampler = sitk.ResampleImageFilter()resampler.SetTransform(transform)# 图像使用线性插值,标签使用最近邻插值if type == 'linear':resampler.SetInterpolator(sitk.sitkLinear)resampler.SetOutputPixelType(sitk.sitkFloat32)  # image用float32存else:resampler.SetInterpolator(sitk.sitkNearestNeighbor)resampler.SetOutputPixelType(sitk.sitkUInt8)  # 标签用int8存储resampler.SetOutputOrigin(vol.GetOrigin())resampler.SetOutputSpacing(outspacing)resampler.SetOutputDirection(vol.GetDirection())resampler.SetSize(outsize)newvol = resampler.Execute(vol)return newvol

参考链接

https://blog.csdn.net/qq_39482438/article/details/106711272
重采样代码

使用SimpleITK读取、保存、处理nii文件相关推荐

  1. bat文件无法保存为ansi_数组矩阵和PNG保存为nii文件

    nii文件或者nii.gz文件是一种特殊的文件格式,可以存储叠加的切片数据或者时序数据,比如MRI头部矢状面扫描的所有切片,CT扫描图,多细胞时移图等等.对于nii文件的读取和存储也有许多的方法. 一 ...

  2. python+itk+读取dicom数据,并保存为nii文件

    上代码 import itk import numpy as npif __name__ == '__main__':file_path = "D:/test/004HeRuiPing_CT ...

  3. python怎么保存为nii文件_Ubuntu+python将nii图像保存成png格式

    这里介绍一个nii文件保存为png格式的方法. 这篇文章是介绍多个nii文件保存为png格式的方法: 系统:Ubuntu 16.04 软件: python 3.5 先用pip安装nibabel.num ...

  4. python怎么保存为nii文件_python处理nii文件

    第一步安装nibabel,可以使用命令:pip install nibabel 之后: from nibabel.viewers import OrthoSlicer3D as osd import ...

  5. opencv C艹:读取视频文件,保存图像,视频文件,读取保存XML YAML文件

    <opencv4快速入门> 认识认识模块 D:\opencv\build\include\opencv2 路径下 calib3d 主要包含相机标定,立体视觉的功能:物体姿势估计,三维重建, ...

  6. python怎么保存为nii文件_nii文件在python中的使用

    NIFTI格式图像 NIFTI(Neuroimaging Informatics Technology Initiative)格式图像是由一个包含头文件元数据和一个包含二进制的图像资料组成的文件. 读 ...

  7. 如何处理.nii文件

    最近读了一篇论文[1],是利用深度学习进行MRI图像重建的,作者在github[2]上提供给我们的他的实现代码,他使用的一个MRI分割比赛的数据集[3],但是将数据集下载下来发现全部都是.nii格式的 ...

  8. python使用nibabel和sitk读取保存nii.gz文件

    nii.gz格式是医学图像常用的压缩格式,python中可用nibabel和sitk来读取保存. 使用nibabel 由于使用nibabel图像会旋转90度,所以读取保存的时候还得保存映射信息,3维图 ...

  9. 如何读取NIFTI格式图像(.nii文件)

    如何读取NIFTI格式图像(.nii文件) 1 NIFTI格式图像 1.1 什么是NIFTI格式图像 1.2 为什么会出现NIFTI格式图像 2 读取NIFTI格式图像 2.1 ITK-SNAP 2. ...

最新文章

  1. 中国安防视频监控行业发展前景分析
  2. openssh升级sftp_Centos7 升级 openSSH 到7.9p1的详细步骤
  3. js br不生效_前端标注工具-AILabel.js
  4. jedis开发过程中遇到的问题及其解决方法
  5. swoole task MySQL连接池
  6. 订单查询管理系统Silverlight4(预告)
  7. CentOS:bash: g++: 未找到命令...
  8. airtest 不同目录下导入air文件方法
  9. powerdesigner 16.5 Could not Initialize JavaVM!
  10. linux ftp命令大全,linux 操作 ftp 常用命令
  11. 【ARM嵌入式】——多寄存器寻址
  12. git clone报错Could not resolve proxy : proxy-szn
  13. 【Android安全】priv-app 系统应用权限
  14. 现代处理器的设计思想
  15. python计算导数_python计算导数并绘图的实例
  16. Codeforces Round #807 (Div. 2) A-C题解
  17. 国产操作系统Office哪个好用?6款工具推荐!
  18. [学习笔记]《零基础做出高逼格PPT》
  19. PAT甲级真题 1011 World Cup Betting (20分) C++实现
  20. R5S OpenWrt下smba共享文件夹

热门文章

  1. java web 图片显示_JavaWeb将图片显示在浏览器中
  2. 腾讯安全发布《2022年DDoS攻击威胁报告》:DDoS威胁4年持续增长
  3. java汽车_java汽车销售系统
  4. c语言平面向量加法考点,平面向量的加减法怎么死活都不会?有没有什么口诀?
  5. 掌控项目采购管理4大流程,其实很简单
  6. 1024,干程序才懂得节日!
  7. IP地址:10.10.1.1/24的“/24”是什么意思?
  8. DeepSpeed零冗余优化器Zero Redundancy Optimizer
  9. 服务器加固指南 -- 思路分享
  10. Harbor实现容器镜像仓库的管理和运维