Image Display

The native SimpleITK approach to displaying images is to use an external viewing program. In the notebook environment it is convenient to use matplotlib to display inline images and if the need arises we can implement some reasonably rich inline graphical user interfaces, combining control components from the ipywidgets package and matplotlib based display.

In this notebook we cover the usage of external programs and matplotlib for viewing images. We also instantiate a more involved inline interface that uses ipywidgets to control display. For the latter type of moderately complex display, used in many of the notebooks, take a look at the gui.py file.

In [1]:
from __future__ import print_function

import SimpleITK as sitk

%matplotlib notebook
import matplotlib.pyplot as plt
import gui

# Utility method that either downloads data from the Girder repository or
# if already downloaded returns the file name for reading from disk (cached data).
%run update_path_to_download_script
from downloaddata import fetch_data as fdata

Image Display with An External Viewer

SimpleITK provides two options for invoking an external viewer, use a procedural interface or an object oriented one.

Procedural interface

SimpleITK provides a built in Show method. This function writes the image out to disk and than launches a program for visualization. By default it is configured to use the Fiji program, because it readily supports many medical image formats and loads quickly. However, the Show visualization program is easily customizable via environment variables:

  • SITK_SHOW_COMMAND: Viewer to use (ITK-SNAP, 3D Slicer...)
  • SITK_SHOW_COLOR_COMMAND: Viewer to use when displaying color images.
  • SITK_SHOW_3D_COMMAND: Viewer to use for 3D images.

In general, the Show command accepts three parameters: (1) image to display; (2) window title; (3) boolean specifying whether to print the invoked command and additional debugging information.

In [2]:
mr_image = sitk.ReadImage(fdata('training_001_mr_T1.mha'))
Fetching training_001_mr_T1.mha
In [3]:
sitk.Show?
In [4]:
try:
    sitk.Show(mr_image)
except RuntimeError:
    print('SimpleITK Show method could not find the viewer (ImageJ not installed or ' +
          'environment variable pointing to non existant viewer).')

Use a different viewer by setting environment variable(s). Do this from within your Jupyter notebook using 'magic' functions, or set in a more permanent manner using your OS specific convention.

In [5]:
%env SITK_SHOW_COMMAND /Applications/ITK-SNAP.app/Contents/MacOS/ITK-SNAP 

try:
    sitk.Show(mr_image)
except RuntimeError:
    print('SimpleITK Show method could not find the viewer (ITK-SNAP not installed or ' +
          'environment variable pointing to non existant viewer).')
env: SITK_SHOW_COMMAND=/Applications/ITK-SNAP.app/Contents/MacOS/ITK-SNAP
In [6]:
%env SITK_SHOW_COMMAND '/Applications/ImageJ/ImageJ.app/Contents/MacOS/JavaApplicationStub'
try:
    sitk.Show(mr_image)
except RuntimeError:
    print('SimpleITK Show method could not find the viewer (ImageJ not installed or ' +
          'environment variable pointing to non existant viewer).')
env: SITK_SHOW_COMMAND='/Applications/ImageJ/ImageJ.app/Contents/MacOS/JavaApplicationStub'
SimpleITK Show method could not find the viewer (ImageJ not installed or environment variable pointing to non existant viewer).
In [7]:
%env SITK_SHOW_COMMAND '/Applications/Slicer.app/Contents/MacOS/Slicer'
try:
    sitk.Show(mr_image)
except RuntimeError:
    print('SimpleITK Show method could not find the viewer (Slicer not installed or ' +
          'environment variable pointing to non existant viewer).')
env: SITK_SHOW_COMMAND='/Applications/Slicer.app/Contents/MacOS/Slicer'

Object Oriented interface

The Image Viewer class provides a more standard approach to controlling image viewing by setting various instance variable values. Also, it ensures that all of your viewing settings are documented, as they are part of the code and not external environment variables.

A caveat to this is that if you have set various environment variables to control SimpleITK settings, the image viewer will use these settings as the default ones and not the standard defaults (Fiji as viewer etc.).

In [8]:
# Which external viewer will the image_viewer use if we don't specify the external viewing application? 
# (see caveat above)
image_viewer = sitk.ImageViewer()
image_viewer.SetApplication('/Applications/Fiji.app/Contents/MacOS/ImageJ-macosx')
image_viewer.SetTitle('MR image')

# Use the default image viewer.
image_viewer.Execute(mr_image)

# Change viewer, and display again.
image_viewer.SetApplication('/Applications/ITK-SNAP.app/Contents/MacOS/ITK-SNAP')
image_viewer.Execute(mr_image)

# Change the viewer command, (use ITK-SNAP -z option to open the image in zoomed mode)
image_viewer.SetCommand('/Applications/ITK-SNAP.app/Contents/MacOS/ITK-SNAP -z 3')
image_viewer.Execute(mr_image)

print('Default format for saved file used in display: ' + image_viewer.GetFileExtension())

# Change the file format (possibly to make it compatible with your viewer of choice)
image_viewer.SetFileExtension('.nrrd')
image_viewer.Execute(mr_image)
Default format for saved file used in display: .mha

Inline display with matplotlib

In [9]:
mr_image = sitk.ReadImage(fdata('training_001_mr_T1.mha'))
npa = sitk.GetArrayViewFromImage(mr_image)

# Display the image slice from the middle of the stack, z axis
z = int(mr_image.GetDepth()/2)
npa_zslice = sitk.GetArrayViewFromImage(mr_image)[z,:,:]

# Three plots displaying the same data, how do we deal with the high dynamic range?
fig = plt.figure(figsize=(10,3))

fig.add_subplot(1,3,1)
plt.imshow(npa_zslice)
plt.title('default colormap', fontsize=10)
plt.axis('off')

fig.add_subplot(1,3,2)
plt.imshow(npa_zslice,cmap=plt.cm.Greys_r);
plt.title('grey colormap', fontsize=10)
plt.axis('off')

fig.add_subplot(1,3,3)
plt.title('grey colormap,\n scaling based on volumetric min and max values', fontsize=10)
plt.imshow(npa_zslice,cmap=plt.cm.Greys_r, vmin=npa.min(), vmax=npa.max())
plt.axis('off');
Fetching training_001_mr_T1.mha
In [10]:
# Display the image slice in the middle of the stack, x axis
    
x = int(mr_image.GetWidth()/2)

npa_xslice = npa[:,:,x]
plt.figure(figsize=(10,2))
plt.imshow(npa_xslice, cmap=plt.cm.Greys_r)
plt.axis('off')

print('Image spacing: {0}'.format(mr_image.GetSpacing()))
Image spacing: (1.25, 1.25, 4.0)
In [11]:
# Collapse along the x axis
extractSliceFilter = sitk.ExtractImageFilter()     
size = list(mr_image.GetSize())
size[0] = 0
extractSliceFilter.SetSize( size )
         
index = (x, 0, 0)
extractSliceFilter.SetIndex(index)
sitk_xslice = extractSliceFilter.Execute(mr_image)

# Resample slice to isotropic
original_spacing = sitk_xslice.GetSpacing()
original_size = sitk_xslice.GetSize()

min_spacing = min(sitk_xslice.GetSpacing())
new_spacing = [min_spacing, min_spacing]
new_size = [int(round(original_size[0]*(original_spacing[0]/min_spacing))), 
            int(round(original_size[1]*(original_spacing[1]/min_spacing)))]
resampleSliceFilter = sitk.ResampleImageFilter()

# Why is the image pixelated?
sitk_isotropic_xslice = resampleSliceFilter.Execute(sitk_xslice, new_size, sitk.Transform(), sitk.sitkNearestNeighbor, sitk_xslice.GetOrigin(),
                                                    new_spacing, sitk_xslice.GetDirection(), 0, sitk_xslice.GetPixelID())
plt.figure(figsize=(10,2))
plt.imshow(sitk.GetArrayViewFromImage(sitk_isotropic_xslice), cmap=plt.cm.Greys_r)
plt.axis('off')
print('Image spacing: {0}'.format(sitk_isotropic_xslice.GetSpacing()))
Image spacing: (1.25, 1.25)

Inline display with matplotlib and ipywidgets

Display two volumes side by side, with sliders to control the displayed slice. The menu on the bottom left allows you to home (return to original view), back and forward between views, pan, zoom and save a view.

A variety of interfaces combining matplotlib display and ipywidgets can be found in the gui.py file.

In [12]:
ct_image = sitk.ReadImage(fdata('training_001_ct.mha'))
ct_window_level = [720,80]
mr_window_level = [790,395]
Fetching training_001_ct.mha
In [13]:
gui.MultiImageDisplay([mr_image, ct_image], figure_size=(10,3), window_level_list=[mr_window_level,ct_window_level]);