Plotly visualization of DICOM images

This notebook is an update of one based on an older version (0.99) of pydicom for Python 2.7. Here we use Python 3.6 and pydicom 1.0.2.

DICOM (Digital Imaging and Communications in Medicine) is a standard for handling, storing, printing, and transmitting information in medical imaging.

DICOM images have the extension dcm. A DICOM file has two parts: the header and the dataset. The header contains information on the encapsulated dataset. It consists of a File Preamble, a DICOM prefix, and the File Meta Elements.

The Python library, pydicom, can read and writedcm` files: https://pydicom.github.io/pydicom/stable/.

In [1]:
import numpy as np
import pydicom
In [2]:
print (pydicom.__version__)
1.0.2

In this notebook we define functions to read DICOM files, transform the corresponding image to get the z-value for a heatmap and plot the heatmap, using the mpl bone colormap/colorscale. If necessary we increase the image contrast applying the histogram equalization, defined by the following function:

In [3]:
def histogram_equalization(img, no_bins):
    
    #img- the image as a numpy.array
    #the appropriate number of bins, `no_bins` in the histogram is chosen by experiments, 
    #until the contrast is convenient
    
    image_hist, bins = np.histogram(img.flatten(), no_bins, normed=True)
    csum = image_hist.cumsum() 
    cdf_mult = np.max(img) * csum / csum[-1] # cdf multiplied by a factor

    #  linear interpolation of cdf_mult to get new pixel values
    im_new = np.interp(img.flatten(), bins[:-1],  cdf_mult)

    return im_new.reshape(img.shape), cdf_mult

Define the Plotly colorscale pl_bone:

In [4]:
pl_bone=[[0.0, 'rgb(0, 0, 0)'],
         [0.05, 'rgb(10, 10, 14)'],
         [0.1, 'rgb(21, 21, 30)'],
         [0.15, 'rgb(33, 33, 46)'],
         [0.2, 'rgb(44, 44, 62)'],
         [0.25, 'rgb(56, 55, 77)'],
         [0.3, 'rgb(66, 66, 92)'],
         [0.35, 'rgb(77, 77, 108)'],
         [0.4, 'rgb(89, 92, 121)'],
         [0.45, 'rgb(100, 107, 132)'],
         [0.5, 'rgb(112, 123, 143)'],
         [0.55, 'rgb(122, 137, 154)'],
         [0.6, 'rgb(133, 153, 165)'],
         [0.65, 'rgb(145, 169, 177)'],
         [0.7, 'rgb(156, 184, 188)'],
         [0.75, 'rgb(168, 199, 199)'],
         [0.8, 'rgb(185, 210, 210)'],
         [0.85, 'rgb(203, 221, 221)'],
         [0.9, 'rgb(220, 233, 233)'],
         [0.95, 'rgb(238, 244, 244)'],
         [1.0, 'rgb(255, 255, 255)']]
In [5]:
def get_pl_image(dicom_filename, hist_equal=False, no_bins=None):
    #dicom_filename- a string 'filename.dcm'
    #no_bins is the number of bins for histogram when hist_equal=False, else it is None
    #returns the np.array that defines the z-value for the heatmap representing the dicom image
    
    dic_file=pydicom.read_file(dicom_filename)
    img=dic_file.pixel_array#get the image as a numpy.array
    if hist_equal and isinstance(no_bins, int):
        img_new=histogram_equalization(img, no_bins)[0]
        img_new=np.array(img_new, dtype=np.int16)
        return np.flipud(img_new)
    else:
        return np.flipud(img)

The following function returns the Plotly figure of the heatmap representing the DICOM image:

In [6]:
def DICOM_heatmap(z, title, width=600, height=600, colorscale=pl_bone):

    data=[dict(type='heatmap', 
           z=z, 
           colorscale=colorscale, 
           zsmooth='best',
           colorbar=dict(thickness=20, ticklen=4),  
              )
         ]

    axis=dict(zeroline=False, showgrid=False, ticklen=4)
    layout=dict(width=600, height=600,
            font=dict(family='Balto', size=12),
            xaxis= dict(axis),
            yaxis= dict(axis),
            title= title
            )
    return  dict(data=data, layout=layout)

Here we plot two DICOM images. Since the second one has a poor contrast we process it through histogram equalization:

In [7]:
import plotly.plotly as py
py.sign_in('empet', '')
In [8]:
from plotly.offline import download_plotlyjs, init_notebook_mode,  iplot, plot
init_notebook_mode(connected=True)
In [9]:
title1="Plotly viz of a DICOM medical image<br>"+\
"Data set: <a href='http://www.barre.nom.fr/medical/samples/'>[1]</a>"
pl_img1=get_pl_image('MR-MONO2-16-head')#this DICOM file has no extension
fig1=DICOM_heatmap(pl_img1, title1)
py.iplot(fig1, filename='DICOM-img-MRIs')
Out[9]:
In [10]:
title2="Plotly viz of a DICOM medical image"+\
"<br>Data set: <a href='http://www.rubomedical.com/dicomfiles/index.html'>[1]</a>"
pl_img2=get_pl_image('MRBRAIN.DCM', hist_equal=True, no_bins=36)
fig2=DICOM_heatmap(pl_img2, title2)
In [11]:
py.iplot(fig2, filename='DICOM-MRBRAIN')
Out[11]:
In [12]:
from IPython.core.display import HTML
def  css_styling():
    styles = open("./custom.css", "r").read()
    return HTML(styles)
css_styling()
Out[12]: