Example Watershed with Seeds

From BoofCV
Revision as of 11:59, 11 June 2014 by Peter (talk | contribs) (Created page with "center|450px|Found watershed around particles drawn in red. Watershed is one of the earlier and still more popular image segmentatio...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search
Found watershed around particles drawn in red.

Watershed is one of the earlier and still more popular image segmentation routines. While very fast, one major problem it suffers from is that it generate an excessive number of regions. In certain applications you can overcome this problem by providing initial seeds to watershed.

Example Code:

Concepts:

  • Image Segmentation
  • Super Pixels

Related Examples:

Relevant Applets:

Example Code

/**
 * Watershed image segmentation will often produce an excessive number of regions since each local minimum is the
 * seed which creates a new region.  To get around this problem you can provide the seeds manually.  The down side
 * to providing manual seeds is that it is no longer a general purpose algorithm and requires knowledge of the image
 * structure to provide the seeds.  This example demonstrates how to do this.
 *
 * @author Peter Abeles
 */
public class ExampleWatershedWithSeeds {
	public static void main(String[] args) {

		BufferedImage image = UtilImageIO.loadImage("../data/applet/particles01.jpg");
		ImageUInt8 input = ConvertBufferedImage.convertFromSingle(image, null, ImageUInt8.class);

		// declare working data
		ImageUInt8 binary = new ImageUInt8(input.width,input.height);
		ImageSInt32 label = new ImageSInt32(input.width,input.height);

		// Try using the mean pixel value to create a binary image then erode it to separate the particles from
		// each other
		double mean = ImageStatistics.mean(input);
		ThresholdImageOps.threshold(input, binary, (int) mean, true);
		ImageUInt8 filtered = BinaryImageOps.erode8(binary, 2, null);
		int numRegions = BinaryImageOps.contour(filtered, ConnectRule.EIGHT, label).size() + 1;
		// +1 to regions because contour only counts blobs and not the background

		// The labeled image can be used as is.  A precondition for seeded watershed is that all seeds have an
		// ID > 0.  Luckily, a value of 0 was used for background pixels in the contour algorithm.
		WatershedVincentSoille1991 watershed = FactorySegmentationAlg.watershed(ConnectRule.FOUR);

		watershed.process(input,label);

		ImageSInt32 output = watershed.getOutput();

		BufferedImage outLabeled = VisualizeBinaryData.renderLabeledBG(label, numRegions, null);
		VisualizeRegions.watersheds(output,image);

		// Removing the watersheds and update the region count
		// NOTE: watershed.getTotalRegions() does not return correct results if seeds are used!
		watershed.removeWatersheds();
		numRegions -= 1;
		BufferedImage outRegions = VisualizeRegions.regions(output,numRegions,null);

		ShowImages.showWindow(outLabeled,"Seeds");
		ShowImages.showWindow(outRegions,"Regions");
		ShowImages.showWindow(image,"Watersheds");

		// Additional processing would be needed for this example to be really useful.
		// The watersheds can be used to characterize the background while the seed binary image the particles
		// From this the particles could be more accurately classified by assigning each pixel one of the two
		// just mentioned groups based distance
	}
}