From 40cc93a92d65bf104358d7bbea9230ed73b57d72 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Thu, 27 Mar 2014 22:47:22 -0500 Subject: [PATCH 1/3] Add example of tinting a grayscale image --- doc/examples/plot_tinting_grayscale_images.py | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 doc/examples/plot_tinting_grayscale_images.py diff --git a/doc/examples/plot_tinting_grayscale_images.py b/doc/examples/plot_tinting_grayscale_images.py new file mode 100644 index 00000000..ee5d0365 --- /dev/null +++ b/doc/examples/plot_tinting_grayscale_images.py @@ -0,0 +1,148 @@ +""" +========================= +Tinting gray-scale images +========================= + +It can be useful to artificially tint an image with some color, either to +highlight particular regions of an image or maybe just to liven up a grayscale +image. This example demonstrates image-tinting by scaling RGB values and by +adjusting colors in the HSV color-space. + +In 2D, color images are often represented in RGB---3 layers of 2D arrays, where +the 3 layers represent (R)ed, (G)reen and (B)lue channels of the image. The +simplest way of getting a tinted image is to set each RGB channel to the +grayscale image scaled by a different multiplier for each channel. For example, +if I want a red image, I can just multiply my green and blue channels by 0 so +that only the red channel appears. Similarly, I can zero-out the blue channel, +leaving only the red and green channels, which combine to form yellow. +""" + +import matplotlib.pyplot as plt +from skimage import data +from skimage import color +from skimage import img_as_float + +grayscale_image = img_as_float(data.camera()[::2, ::2]) +image = color.gray2rgb(grayscale_image) + +red_multiplier = [1, 0, 0] +yellow_multiplier = [1, 1, 0] + +fig, (ax1, ax2) = plt.subplots(ncols=2) +ax1.imshow(red_multiplier * image) +ax2.imshow(yellow_multiplier * image) + +""" +.. image:: PLOT2RST.current_figure + +In many cases, dealing with RGB values may not be ideal. Because of that, there +are many other `color spaces`_ in which you can represent a color image. One +popular color space is called HSV_, which represents hue (~the color), +saturation (~colorfulness), and value (~brightness). For example, a color +(hue) might be green, but it's saturation is how intense that green is---where +olive is on the low end and neon on the high end. + +In some implementations, the hue in HSV goes from 0 to 360, since hues wrap +around in a circle. In scikit-image, however, hues are float values from 0 to +1, so that hue, saturation, and value all share the same scale. + +Below, we plot a linear gradient in the hue, with the saturation and value +turned all the way up: +""" +import numpy as np + +hue_gradient = np.linspace(0, 1) +hsv = np.ones(shape=(1, len(hue_gradient), 3), dtype=float) +hsv[:, :, 0] = hue_gradient + +all_hues = color.hsv2rgb(hsv) + +fig, ax = plt.subplots(figsize=(5, 2)) +# Set image extent so hues go from 0 to 1 and the image is a nice aspect ratio. +ax.imshow(all_hues, extent=(0, 1, 0, 0.2)) +ax.set_axis_off() + +""" +.. image:: PLOT2RST.current_figure + +Notice how the colors at the far left and far right are the same. That reflects +the fact that the hues wrap around like the color wheel (see HSV_ for more +info). + +Now, lets create a little utility function to take an RGB image and: + +1. Transform the RGB image to HSV +2. Set the hue and saturation +3. Transform the HSV image back to RGB + +""" + +def colorize(image, hue, saturation=1): + """ Add color of the given hue to an RGB image. + + By default, set the saturation to 1 so that the colors to pop! + """ + hsv = color.rgb2hsv(image) + hsv[:, :, 1] = saturation + hsv[:, :, 0] = hue + return color.hsv2rgb(hsv) + +""" +Notice that we need to bump up the saturation; images with zero saturation are +grayscale, so we need to a non-zero value to actually see the color we've set. + +Using the function above, we plot six images with a linear gradient in the hue +and a non-zero saturation: +""" + +hue_rotations = np.linspace(0, 1, 6) + +fig, axes = plt.subplots(nrows=2, ncols=3) + +for ax, hue in zip(axes.flat, hue_rotations): + # Turn down the saturation to give it that vintage look. + tinted_image = colorize(image, hue, saturation=0.3) + ax.imshow(tinted_image, vmin=0, vmax=1) + ax.set_axis_off() +fig.tight_layout() + +""" +.. image:: PLOT2RST.current_figure + +You can combine this tinting effect with numpy slicing and fancy-indexing to +selectively tint your images. In the example below, we set the hue of some +rectangles using slicing and scale the RGB values of some pixels found by +thresholding. In practice, you might want to define a region for tinting based +on segmentation results or blob detection methods. +""" + +# Square regions defined as slices over the first two dimensions. +top_left = (slice(100),) * 2 +bottom_right = (slice(-100, None),) * 2 + +image[top_left] = colorize(image[top_left], 0) +image[bottom_right] = colorize(image[bottom_right], 0.5) + +# Create a mask selecting the brightest pixels and scale the RGB values. +# Note that using `colorize` here is a bit more difficult, since `rgb2hsv` +# expects an RGB image (height x width x channel), but fancy-indexing returns +# a set of RGB pixels (# pixels x channel). +bright_pixels = image[:, :, 0] > 0.75 +image[bright_pixels, :] *= yellow_multiplier + +fig, ax = plt.subplots() +ax.imshow(image) +ax.set_axis_off() + +plt.show() + +""" +.. image:: PLOT2RST.current_figure + +For coloring multiple regions, you may also be interested in +`skimage.color.label2rgb `_. + +.. _color spaces: + http://en.wikipedia.org/wiki/List_of_color_spaces_and_their_uses +.. _HSV: http://en.wikipedia.org/wiki/HSL_and_HSV +""" From a881d2fc5f6fc9d8d7ce76456f0d0a504f01f263 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 29 Mar 2014 10:28:08 -0500 Subject: [PATCH 2/3] Incorporate PR feedback - Change wording to remove "I" - Fix typo - Resize figure for better display - Create mask using entropy filter to improve colored regions --- doc/examples/plot_tinting_grayscale_images.py | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/doc/examples/plot_tinting_grayscale_images.py b/doc/examples/plot_tinting_grayscale_images.py index ee5d0365..56bd9765 100644 --- a/doc/examples/plot_tinting_grayscale_images.py +++ b/doc/examples/plot_tinting_grayscale_images.py @@ -12,9 +12,9 @@ In 2D, color images are often represented in RGB---3 layers of 2D arrays, where the 3 layers represent (R)ed, (G)reen and (B)lue channels of the image. The simplest way of getting a tinted image is to set each RGB channel to the grayscale image scaled by a different multiplier for each channel. For example, -if I want a red image, I can just multiply my green and blue channels by 0 so -that only the red channel appears. Similarly, I can zero-out the blue channel, -leaving only the red and green channels, which combine to form yellow. +multiplying the green and blue channels by 0 leaves only the red channel and +produces a bright red image. Similarly, zeroing-out the blue channel leaves +only the red and green channels, which combine to form yellow. """ import matplotlib.pyplot as plt @@ -28,7 +28,7 @@ image = color.gray2rgb(grayscale_image) red_multiplier = [1, 0, 0] yellow_multiplier = [1, 1, 0] -fig, (ax1, ax2) = plt.subplots(ncols=2) +fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(8, 4)) ax1.imshow(red_multiplier * image) ax2.imshow(yellow_multiplier * image) @@ -80,7 +80,7 @@ Now, lets create a little utility function to take an RGB image and: def colorize(image, hue, saturation=1): """ Add color of the given hue to an RGB image. - By default, set the saturation to 1 so that the colors to pop! + By default, set the saturation to 1 so that the colors pop! """ hsv = color.rgb2hsv(image) hsv[:, :, 1] = saturation @@ -116,23 +116,28 @@ thresholding. In practice, you might want to define a region for tinting based on segmentation results or blob detection methods. """ +from skimage.filter import rank + # Square regions defined as slices over the first two dimensions. top_left = (slice(100),) * 2 bottom_right = (slice(-100, None),) * 2 -image[top_left] = colorize(image[top_left], 0) -image[bottom_right] = colorize(image[bottom_right], 0.5) +sliced_image = image.copy() +sliced_image[top_left] = colorize(image[top_left], 0.82, saturation=0.5) +sliced_image[bottom_right] = colorize(image[bottom_right], 0.5, saturation=0.5) -# Create a mask selecting the brightest pixels and scale the RGB values. +# Create a mask selecting regions with interesting texture. +noisy = rank.entropy(grayscale_image, np.ones((9, 9))) +textured_regions = noisy > 4 # Note that using `colorize` here is a bit more difficult, since `rgb2hsv` # expects an RGB image (height x width x channel), but fancy-indexing returns # a set of RGB pixels (# pixels x channel). -bright_pixels = image[:, :, 0] > 0.75 -image[bright_pixels, :] *= yellow_multiplier +masked_image = image.copy() +masked_image[textured_regions, :] *= red_multiplier -fig, ax = plt.subplots() -ax.imshow(image) -ax.set_axis_off() +fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(8, 4)) +ax1.imshow(sliced_image) +ax2.imshow(masked_image) plt.show() From 040890f5943f6ca8c80eac1b3df5f57bc12e80f3 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 29 Mar 2014 18:49:57 -0500 Subject: [PATCH 3/3] Fix a couple of grammar typos --- doc/examples/plot_tinting_grayscale_images.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/examples/plot_tinting_grayscale_images.py b/doc/examples/plot_tinting_grayscale_images.py index 56bd9765..8b07b41d 100644 --- a/doc/examples/plot_tinting_grayscale_images.py +++ b/doc/examples/plot_tinting_grayscale_images.py @@ -39,7 +39,7 @@ In many cases, dealing with RGB values may not be ideal. Because of that, there are many other `color spaces`_ in which you can represent a color image. One popular color space is called HSV_, which represents hue (~the color), saturation (~colorfulness), and value (~brightness). For example, a color -(hue) might be green, but it's saturation is how intense that green is---where +(hue) might be green, but its saturation is how intense that green is---where olive is on the low end and neon on the high end. In some implementations, the hue in HSV goes from 0 to 360, since hues wrap @@ -69,7 +69,7 @@ Notice how the colors at the far left and far right are the same. That reflects the fact that the hues wrap around like the color wheel (see HSV_ for more info). -Now, lets create a little utility function to take an RGB image and: +Now, let's create a little utility function to take an RGB image and: 1. Transform the RGB image to HSV 2. Set the hue and saturation