Module 11

So you want to filter out bad segmentations

This lesson adapts `3_sklearn_segmentation_filtering.ipynb`, which combines instance segmentation, morphological measurements, and classification to identify badly segmented cells.

Estimated time: 75 to 105 min Main tools: scikit-image, SciPy, scikit-learn

Main technical steps from the notebook

  1. Load phase-contrast and binary-mask images.
  2. Fill holes in binary masks.
  3. Create a distance transform.
  4. Find local maxima as markers.
  5. Use watershed to split touching cells into instances.
  6. Measure morphological features.
  7. Train a classifier to detect badly segmented objects.

Why this notebook is especially useful

It teaches a realistic workflow problem rather than an abstract one. In real projects, segmentation errors are common, and a large part of analysis work is deciding which objects to trust.

Website teaching structure

Part 1: build the instance segmentation

Start from the binary mask and show why touching cells are a problem. Walk through hole filling, distance transforms, local maxima, and watershed one step at a time.

Part 2: measure morphology

Once individual objects exist, connect them to per-cell measurements. This is a nice bridge back to the earlier classification module.

Part 3: classify segmentation quality

Present this not as “AI fixes everything,” but as a pragmatic way to reduce manual cleanup by identifying likely bad segmentations.

Representative code examples

Load images and fill holes

from skimage.io import imread
from scipy.ndimage import binary_fill_holes

phase = imread("../data/images/wt_phase_contrast.tif")
mask = imread("../data/images/wt_mask.tif")
filled_mask = binary_fill_holes(mask)

Distance transform and markers

import numpy as np
from scipy.ndimage import distance_transform_edt, label
from skimage.feature import peak_local_max

distances = distance_transform_edt(filled_mask)
coordinates = peak_local_max(distances, labels=filled_mask)
coordinates_tuple = tuple(coordinates.T)
local_maxima = np.zeros_like(filled_mask, dtype=bool)
local_maxima[coordinates_tuple] = True
markers = label(local_maxima)[0]

Watershed

from skimage.segmentation import watershed

labels = watershed(-distances, markers, mask=filled_mask)

Important reasoning skill

Learners should be encouraged to inspect failures visually. A classifier that filters segmentations is only useful if the labels used for training reflect the biological and analytical goals of the study.

Exercises worth integrating

  1. Display the phase image and mask side by side.
  2. Show the hole-filled mask and explain what changed.
  3. Display the distance transform and marker image.
  4. Run watershed and inspect where it succeeds or fails.
  5. Use measured features to train a classifier for segmentation quality.