当前位置:   article > 正文

脑PET图像分析与疾病预测 - nii文件数据处理与简单CNN训练_利用nii文件训练

利用nii文件训练

背景

笔者正在 Datawhale 举办的 AI 夏令营中参与 CV 方向的学习,研究课题为发布在讯飞 AI 开发者大赛上的脑PET图像分析和疾病预测挑战赛,需要对 nii 格式的医学影像文件进行学习,并进行疾病预测

第一轮学习中,Datawhale 团队给出了基于logistic回归进行预测的baseline,但其中并没有对 nii 文件进行详细介绍;且为了适配 logistic 回归模型,并缩小数据规模,其数据处理过程(个人认为)产生了不可忽视的信息丢失,直接导致预测的准确度仅略高于0.5——这跟瞎猜也没啥区别了吧……

鉴于此,笔者在探索中,总结出一篇对nii文件进行数据处理,并采用学习能力更强的简单CNN模型进行训练的教程

nii文件

数据格式

nii 文件是医学图像处理中经常使用的一种 NIFTI 格式图像,关于 nii 文件具体的底层原理,这里不做详细介绍,有兴趣的同学可以参见:Brainder.org的讲解。我们今天主要聚焦于,如何合理地处理 nii 文件中的数据,以便模型训练

数据集中的nii文件对一个人脑进行了三维建模。python 的 nibabel 库专门用于处理 nii 文件,我们可以通过 load() 函数读取 nii 文件,获取其信息:

  1. #1.py
  2. import nibabel as nib
  3. import numpy as np
  4. im=nib.load('脑PET图像分析和疾病预测挑战赛数据集/Train/NC/1.nii')
  5. im_data=np.array(im.get_fdata()) #获取文件中的所有数值,并转换为numpy数组便于后续处理
  6. print(im_data.shape) #查看数据的形状
  7. #返回:(128, 128, 63, 1)

可以看到,数据集中的 nii 文件包含四维数据:其中前三维确定某一个像素点的空间位置,其中左右和前后方向各分128层,上下方向分63层;第四维记录了该点的状态值(类似图片的灰度) 

数据处理

在整份 nii 数据中,所有的数值均为正整数,随便挑出一个值看一看:

  1. #1.py
  2. print(im_data[64,64,55,0])
  3. #返回:10550.0

如此多这么大的数值,如果直接将其投入模型进行训练,效果会很差,必须对数据进行预处理,减小其规模。前面提到的 baseline 中的示例代码给出的方法是人工进行特征提取:

  1. #1.py
  2. feat = [(im_data != 0).sum(), # 非零像素的数量
  3. (im_data == 0).sum(), # 零像素的数量
  4. im_data.mean(), # 平均值
  5. im_data.std(), # 标准差
  6. len(np.where(im_data.mean(0))[0]), # 在列方向上平均值不为零的数量
  7. len(np.where(im_data.mean(1))[0]), # 在行方向上平均值不为零的数量
  8. im_data.mean(0).max(), # 列方向上的最大平均值
  9. im_data.mean(1).max() # 行方向上的最大平均值
  10. ]

这种人工特征提取的方法,优势在于极大地减小了数据规模:每份文件从128*128*63=1032192个数值,减小到8个数值,大幅提升了训练速度。但或许其劣势也在于此:如此大规模的删减,势必造成严重的信息丢失

通常情况下,我们不对数据进行大量的丢弃与删除,而是对所有数据进行“归一化”,使得它们均值为0,标准差为1。具体操作为:求所有数据的平均值与标准差;随后对每个数据,减去平均值,再除以标准差:

  1. #1.py
  2. def norm(image):
  3. m=image.mean()
  4. s=image.std()
  5. return (image-m)/s
  6. im_norm=norm(im_data)
  7. #看看刚才的10550变成了多少
  8. print(im_norm[64,64,54,0])
  9. #返回:3.955

理论上来说,似此般对所有的 nii 文件做读取和归一化操作,就可以喂给模型做训练了。但是在尝试中我发现,数据集中的文件并非全部是 (128, 128, 63, 1) 的形状!少部分数据的前三个值出现了变化,比如256, 256, 47!这些数据可能受到了损坏,或者它本来就那样……通过一段代码,我们可以看到数据集中的 nii 都有哪些尺寸:

  1. #2.py
  2. import nibabel as nib
  3. import numpy as np
  4. import glob
  5. path=glob.glob('./脑PET图像分析和疾病预测挑战赛数据集/Train/*/*')
  6. path2=glob.glob('./脑PET图像分析和疾病预测挑战赛数据集/Test/*')
  7. sizeSet=set()
  8. for i in path:
  9. im=nib.load(i)
  10. im_data=np.array(im.get_fdata())
  11. sizeSet.add(im_data.shape)
  12. for i in path2:
  13. im=nib.load(i)
  14. im_data=np.array(im.get_fdata())
  15. sizeSet.add(im_data.shape)
  16. print(sizeSet)
  17. #返回:{
  18. # (256, 256, 207, 1), (128, 128, 768, 1), (128, 128, 47, 1),
  19. # (256, 256, 47, 1), (168, 168, 82, 1), (168, 168, 81, 1),
  20. # (400, 400, 109, 1), (128, 128, 89, 1), (128, 128, 540, 1),
  21. # (128, 128, 63, 1), (256, 256, 81, 1), (128, 128, 88, 1)
  22. # }

我初步的解决方法简单粗暴:在处理数据时,只要不是 (128, 128, 63, 1) 尺寸的数据,就直接丢弃它们!

  1. #1.py
  2. def process(path):
  3. im=nib.load(path)
  4. im_data=norm(np.array(im.get_fdata()))
  5. if im_data.shape==(128, 128, 63, 1): #判断数据形状是否异常
  6. if 'NC' in path:
  7. return True,im_data.reshape(-1),0 #表示正常(NC)
  8. else:
  9. return True,im_data.reshape(-1),1 #表示异常(MCI)
  10. else:
  11. return False,None,None #对于异常数据,直接不返回它们

不幸的是,测试集中的数据也有类似的情况(100个数据里有31个尺寸不正确)。对于这些数据,我只能暂时给它们随机分配“NC”和“MCI”标签来完成预测。这样造成的损失完全不亚于我所吐槽的示例代码

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/45523
推荐阅读
相关标签