Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Load DICOM data into a NumPy array with PyDICOM #python #dicom #medical #imagedata #pydicom #fileIO

We start with the imports:

import dicom
import os
import numpy

The pydicom package can be installed through pip and can be found in https://pypi.python.org/pypi/pydicom/

Populate a lstFilesDCM with the filenames of the DICOM files under a given PathDicom directory:

PathDicom = "./dir_with_dicom_series/"
lstFilesDCM = []  # create an empty list
for dirName, subdirList, fileList in os.walk(PathDicom):
    for filename in fileList:
        if ".dcm" in filename.lower():  # check whether the file's DICOM
            lstFilesDCM.append(os.path.join(dirName,filename))

Use the first of the DICOM files to read in some of the metadata, specifically the image dimensions, the pixel-spacing, and the slice-thickness:

# Get ref file
RefDs = dicom.read_file(lstFilesDCM[0])

# Load dimensions based on the number of rows, columns, and slices (along the Z axis)
ConstPixelDims = (int(RefDs.Rows), int(RefDs.Columns), len(lstFilesDCM))

# Load spacing values (in mm)
ConstPixelSpacing = (float(RefDs.PixelSpacing[0]), float(RefDs.PixelSpacing[1]), float(RefDs.SliceThickness))

Load all the pixel data into an appropriate sized NumPy array named ArrayDicom:

# The array is sized based on 'ConstPixelDims'
ArrayDicom = numpy.zeros(ConstPixelDims, dtype=RefDs.pixel_array.dtype)

# loop through all the DICOM files
for filenameDCM in lstFilesDCM:
    # read the file
    ds = dicom.read_file(filenameDCM)
    # store the raw image data
    ArrayDicom[:, :, lstFilesDCM.index(filenameDCM)] = ds.pixel_array

The entire code can be seen in the accompanying .py file

import dicom
import os
import numpy
PathDicom = "./dir_with_dicom_series/"
lstFilesDCM = [] # create an empty list
for dirName, subdirList, fileList in os.walk(PathDicom):
for filename in fileList:
if ".dcm" in filename.lower(): # check whether the file's DICOM
lstFilesDCM.append(os.path.join(dirName,filename))
# Get ref file
RefDs = dicom.read_file(lstFilesDCM[0])
# Load dimensions based on the number of rows, columns, and slices (along the Z axis)
ConstPixelDims = (int(RefDs.Rows), int(RefDs.Columns), len(lstFilesDCM))
# Load spacing values (in mm)
ConstPixelSpacing = (float(RefDs.PixelSpacing[0]), float(RefDs.PixelSpacing[1]), float(RefDs.SliceThickness))
# The array is sized based on 'ConstPixelDims'
ArrayDicom = numpy.zeros(ConstPixelDims, dtype=RefDs.pixel_array.dtype)
# loop through all the DICOM files
for filenameDCM in lstFilesDCM:
# read the file
ds = dicom.read_file(filenameDCM)
# store the raw image data
ArrayDicom[:, :, lstFilesDCM.index(filenameDCM)] = ds.pixel_array
@Rana-Mahmoud
Copy link

Rana-Mahmoud commented Jan 23, 2017

I tried this code on Dataset I have but it gives me the attached error about SliceThickness !

slicethikness

@yzexeter
Copy link

yzexeter commented Feb 9, 2017

I also encountered the same problem. My DICOM files have no "SliceThickness". Has anyone tackled the problem?

@larsfjaera
Copy link

larsfjaera commented Mar 17, 2017

The script is apparently made to work if you have a directory containing only CT images. If you have different kinds of DICOM files in the directory, you could either make sure that you remove all files not CT or you could add the following lines to your code (starting from line 13):

if ".dcm" in filename.lower():
    ds = dicom.read_file(filename)
    if ds.SOPClassUID == '1.2.840.10008.5.1.4.1.1.2':  # CT images
        lstFilesDCM.append(os.path.join(dirName,filename))

Then only the CT images will be added to your list.

EDIT: It may not be ONLY CT. Could also be for example MRI images. Then you should use:
if ds.SOPClassUID == '1.2.840.10008.5.1.4.1.1.4': # MRI images

More info on SOPClaissUID here

@canbax
Copy link

canbax commented May 21, 2017

Why every slice has a property called SliceThickness? For a 3D image, every slice should have the same thickness to be consistent. Also I heard that slice thickness is based on the machine settings or machine type which takes the CT scan.

@rachanapotpelwar
Copy link

rachanapotpelwar commented Sep 7, 2017

RefDs = dicom.read_file(lstFilesDCM[0])
at this point i m getting error
IndexError: list index out of range

In

@naimavahab
Copy link

naimavahab commented Nov 13, 2017

Can anyone tell what is this error is .. AttributeError: Dataset does not have attribute 'PixelSpacing'.

@Acedorkz
Copy link

Acedorkz commented Nov 25, 2017

Have the same problem "Dataset does not have attribute 'PixelSpacing'"...

@IsraelBorges
Copy link

IsraelBorges commented Mar 4, 2018

I have the same problems to load dicom images in python. Can anyone help me?

@ZhangYuef
Copy link

ZhangYuef commented Apr 9, 2018

I bumped into the same problem as @naimavahab mentioned.

@radhika98ravi
Copy link

radhika98ravi commented May 23, 2018

i used the same code but it gives " Dataset has no attribute Pixel Spacing"

@suriya18
Copy link

suriya18 commented Jan 28, 2020

How to overcome this error ?
6 ds = pydicom.read_file(filenameDCM)
7 # store the raw image data
----> 8 ArrayDicom[:, :, lstFilesDCM.index(filenameDCM)] = ds.pixel_array

ValueError: could not broadcast input array from shape (552,474) into shape (512,512)

@somada141
Copy link
Author

somada141 commented Jan 29, 2020

@suriya18 this means that ArrayDicom has the wrong dimensions. You've clearly made it at 512x512x but your DICOM's dimensions are 552x474x

@Naeemmariam7
Copy link

Naeemmariam7 commented Jun 8, 2020

This code returns a 2D array, How can I get 3D array?

@somada141
Copy link
Author

somada141 commented Jun 9, 2020

The code should return a 3D array by stacking the 2D dicom slices as you can see in the final loop. If you're only getting a 2D array that must mean that your path-walk only returned a single file. Have you checked that your filenames are retrieved correctly?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment