How to Convert a Nifti File into Dicom Series Using Python

Facebook
Twitter
LinkedIn
Nifti to Dicom
Photo by National Cancer Institute on Unsplash

Abstract

During my internship for my master’s degree in computer vision, I worked on a project that used U-Net to segment tumors throughout the body.

It was a difficult project; I had a lot of tasks to complete, including data preparation. So, in terms of data preparation, I experimented with a variety of approaches in order to improve my results. Anyway, this isn’t our topic. One of the things I was doing to prepare my data was making small nifti files with 128 slices for each file. My dataset, on the other hand, was a collection of patients with a random number of slices. As a result, I needed to convert these patients into dicom files before creating the small nifti files with the desired number of slices.

We all know that there is no such library or function to convert nifti files into dicoms, so I struggled by manually converting the files one by one with the software 3D slicer. It took me an eternity to finish this conversion.

I wasn’t thinking about writing my own function to do the conversion for me at the time; perhaps I was too lazy to think about it. But now I’ve decided to make it so that anyone who requires this type of conversion can use it.

Even the concept of creating a function that converts nifti files into dicom series was simple; all that was required was to return the frame data from the nifti files, divide it into slices, and then convert each slice into one dicom.

The inspiration for this conversion came from a function I wrote to convert JPG or PNG images to dicoms.

So, in this blog, I will demonstrate how simple it is to create such a function and make your life easier.

The steps

  • Using pre-existing dicom file.
  • The packages that we need.
  • Extract the frame data from the nifti file.
  • Prepare the array to be converted.
  • Convert one nifti file into dicom series.
  • Convert multiple nifti files into multiple dicom series.

Using a Pre-existing dicom File

You may be wondering why we need a dicom file if we are attempting to convert to a dicom. The answer can be found on the blog where we converted from JPG to dicom. Because when we want to create a dicom file, we can’t just put the pixel data in, because a dicom file contains more information than just the values of the pixels.
And we are unable to provide this information without the assistance of another dicom file. As a result, we must use an existing dicom file and modify its information to match what we have (need).

If you don’t have a dicom file, don’t worry; I’ll provide a Github link where you can clone the project with a pre-existing dicom file.


The Packages that We Need

As with any other program, we need some packages to complete this conversion, so in this project, you will need to install the following packages individually.

  • nibabel: pip install nibabel
  • pydicom: pip install pydicom
  • numpy: pip install numpy
  • tqdm: pip install tqdm(this one is just to print the progress of the conversion)

Extract the Frame Data From the nifti File

First, we must extract the frame data (pixel array) from the nifti file in order to convert it. This array is a matrix with a slice in each row. As a result, we convert each slice (row) into dicom.

To do this, you can use the nibabel lib to load the nifti file then there is a function called get_fdata for frame data, this function will extract the pixel array (it will be a numpy array).

import nibabel

nifti_file = nibabel.load(nifti_dir)
nifti_array = nifti_file.get_fdata()

Prepare the Array to be Converted

After we have extracted the frame data, we must prepare it so that it can be converted into dicoms. Don’t be concerned about the preparation. We must first convert the pixel values into unsigned integers of 16 bits before taking a pre-existing dicom file and filling in some parameters to mutch ours (width, height,…).
Here is the function I created (it is the same used for the jpg and png).

def convertNsave(arr,file_dir, index=0):
    """
    `arr`: parameter will take a numpy array that represents only one slice.
    `file_dir`: parameter will take the path to save the slices
    `index`: parameter will represent the index of the slice, so this parameter will be used to put 
    the name of each slice while using a for loop to convert all the slices
    """
    
    dicom_file = pydicom.dcmread('images/dcmimage.dcm')
    arr = arr.astype('uint16')
    dicom_file.Rows = arr.shape[0]
    dicom_file.Columns = arr.shape[1]
    dicom_file.PhotometricInterpretation = "MONOCHROME2"
    dicom_file.SamplesPerPixel = 1
    dicom_file.BitsStored = 16
    dicom_file.BitsAllocated = 16
    dicom_file.HighBit = 15
    dicom_file.PixelRepresentation = 1
    dicom_file.PixelData = arr.tobytes()

And that’s it, after setting these parameters, we can save the array using the save function from pydicom library.

dicom_file.save_as(os.path.join(file_dir, f'slice{index}.dcm'))

Note: This function will only convert one slice, so to convert a single nifti file, we must pass this function by all of the slices (in the next step).


Convert One nifti File into dicom Series

As I mentioned in the previous paragraph, the function convertNsave will convert one slice only.

For that, I created the function nifti2dicom_1fileso that you can use it to convert one nifti file directly, and in the next step I will show you how you can do the conversion for multiple nifti files.

Here is the function nifti2dicom_1fileto convert one file:

def nifti2dicom_1file(nifti_dir, out_dir):
    """
    This function is to convert only one nifti file into dicom series
    `nifti_dir`: the path to the one nifti file
    `out_dir`: the path to output
    """

    nifti_file = nibabel.load(nifti_dir)
    nifti_array = nifti_file.get_fdata()
    number_slices = nifti_array.shape[2]

    for slice_ in tqdm(range(number_slices)):
        convertNsave(nifti_array[:,:,slice_], out_dir, slice_)

As you can see, the function convertNsaveis at the heart of this function. I only added a loop to this function to pass through all of the slices (I know it is easy, but I wanted to make it ready so that you can use it directly)


Convert Multiple nifti Files into Multiple dicom Series

Now to convert multiple nifti files, we will use only the function nifti2dicom_1file but we call it multiple times using a loop. Here is the script to do that:

def nifti2dicom_mfiles(nifti_dir, out_dir=''):
    """
    This function is to convert multiple nifti files into dicom files
    `nifti_dir`: You enter the global path to all of the nifti files here.
    `out_dir`: Put the path to where you want to save all the dicoms here.
    PS: Each nifti file's folders will be created automatically, so you do not need to create an empty folder for each patient.
    """

    files = os.listdir(nifti_dir)
    for file in files:
        in_path = os.path.join(nifti_dir, file)
        out_path = os.path.join(out_dir, file)
        os.mkdir(out_path)
        nifti2dicom_1file(in_path, out_path)

That’s all the code you’ll need to complete the conversion; of course, I’ll provide the GitHub link so you can simply clone the repository and use the functions.

Get the GitHub repository here.

More to explorer

Making Sense of AI in Medical Images

Explore how AI revolutionizes medical imaging, enhancing diagnosis and treatment. Dive into real-world AI applications for better healthcare outcomes.

DICOM Viewer in Python

Discover how to create a DICOM viewer with Python and VTK. Simplify medical imaging with our straightforward guide on visualizing DICOM files.