In [1]:
# Compatibility with Python 3
from __future__ import print_function  # print('me') instead of print 'me'
from __future__ import division  # 1/2 == 0.5, not 0
In [2]:
# Show figures inside the notebook
%matplotlib inline
In [3]:
import numpy as np  # Python array library
import matplotlib.pyplot as plt  # Python plotting library

The major arteries in a T1 MRI image often have high signal (white when displaying in grayscale).

Our task is to see if we can pick out the courses of the vertebral, basilar and carotid arteries on this image.

This time we are going to load an image using the nibabel library. The image is ds107_sub001_highres.nii in the same directory as this notebook.

In [4]:
import nibabel as nib

Try loading the image using nibabel, to make an image object. Use tab completion on nib. or look at the the day0 introduction notebook to work out how to do this.

In [5]:
# img = ?
img = nib.load('ds107_sub001_highres.nii')

Now get the image array data from the nibabel image object. Don't forget to use tab completion on the image object if you can remember or don't know the methods of the object.

In [6]:
# data = ?
data = img.get_data()

Try plotting a few slices over the third dimension to see whether you can see the arteries. For example, to plot the first slice over the third dimension, you might use:

plt.imshow(data[:, :, 0], cmap='gray')

where data is your image array data.

In [7]:
# Plotting some slices over the third dimension
plt.imshow(data[:, :, 30], cmap='gray')
Out[7]:
<matplotlib.image.AxesImage at 0x1088d9650>

Now try looking for a good threshold so that you pick up only the very high signal in the brain. A good place to start is to use plt.hist to get an idea of the spread of values within the volume and within the slice.

In [8]:
# Here you might try plt.hist or something else to find a threshold
data_1d = data.ravel()
plt.hist(data_1d, bins=100)
Out[8]:
(array([  9.07693900e+06,   5.94343000e+05,   1.58396000e+05,
          9.88360000e+04,   7.72150000e+04,   6.64160000e+04,
          6.05390000e+04,   5.78870000e+04,   5.65420000e+04,
          5.73010000e+04,   6.05080000e+04,   6.58860000e+04,
          7.28520000e+04,   8.12560000e+04,   9.34790000e+04,
          1.15716000e+05,   1.32776000e+05,   1.92791000e+05,
          2.06473000e+05,   1.84949000e+05,   1.62487000e+05,
          1.50438000e+05,   1.45475000e+05,   1.60722000e+05,
          1.62927000e+05,   9.66320000e+04,   4.06470000e+04,
          2.15860000e+04,   1.70360000e+04,   1.47190000e+04,
          1.33950000e+04,   1.20860000e+04,   1.09790000e+04,
          8.78700000e+03,   8.97700000e+03,   8.11100000e+03,
          7.28600000e+03,   6.07200000e+03,   5.23400000e+03,
          4.18300000e+03,   3.29000000e+03,   2.42700000e+03,
          1.67800000e+03,   1.22900000e+03,   9.34000000e+02,
          5.99000000e+02,   4.48000000e+02,   3.58000000e+02,
          2.86000000e+02,   2.11000000e+02,   1.95000000e+02,
          1.84000000e+02,   1.45000000e+02,   1.54000000e+02,
          1.31000000e+02,   1.38000000e+02,   1.42000000e+02,
          1.21000000e+02,   1.00000000e+02,   1.08000000e+02,
          1.06000000e+02,   1.04000000e+02,   1.09000000e+02,
          9.80000000e+01,   9.00000000e+01,   6.10000000e+01,
          6.60000000e+01,   5.30000000e+01,   4.60000000e+01,
          4.10000000e+01,   4.40000000e+01,   3.50000000e+01,
          3.10000000e+01,   2.40000000e+01,   3.10000000e+01,
          2.30000000e+01,   2.40000000e+01,   2.10000000e+01,
          2.80000000e+01,   1.40000000e+01,   1.20000000e+01,
          1.40000000e+01,   1.30000000e+01,   9.00000000e+00,
          3.00000000e+00,   7.00000000e+00,   1.00000000e+01,
          5.00000000e+00,   3.00000000e+00,   5.00000000e+00,
          7.00000000e+00,   1.00000000e+00,   2.00000000e+00,
          5.00000000e+00,   2.00000000e+00,   1.00000000e+00,
          4.00000000e+00,   0.00000000e+00,   2.00000000e+00,
          1.00000000e+00]),
 array([   0.  ,    7.94,   15.88,   23.82,   31.76,   39.7 ,   47.64,
          55.58,   63.52,   71.46,   79.4 ,   87.34,   95.28,  103.22,
         111.16,  119.1 ,  127.04,  134.98,  142.92,  150.86,  158.8 ,
         166.74,  174.68,  182.62,  190.56,  198.5 ,  206.44,  214.38,
         222.32,  230.26,  238.2 ,  246.14,  254.08,  262.02,  269.96,
         277.9 ,  285.84,  293.78,  301.72,  309.66,  317.6 ,  325.54,
         333.48,  341.42,  349.36,  357.3 ,  365.24,  373.18,  381.12,
         389.06,  397.  ,  404.94,  412.88,  420.82,  428.76,  436.7 ,
         444.64,  452.58,  460.52,  468.46,  476.4 ,  484.34,  492.28,
         500.22,  508.16,  516.1 ,  524.04,  531.98,  539.92,  547.86,
         555.8 ,  563.74,  571.68,  579.62,  587.56,  595.5 ,  603.44,
         611.38,  619.32,  627.26,  635.2 ,  643.14,  651.08,  659.02,
         666.96,  674.9 ,  682.84,  690.78,  698.72,  706.66,  714.6 ,
         722.54,  730.48,  738.42,  746.36,  754.3 ,  762.24,  770.18,
         778.12,  786.06,  794.  ]),
 <a list of 100 Patch objects>)

Try making a binarized image with your threshold and displaying slices with that. What structures are you picking up?

In [9]:
# Maybe display some slices from the data binarized with a threshold
threshold = 300
binarized_data = data > threshold
plt.imshow(binarized_data[:, :, 30], cmap='gray')
Out[9]:
<matplotlib.image.AxesImage at 0x10acb1690>

Now try taking a 3D subvolume out of the middle of the image (the approximate middle in all three axes) to pick out a good subvolume of the image that still contains the big arteries.

In [10]:
# Create a smaller 3D subvolume from the image data that still contains the arteries
subvolume = data[90:-90, 90:-90, 10:130]

Try binarizing that with some thresholds to see whether you can pick out the arteries without much other stuff. Hint - you might consider using np.percentile or plt.hist to find a good threshold.

In [11]:
# Try a few plots of binarized slices and other stuff to find a good threshold
pct_99 = np.percentile(subvolume, 99)
binarized_subvolume = subvolume > pct_99
plt.imshow(binarized_subvolume[:, :, 20], cmap='gray')
Out[11]:
<matplotlib.image.AxesImage at 0x10bc13810>

If you have a good threshold and a good binarized subset, see if you can see the arterial structure using the fancy function to plot the binarized image with a 3D rendering.

In [12]:
# This function uses matplotlib 3D plotting and sckit-image for rendering
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from skimage import measure

def binarized_surface(binary_array):
    """ Do a 3D plot of the surfaces in a binarized image
    
    This uses scikit-image and some fancy commands that we don't
    need to worry about at the moment, to do the plot.
    """
    verts, faces = measure.marching_cubes(binary_array, 0)
    fig = plt.figure(figsize=(10, 12))
    ax = fig.add_subplot(111, projection='3d')

    # Fancy indexing: `verts[faces]` to generate a collection of triangles
    mesh = Poly3DCollection(verts[faces], linewidths=0, alpha=0.5)
    ax.add_collection3d(mesh)
    ax.set_xlim(0, binary_array.shape[0])
    ax.set_ylim(0, binary_array.shape[1])
    ax.set_zlim(0, binary_array.shape[2])

For example, let's say you have a binarized subvolume of the original data called binarized_subvolume. You could do a 3D rendering of this binary image with:

binarized_surface(binarized_subvolume)

In [13]:
binarized_surface(binarized_subvolume)