I have a series of 3D, MR volumes acquired from different scanners. I would like to resample all volumes to their median voxel size [0.39, 0.39, 0.55] mm. Moreover, for each volume, I also have a binary mask (same size or MR) that delineates a ROI.
By looking at similar topics, I came up with a solution that seems to work. However, when I load the newly created volume with itksnap, this is not centered and I can only see part of it.
Can someone please tell me what is wrong? Thanks a lot!
Here’s my code:
import numpy as np
import SimpleITK as sitk
def resample_volume(volume_path, mask=False):
volume = sitk.ReadImage(volume_path)
volume = sitk.Cast(volume, sitk.sitkFloat32) # cast to float32
resample_vol = sitk.ResampleImageFilter() # create resampler object
if mask: # if mask is True
resample_vol.SetInterpolator = sitk.sitkNearestNeighbor # set interpolator for mask (it does not create new masks)
else:
resample_vol.SetInterpolator = sitk.sitkLinear # set interpolator for volume
resample_vol.SetOutputDirection = volume.GetDirection() # set output volume direction equal to input volume direction
resample_vol.SetOutputOrigin = volume.GetOrigin() # set output volume origin equal to input volume origin
new_spacing = [0.39, 0.39, 0.55]
resample_vol.SetOutputSpacing(new_spacing)
orig_size = np.array(volume.GetSize(), dtype=np.int)
orig_spacing = volume.GetSpacing()
new_size = orig_size * (np.divide(orig_spacing, new_spacing))
new_size = np.ceil(new_size).astype(np.int) # volume dimensions are in integers
new_size = [int(s) for s in new_size] # convert from np.array to list
resample_vol.SetSize(new_size)
resampled_volume = resample_vol.Execute(volume)
return resampled_volume
path_to_MR_volume = "/home/newuser/.../mr.nii.gz"
path_to_mask = "/home/newuser/.../mask.nii.gz"
resampled_MR = resample_volume(path_to_MR_volume) # resample volume
resampled_mask = resample_volume(path_to_mask, mask=True) # resample mask
Didn’t look too deeply into the code as it is rather long for the task. Please find below a shorter version that will resample volumes. As the only difference between resampling a mask and a scalar volume is in the interpolator that is a required parameter and not a boolean flag. Also, not sure why the volumes are converted to sitkFloat32 after reading, but I assume you have your reasons, so combined it with the reading:
To expand upon @dzenanz’s answer, the philosophy of ITK/SimpleITK is that we work in the physical world. That is, there is a physical point associated with the indexes into the image and you move between indexes and physical points using methods from the Image class. The relevant methods are TransformContinuousIndexToPhysicalPoint, TransformIndexToPhysicalPoint, TransformPhysicalPointToContinuousIndex, and TransformPhysicalPointToIndex.