本文為轉載文章,原文鏈接:https://blog.csdn.net/weixin_40640335/article/details/115798249
記:關於圖像重采樣(resample)最終發現的簡單實現方法
需求:已有配准好的CT以及PET圖像,而金標准label是在CT上勾畫的,因此有一些簡單的需求,一種是把PET圖像重采樣到與CT圖像一樣的大小(比如從192×192×371到512×512×484),或者把金標准Mask降到同PET的大小(即反過來)。
怎麼找的方法:ITK-SNAP(3.8版本)的讀圖功能是支持不同大小、spacing、origin、direction的圖像一起展示的,軟件會相當於resample後續加入的圖像; 因此,已知ITK存在解決的方法了,剩下就是找對應代碼。
import SimpleITK as sitk
def resize_image_itk(ori_img, target_img, resamplemethod=sitk.sitkNearestNeighbor):
""" 用itk方法將原始圖像resample到與目標圖像一致 :param ori_img: 原始需要對齊的itk圖像 :param target_img: 要對齊的目標itk圖像 :param resamplemethod: itk插值方法: sitk.sitkLinear-線性 sitk.sitkNearestNeighbor-最近鄰 :return:img_res_itk: 重采樣好的itk圖像 使用示范: import SimpleITK as sitk target_img = sitk.ReadImage(target_img_file) ori_img = sitk.ReadImage(ori_img_file) img_r = resize_image_itk(ori_img, target_img, resamplemethod=sitk.sitkLinear) """
target_Size = target_img.GetSize() # 目標圖像大小 [x,y,z]
target_Spacing = target_img.GetSpacing() # 目標的體素塊尺寸 [x,y,z]
target_origin = target_img.GetOrigin() # 目標的起點 [x,y,z]
target_direction = target_img.GetDirection() # 目標的方向 [冠,矢,橫]=[z,y,x]
# itk的方法進行resample
resampler = sitk.ResampleImageFilter()
resampler.SetReferenceImage(ori_img) # 需要重新采樣的目標圖像
# 設置目標圖像的信息
resampler.SetSize(target_Size) # 目標圖像大小
resampler.SetOutputOrigin(target_origin)
resampler.SetOutputDirection(target_direction)
resampler.SetOutputSpacing(target_Spacing)
# 根據需要重采樣圖像的情況設置不同的dype
if resamplemethod == sitk.sitkNearestNeighbor:
resampler.SetOutputPixelType(sitk.sitkUInt8) # 近鄰插值用於mask的,保存uint8
else:
resampler.SetOutputPixelType(sitk.sitkFloat32) # 線性插值用於PET/CT/MRI之類的,保存float32
resampler.SetTransform(sitk.Transform(3, sitk.sitkIdentity))
resampler.SetInterpolator(resamplemethod)
itk_img_resampled = resampler.Execute(ori_img) # 得到重新采樣後的圖像
return itk_img_resampled
一開始找到這樣一份代碼,是通過兩個圖像的spacing來計算重采樣之後的圖像的大小:
# 初始版本,from 網上,適用於只有spacing不同的兩個圖
def resize_image(itkimage, newSize, resamplemethod=sitk.sitkNearestNeighbor):
print('--resize ing--')
resampler = sitk.ResampleImageFilter()
originSize = itkimage.GetSize() # 原來的體素塊尺寸
originSpacing = itkimage.GetSpacing()
newSize = np.array(newSize, float)
factor = originSize / newSize
newSpacing = originSpacing * factor
newSize = newSize.astype(np.int) # spacing肯定不能是整數
resampler.SetReferenceImage(itkimage) # 需要重新采樣的目標圖像
resampler.SetSize(newSize.tolist())
resampler.SetOutputSpacing(newSpacing.tolist())
resampler.SetTransform(sitk.Transform(3, sitk.sitkIdentity))
resampler.SetInterpolator(resamplemethod)
itk_img_res = resampler.Execute(itkimage) # 得到重新采樣後的圖像
print('--resize finish--')
return itk_img_res
實際使用發現,如果通過計算得到的newsize來 resampler.SetSize(new_size) 的話,new_size不一定和目標圖像的size一致,原因是兩個圖像在origin、direction方面很有可能不一致(尤其對於醫學影像),因此使用這份代碼會導致後面還需要對resample後的圖像進行各種後處理操作,比如pad空矩陣或者cut圖像啥的,更會涉及復雜的空間坐標變換。
最後是查看sitk.ResampleImageFilter()的各個功能函數,突然想試試如果setsize的是目標圖像的大小的話,是不是應該跟軟件一樣直接給到正確的結果呢,結果發現,確實。。。
溫馨提示:
讀入ori和target的sitk圖像時,要確保spacing這些信息沒有丟失,如果前面有從sitk轉array處理過再轉回sitk的操作的話,記得用 sitk.CopyInformation( ) 把原本的信息復制過來再進行resample,否則會導致輸出圖像為空矩陣。