{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "> This is one of the 100 recipes of the [IPython Cookbook](http://ipython-books.github.io/), the definitive guide to high-performance scientific computing and data science in Python.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 11.3. Segmenting an image" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1. Let's import the packages." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "from skimage.data import coins\n", "from skimage.filter import threshold_otsu\n", "from skimage.segmentation import clear_border\n", "from skimage.morphology import closing, square\n", "from skimage.measure import regionprops, label\n", "from skimage.color import lab2rgb\n", "import matplotlib as mpl\n", "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "2. We create a function to display a grayscale image." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def show(img, cmap=None):\n", " cmap = cmap or plt.cm.gray\n", " plt.figure(figsize=(4,2));\n", " plt.imshow(img, cmap=cmap);\n", " plt.axis('off');\n", " plt.show();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "3. We retrieve a test image bundled in scikit-image, showing various coins on a plain background." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "img = coins()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "show(img)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "4. The first step to segment the image consists in finding an intensity threshold separating the (bright) coins from the (dark) background. **Otsu's method** defines a simple algorithm to find such a threshold automatically." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "threshold_otsu(img)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "show(img>107)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "5. There appears to be a problem in the top left corner of the image, with part of the background being too bright. Let's use the notebook widgets to find a better threshold." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from IPython.html import widgets\n", "@widgets.interact(t=(10, 240))\n", "def threshold(t):\n", " show(img>t)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "6. The threshold 120 looks better. The next step consists in cleaning the binary image by smoothing the coins and removing the border. Scikit-image contains a few functions for these purposes." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "img_bin = clear_border(closing(img>120, square(5)))\n", "show(img_bin)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "7. Next, we perform the segmentation task itself with the `label` function. This function detects the connected components in the image, and attributes a unique label to every component. Here, we color-code the labels in the binary image." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "labels = label(img_bin)\n", "show(labels, cmap=plt.cm.rainbow)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "8. Small artifacts in the image result in spurious labels that do not correspond to coins. Therefore we only keep components with more than 100 pixels. The `regionprops` function allows us to retrieve specific properties of the components (here, the area and the bounding box)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "regions = regionprops(labels)\n", "boxes = np.array([label['BoundingBox'] for label in regions \n", " if label['Area'] > 100])\n", "print(\"There are {0:d} coins.\".format(len(boxes)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "9. Finally, we show the label number on top of each component in the original image." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "plt.figure(figsize=(6,4));\n", "plt.imshow(img, cmap=plt.cm.gray);\n", "plt.axis('off');\n", "xs = boxes[:,[1,3]].mean(axis=1)\n", "ys = boxes[:,[0,2]].mean(axis=1)\n", "for i, box in enumerate(boxes):\n", " plt.text(xs[i]-5, ys[i]+5, str(i))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> You'll find all the explanations, figures, references, and much more in the book (to be released later this summer).\n", "\n", "> [IPython Cookbook](http://ipython-books.github.io/), by [Cyrille Rossant](http://cyrille.rossant.net), Packt Publishing, 2014 (500 pages)." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.4.2" } }, "nbformat": 4, "nbformat_minor": 0 }