admin管理员组

文章数量:1516870

关于spacing和重采样、降采样的理解

假设
读入的3D数据size大小为(75, 512,512)spacing为(0.703125, 0.703125, 5.0)(x,y,z)
我们需要把z轴的spacing调整为1mm
所以需要先计算真实3D数据的大小:(75*5, 512*0.703125, 512*0.706125) = (375, 360, 360)mm
x,y,z轴的spacing调整为1mm,也就是目前3D数据size = (375 / 1, 360 / 1, 360 / 1) =(375, 360, 360)换句话说,spacing为(0.703125, 0.703125, 5.0) 读入的3D数据size为(75, 512,512)
当spacing为(1, 1, 1),读取的3D数据的size为(375, 360, 360)而真实3D数据的大小是不变的,为(375, 360, 360)mm如果我们对读入的3D数据进行了降采样,例如降采样后的size是(375, 256, 256)
那么spacing应该是(375 / 375, 360 / 256, 360 / 256) 为 (1.40625, 1.40625, 1)上面说的是计算层面上的,对于代码层面,我们没有搞这么繁琐:我们对3D数据重采样和降采样,只需要一句话完成假设输入ct图像的size(非真实size)为(75, 512, 512),spacing为(0.703125, 0.703125, 5.0)
你希望把z轴spacing调整为1mm, 把图像下采样到256*256
你需要,
1.获得ct的spacing,÷你想要的spacing,ct.GetSpaing()[-1] / 1
2.获得下采样率,down_scale = 512 / 256
执行
ct_array = ndimage.zoom(ct_array, (ct.GetSpaing()[-1] / 1, down_scale, down_scale))
运行上述这句话
size会变成(75 * 5 / 1, 256, 256) = (375, 256, 256)
此时的size是你想要的,并且z轴的spacing已经变成1mm了,spacing为(375/375, 360/256,360/256) = (1.40625, 1.40625, 1)接下来你会对图像进行其他预处理操作,例如切片,等等
new_ct_array = 切片(ct_array)
new_ct = sitk.GetArrayFromImage(new_ct_array)
执行sitk.GetArrayFromImage,你的spacing会默认变成(1,1,1)(目前也不懂为什么)所以new_ct的sapcing要再设置成(1.40625, 1.40625, 1)
new_ct.SetSpacing((1.40625, 1.40625, 1))

这样才算完成了预处理操作

下面附上lits挑战赛预处理代码,帮助理解

"""
获取可用于训练网络的训练数据集
需要四十分钟左右,产生的训练数据大小3G左右
"""import os
import sys
sys.path.append(os.path.split(sys.path[0])[0])
import shutil
from time import time
import numpy as np
from tqdm import tqdm
import SimpleITK as sitk
import scipy.ndimage as ndimageimport lits_para as paraif os.path.exists(para.training_set_path):shutil.rmtree(para.training_set_path)new_ct_path = os.path.join(para.training_set_path, 'imgae')
new_seg_dir = os.path.join(para.training_set_path, 'label')# os.mkdir(para.training_set_path)
# os.mkdir(new_ct_path)
# os.mkdir(new_seg_dir)start = time()
os.listdir()
patients = os.listdir(para.train_ct_path)
patients.sort(key=lambda x:int(x.split('.')[0].split('-')[-1]))
for i in tqdm(range(len(patients))):# 将CT和金标准入读内存ct = sitk.ReadImage(os.path.join(para.train_ct_path, patients[i]), sitk.sitkInt16)ct_array = sitk.GetArrayFromImage(ct)seg = sitk.ReadImage(os.path.join(para.train_seg_path, patients[i].replace('volume', 'segmentation')), sitk.sitkUInt8)seg_array = sitk.GetArrayFromImage(seg)# 将金标准中肝脏和肝肿瘤的标签融合为一个seg_array[seg_array > 0] = 1# 将灰度值在阈值之外的截断掉# print(ct_array.max())# print(ct_array.min())# ct_array[ct_array > para.upper] = para.upper# ct_array[ct_array < para.lower] = para.lower# 对CT数据在横断面上进行降采样,并进行重采样,将所有数据的z轴的spacing调整到1mmprint(ct.GetSpacing())# ct(0.703125, 0.703125, 5.0)print(ct.GetSpacing()[-1] / para.slice_thickness, para.down_scale, para.down_scale)# 5.0 0.5 0.5ct_array = ndimage.zoom(ct_array, (ct.GetSpacing()[-1] / para.slice_thickness, para.down_scale, para.down_scale), order=3)seg_array = ndimage.zoom(seg_array, (ct.GetSpacing()[-1] / para.slice_thickness, para.down_scale, para.down_scale), order=0)# ct_array size从(75,512,512)->(375,256,256)# 其他操作# 找到肝脏区域开始和结束的slice,并各向外扩张slicez = np.any(seg_array, axis=(1, 2))start_slice, end_slice = np.where(z)[0][[0, -1]]# 两个方向上各扩张slicestart_slice = max(0, start_slice - para.expand_slice)end_slice = min(seg_array.shape[0] - 1, end_slice + para.expand_slice)# 如果这时候剩下的slice数量不足size,直接放弃该数据,这样的数据很少,所以不用担心if end_slice - start_slice + 1 < para.size:print('!!!!!!!!!!!!!!!!')print(patients[i], 'have too little slice', ct_array.shape[0])print('!!!!!!!!!!!!!!!!')continuect_array = ct_array[start_slice:end_slice + 1, :, :]seg_array = seg_array[start_slice:end_slice + 1, :, :]# 最终将数据保存为nii.gznew_ct = sitk.GetImageFromArray(ct_array)new_ct.SetDirection(ct.GetDirection())new_ct.SetOrigin(ct.GetOrigin())print((ct.GetSpacing()[0] * int(1 / para.down_scale), ct.GetSpacing()[1] * int(1 / para.down_scale), para.slice_thickness))# (1.40625, 1.40625, 1)# 最后调整好spacingnew_ct.SetSpacing((ct.GetSpacing()[0] * int(1 / para.down_scale), ct.GetSpacing()[1] * int(1 / para.down_scale), para.slice_thickness))new_seg = sitk.GetImageFromArray(seg_array)new_seg.SetDirection(ct.GetDirection())new_seg.SetOrigin(ct.GetOrigin())new_seg.SetSpacing((ct.GetSpacing()[0], ct.GetSpacing()[1], para.slice_thickness))sitk.WriteImage(new_ct, os.path.join(new_ct_path, 'volume-' + str(i) + '.nii.gz'))sitk.WriteImage(new_seg, os.path.join(new_seg_dir, 'segmentation-' + str(i) + '.nii.gz'))

本文标签: 关于spacing和重采样降采样的理解