1 前言
对于不同的数据类型重采样的方法和目的都不相同。例如在遥感中,重采样是从高分辨率遥感影像中提取出低分辨率影像的过程;在数据挖掘中,重采样是指为了解决训练数据类别不均衡,通过在训练期间通过增加小样本的数量或者减少大样本的数量保持样本类别均衡的算法;在医疗图像中,重采样是指将医疗图像中大小不同的体素归一化到相同的大小。体素是体积元素(Volume Pixel)的简称,一张3D医疗图像可以看成是由若干个体素构成的,体素是一张3D医疗图像在空间上的最小单元,具体解释可见
上一篇博客
。本文主要包含两个部分:第一、通过python和SimpleITK实现医疗图像重采样,并对结果进行分析;第二是讲解一下医疗图像重采样所代表的现实意义。本文所使用的数据集为公开的
胰腺分割数据集
,其包含82个病人的胰腺数据集。
1.1 医疗图像重采样
对于一张大小为128*128的彩色图像,其在计算机中可以表示为128*128*3的矩阵,其中每一个像素点的取值范围为0-255,不同的数值代表不同的亮度。但是对于医疗图像其是由若干个slice组成的,假设每一个slice的大小为512*512的单通道的图像,其中
每一个像素点表示的是一个体素的取值,
其范围可以-1000~2000之间。接下来通过以胰腺分割数据集中PANCREAS_0015.nii.gz为例,对医疗图像中体素这个概念进行讲解。Spacing(0.78125, 0.78125, 1.0)表示的是原始图像体素的大小,也可以将Spacing想象成大小为(0.78125, 0.78125, 1.0)的长方体。而原始图像的Size为 (512, 512, 247),表示的是原始在X轴,Y轴,Z轴中体素的个数。
原始图像的size*对应的Spacing既可以得到真实3D图像大小
(512*0.78125,512*0.78125,247*1 ),在图像重采样只是修改体素的大小,而真实3D图像大小是保持不变的,因此假设我们将Spacing修改成(1.0, 1.0, 2.0)的时候,则修改之后其对应的size应该为((512*0.78125)/ 1.0,(512*0.78125)/ 1.0,(247*1 ))即(400, 400, 124)。结果如下所示。
1.2 医疗图像重采样代码分析
对于医疗图像重采样,可以分成三个步骤:首先使用SimpleITK读取数据,获得原始图像的对应的Spacing以及Size,得到图像原始的大小;然后图像原始的大小除以新Spacing得到新Size;最后将新新Spacing得到新Size赋值到读取的数据即可。
# -*- coding: utf-8 -*-
# @Time : 2020/12/27 16:36
# @Author : YYLin
# @Email : 854280599@qq.com
# @File : Resample_img.py
import SimpleITK as sitk
import numpy as np
# 对医疗图像进行重采样,仅仅需要将out_spacing替换成自己想要的输出即可
def resample_image(itk_image, out_spacing=[1.0, 1.0, 2.0]):
original_spacing = itk_image.GetSpacing()
original_size = itk_image.GetSize()
# 根据输出out_spacing设置新的size
out_size = [
int(np.round(original_size[0] * original_spacing[0] / out_spacing[0])),
int(np.round(original_size[1] * original_spacing[1] / out_spacing[1])),
int(np.round(original_size[2] * original_spacing[2] / out_spacing[2]))
]
resample = sitk.ResampleImageFilter()
resample.SetOutputSpacing(out_spacing)
resample.SetSize(out_size)
resample.SetOutputDirection(itk_image.GetDirection())
resample.SetOutputOrigin(itk_image.GetOrigin())
resample.SetTransform(sitk.Transform())
resample.SetDefaultPixelValue(itk_image.GetPixelIDValue())
resample.SetInterpolator(sitk.sitkBSpline)
return resample.Execute(itk_image)
gz_path = 'PANCREAS_0015.nii.gz'
print('测试文件名为:', gz_path)
# 使用sitk读取对应的数据
Original_img = sitk.ReadImage(gz_path)
print('原始图像的Spacing:', Original_img.GetSpacing())
print('原始图像的Size:', Original_img.GetSize())
# 对数据进行重采样
Resample_img = resample_image(Original_img)
print('经过resample之后图像的Spacing是:', Resample_img.GetSpacing())
print('经过resample之后图像的Size是:', Resample_img.GetSize())
1.3 实验结果对比
从整体质量上来说,本文所使用的重采样并没有对图像的质量有明显的影响,但是当我们把Z轴的放缩因子变成2之后,我们发现重采样癌变区域对应的slice的为未重采样的slice一般。这也说明了spacing、图像slice个数和图像整体大小之间存在的关系的。
1.3.1 重采样之前
1.3.2 重采样之后
1.4 小结
通过1.1节,我们可以知道使用重采样归一化医疗图像的原理,以及其图像对应的Spacing和Size的变化;通过1.2节,我们可以使用python和SimpleITK实现医疗图像的重采样。那么问题来了,我们在什么时候要使用图像重采样呢?怎么设置图像重采样的Spacing呢?
针对第一个问题:在我看到的资料中一般是在构建一个3D医疗图像模型时,使用图像图重采样技术,对此知乎上的一个解释可以仅供参考,CNN中Conv操作被提出来的其中一个重要motivation就是图像中有相似的块能用共享的卷积来提取特征,因此对所有图像重采样能减少不同图像之间的不一致性,便于卷积操作提取共同的特征
针对第二个问题:我个人感觉,重采样中Spacing的设置就是一个超参。对于这个超参数,我的想法是新设置的Spacing应该尽可能使得不同图像之间的体素差异性尽可能的小,差异越小效果越好。在2D图像中,我更喜欢保持X轴,Y轴尽可能的不变,而把Z轴变小,这样不会影响图像的分辨率,而且能够增加训练数据集。
2 参考链接
https://zhuanlan.zhihu.com/p/76057976
https://www.zhihu.com/question/364844125
https://academictorrents.com/details/80ecfefcabede760cdbdf63e38986501f7becd49
https://baike.baidu.com/item/%E9%87%8D%E9%87%87%E6%A0%B7/4949402?fr=aladdin