Focused Ion Beam Scanning Electron Microscopy Image Segmentation

Summary:

  1. SimpleITK supports a large number of filters that facilitate classical segmentation algorithms (variety of thresholding algorithms, watersheds...).
  2. Once your data is segmented SimpleITK enables you to efficiently post process the segmentation (e.g. label distinct objects, analyze object shapes).

This notebook will illustrate the use of SimpleITK for segmentation of bacteria from a 3D Focused Ion Beam Scanning Electron Microscopy (FIB-SEM) image. The specific bacterium is bacillus subtilis, a rod shaped organism naturally found in soil and plants. The bacteria have been subjected to stress to initiate the process of forming an endospore. These endospores can be seen as a generally dark ellipsoid inside the individual bacterium.

In [1]:
import SimpleITK as sitk
import pandas as pd

%matplotlib nbagg

import matplotlib.pyplot as plt
import gui
from math import ceil
from downloaddata import fetch_data as fdata

Load data

Load the 3D volume and display it.

In [2]:
img = sitk.ReadImage(fdata("fib_sem_bacillus_subtilis.mha"))
gui.MultiImageDisplay(image_list = [img], figure_size=(8,4));
Fetching fib_sem_bacillus_subtilis.mha

Segmentation

To allow us to analyze the shape of whole bacteria we first need to segment them. We will do this in several steps:

  1. Separate the bacteria from the embedding resin background.
  2. Mark each potential bacterium with a unique label, to evaluate the segmentation.
  3. Remove small components and fill small holes using binary morphology operators (opening and closing).
  4. Use seed based watersheds to perform final segmentation.
  5. Remove bacterium that are connected to the image boundary.

Separate the bacteria from the background

Based on the visualization of the data above, it intuitively appears that the background and foreground are separable using a single intensity threshold. Our first step towards validating this observation is to plot the intensity distribution.

In [3]:
plt.figure()
plt.hist(sitk.GetArrayViewFromImage(img).flatten(), bins=100)
plt.show()

The histogram is bi-modal with a clear separation, which we have manually identified as having an intensity value of 120.

We can also use one of several binary threshold selection filters available in SimpleITK.

In [4]:
threshold_filters = {'Otsu': sitk.OtsuThresholdImageFilter(),
                     'Triangle' : sitk.TriangleThresholdImageFilter(),
                     'Huang' : sitk.HuangThresholdImageFilter(),
                     'MaxEntropy' : sitk.MaximumEntropyThresholdImageFilter()}

filter_selection = 'Manual'
try:
  thresh_filter = threshold_filters[filter_selection]
  thresh_filter.SetInsideValue(0)
  thresh_filter.SetOutsideValue(1)
  thresh_img = thresh_filter.Execute(img)
  thresh_value = thresh_filter.GetThreshold()
except KeyError:
  thresh_value = 120
  thresh_img = img>thresh_value

print("Threshold used: " + str(thresh_value))    
gui.MultiImageDisplay(image_list = [sitk.LabelOverlay(img, thresh_img)],                   
                      title_list = ['Binary Segmentation'], figure_size=(8,4));
Threshold used: 120