Source code for resomapper.format_conversion.DICOM_conversion

import os
# import nibabel as nib
# import numpy as np
import SimpleITK as sitk
from pydicom import dcmread

import warnings

warnings.filterwarnings("ignore")

#### DICOM CONVERSION FUNCTIONS ####


# def convert_dicom_series(dicom_series_path, output_nifti_path):
#     # Read the DICOM series
#     reader = sitk.ImageSeriesReader()
#     dicom_series = reader.GetGDCMSeriesFileNames(dicom_series_path)
#     reader.SetFileNames(dicom_series)
#     image = reader.Execute()

#     # Convert the image to NIfTI format and save
#     sitk.WriteImage(image, output_nifti_path)


[docs] def convert_dicom_series(dicom_series_path, output_nifti_path): # Read the series of DICOM files reader = sitk.ImageSeriesReader() dicom_series = reader.GetGDCMSeriesFileNames(dicom_series_path) reader.SetFileNames(dicom_series) # Read DICOM metadata to identify temporal positions (0020,0105) temporal_positions = set() # Store unique temporal positions dicom_files = [] # Extract temporal position for each DICOM file for dicom_file in dicom_series: ds = dcmread(dicom_file) # Get the temporal position from tag (0020,0105), default to 1 if not available temporal_position = getattr(ds, 'TemporalPositionIdentifier', 1) temporal_positions.add(temporal_position) dicom_files.append((temporal_position, dicom_file)) # Sort dicom_files by temporal position dicom_files.sort(key=lambda x: x[0]) # Group the files by temporal positions if more than 1 position dicom_files_grouped = {} for position, dicom_file in dicom_files: if position not in dicom_files_grouped: dicom_files_grouped[position] = [] dicom_files_grouped[position].append(dicom_file) # Process each temporal position group images = [] for position, files in dicom_files_grouped.items(): # Set filenames for the current temporal position group reader.SetFileNames(files) # Read image for this temporal position image = reader.Execute() images.append(image) # If there are multiple temporal positions, join them into a 4D image if len(images) > 1: image_4d = sitk.JoinSeries(images) else: image_4d = images[0] # Only one position, use the single image (3D) # Save the image as NIfTI sitk.WriteImage(image_4d, output_nifti_path)
[docs] def convert_dicom_localizer(dicom_series_path, output_nifti_path): dicom_files = [os.path.join(dicom_series_path, f) for f in os.listdir(dicom_series_path)] # Read DICOM files individually images = [] for dicom_file in dicom_files: ds = dcmread(dicom_file) pixel_array = ds.pixel_array image = sitk.GetImageFromArray(pixel_array) # Get spacing from DICOM header if 'PixelSpacing' in ds: spacing_xy = ds.PixelSpacing # X and Y spacing else: spacing_xy = [1.0, 1.0] # Default values if 'SliceThickness' in ds: spacing_z = ds.SliceThickness # Z spacing else: spacing_z = 1.0 # Default value # If zspacing is 0, adjust to a small value if spacing_z == 0: spacing_z = 1.0 # Adjust if neccesary new_spacing = [float(spacing_xy[0]), float(spacing_xy[1]), float(spacing_z)] image.SetSpacing(new_spacing) images.append(image) # Combine images into 3D stack combined_image = sitk.JoinSeries(images) sitk.WriteImage(combined_image, output_nifti_path)
[docs] def get_echo_times_from_dicom(dicom_series_path, output_echo_times_path=None): echo_times = [] for file in os.listdir(dicom_series_path): ds = dcmread(os.path.join(dicom_series_path, file)) echo_times.append(int(ds.EchoTime)) # TODO: or float?? unique_echos_list = [ item for index, item in enumerate(echo_times) if item not in echo_times[:index] ] if output_echo_times_path is not None: with open(output_echo_times_path, "w") as f: f.write(" ".join(map(str, unique_echos_list))) else: return unique_echos_list
[docs] def get_rep_times_from_dicom(dicom_series_path, output_rep_times_path=None): repetition_times = [] for file in os.listdir(dicom_series_path): ds = dcmread(os.path.join(dicom_series_path, file)) repetition_times.append(int(ds.RepetitionTime)) # TODO: or float?? unique_reps_list = [ item for index, item in enumerate(repetition_times) if item not in repetition_times[:index] ] if output_rep_times_path is not None: with open(output_rep_times_path, "w") as f: f.write(" ".join(map(str, unique_reps_list))) else: return unique_reps_list
# def reshape_nifti_from_times_file(nifti_path, times_files_path, output_path): # img = nib.load(nifti_path) # data = img.get_fdata() # # TODO: use array instead of file # with open(os.path.join(times_files_path), "r") as f: # times_str = f.read().split() # times = [int(time) for time in times_str] # num_times = len(times) # pixel_res_1 = int(img.shape[0]) # pixel_res_2 = int(img.shape[1]) # num_slices = int(img.shape[2] / num_times) # desired_shape = (pixel_res_1, pixel_res_2, num_times, num_slices) # # Assuming slices are along the first dimension # reshaped_data = data.reshape(desired_shape) # reshaped_data = np.swapaxes(reshaped_data, 2, 3) # # Save the reshaped data as a new NIfTI file # reshaped_img = nib.Nifti1Image(reshaped_data, img.affine) # nib.save(reshaped_img, output_path)