Welcome to dicomtools’ documentation!

The dicomtools package is designed to simplify many common DICOM processing steps, and is based on the pydicom package. It’s designed primarily for research use. This code is still very basic and the structure will likely change. It tries to somewhat follow the DICOM standard, or to at least avoid vendor-specific attributes.

Contents:

Examples

These examples demonstrate some of the basic use-cases of dicomtools.

Reading DICOM Data

You can either read a single DICOM file, multiple DICOM files from the same series, or a DICOMDIR file. A dicomtools.series.DicomSeries object will be returned, except in the case of dicomtools.dicom_read.read_dicomdir(), which will return a list of dicomtools.series.DicomSeries objects.

Reading a DICOMDIR file:

>>> import dicomtools
>>> dicomtools.dicom_read.read_dicomdir('data/DICOMDIR')
[<dicomtools.series.DicomSeries object at 0x00000000054A9EB8>,
 <dicomtools.series.DicomSeries object at 0x0000000007EF3710>,
 <dicomtools.series.DicomSeries object at 0x0000000007EF3DD8>]

Reading series of DICOM files:

>>> import dicomtools
>>> dicomtools.read_dicom_series(['data/im_001.dcm', 'data/im_002.dcm', 'data/im_003.dcm'])
<dicomtools.series.DicomSeries object at 0x0000000008EF85C0>

Reading a single DICOM file:

>>> import dicomtools
>>> dicomtools.read_dicom('data/im_dat.dcm')
<dicomtools.series.DicomSeries object at 0x0000000006718128>

Building a 3D Volume Dataset

If a dicomtools.series.DicomSeries object represents 3D data as a multi-frame dataset or multiple DICOM files within a series, you can easily process this using the dicomtools.volume.DicomVolume.

View a single slice of the 3D multi-frame dataset:

>>> import dicomtools
>>> series = dicomtools.read_dicom('data/im_dat.dcm')
>>> volume = dicomtools.volume.DicomVolume(series)
>>> dicomtools.visualization.plot_slice(volume, 2, 40)
_images/plot_screenshot.png

Moving Between Image/Pixel and DICOM Patient Coordinates

The dicomtools.coordinates module contains useful functions for transforming points between coordinate systems, but with a dicomtools.volume.DicomVolume object, it’s much simpler.

Transform pixel (5,5) to the position in patient coordinates:

>>> volume = dicomtools.volume.DicomVolume(series)
>>> img2pat = volume.build_image_to_patient_matrix()
>>> img2pat
array([[   0.   ,    0.   ,   -1.2  ,   59.4  ],
       [   1.136,    0.   ,    0.   , -180.   ],
       [   0.   ,   -1.136,    0.   ,  180.   ],
       [   0.   ,    0.   ,    0.   ,    1.   ]])
>>> pixel_position = [5, 5]
>>> dicomtools.coordinates.transform_vectors(img2pat, pixel_position)
array([  59.4  , -174.318,  174.318])

Transform pixel (4,5,6) to the position in patient coordinates:

>>> volume = dicomtools.volume.DicomVolume(series)
>>> img2pat = volume.build_image_to_patient_matrix()
>>> img2pat
array([[   0.   ,    0.   ,   -1.2  ,   59.4  ],
       [   1.136,    0.   ,    0.   , -180.   ],
       [   0.   ,   -1.136,    0.   ,  180.   ],
       [   0.   ,    0.   ,    0.   ,    1.   ]])
>>> pixel_position = [4, 5, 6]
>>> dicomtools.coordinates.transform_vectors(img2pat, pixel_position)
array([  52.2  , -175.455,  174.318])

Transform a position in patient coordinates back to a pixel position:

>>> import numpy as np
>>> volume = dicomtools.volume.DicomVolume(series)
>>> img2pat = volume.build_image_to_patient_matrix()
>>> pat2img = np.linalg.inv(img2pat)
>>> pat2img
array([[   0.   ,    0.88 ,    0.   ,  158.4  ],
       [  -0.   ,   -0.   ,   -0.88 ,  158.4  ],
       [  -0.833,   -0.   ,   -0.   ,   49.5  ],
       [   0.   ,    0.   ,    0.   ,    1.   ]])
>>> dicomtools.coordinates.transform_vectors(pat2img, [59.4, -174.318, 174.318])
array([ 5.,  5.,  0.])
>>> dicomtools.coordinates.transform_vectors(pat2img, [52.2, -175.455, 174.318])
array([ 4.,  5.,  6.])

Transform multiple positions simultaneously (faster than transforming each individually):

>>> volume = dicomtools.volume.DicomVolume(series)
>>> img2pat = volume.build_image_to_patient_matrix()
>>> img2pat
array([[   0.   ,    0.   ,   -1.2  ,   59.4  ],
       [   1.136,    0.   ,    0.   , -180.   ],
       [   0.   ,   -1.136,    0.   ,  180.   ],
       [   0.   ,    0.   ,    0.   ,    1.   ]])
>>> pixel_positions = [[4,5,6], [5,5,0]]
>>> dicomtools.coordinates.transform_vectors(img2pat, pixel_positions)
array([[  52.2  , -175.455,  174.318],
       [  59.4  , -174.318,  174.318]])

Exporting DICOM Images to PNG

The dicomtools.export module contains useful functions for exporting images.

Exporting a dicomtools.volume.DicomVolume pixel data to multiple image files:

>>> volume = dicomtools.volume.DicomVolume(series)
>>> volume.export_images('images_dir', 'image')

Exporting a single image slice:

>>> volume = dicomtools.volume.DicomVolume(series)
>>> im_data = volume.info['pixel_data'][:,:,10]
>>> dicomtools.export.export_image_to_png(im_data, 'images_dir/image.png')

Library Reference

dicomtools package

Submodules

dicomtools.coordinates module
dicomtools.coordinates.build_image_to_patient_matrix(origin_position, pixel_spacing, row_vec, column_vec, slice_vec=None)

Get a matrix to transform a pixel coordinate to a DICOM patient coordinate. The pixel coordinate corresponds to the center of that pixel/voxel.

The DICOM standard defines the patient coordinate system as:

  • x -> increasing to the left hand side of the patient
  • y -> increasing to the posterior side of the patient
  • z -> increasing toward the head of the patient

source: https://public.kitware.com/IGSTKWIKI/index.php/DICOM_data_orientation

dicomtools.coordinates.build_patient_to_physical_matrix(patient_position)

This function builds a rotation matrix to transform a position in patient coordinates to a position in physical coordinates. This physical coordinate space is arbitrary, but it simply undoes the effect of the patient position. The transformation matrix is the identity matrix for a patient in feet-first prone position. This is useful if you have a robot within the imaging device, and want a consistent coordinate system regardless of the patient position. For example, the up direction will always remain the same for both prone and supine positions. Due to the unknown orientation of the imaging device, we cannot assign direction labels to these physical axes, so you must test it yourself.

Possible patient positions are:

  • HFP = head first-prone
  • HFS = head first-supine
  • HFDR = head first-decibitus right
  • HFDL = head first-decubiturs left
  • FFP = feet first-prone
  • FFS = feet first-supine
  • FFDR = feet first-decibitus right
  • FFDL = feet first-decibitus left

source: https://public.kitware.com/IGSTKWIKI/index.php/DICOM_data_orientation

dicomtools.coordinates.build_translation_matrix(translation)

For a given translation vector, this function builds the corresponding transformation matrix.

Example:

>>> build_translation_matrix([4,5,6])
array([[1 0 0 4]
       [0 1 0 5]
       [0 0 1 6]
       [0 0 0 1]])
dicomtools.coordinates.expand_transformation_dimension(transformation, new_size, move_translation)

This function takes an \(n \times n\) transformation matrix and expands it to a \(new\_size \times new\_size\) matrix. It expands the array, fills in ones along the diagonal, and moves the translation values to the new right column if requested.

Example:

>>> test = np.array([[1,2,3],[4,5,6],[0,0,1]])
>>> test
array([[1 2 3]
       [4 5 6]
       [0 0 1]])

>>> expand_transformation_dimension(test, 6, True)
array([[1 2 0 0 0 3]
       [4 5 0 0 0 6]
       [0 0 1 0 0 0]
       [0 0 0 1 0 0]
       [0 0 0 0 1 0]
       [0 0 0 0 0 1]])
dicomtools.coordinates.transform_vectors(transformation_matrix, vectors)

This function applies (LHS) the \(n \times n\) transformation matrix to a list of vectors and returns a list of the transformed vectors.

The vectors can be any length less than n. The vectors will be zero-filled so that they have length \(n-1\). If the input is one-dimensional, it is assumed that a single vector was given and a one-dimensional vector will be returned.

dicomtools.dicom_read module
dicomtools.dicom_read.read_dicom(dicom_file)

Build a DicomSeries object containing the DICOM.

dicomtools.dicom_read.read_dicom_series(dicom_file_list)

Build a DicomSeries object containing all of the given DICOMs in a series.

dicomtools.dicom_read.read_dicomdir(dicomdir_file)

Build a list of DicomSeries objects, one for each series in the ‘DICOMDIR’ file.

dicomtools.export module
dicomtools.export.export_image_to_png(image, filename)

Given a 2-dimensional image, save it to a file.

dicomtools.export.export_stack_to_png(images, axis, directory, filename_prefix)

Given a 3-dimensional array, save each slice to a file. Use the ‘axis’ argument to describe which axis to iterate over.

dicomtools.series module
class dicomtools.series.DicomSeries(dicom_list)

Bases: object

A class for storing and processing DICOM series. Instances are verified to all have consistent SeriesInstanceUID attributes.

get_instances_with_image_data()

Get all of the DICOM instances in the series which contain image data (has the pixel_array property).

get_instances_without_image_data()

Get all of the DICOM instances in the series which do not contain image data (do not have the pixel_array property).

dicomtools.visualization module
dicomtools.visualization.plot_slice(dicom_volume, slice_axis, slice_index, figure=None)

Plot a single slice (along axis 0, 1, or 2) of a dicomtools.volume.DicomVolume using matplotlib.

dicomtools.volume module
class dicomtools.volume.DicomVolume(dicom_series)

Bases: object

Simplifies working with 3D DICOM data.

build_image_to_patient_matrix()

Get a matrix to transform a pixel coordinate to a DICOM patient coordinate. The pixel coordinate corresponds to the center of that pixel/voxel.

The DICOM standard defines the patient coordinate system as:

  • x -> increasing to the left hand side of the patient
  • y -> increasing to the posterior side of the patient
  • z -> increasing toward the head of the patient

source: https://public.kitware.com/IGSTKWIKI/index.php/DICOM_data_orientation

export_images(directory, filename_prefix, axis=2)

Save slices of the volume to images. The pixels in the resulting images will be square, regardless of the DICOM pixel size. These images should not be expected to have perfect pixel-accuracy, and compression may be used.

get_dimensions_in_mm()

Get the dimensions in millimeters for each axis of the volume. Returns a list of length 3.

For 3 pixels...

+---+   +---+   +---+
| 1 |   | 2 |   | 3 |
+---+   +---+   +---+

|-|-------|-------|-|
 ^    ^       ^    ^
 |    |       |    |
 |    |       |    ---- 1/2 pixel_size
 |    |       --------- 1 pixel_spacing
 |    ----------------- 1 pixel_spacing
 ---------------------- 1/2 pixel_size
dicomtools.volume.compare_volume_metadata(volume1, volume2)

This compares the volume metadata (position, pixel_size, etc) and shape of the pixel data, but not the actual pixel data. Returns True if equal, otherwise returns False.

Module contents

Indices and tables