{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "%matplotlib inline\n", "import matplotlib\n", "matplotlib.rcParams['image.cmap'] = 'gray'\n", "import matplotlib.pyplot as plt\n", "import numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercise: Going interplanetary\n", "\n", "The sun is one of the most spherical objects in our solar system.\n", "According to an [article in Scientific American](http://www.scientificamerican.com/gallery/well-rounded-sun-stays-nearly-spherical-even-when-it-freaks-out/):\n", "\n", "> Earth's closest star is one of the roundest objects humans have\n", "> measured. If you shrank the sun down to beach ball size, the\n", "> difference between its north-south and the east-west diameters would\n", "> be thinner than the width of a human hair, says Jeffery Kuhn, a\n", "> physicist and solar researcher at the University of Hawaii at\n", "> Manoa. \"Not only is it very round, but it's too round,\" he adds. The\n", "> sun is more spherical and more invariable than theories predict.\n", "\n", "If the sun is spherical, we should be able to fit a circle to a 2D\n", "slice of it! Your task is to do just that, using RANSAC and scikit-image's CircleModel.\n", "\n", "Let's start by loading an example image:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from skimage import io\n", "\n", "image = io.imread('../../images/superprom_prev.jpg')\n", "\n", "f, ax = plt.subplots(figsize=(8, 8))\n", "ax.imshow(image);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this specific image, we got a bit more than we bargained for in the\n", "form of magnificently large solar flares. Let's see if some *canny\n", "edge detection* will help isolate the sun's boundaries." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from skimage import feature, color\n", "\n", "f, ax = plt.subplots(figsize=(10, 10))\n", "\n", "edges = feature.canny(color.rgb2gray(image), sigma=2)\n", "ax.imshow(edges, cmap='gray');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The edges look good, but there's a lot going on inside the sun. We\n", "use RANSAC to fit a robust circle model." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "from skimage.measure import ransac, CircleModel\n", "\n", "points = np.array(np.nonzero(edges)).T\n", "\n", "model_robust, inliers = ransac(points, CircleModel, min_samples=3,\n", " residual_threshold=2, max_trials=5000)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The parameters of the circle are center x, y and radius:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "model_robust.params" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's visualize the results, drawing a circle on the sun, and also\n", "highlighting inlier vs outlier edge pixels:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from skimage import draw\n", "\n", "cy, cx, r = model_robust.params\n", "\n", "f, (ax0, ax1) = plt.subplots(1, 2, figsize=(15, 8))\n", "\n", "ax0.imshow(image)\n", "ax1.imshow(image)\n", "\n", "ax1.plot(points[inliers, 1], points[inliers, 0], 'b.', markersize=1)\n", "ax1.plot(points[~inliers, 1], points[~inliers, 0], 'g.', markersize=1)\n", "ax1.axis('image')\n", "\n", "circle = plt.Circle((cx, cy), radius=r, facecolor='none', linewidth=2)\n", "ax0.add_patch(circle);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The circular fit is, indeed, excellent, and rejects all the inner\n", "squiggly edges generated by solar turbulence!\n", "\n", "Note a general principle here: algorithms that aggregate across an\n", "entire path are often robust against noise. Here, we have *high\n", "uncertainty* in the solar edge, but also know that only the solar edge\n", "pixels contribute coherently to the full circular path around the\n", "solar edge." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercise: CardShark\n", "\n", "Your small start-up, CardShark, run from your garage over nights and\n", "evenings, takes photos of credit cards and turns them into machine\n", "readable information.\n", "\n", "The first step is to identify where in a photo the credit card is\n", "located.\n", "\n", "1. Load the photo `../../images/credit_card.jpg`\n", "2. Using RANSAC and LineModelND shown above, find the first most\n", " prominent edge of the card\n", "3. Remove the datapoints belonging to the most prominent edge, and\n", " repeat the process to find the second, third, and fourth" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f, ax = plt.subplots()\n", "\n", "image = io.imread('../../images/credit_card.jpg')\n", "ax.imshow(image);" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from skimage.measure import LineModelND\n", "\n", "f, ax = plt.subplots(figsize=(10, 10))\n", "\n", "edges = feature.canny(color.rgb2gray(image), sigma=3)\n", "edge_pts = np.array(np.nonzero(edges), dtype=float).T\n", "edge_pts_xy = edge_pts[:, ::-1]\n", "\n", "for i in range(4):\n", " model_robust, inliers = ransac(edge_pts_xy, LineModelND, min_samples=2,\n", " residual_threshold=1, max_trials=1000)\n", "\n", " x = np.arange(800)\n", " plt.plot(x, model_robust.predict_y(x))\n", "\n", " edge_pts_xy = edge_pts_xy[~inliers]\n", "\n", "plt.imshow(edges);" ] } ], "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.6.0" } }, "nbformat": 4, "nbformat_minor": 1 }