.. _example_applications_plot_coins_segmentation.py:


===============================================================
Comparing edge-based segmentation and region-based segmentation
===============================================================

In this example, we will see how to segment objects from a background. We use
the ``coins`` image from ``skimage.data``, which shows several coins outlined
against a darker background.


.. code-block:: python

	
	import numpy as np
	import matplotlib.pyplot as plt
	
	from skimage import data
	
	coins = data.coins()
	hist = np.histogram(coins, bins=np.arange(0, 256))
	
	fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 3))
	ax1.imshow(coins, cmap=plt.cm.gray, interpolation='nearest')
	ax1.axis('off')
	ax2.plot(hist[1][:-1], hist[0], lw=2)
	ax2.set_title('histogram of grey values')
	
	

.. image:: images/plot_coins_segmentation_1.png

Thresholding
============

A simple way to segment the coins is to choose a threshold based on the
histogram of grey values. Unfortunately, thresholding this image gives a binary
image that either misses significant parts of the coins or merges parts of the
background with the coins:



.. code-block:: python

	
	fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(6, 3))
	ax1.imshow(coins > 100, cmap=plt.cm.gray, interpolation='nearest')
	ax1.set_title('coins > 100')
	ax1.axis('off')
	ax2.imshow(coins > 150, cmap=plt.cm.gray, interpolation='nearest')
	ax2.set_title('coins > 150')
	ax2.axis('off')
	margins = dict(hspace=0.01, wspace=0.01, top=1, bottom=0, left=0, right=1)
	fig.subplots_adjust(**margins)
	
	

.. image:: images/plot_coins_segmentation_2.png


Edge-based segmentation
=======================

Next, we try to delineate the contours of the coins using edge-based
segmentation. To do this, we first get the edges of features using the Canny
edge-detector.


.. code-block:: python

	
	from skimage.filter import canny
	edges = canny(coins/255.)
	
	fig, ax = plt.subplots(figsize=(4, 3))
	ax.imshow(edges, cmap=plt.cm.gray, interpolation='nearest')
	ax.axis('off')
	ax.set_title('Canny detector')
	
	

.. image:: images/plot_coins_segmentation_3.png

These contours are then filled using mathematical morphology.


.. code-block:: python

	
	from scipy import ndimage
	
	fill_coins = ndimage.binary_fill_holes(edges)
	
	fig, ax = plt.subplots(figsize=(4, 3))
	ax.imshow(fill_coins, cmap=plt.cm.gray, interpolation='nearest')
	ax.axis('off')
	ax.set_title('Filling the holes')
	
	

.. image:: images/plot_coins_segmentation_4.png

Small spurious objects are easily removed by setting a minimum size for valid
objects.


.. code-block:: python

	from skimage import morphology
	coins_cleaned = morphology.remove_small_objects(fill_coins, 21)
	
	fig, ax = plt.subplots(figsize=(4, 3))
	ax.imshow(coins_cleaned, cmap=plt.cm.gray, interpolation='nearest')
	ax.axis('off')
	ax.set_title('Removing small objects')
	
	

.. image:: images/plot_coins_segmentation_5.png

However, this method is not very robust, since contours that are not perfectly
closed are not filled correctly, as is the case for one unfilled coin above.


Region-based segmentation
=========================

We therefore try a region-based method using the watershed transform. First, we
find an elevation map using the Sobel gradient of the image.



.. code-block:: python

	
	from skimage.filter import sobel
	
	elevation_map = sobel(coins)
	
	fig, ax = plt.subplots(figsize=(4, 3))
	ax.imshow(elevation_map, cmap=plt.cm.jet, interpolation='nearest')
	ax.axis('off')
	ax.set_title('elevation_map')
	
	

.. image:: images/plot_coins_segmentation_6.png

Next we find markers of the background and the coins based on the extreme parts
of the histogram of grey values.


.. code-block:: python

	
	markers = np.zeros_like(coins)
	markers[coins < 30] = 1
	markers[coins > 150] = 2
	
	fig, ax = plt.subplots(figsize=(4, 3))
	ax.imshow(markers, cmap=plt.cm.spectral, interpolation='nearest')
	ax.axis('off')
	ax.set_title('markers')
	
	

.. image:: images/plot_coins_segmentation_7.png

Finally, we use the watershed transform to fill regions of the elevation map
starting from the markers determined above:



.. code-block:: python

	segmentation = morphology.watershed(elevation_map, markers)
	
	fig, ax = plt.subplots(figsize=(4, 3))
	ax.imshow(segmentation, cmap=plt.cm.gray, interpolation='nearest')
	ax.axis('off')
	ax.set_title('segmentation')
	
	

.. image:: images/plot_coins_segmentation_8.png

This last method works even better, and the coins can be segmented and labeled
individually.



.. code-block:: python

	
	from skimage.color import label2rgb
	
	segmentation = ndimage.binary_fill_holes(segmentation - 1)
	labeled_coins, _ = ndimage.label(segmentation)
	image_label_overlay = label2rgb(labeled_coins, image=coins)
	
	fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(6, 3))
	ax1.imshow(coins, cmap=plt.cm.gray, interpolation='nearest')
	ax1.contour(segmentation, [0.5], linewidths=1.2, colors='y')
	ax1.axis('off')
	ax2.imshow(image_label_overlay, interpolation='nearest')
	ax2.axis('off')
	
	fig.subplots_adjust(**margins)
	
	

.. image:: images/plot_coins_segmentation_9.png



.. code-block:: python

	
	plt.show()
	

**Python source code:** :download:`download <plot_coins_segmentation.py>`
(generated using ``skimage`` |version|)



**IPython Notebook:** :download:`download <./notebook/plot_coins_segmentation.ipynb>`
(generated using ``skimage`` |version|)

