Watershed

Prerequisites

Before starting this lesson, you should be familiar with:

Learning Objectives

After completing this lesson, learners should be able to:
  • Understand the concept of watersheds in image analysis.

  • Understand that a watershed algorithm is often applied to a distance map to split objects by their shape.

  • Be able to run a watershed algorithm in an image analysis platform.

Motivation

The segmentation of touching objects often is a challenge in image analysis. The watershed algorithm is a very common operation to split touching objects and is available in most image analysis frameworks.

Concept map

graph TD T("Image") --> W("Watershed transform") SP("Seed points (at local intensity minima)") --> W W --> S("Segmented image") S --- B("Boundaries / Watersheds (at intensity ridges)")



Figure


Illustration of the watershed transform. a) Image with three objects that cannot be separated by a simple threshold. b) Foreground/background segmentation of (a). c) Inverse of (a). d) Intensity line profile along the line depicted in (c) with illustration of filling up the basins up to a the level where the yellow and blue regions meet and a first watershed is build. e) As (d) but filling up the basins to a higher level where a second watershed is build between the blue and red region. f) Watershed transform of (c). g) (f) masked with (b).






Activities


Show activity for:  

ImageJ Macro: MorpholibJ basic watershed

/*
 * Basic watershed in Fiji
 * 
 * Requirements: 
 * - IJPB-Plugins update site
 */

run("Close All");
setOption("BlackBackground", true);


open("https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_8bit__touching_objects.tif");
rename("input");

// create mask
run("Duplicate...", "title=mask");
setThreshold(14, 255);
run("Convert to Mask");

// invert
selectWindow("input");
run("Duplicate...", "title=invert");
run("Invert");
run("Enhance Contrast", "saturated=0.35");

// watershed
run("Classic Watershed", "input=invert mask=None use min=0 max=255");
rename("watershed");

// watershed with mask
selectWindow("invert");
run("Classic Watershed", "input=invert mask=mask use min=0 max=255");
rename("instance segmentation");
run("glasbey_inverted");

ImageJ GUI: MorpholibJ basic watershed

  • Open the input image, and invert it using [Edit > Invert] or [Ctrl+Shift+I]
  • Apply watershed transform on inverted image using [Plugins > MorpholibJ > Segmentation > Classic Watershed]
    • Input = xy_8bit__touching_objects.tif
    • Mask = none
    • [X] use diagonal connectivity
    • Min h = 0
    • Max h = 255
  • Create mask
    • Duplicate the input image using [Image > Duplicate] Title = mask
    • Find/apply threshold using [Image >Adjust > Threshold…] (e.g. Lower Threshold Level = 9) and press Apply
  • Apply watershed transform on inverted image and selecting mask using [Plugins > MorpholibJ > Segmentation > Classic Watershed]
    • Input = xy_8bit__touching_objects.tif
    • Mask = mask
    • [X] use diagonal connectivity
    • Min h = 0
    • Max h = 255

ImageJ Macro: MorpholibJ shape watershed

/*
 * Shape watershed (with distance transform)  in Fiji
 * 
 * Requirements: 
 * - IJPB-Plugins update site
 */

run("Close All");
setOption("BlackBackground", true);

// open image
open("https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_8bit__touching_objects_same_intensity.tif");
rename("input");

// create mask
run("Duplicate...", "title=mask");
setThreshold(83, 255);
run("Convert to Mask");

// create distance map
run("Chamfer Distance Map", "distances=[Chessknight (5,7,11)] output=[16 bits] normalize");
rename("dist");
run("Invert");
// remove spurious minima in distance map (choose sigma smaller than object radii)
run("Mean...", "sigma=20");

// watershed on distance map with mask
run("Classic Watershed", "input=dist mask=mask use min=0 max=255");

ImageJ Macro: MorpholibJ seeded watershed

/*
 * Seeded watershed (with distance transform)  in Fiji
 * 
 * Requirements: 
 * - IJPB-Plugins update site
 */

run("Close All");
setOption("BlackBackground", true);

open("https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_8bit__noisy_touching_objects.tif");
rename("input");
run("Duplicate...", "title=invert");
run("Invert");
run("Enhance Contrast", "saturated=0.35");

// watershed
run("Classic Watershed", "input=invert mask=None use min=0 max=255");

// seeded watershed
open("https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_8bit_binary__touching_objects_markers.tif");
rename("seeds");
run("Marker-controlled Watershed", "input=invert marker=seeds mask=None compactness=0 binary calculate use");

Exercises

Show exercise/solution for:

ImageJ Macro: MorpholibJ shape watershed

/*
 * Shape watershed (with distance transform)  in Fiji
 * 
 * Requirements: 
 * - IJPB-Plugins update site
 */

run("Close All");
setOption("BlackBackground", true);

open("https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_8bit__several_touching_nuclei.tif");
rename("input");

// create mask
run("Duplicate...", "title=mask");
setThreshold(61, 255);
run("Convert to Mask");

run("Chamfer Distance Map", "distances=[Chessknight (5,7,11)] output=[16 bits] normalize");
rename("dist");
run("Invert");
// remove spurious minima in distance map (choose sigma smaller than object radii)
run("Mean...", "sigma=2");

// watershed with mask
run("Classic Watershed", "input=dist mask=mask use min=0 max=255");

ImageJ Macro: MorpholibJ seeded watershed

/*
 * Seeded watershed in Fiji
 * 
 * Requirements: 
 * - IJPB-Plugins update site
 */

run("Close All");
setOption("BlackBackground", true);

// open and rename the images
open("https://github.com/NEUBIAS/training-resources/raw/master/image_data/watershed/xy_8bit_binary__tubulin.tif");
rename("tubulin_mask");

open("https://github.com/NEUBIAS/training-resources/raw/master/image_data/watershed/xy_8bit_binary__nuclei.tif");
rename("nuclei_mask");

open("https://github.com/NEUBIAS/training-resources/raw/master/image_data/watershed/xy_16bit__tubulin_smooth.tif");
rename("tubulin_smooth");

// invert tubulin image for watershed
selectWindow("tubulin_smooth");
run("Invert");

// watershed on inverted tubulin with nuclei as seeds and binary tubulin as mask
run("Marker-controlled Watershed", "input=tubulin_smooth marker=nuclei_mask mask=tubulin_mask compactness=0 binary");



Assessment

Fill in the blanks

Solution

  • label mask image
  • inverts and smoothes
  • seeded (or marker controlled)

Key points

  • A watershed transform can separate touching objects if there are intensity valleys (or ridges) between touching objects. In case of intensity ridges the image needs to be inverted before being subjected to the watershed transform.

  • To separate object by their shape, use a distance transform on the binary image and inject this into the watershed transform. It is often good to smooth the distance transform to remove spurious minima, which could serve as wrong seed points and thus lead to an over-segmentation.




Follow-up material

Recommended follow-up modules:

Learn more: