Skip to main content

How are DICOMs parsed?

The highest-level function to transform DICOM files into the unified, usable datastructure Volume is the load_volumes_from_dicoms function. Given a list of pydicom objects representing one or more DICOM instances, this function automatically groups related DICOM instances (related in the sense of being a part of a single 3D-volume) and constructs a Volume object for each 3D-volume.

Internally, the function performs the following steps:

  1. Dismisses any invalid DICOMs: e.g. DICOMs with invalid pixel data, or PhoenixZIP report or localizers.
  2. Groups the DICOMs. In the case of slice-based DICOMs, each dicom object only represents a single 2D slice of the 3D volume. DICOMs representing slices of the same 3D volumes are therefore grouped together using either the SeriesInstanceUID header tag, and, in the case of GE images, their diffusion gradient directions and b_values. See _get_partitions_of_3d_volumes for more details.
  3. Each partition of DICOMs is then converted into a Volume object. This step utilizes the dcm2niix tool to convert the DICOMs into NIfTI files, and then uses the pixel data and affine matrix from the created nifti file to obtain the Volume object. DICOM header tag information is read using the ReaderRegistry class.

Reading DICOMs from different vendors

As DICOM files and their header structure varies significantly between vendors and even between different (software) models of the same vendor, a flexible and extensible mechanism to extract information from the DICOM headers is required.

!!! example

For example, the b-value of a diffusion-weighted image is stored in vastly different places depending on the vendor and software setting of the MRI machine:

  • For Siemens 3D DICOMs, the b-value is stored in a tag inside the PerFrameFunctionalGroupsSequence tags.
  • For Siemens slice-based DICOMs, the b-value is stored in the tag 0x0019, 0x100C.
  • For GE DICOMs, the b-value is stored in the tag 0x0018, 0x9087.

ReaderRegistry schematic functionality

ReaderRegistry schematic functionality

The ReaderRegistry class provides this mechanism.

  • Defines a register_getter(attribute_name, dicom_scheme) decorator method: This decorator method "registers" the decorated function and indicates that the decorated function extracts a specified attribute from specified types of DICOM headers. The attribute_name argument is the name of the attribute that the function extracts, and the dicom_scheme argument is a VolumeScheme enum instance that indicates for which type of DICOM header the decorated function is compatible.

  • Provides the get_getters(attribute_name, dicom_scheme) function. It returns a list of functions that are registered to extract the attribute attribute_name from DICOM headers of type dicom_scheme.

    • The get_getters_in_priority function is a wrapper around the get_getters function that returns the list of all getter functions for specified attribute in order of priority. Meaning: getters specifically marked for the specified dicom_scheme are returned first, followed by all getter functions registered to the default scheme, followed by all other getter functions.
  • In get_all_header_data, the get_getters_in_priority function is used to obtain the getter functions for each attribute that should be extracted from the DICOM headers. The getters for an attribute are called in this order until one of them returns a non-None value. For slice-based DICOMs, the function first passes all DICOM object for the 3D volume to registered getters. Following this "first round" of execution of getters, the function passes only the first DICOM object in the list to the getters. For 3D DICOMs, this single DICOM object is only passed once to the getters.

The consequence of this design is the following: For each attribute that should be extracted from DICOM headers and stored in the Volume object, a getter function needs to be written. The getter can be scheme-specific, or simply be registered to the default scheme. The getter should be defined in the dicom/dicom_reader.py file. This makes adding support for new DICOM header formats and new attributes to extract very easy. :)