Source code for dicom2nifti.convert_dicom

# -*- coding: utf-8 -*-
"""
dicom2nifti

@author: abrys
"""
from __future__ import print_function

import logging

import dicom2nifti.compressed_dicom as compressed_dicom
import dicom2nifti.patch_pydicom_encodings
from dicom2nifti import convert_hitachi

dicom2nifti.patch_pydicom_encodings.apply()

import os
import tempfile
import shutil
import sys

from six import reraise

from pydicom.tag import Tag

from dicom2nifti.exceptions import ConversionValidationError, ConversionError
import dicom2nifti.convert_generic as convert_generic
import dicom2nifti.convert_siemens as convert_siemens
import dicom2nifti.convert_ge as convert_ge
import dicom2nifti.convert_philips as convert_philips
import dicom2nifti.common as common
import dicom2nifti.image_reorientation as image_reorientation
import dicom2nifti.settings as settings
import dicom2nifti.resample as resample
logger = logging.getLogger(__name__)


# Disable this warning as there is not reason for an init class in an enum
# pylint: disable=w0232, r0903, C0103


[docs]class Vendor(object): """ Enum with the vendor """ GENERIC = 0 SIEMENS = 1 GE = 2 PHILIPS = 3 HITACHI = 4
# pylint: enable=w0232, r0903, C0103
[docs]def dicom_series_to_nifti(original_dicom_directory, output_file=None, reorient_nifti=True): """ Converts dicom single series (see pydicom) to nifty, mimicking SPM Examples: See unit test will return a dictionary containing - the NIFTI under key 'NIFTI' - the NIFTI file path under 'NII_FILE' - the BVAL file path under 'BVAL_FILE' (only for dti) - the BVEC file path under 'BVEC_FILE' (only for dti) IMPORTANT: If no specific sequence type can be found it will default to anatomical and try to convert. You should check that the data you are trying to convert is supported by this code Inspired by http://nipy.sourceforge.net/nibabel/dicom/spm_dicom.html Inspired by http://code.google.com/p/pydicom/source/browse/source/dicom/contrib/pydicom_series.py :param reorient_nifti: if True the nifti affine and data will be updated so the data is stored LAS oriented :param output_file: file path to write to if not set to None :param original_dicom_directory: directory with the dicom files for a single series/scan :return nibabel image """ # copy files so we can can modify without altering the original temp_directory = tempfile.mkdtemp() try: dicom_directory = os.path.join(temp_directory, 'dicom') shutil.copytree(original_dicom_directory, dicom_directory) dicom_input = common.read_dicom_directory(dicom_directory) return dicom_array_to_nifti(dicom_input, output_file, reorient_nifti) except AttributeError as exception: reraise( tp=ConversionError, value=ConversionError(str(exception)), tb=sys.exc_info()[2]) finally: # remove the copied data shutil.rmtree(temp_directory)
[docs]def dicom_array_to_nifti(dicom_list, output_file, reorient_nifti=True): """ Converts dicom single series (see pydicom) to nifty, mimicking SPM Examples: See unit test will return a dictionary containing - the NIFTI under key 'NIFTI' - the NIFTI file path under 'NII_FILE' - the BVAL file path under 'BVAL_FILE' (only for dti) - the BVEC file path under 'BVEC_FILE' (only for dti) IMPORTANT: If no specific sequence type can be found it will default to anatomical and try to convert. You should check that the data you are trying to convert is supported by this code Inspired by http://nipy.sourceforge.net/nibabel/dicom/spm_dicom.html Inspired by http://code.google.com/p/pydicom/source/browse/source/dicom/contrib/pydicom_series.py :param reorient_nifti: if True the nifti affine and data will be updated so the data is stored LAS oriented :param output_file: file path to write to :param dicom_list: list with uncompressed dicom objects as read by pydicom """ # copy files so we can can modify without altering the original if not are_imaging_dicoms(dicom_list): raise ConversionValidationError('NON_IMAGING_DICOM_FILES') vendor = _get_vendor(dicom_list) if vendor == Vendor.GENERIC: results = convert_generic.dicom_to_nifti(dicom_list, output_file) elif vendor == Vendor.SIEMENS: results = convert_siemens.dicom_to_nifti(dicom_list, output_file) elif vendor == Vendor.GE: results = convert_ge.dicom_to_nifti(dicom_list, output_file) elif vendor == Vendor.PHILIPS: results = convert_philips.dicom_to_nifti(dicom_list, output_file) elif vendor == Vendor.HITACHI: results = convert_hitachi.dicom_to_nifti(dicom_list, output_file) else: raise ConversionValidationError("UNSUPPORTED_DATA") if settings.resample: if not common.is_orthogonal(dicom_list): resample.resample_image(results['NII_FILE']) # do image reorientation if needed if reorient_nifti: image_reorientation.reorient_image(results['NII_FILE'], results['NII_FILE']) return results
[docs]def are_imaging_dicoms(dicom_input): """ This function will check the dicom headers to see which type of series it is Possibilities are fMRI, DTI, Anatomical (if no clear type is found anatomical is used) :param dicom_input: directory with dicom files or a list of dicom objects """ # if it is philips and multiframe dicom then we assume it is ok if common.is_philips(dicom_input): if common.is_multiframe_dicom(dicom_input): return True # for all others if there is image position patient we assume it is ok header = dicom_input[0] return Tag(0x0020, 0x0037) in header
def _get_vendor(dicom_input): """ This function will check the dicom headers to see which type of series it is Possibilities are fMRI, DTI, Anatomical (if no clear type is found anatomical is used) """ # check if it is siemens if common.is_siemens(dicom_input): logger.info('Found manufacturer: SIEMENS') return Vendor.SIEMENS # check if it is ge if common.is_ge(dicom_input): logger.info('Found manufacturer: GE') return Vendor.GE # check if it is philips if common.is_philips(dicom_input): logger.info('Found manufacturer: PHILIPS') return Vendor.PHILIPS # check if it is philips if common.is_hitachi(dicom_input): logger.info('Found manufacturer: HITACHI') return Vendor.HITACHI # generic by default logger.info('WARNING: Assuming generic vendor conversion (ANATOMICAL)') return Vendor.GENERIC def _get_first_header(dicom_directory): """ Function to get the first dicom file form a directory and return the header Useful to determine the type of data to convert :param dicom_directory: directory with dicom files """ # looping over all files for root, _, file_names in os.walk(dicom_directory): # go over all the files and try to read the dicom header for file_name in file_names: file_path = os.path.join(root, file_name) # check wither it is a dicom file if not compressed_dicom.is_dicom_file(file_path): continue # read the headers return compressed_dicom.read_file(file_path, stop_before_pixels=True, force=dicom2nifti.settings.pydicom_read_force) # no dicom files found raise ConversionError('NO_DICOM_FILES_FOUND')