{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Image Manipulation with skimage" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This example builds a simple UI for performing basic image manipulation with [scikit-image](http://scikit-image.org/)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Stdlib imports\n", "from io import BytesIO\n", "\n", "# Third-party libraries\n", "from IPython.display import Image\n", "from ipywidgets import interact, interactive, fixed\n", "import matplotlib as mpl\n", "from skimage import data, filters, io, img_as_float\n", "import numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's load an image from scikit-image's collection, stored in the `data` module. These come back as regular numpy arrays:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "i = img_as_float(data.coffee())\n", "i.shape" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's make a little utility function for displaying Numpy arrays with the IPython display protocol:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def arr2img(arr):\n", " \"\"\"Display a 2- or 3-d numpy array as an image.\"\"\"\n", " if arr.ndim == 2:\n", " format, cmap = 'png', mpl.cm.gray\n", " elif arr.ndim == 3:\n", " format, cmap = 'jpg', None\n", " else:\n", " raise ValueError(\"Only 2- or 3-d arrays can be displayed as images.\")\n", " # Don't let matplotlib autoscale the color range so we can control overall luminosity\n", " vmax = 255 if arr.dtype == 'uint8' else 1.0\n", " with BytesIO() as buffer:\n", " mpl.image.imsave(buffer, arr, format=format, cmap=cmap, vmin=0, vmax=vmax)\n", " out = buffer.getvalue()\n", " return Image(out)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "arr2img(i)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, let's create a simple \"image editor\" function, that allows us to blur the image or change its color balance:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def edit_image(image, sigma=0.1, R=1.0, G=1.0, B=1.0):\n", " new_image = filters.gaussian(image, sigma=sigma, multichannel=True)\n", " new_image[:,:,0] = R*new_image[:,:,0]\n", " new_image[:,:,1] = G*new_image[:,:,1]\n", " new_image[:,:,2] = B*new_image[:,:,2]\n", " return arr2img(new_image)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can call this function manually and get a new image. For example, let's do a little blurring and remove all the red from the image:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "edit_image(i, sigma=5, R=0.1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But it's a lot easier to explore what this function does by controlling each parameter interactively and getting immediate visual feedback. IPython's `ipywidgets` package lets us do that with a minimal amount of code:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lims = (0.0,1.0,0.01)\n", "interact(edit_image, image=fixed(i), sigma=(0.0,10.0,0.1), R=lims, G=lims, B=lims);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Browsing the scikit-image gallery, and editing grayscale and jpg images\n", "\n", "The coffee cup isn't the only image that ships with scikit-image, the `data` module has others. Let's make a quick interactive explorer for this:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def choose_img(name):\n", " # Let's store the result in the global `img` that we can then use in our image editor below\n", " global img\n", " img = getattr(data, name)()\n", " return arr2img(img)\n", "\n", "# Skip 'load' and 'lena', two functions that don't actually return images\n", "interact(choose_img, name=sorted(set(data.__all__)-{'lena', 'load'}));" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And now, let's update our editor to cope correctly with grayscale and color images, since some images in the scikit-image collection are grayscale. For these, we ignore the red (R) and blue (B) channels, and treat 'G' as 'Grayscale':" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lims = (0.0, 1.0, 0.01)\n", "\n", "def edit_image(image, sigma, R, G, B):\n", " new_image = filters.gaussian(image, sigma=sigma, multichannel=True)\n", " if new_image.ndim == 3:\n", " new_image[:,:,0] = R*new_image[:,:,0]\n", " new_image[:,:,1] = G*new_image[:,:,1]\n", " new_image[:,:,2] = B*new_image[:,:,2]\n", " else:\n", " new_image = G*new_image\n", " return arr2img(new_image)\n", "\n", "interact(edit_image, image=fixed(img), sigma=(0.0, 10.0, 0.1), \n", " R=lims, G=lims, B=lims);" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "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.4" } }, "nbformat": 4, "nbformat_minor": 2 }