Pydicom: Converting a dicom dataset to a standard python dictionary

Created on 26 Feb 2017  路  6Comments  路  Source: pydicom/pydicom

I have not been able to find an easy way to do this by reading the documentation or skimming the source code.

To give a concrete example, I'd like to convert this example from the docs

(0008, 0012) Instance Creation Date              DA: '20030903'
(0008, 0013) Instance Creation Time              TM: '150031'
(0008, 0016) SOP Class UID                       UI: RT Plan Storage
(0008, 0018) SOP Instance UID                    UI: 1.2.777.777.77.7.7777.7777.20030903150023
(0008, 0020) Study Date                          DA: '20030716'
(0008, 0030) Study Time                          TM: '153557'
(0008, 0050) Accession Number                    SH: ''
(0008, 0060) Modality                            CS: 'RTPLAN'

to a dictionary something like this:

{'Instance Creation Date': '20030903', ...}

One solution looks something like this:

dicom_file = dicom.read_file("rtplan.dcm")

d = dict()
for k in dicom_file.__dir__():
    if not k.startswith("__"):
        try:
            d[k] = dicom_file.data_element(k).value
        except:
            pass

However, that's not particularly elegant.

Most helpful comment

I've used the following to convert a dataset to a dict (for storing as JSON) if it's any help. The repr call to populate the elements feels like hack though.

def dicom_dataset_to_dict(dicom_header):
    dicom_dict = {}
    repr(dicom_header)
    for dicom_value in dicom_header.values():
        if dicom_value.tag == (0x7fe0, 0x0010):
            # discard pixel data
            continue
        if type(dicom_value.value) == dicom.dataset.Dataset:
            dicom_dict[dicom_value.tag] = dicom_dataset_to_dict(dicom_value.value)
        else:
            v = _convert_value(dicom_value.value)
            dicom_dict[dicom_value.tag] = v
    return dicom_dict


def _sanitise_unicode(s):
    return s.replace(u"\u0000", "").strip()


def _convert_value(v):
    t = type(v)
    if t in (list, int, float):
        cv = v
    elif t == str:
        cv = _sanitise_unicode(v)
    elif t == bytes:
        s = v.decode('ascii', 'replace')
        cv = _sanitise_unicode(s)
    elif t == dicom.valuerep.DSfloat:
        cv = float(v)
    elif t == dicom.valuerep.IS:
        cv = int(v)
    elif t == dicom.valuerep.PersonName3:
        cv = str(v)
    else:
        cv = repr(v)
    return cv

All 6 comments

Your example won't work for sequences.

def dictify(ds):
    """Turn a pydicom Dataset into a dict with keys derived from the Element tags.

    Parameters
    ----------
    ds : pydicom.dataset.Dataset
        The Dataset to dictify

    Returns
    -------
    output : dict
    """
    output = dict()
    for elem in ds:
        if elem.VR != 'SQ':
            output[elem.tag] = elem.value
        else:
            output[elem.tag] = [dictify(item) for item in elem]
    return output

You could also use elem.name or elem.keyword instead of elem.tag, however these may not be unique if there are private data elements.

@scaramallion Thank you very much for the help.

elem.keyword yields an AttributeError on my data. However, using elem.name instead works very well. I'm not clear on why.

That said, I think that a function like the one you have written would make a very nice addition to the library.

I've used the following to convert a dataset to a dict (for storing as JSON) if it's any help. The repr call to populate the elements feels like hack though.

def dicom_dataset_to_dict(dicom_header):
    dicom_dict = {}
    repr(dicom_header)
    for dicom_value in dicom_header.values():
        if dicom_value.tag == (0x7fe0, 0x0010):
            # discard pixel data
            continue
        if type(dicom_value.value) == dicom.dataset.Dataset:
            dicom_dict[dicom_value.tag] = dicom_dataset_to_dict(dicom_value.value)
        else:
            v = _convert_value(dicom_value.value)
            dicom_dict[dicom_value.tag] = v
    return dicom_dict


def _sanitise_unicode(s):
    return s.replace(u"\u0000", "").strip()


def _convert_value(v):
    t = type(v)
    if t in (list, int, float):
        cv = v
    elif t == str:
        cv = _sanitise_unicode(v)
    elif t == bytes:
        s = v.decode('ascii', 'replace')
        cv = _sanitise_unicode(s)
    elif t == dicom.valuerep.DSfloat:
        cv = float(v)
    elif t == dicom.valuerep.IS:
        cv = int(v)
    elif t == dicom.valuerep.PersonName3:
        cv = str(v)
    else:
        cv = repr(v)
    return cv

Ah yeah, sorry, keyword is in 1.0.0a1, not 0.9.9 which you seem to be using.

Thinking about it a bit more, you're better off using elem.tag as this is guaranteed to be unique. For private elements the name/keyword is unlikely to be unique. I've updated my solution above accordingly.

Thank you very much @scaramallion and @jstutters.

Was this page helpful?
0 / 5 - 0 ratings