Skip to content

Instantly share code, notes, and snippets.

@sarthakpati
Last active January 12, 2024 14:09
Show Gist options
  • Save sarthakpati/68226fee5eaf6affb5647d2e83f499a0 to your computer and use it in GitHub Desktop.
Save sarthakpati/68226fee5eaf6affb5647d2e83f499a0 to your computer and use it in GitHub Desktop.
Downsample DICOM images and write out as DICOM or fall back to NIfTI
import os, time, traceback, pathlib
import SimpleITK as sitk
def downsample_dicom(
dicom_path: str, output_path: str, downsample_factor: int = 0.5
) -> None:
"""
Downsample DICOM images and save them to the output path.
Args:
dicom_path (str): The path to the DICOM images.
output_path (str): The path to save the downsampled DICOM images.
downsample_factor (int, optional): The downsample factor. Defaults to 0.5.
"""
if not output_path.endswith(".nii.gz"):
pathlib.Path(output_path).mkdir(parents=True, exist_ok=True)
dicom_detected = False
if os.path.isdir(dicom_path):
# Read DICOM images
reader = sitk.ImageSeriesReader()
dicom_names = reader.GetGDCMSeriesFileNames(dicom_path)
reader.SetFileNames(dicom_names)
reader.MetaDataDictionaryArrayUpdateOn()
image = reader.Execute()
dicom_detected = True
else:
# Read image using generic SimpleITK reader
image = sitk.ReadImage(dicom_path)
# Downsample DICOM images
downsampled_image = sitk.Resample(
image,
[
int(image.GetWidth() * downsample_factor),
int(image.GetHeight() * downsample_factor),
int(image.GetDepth() * downsample_factor),
],
sitk.Transform(),
sitk.sitkLinear,
image.GetOrigin(),
image.GetSpacing(),
image.GetDirection(),
0,
image.GetPixelID(),
)
if dicom_detected:
# Save downsampled DICOM images
writer = sitk.ImageFileWriter()
tags_to_copy = [
# "0010|0010", # Patient Name
"0010|0020", # Patient ID
"0010|0030", # Patient Birth Date
"0020|000D", # Study Instance UID, for machine consumption
"0020|0010", # Study ID, for human consumption
"0008|0020", # Study Date
"0008|0030", # Study Time
"0008|0050", # Accession Number
"0008|0060", # Modality
]
# Use the study/series/frame of reference information given in the meta-data
# dictionary and not the automatically generated information from the file IO
writer.KeepOriginalImageUIDOn()
modification_time = time.strftime("%H%M%S")
modification_date = time.strftime("%Y%m%d")
direction = downsampled_image.GetDirection()
series_tag_values = [
(k, reader.GetMetaData(0, k.lower()))
for k in tags_to_copy
if reader.HasMetaDataKey(0, k.lower())
] + [
("0008|0031", modification_time), # Series Time
("0008|0021", modification_date), # Series Date
("0008|0008", "DERIVED\\SECONDARY"), # Image Type
(
"0020|000e",
"1.2.826.0.1.3680043.2.1125."
+ modification_date
+ ".1"
+ modification_time,
),
# Series Instance UID
(
"0020|0037",
"\\".join(
map(
str,
(
direction[0],
direction[3],
direction[6],
direction[1],
direction[4],
direction[7],
), # Image Orientation (Patient)
)
),
),
(
"0008|103e",
reader.GetMetaData(0, "0008|103e")
if reader.HasMetaDataKey(0, "0008|103e")
else "" + " Processed-SimpleITK",
), # Series Description is an optional tag, so may not exist
]
try:
for i in range(downsampled_image.GetDepth()):
image_slice = downsampled_image[:, :, i]
# Tags shared by the series.
for tag, value in series_tag_values:
image_slice.SetMetaData(tag, value)
# Slice specific tags.
# Instance Creation Date
image_slice.SetMetaData("0008|0012", time.strftime("%Y%m%d"))
# Instance Creation Time
image_slice.SetMetaData("0008|0013", time.strftime("%H%M%S"))
# Image Position (Patient)
image_slice.SetMetaData(
"0020|0032",
"\\".join(
map(str, downsampled_image.TransformIndexToPhysicalPoint((0, 0, i)))
),
)
# Instance Number
image_slice.SetMetaData("0020|0013", str(i))
# Write to the output directory and add the extension dcm, to force writing
# in DICOM format.
writer.SetFileName(os.path.join(output_path, str(i) + ".dcm"))
writer.Execute(image_slice)
except Exception:
print("ERROR: Could not write DICOM image, falling back to NIfTI")
print("Traceback:", traceback.format_exc())
sitk.WriteImage(
downsampled_image,
os.path.join(output_path, f"downsampled_{downsample_factor}.nii.gz"),
)
else:
# Save downsampled image
if not output_path.endswith(".nii.gz"):
output_path = os.path.join(output_path, f"downsampled_{downsample_factor}.nii.gz")
sitk.WriteImage(
downsampled_image,
os.path.join(output_path),
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment