Merge pull request #457 from tonysyu/logo_refactor

RF: Refactor code that generates scikit-image logo.
This commit is contained in:
Stefan van der Walt
2013-03-07 10:02:08 -08:00
2 changed files with 81 additions and 145 deletions
+75 -135
View File
@@ -1,17 +1,26 @@
""" """
Script to draw skimage logo using Scipy logo as stencil. The easiest Script to draw skimage logo using Scipy logo as stencil. The easiest
starting point is the `plot_colorized_logo`; the "if-main" demonstrates its use. starting point is the `plot_colorized_logo`.
Original snake image from pixabay [1]_ Original snake image from pixabay [1]_
.. [1] http://pixabay.com/en/snake-green-toxic-close-yellow-3237/ .. [1] http://pixabay.com/en/snake-green-toxic-close-yellow-3237/
""" """
import numpy as np import sys
if len(sys.argv) != 2 or sys.argv[1] != '--no-plot':
print "Run with '--no-plot' flag to generate logo silently."
else:
import matplotlib as mpl
mpl.use('Agg')
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import scipy.misc
import numpy as np
import skimage.io as sio import skimage.io as sio
import skimage.filter as imfilt from skimage import img_as_float
from skimage.color import gray2rgb, rgb2gray
from skimage.exposure import rescale_intensity
from skimage.filter import sobel
import scipy_logo import scipy_logo
@@ -19,42 +28,21 @@ import scipy_logo
# Utility functions # Utility functions
# ================= # =================
def get_edges(img): def colorize(image, color, whiten=False):
edge = np.empty(img.shape) """Return colorized image from gray scale image.
if len(img.shape) == 3:
for i in range(3):
edge[:, :, i] = imfilt.sobel(img[:, :, i])
else:
edge = imfilt.sobel(img)
edge = rescale_intensity(edge)
return edge
def rescale_intensity(img): The colorized image has values from ranging between black at the lowest
i_range = float(img.max() - img.min()) intensity to `color` at the highest. If `whiten=True`, then the color
img = (img - img.min()) / i_range * 255 ranges from `color` to white.
return np.uint8(img)
def colorize(img, color, whiten=False):
"""Return colorized image from gray scale image
Parameters
----------
img : N x M array
grayscale image
color : length-3 sequence of floats
RGB color spec. Float values should be between 0 and 1.
whiten : bool
If True, a color value less than 1 increases the image intensity.
""" """
color = np.asarray(color)[np.newaxis, np.newaxis, :] color = np.asarray(color)[np.newaxis, np.newaxis, :]
img = img[:, :, np.newaxis] image = image[:, :, np.newaxis]
if whiten: if whiten:
# truncate and stretch intensity range to enhance contrast # truncate and stretch intensity range to enhance contrast
img = np.clip(img, 80, 255) image = rescale_intensity(image, in_range=(0.3, 1))
img = rescale_intensity(img) return color * (1 - image) + image
return np.uint8(color * (255 - img) + img)
else: else:
return np.uint8(img * color) return image * color
def prepare_axes(ax): def prepare_axes(ax):
@@ -65,16 +53,6 @@ def prepare_axes(ax):
spine.set_visible(False) spine.set_visible(False)
_rgb_stack = np.ones((1, 1, 3), dtype=bool)
def gray2rgb(arr):
"""Return RGB image from a grayscale image.
Expand h x w image to h x w x 3 image where color channels are simply copies
of the grayscale image.
"""
return arr[:, :, np.newaxis] * _rgb_stack
# Logo generating classes # Logo generating classes
# ======================= # =======================
@@ -82,21 +60,17 @@ class LogoBase(object):
def __init__(self): def __init__(self):
self.logo = scipy_logo.ScipyLogo(radius=self.radius) self.logo = scipy_logo.ScipyLogo(radius=self.radius)
self.mask_1 = self.logo.get_mask(self.img.shape, 'upper left') self.mask_1 = self.logo.get_mask(self.image.shape, 'upper left')
self.mask_2 = self.logo.get_mask(self.img.shape, 'lower right') self.mask_2 = self.logo.get_mask(self.image.shape, 'lower right')
self.edges = get_edges(self.img)
edges = np.array([sobel(img) for img in self.image.T]).T
# truncate and stretch intensity range to enhance contrast # truncate and stretch intensity range to enhance contrast
self.edges = np.clip(self.edges, 0, 100) self.edges = rescale_intensity(edges, in_range=(0, 0.4))
self.edges = rescale_intensity(self.edges)
def _crop_image(self, image):
def _crop_image(self, img):
w = 2 * self.radius w = 2 * self.radius
x, y = self.origin x, y = self.origin
return img[y:y+w, x:x+w] return image[y:y + w, x:x + w]
def get_canvas(self):
return 255 * np.ones(self.img.shape, dtype=np.uint8)
def plot_curve(self, **kwargs): def plot_curve(self, **kwargs):
self.logo.plot_snake_curve(**kwargs) self.logo.plot_snake_curve(**kwargs)
@@ -104,15 +78,13 @@ class LogoBase(object):
class SnakeLogo(LogoBase): class SnakeLogo(LogoBase):
def __init__(self): radius = 250
self.radius = 250 origin = (420, 0)
self.origin = (420, 0)
img = sio.imread('data/snake_pixabay.jpg')
img = self._crop_image(img)
img = img.astype(float) * 1.1 def __init__(self):
img[img > 255] = 255 image = sio.imread('data/snake_pixabay.jpg')
self.img = img.astype(np.uint8) image = self._crop_image(image)
self.image = img_as_float(image)
LogoBase.__init__(self) LogoBase.__init__(self)
@@ -120,107 +92,75 @@ class SnakeLogo(LogoBase):
snake_color = SnakeLogo() snake_color = SnakeLogo()
snake = SnakeLogo() snake = SnakeLogo()
# turn RGB image into gray image # turn RGB image into gray image
snake.img = np.mean(snake.img, axis=2) snake.image = rgb2gray(snake.image)
snake.edges = np.mean(snake.edges, axis=2) snake.edges = rgb2gray(snake.edges)
# Demo plotting functions # Demo plotting functions
# ======================= # =======================
def plot_colorized_logo(logo, color, edges='light', switch=False, whiten=False): def plot_colorized_logo(logo, color, edges='light', whiten=False):
"""Convenience function to plot artificially colored logo. """Convenience function to plot artificially-colored logo.
The upper-left half of the logo is an edge filtered image, while the
lower-right half is unfiltered.
Parameters Parameters
---------- ----------
logo : subclass of LogoBase logo : LogoBase instance
color : length-3 sequence of floats color : length-3 sequence of floats or 2 length-3 sequences
RGB color spec. Float values should be between 0 and 1. RGB color spec. Float values should be between 0 and 1.
edges : {'light'|'dark'} edges : {'light'|'dark'}
Specifies whether Sobel edges are drawn light or dark Specifies whether Sobel edges are drawn light or dark
switch : bool whiten : bool or 2 bools
If False, the image is drawn on the southeast half of the Scipy curve
and the edge image is drawn on northwest half.
whiten : bool
If True, a color value less than 1 increases the image intensity. If True, a color value less than 1 increases the image intensity.
""" """
if not hasattr(color[0], '__iter__'): if not hasattr(color[0], '__iter__'):
color = [color] * 2 color = [color] * 2 # use same color for upper-left & lower-right
if not hasattr(whiten, '__iter__'): if not hasattr(whiten, '__iter__'):
whiten = [whiten] * 2 whiten = [whiten] * 2 # use same setting for upper-left & lower-right
img = gray2rgb(logo.get_canvas())
image = gray2rgb(np.ones_like(logo.image))
mask_img = gray2rgb(logo.mask_2) mask_img = gray2rgb(logo.mask_2)
mask_edge = gray2rgb(logo.mask_1) mask_edge = gray2rgb(logo.mask_1)
if switch:
mask_img, mask_edge = mask_edge, mask_img # Compose image with colorized image and edge-image.
if edges == 'dark': if edges == 'dark':
lg_edge = colorize(255 - logo.edges, color[0], whiten=whiten[0]) logo_edge = colorize(1 - logo.edges, color[0], whiten=whiten[0])
else: else:
lg_edge = colorize(logo.edges, color[0], whiten=whiten[0]) logo_edge = colorize(logo.edges, color[0], whiten=whiten[0])
lg_img = colorize(logo.img, color[1], whiten=whiten[1]) logo_img = colorize(logo.image, color[1], whiten=whiten[1])
img[mask_img] = lg_img[mask_img] image[mask_img] = logo_img[mask_img]
img[mask_edge] = lg_edge[mask_edge] image[mask_edge] = logo_edge[mask_edge]
logo.plot_curve(lw=5, color='w')
plt.imshow(img)
logo.plot_curve(lw=5, color='w') # plot snake curve on current axes
def red_light_edges(logo, **kwargs): plt.imshow(image)
plot_colorized_logo(logo, (1, 0, 0), edges='light', **kwargs)
def red_dark_edges(logo, **kwargs):
plot_colorized_logo(logo, (1, 0, 0), edges='dark', **kwargs)
def blue_light_edges(logo, **kwargs):
plot_colorized_logo(logo, (0.35, 0.55, 0.85), edges='light', **kwargs)
def blue_dark_edges(logo, **kwargs):
plot_colorized_logo(logo, (0.35, 0.55, 0.85), edges='dark', **kwargs)
def green_orange_light_edges(logo, **kwargs):
colors = ((0.6, 0.8, 0.3), (1, 0.5, 0.1))
plot_colorized_logo(logo, colors, edges='light', **kwargs)
def green_orange_dark_edges(logo, **kwargs):
colors = ((0.6, 0.8, 0.3), (1, 0.5, 0.1))
plot_colorized_logo(logo, colors, edges='dark', **kwargs)
if __name__ == '__main__': if __name__ == '__main__':
# Colors to use for the logo:
import sys red = (1, 0, 0)
plot = False blue = (0.35, 0.55, 0.85)
if len(sys.argv) < 2 or sys.argv[1] != '--no-plot': green_orange = ((0.6, 0.8, 0.3), (1, 0.5, 0.1))
plot = True
print "Run with '--no-plot' flag to generate logo silently."
def plot_all(): def plot_all():
plotters = (red_light_edges, red_dark_edges, color_list = [red, blue, green_orange]
blue_light_edges, blue_dark_edges, edge_list = ['light', 'dark']
green_orange_light_edges, green_orange_dark_edges) f, axes = plt.subplots(nrows=len(edge_list), ncols=len(color_list))
for axes_row, edges in zip(axes, edge_list):
f, axes_array = plt.subplots(nrows=2, ncols=len(plotters)) for ax, color in zip(axes_row, color_list):
for plot, ax_col in zip(plotters, axes_array.T): prepare_axes(ax)
prepare_axes(ax_col[0]) plot_colorized_logo(snake, color, edges=edges)
plot(snake)
prepare_axes(ax_col[1])
plot(snake, whiten=True)
plt.tight_layout() plt.tight_layout()
def plot_snake(): def plot_official_logo():
f, ax = plt.subplots() f, ax = plt.subplots()
prepare_axes(ax) prepare_axes(ax)
green_orange_dark_edges(snake, whiten=(False, True)) plot_colorized_logo(snake, green_orange, edges='dark',
whiten=(False, True))
plt.savefig('green_orange_snake.png', bbox_inches='tight') plt.savefig('green_orange_snake.png', bbox_inches='tight')
if plot: plot_all()
plot_all() plot_official_logo()
plot_snake()
if plot:
plt.show()
plt.show()
+6 -10
View File
@@ -3,10 +3,11 @@ Code used to trace Scipy logo.
""" """
import numpy as np import numpy as np
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import skimage.io as imgio
from scipy.misc import lena
import matplotlib.nxutils as nx import matplotlib.nxutils as nx
from skimage import io
from skimage import data
class SymmetricAnchorPoint(object): class SymmetricAnchorPoint(object):
"""Anchor point in a parametric curve with symmetric handles """Anchor point in a parametric curve with symmetric handles
@@ -185,7 +186,7 @@ class ScipyLogo(object):
def plot_image(self, **kwargs): def plot_image(self, **kwargs):
ax = kwargs.pop('ax', plt.gca()) ax = kwargs.pop('ax', plt.gca())
img = imgio.imread('data/scipy.png') img = io.imread('data/scipy.png')
ax.imshow(img, **kwargs) ax.imshow(img, **kwargs)
def get_mask(self, shape, region): def get_mask(self, shape, region):
@@ -236,9 +237,7 @@ def plot_snake_overlay():
logo = ScipyLogo((670, 250), 250) logo = ScipyLogo((670, 250), 250)
logo.plot_snake_curve() logo.plot_snake_curve()
logo.plot_circle() logo.plot_circle()
img = imgio.imread('data/snake_pixabay.jpg') img = io.imread('data/snake_pixabay.jpg')
#mask = logo.get_mask(img.shape, 'upper left')
#img[mask] = 255
plt.imshow(img) plt.imshow(img)
@@ -247,9 +246,7 @@ def plot_lena_overlay():
logo = ScipyLogo((300, 300), 180) logo = ScipyLogo((300, 300), 180)
logo.plot_snake_curve() logo.plot_snake_curve()
logo.plot_circle() logo.plot_circle()
img = lena() img = data.lena()
#mask = logo.get_mask(img.shape, 'upper left')
#img[mask] = 255
plt.imshow(img) plt.imshow(img)
@@ -259,4 +256,3 @@ if __name__ == '__main__':
plot_lena_overlay() plot_lena_overlay()
plt.show() plt.show()