How to resize DICOM properly?

Hello, I’m new to simpleITK and have a question about resizing the image. In my understanding, spacing is the distance between the pixels. So I thought if I reduce the spacing by half, I can get a new half-size image without pixel data loss. However, when I run the code below, I needed to increase spacing twice to get a half-size image. Also, the new file size was much smaller than the original, so I was worried about the data loss. Am I doing something wrong here?

dicom_names = reader.GetGDCMSeriesFileNames(data_directory)
reader.SetFileNames(dicom_names)
image = reader.Execute()
size = image.GetSize()
spacing = image.GetSpacing()
print("Original image size:", size)
print("Original image spacing:", spacing)

new_spacing = np.array(spacing) * 2
new_size = (np.round(size * (np.array(spacing)/new_spacing))).astype(int).tolist()

resampled_image = sitk.Resample(image, new_size, sitk.Transform(), sitk.sitkNearestNeighbor, image.GetOrigin(), new_spacing, image.GetDirection(), 0.0, image.GetPixelID())
resampled_image_size = resampled_image.GetSize()
resampled_image_spacing = resampled_image.GetSpacing()
print("Resampled image size:", resampled_image_size)
print("Resampled image spacing:", resampled_image_spacing)

This causes loss. What you probably want is something like

# read image
spacing=image.GetSpacing()
new_spacing = np.array(spacing) * 0.5
image.SetSpacing(new_spacing)
# image is now twice smaller in physical space, with no loss of quality
1 Like

Hello @TWK,

My understanding from looking at your code is that you want the number of pixels/voxels to be half that of the original image, but that they still cover the same physical extent? Something that you would do if you were creating an image pyramid. This is the shortest code to get what you want:

resampled_image = image[::2,::2,::2]

This is not the best approach to resizing an image as it will introduce aliasing. For a better approach take a look at the smooth_and_resample function in this Jupyter notebook.

Or a compromise between the two (no smoothing at all, Gaussian smoothing) is the BinShrink filter.

1 Like

Thank you for your reply. I thought .GetSize() returns the size in physical space, but it was the number of pixels and I am happy it remains same :slight_smile:
Thank you for your help!

Sorry but I have another issue. Now I changed a spacing and store modified dicom series by the code below. However, when I call new dicom series with show, it says it cannot get filename info.
Do I need to pass special tag from previous series?

data_directory = "./dicomInput"
reader = sitk.ImageSeriesReader()
dicom_names = reader.GetGDCMSeriesFileNames(data_directory)
reader.SetFileNames(dicom_names)
image = reader.Execute()
size = image.GetSize()
spacing = image.GetSpacing()
print("Original image size(n_pixel):", size)
print("Original image spacing:", spacing)

image.SetSpacing(np.array(spacing) * 0.5)

resampled_size = image.GetSize()
resampled_spacing = image.GetSpacing()
print("Resampled image size(n_pixel):", resampled_size)
print("Resampled image spacing:", resampled_spacing)

writer = sitk.ImageFileWriter()
writer.KeepOriginalImageUIDOn()
#Bring input image_file_names and sort
inputImageList = os.listdir('./dicomInput')
inputImageList.sort()
#Write to the output_directory
for i in range(image.GetDepth()):
    resampled_image_slice = image[:,:,i]
    writer.SetFileName(os.path.join('./dicomOutput', inputImageList[i]))
    writer.Execute(resampled_image_slice

data_directory = "./dicomOuput"
newreader = sitk.ImageSeriesReader()
dicom_names = newreader.GetGDCMSeriesFileNames(data_directory)
newreader.SetFileNames(dicom_names)
image = newreader.Execute()
sitk.WriteImage( image, "3DVolume.img" )
if ( not "SITK_NOSHOW" in os.environ ):
    sitk.Show( image, "Dicom Series" )  -> Cause error: sitk::ERROR: File names information is empty. Cannot read series.

Hello @TWK,

Unfortunately, this isn’t as straightforward as in your code. This example shows how to read-modify-write a DICOM series.

Hello, @zivy. Would you please suggest any concepts or documentation that I need to look at? I already looked at documentation you mentioned but don’t know how to achieve my goal.
What I want to do is read a series of dicom images, modify spacing by half without pixel loss, and then store in the output folder as a dicom series. Do you think I need to modify spacing tap in dicom images to achieve this?

Hello @TWK,

If I understand your goal correctly, the only line you need to modify in the example is:

filtered_image = sitk.DiscreteGaussian(image3D)

to:

filtered_image = image3D[::2,::2,::2]

If this isn’t what you want, please provide additional details.