简单ITK 调整图像大小

5

我有一组用SimpleITK读取的3D数据卷。

import SimpleITK as sitk
for filename in filenames:
    image = sitk.ReadImage(filename)

每个数据集的大小、间距、起点和方向都各不相同。这段代码会针对不同的图像得出不同的数值:
print(image.GetSize())
print(image.GetOrigin())
print(image.GetSpacing())
print(image.GetDirection())

我的问题是:我该如何将图像转换为具有相同大小和间距的格式,以便在转换为numpy数组时,它们都具有相同的分辨率和大小。类似于:

import SimpleITK as sitk
for filename in filenames:
    image = sitk.ReadImage(filename)
    image = transform(image, fixed_size, fixed_spacing)
    array = sitk.GetArrayFromImage(image)
2个回答

8
使用Resample函数以固定/任意大小和间距来完成此操作。以下是一个代码片段,显示构建这个“reference_image”空间的过程:
reference_origin = np.zeros(dimension)
reference_direction = np.identity(dimension).flatten()
reference_size = [128]*dimension # Arbitrary sizes, smallest size that yields desired results. 
reference_spacing = [ phys_sz/(sz-1) for sz,phys_sz in zip(reference_size, reference_physical_size) ]

reference_image = sitk.Image(reference_size, data[0].GetPixelIDValue())
reference_image.SetOrigin(reference_origin)
reference_image.SetSpacing(reference_spacing)
reference_image.SetDirection(reference_direction)

为了提供一个一揽子解决方案,请查看这个 Jupyter notebook,它演示了如何使用 SimpleITK 对变量大小的图像进行数据增强(上面的代码来自笔记本)。您可能还会发现其他来自SimpleITK 笔记本存储库的笔记本也很有用。

1
在仅想要调整大小的情况下,Resample()函数应使用哪些转换?另外,您能否就插值器和默认值参数发表评论?谢谢。 - Miguel Monteiro
2
我创建了一个github gist,其中展示了如何进行重采样。对于大多数情况,线性插值器已经足够好了,但是对于标签插值,您需要最近邻插值器。default_intensity_value是在映射到图像边界外时设置的值。 - zivy
抱歉再次打扰您。当重新采样到给定的分辨率和大小,然后再返回时,必然会有损失。对于常规图像,我发现这些损失是可以接受的,但对于标记图像,即使使用最近邻插值,有时也会出现分割区域损失20%的情况。有什么建议来解决这个问题吗? - Miguel Monteiro
1
使用最近邻的唯一原因是它不会引入新标签,但它会使混叠伪影变得更糟。可能将分割图像视为实值图像,而不是二进制图像,并使用任何其他插值器,然后进行阈值处理以获取二进制图像。此外,在转换到较粗分辨率时应平滑图像。这只是缓解问题,而不是解决问题。有关未来讨论,请使用 https://discourse.itk.org/(simpleitk 标签),stackoverflow 上的评论字符限制很严格。 - zivy

4
根据SimpleITK的文档,图像重采样的过程包括4个步骤:
  1. 图像 - 我们要重采样的图像,给定在坐标系中;
  2. 重采样网格 - 由一组规则的点组成,给定在坐标系中,将被映射到坐标系中;
  3. 变换 - 将点从坐标系映射到坐标系;
  4. 插值器 - 用于从由图像定义的点的值,在坐标系中任意点处获取强度值的方法。
下面的代码片段是用于保留其坐标系统属性的图像降采样:
def downsamplePatient(patient_CT, resize_factor):

    original_CT = sitk.ReadImage(patient_CT,sitk.sitkInt32)
    dimension = original_CT.GetDimension()
    reference_physical_size = np.zeros(original_CT.GetDimension())
    reference_physical_size[:] = [(sz-1)*spc if sz*spc>mx  else mx for sz,spc,mx in zip(original_CT.GetSize(), original_CT.GetSpacing(), reference_physical_size)]
    
    reference_origin = original_CT.GetOrigin()
    reference_direction = original_CT.GetDirection()

    reference_size = [round(sz/resize_factor) for sz in original_CT.GetSize()] 
    reference_spacing = [ phys_sz/(sz-1) for sz,phys_sz in zip(reference_size, reference_physical_size) ]

    reference_image = sitk.Image(reference_size, original_CT.GetPixelIDValue())
    reference_image.SetOrigin(reference_origin)
    reference_image.SetSpacing(reference_spacing)
    reference_image.SetDirection(reference_direction)

    reference_center = np.array(reference_image.TransformContinuousIndexToPhysicalPoint(np.array(reference_image.GetSize())/2.0))
    
    transform = sitk.AffineTransform(dimension)
    transform.SetMatrix(original_CT.GetDirection())

    transform.SetTranslation(np.array(original_CT.GetOrigin()) - reference_origin)
  
    centering_transform = sitk.TranslationTransform(dimension)
    img_center = np.array(original_CT.TransformContinuousIndexToPhysicalPoint(np.array(original_CT.GetSize())/2.0))
    centering_transform.SetOffset(np.array(transform.GetInverse().TransformPoint(img_center) - reference_center))
    centered_transform = sitk.Transform(transform)
    centered_transform.AddTransform(centering_transform)

    # sitk.Show(sitk.Resample(original_CT, reference_image, centered_transform, sitk.sitkLinear, 0.0))
    
    return sitk.Resample(original_CT, reference_image, centered_transform, sitk.sitkLinear, 0.0)

使用上面的代码片段进行脑部CT扫描,我们得到以下结果: 原始CT扫描图像

下采样CT扫描图像


1
中心化变换应该是:centered_transform = sitk.CompositeTransform(transform),而不是centered_transform = sitk.Transform(transform)。 - Ningrong Ye

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接