diff --git a/doc/examples/plot_join_segmentations.py b/doc/examples/plot_join_segmentations.py index 0a14df0d..b8bbd6c3 100644 --- a/doc/examples/plot_join_segmentations.py +++ b/doc/examples/plot_join_segmentations.py @@ -13,11 +13,11 @@ segmentations. import numpy as np from scipy import ndimage as nd import matplotlib.pyplot as plt -import matplotlib as mpl from skimage.filter import sobel from skimage.segmentation import slic, join_segmentations from skimage.morphology import watershed +from skimage.color import image_label2rgb from skimage import data @@ -43,24 +43,21 @@ seg2 = slic(coins_colour, n_segments=30, max_iter=160, sigma=1, ratio=9, # combine the two segj = join_segmentations(seg1, seg2) -### Display the result ### - -# make a random colormap for a set number of values -def random_cmap(im): - np.random.seed(9) - cmap_array = np.concatenate( - (np.zeros((1, 3)), np.random.rand(np.ceil(im.max()), 3))) - return mpl.colors.ListedColormap(cmap_array) - # show the segmentations fig, axes = plt.subplots(ncols=4, figsize=(9, 2.5)) axes[0].imshow(coins, cmap=plt.cm.gray, interpolation='nearest') axes[0].set_title('Image') -axes[1].imshow(seg1, cmap=random_cmap(seg1), interpolation='nearest') + +color1 = image_label2rgb(coins, seg1, bg_label=0) +axes[1].imshow(color1, interpolation='nearest') axes[1].set_title('Sobel+Watershed') -axes[2].imshow(seg2, cmap=random_cmap(seg2), interpolation='nearest') + +color2 = image_label2rgb(coins, seg2, image_alpha=0.5) +axes[2].imshow(color2, interpolation='nearest') axes[2].set_title('SLIC superpixels') -axes[3].imshow(segj, cmap=random_cmap(segj), interpolation='nearest') + +color3 = image_label2rgb(coins, segj, image_alpha=0.5) +axes[3].imshow(color3, interpolation='nearest') axes[3].set_title('Join') for ax in axes: diff --git a/skimage/_shared/utils.py b/skimage/_shared/utils.py index acdf9c16..3271cfb0 100644 --- a/skimage/_shared/utils.py +++ b/skimage/_shared/utils.py @@ -2,7 +2,18 @@ import warnings import functools -__all__ = ['deprecated'] +__all__ = ['deprecated', 'is_str'] + + +try: + isinstance("", basestring) + def is_str(s): + """Return True if `s` is a string. Safe for Python 2 and 3.""" + return isinstance(s, basestring) +except NameError: + def is_str(s): + """Return True if `s` is a string. Safe for Python 2 and 3.""" + return isinstance(s, str) class deprecated(object): diff --git a/skimage/color/__init__.py b/skimage/color/__init__.py index 52d6e760..de24fbe9 100644 --- a/skimage/color/__init__.py +++ b/skimage/color/__init__.py @@ -41,6 +41,9 @@ from .colorconv import (convert_colorspace, is_rgb, is_gray) +from .colorlabel import color_dict, image_label2rgb + + __all__ = ['convert_colorspace', 'rgb2hsv', 'hsv2rgb', @@ -82,4 +85,6 @@ __all__ = ['convert_colorspace', 'rgb_from_hpx', 'hpx_from_rgb', 'is_rgb', - 'is_gray'] + 'is_gray', + 'color_dict', + 'image_label2rgb'] diff --git a/skimage/color/colorlabel.py b/skimage/color/colorlabel.py new file mode 100644 index 00000000..22027401 --- /dev/null +++ b/skimage/color/colorlabel.py @@ -0,0 +1,92 @@ +import os +import ast +import itertools +import ConfigParser + +import numpy as np + +from skimage import img_as_float +from skimage._shared.utils import is_str +from .colorconv import rgb2gray, gray2rgb + + +__all__ = ['color_dict', 'image_label2rgb', 'DEFAULT_COLORS'] + + +DEFAULT_COLORS = ('red', 'blue', 'yellow', 'magenta', 'green', + 'indigo', 'darkorange', 'cyan', 'pink', 'yellowgreen') + + +def _load_colors(): + directory, _ = os.path.split(os.path.abspath(__file__)) + config_file = os.path.join(directory, 'colors.ini') + + parser = ConfigParser.ConfigParser() + parser.read(config_file) + return dict((k, ast.literal_eval(v)) for k, v in parser.items('colors')) +color_dict = _load_colors() + + +def _rgb_vector(color): + """Return RGB color as (1, 3) array. + + This RGB array gets multiplied by masked regions of an RGB image, which are + partially flattened by masking (i.e. dimensions 2D + RGB -> 1D + RGB). + + Parameters + ---------- + color : str or array + Color name in `color_dict` or RGB float values between [0, 1]. + """ + if is_str(color): + color = color_dict[color] + # slice to handle RGBA colors + return np.array(color[:3]).reshape(1, 3) + + +def image_label2rgb(image, label, colors=None, alpha=0.3, + bg_label=-1, bg_color=None, image_alpha=1): + """Return an RGB image where color-coded labels are painted over the image. + + Parameters + ---------- + image : array + Input image. If the input is an RGB image, it's converted to grayscale + before coloring. + label : array + Integer array of labels with the same shape as `image`. + colors : list + List of colors. If the number of labels exceeds the number of colors, + then the colors are cycled. + alpha : float [0, 1] + Opacity of colorized labels. + bg_label : int + Label that's treated as the background. + bg_color : str or array + Background color. Must be a name in `color_dict` or RGB float values + between [0, 1]. + image_alpha : float [0, 1] + Opacity of the image. + """ + if colors is None: + colors = DEFAULT_COLORS + colors = [_rgb_vector(c) for c in colors] + + image = img_as_float(rgb2gray(image)) + colorized = gray2rgb(image) * image_alpha + (1 - image_alpha) + + labels = list(set(label.flat)) + color_cycle = itertools.cycle(colors) + + if bg_label in labels: + labels.remove(bg_label) + if bg_color is not None: + labels.insert(0, bg_label) + bg_color = _rgb_vector(bg_color) + color_cycle = itertools.chain(bg_color, color_cycle) + + for c, i in itertools.izip(color_cycle, labels): + mask = (label == i) + colorized[mask] = c * alpha + colorized[mask] * (1 - alpha) + + return colorized diff --git a/skimage/color/colors.ini b/skimage/color/colors.ini new file mode 100644 index 00000000..659c0e36 --- /dev/null +++ b/skimage/color/colors.ini @@ -0,0 +1,147 @@ +[colors] +aliceblue = (0.941, 0.973, 1) +antiquewhite = (0.98, 0.922, 0.843) +aqua = (0, 1, 1) +aquamarine = (0.498, 1, 0.831) +azure = (0.941, 1, 1) +beige = (0.961, 0.961, 0.863) +bisque = (1, 0.894, 0.769) +black = (0, 0, 0) +blanchedalmond = (1, 0.922, 0.804) +blue = (0, 0, 1) +blueviolet = (0.541, 0.169, 0.886) +brown = (0.647, 0.165, 0.165) +burlywood = (0.871, 0.722, 0.529) +cadetblue = (0.373, 0.62, 0.627) +chartreuse = (0.498, 1, 0) +chocolate = (0.824, 0.412, 0.118) +coral = (1, 0.498, 0.314) +cornflowerblue = (0.392, 0.584, 0.929) +cornsilk = (1, 0.973, 0.863) +crimson = (0.863, 0.0784, 0.235) +cyan = (0, 1, 1) +darkblue = (0, 0, 0.545) +darkcyan = (0, 0.545, 0.545) +darkgoldenrod = (0.722, 0.525, 0.0431) +darkgray = (0.663, 0.663, 0.663) +darkgreen = (0, 0.392, 0) +darkgrey = (0.663, 0.663, 0.663) +darkkhaki = (0.741, 0.718, 0.42) +darkmagenta = (0.545, 0, 0.545) +darkolivegreen = (0.333, 0.42, 0.184) +darkorange = (1, 0.549, 0) +darkorchid = (0.6, 0.196, 0.8) +darkred = (0.545, 0, 0) +darksalmon = (0.914, 0.588, 0.478) +darkseagreen = (0.561, 0.737, 0.561) +darkslateblue = (0.282, 0.239, 0.545) +darkslategray = (0.184, 0.31, 0.31) +darkslategrey = (0.184, 0.31, 0.31) +darkturquoise = (0, 0.808, 0.82) +darkviolet = (0.58, 0, 0.827) +deeppink = (1, 0.0784, 0.576) +deepskyblue = (0, 0.749, 1) +dimgray = (0.412, 0.412, 0.412) +dimgrey = (0.412, 0.412, 0.412) +dodgerblue = (0.118, 0.565, 1) +firebrick = (0.698, 0.133, 0.133) +floralwhite = (1, 0.98, 0.941) +forestgreen = (0.133, 0.545, 0.133) +fuchsia = (1, 0, 1) +gainsboro = (0.863, 0.863, 0.863) +ghostwhite = (0.973, 0.973, 1) +gold = (1, 0.843, 0) +goldenrod = (0.855, 0.647, 0.125) +gray = (0.502, 0.502, 0.502) +green = (0, 0.502, 0) +greenyellow = (0.678, 1, 0.184) +grey = (0.502, 0.502, 0.502) +honeydew = (0.941, 1, 0.941) +hotpink = (1, 0.412, 0.706) +indianred = (0.804, 0.361, 0.361) +indigo = (0.294, 0, 0.51) +ivory = (1, 1, 0.941) +khaki = (0.941, 0.902, 0.549) +lavender = (0.902, 0.902, 0.98) +lavenderblush = (1, 0.941, 0.961) +lawngreen = (0.486, 0.988, 0) +lemonchiffon = (1, 0.98, 0.804) +lightblue = (0.678, 0.847, 0.902) +lightcoral = (0.941, 0.502, 0.502) +lightcyan = (0.878, 1, 1) +lightgoldenrodyellow = (0.98, 0.98, 0.824) +lightgray = (0.827, 0.827, 0.827) +lightgreen = (0.565, 0.933, 0.565) +lightgrey = (0.827, 0.827, 0.827) +lightpink = (1, 0.714, 0.757) +lightsalmon = (1, 0.627, 0.478) +lightseagreen = (0.125, 0.698, 0.667) +lightskyblue = (0.529, 0.808, 0.98) +lightslategray = (0.467, 0.533, 0.6) +lightslategrey = (0.467, 0.533, 0.6) +lightsteelblue = (0.69, 0.769, 0.871) +lightyellow = (1, 1, 0.878) +lime = (0, 1, 0) +limegreen = (0.196, 0.804, 0.196) +linen = (0.98, 0.941, 0.902) +magenta = (1, 0, 1) +maroon = (0.502, 0, 0) +mediumaquamarine = (0.4, 0.804, 0.667) +mediumblue = (0, 0, 0.804) +mediumorchid = (0.729, 0.333, 0.827) +mediumpurple = (0.576, 0.439, 0.859) +mediumseagreen = (0.235, 0.702, 0.443) +mediumslateblue = (0.482, 0.408, 0.933) +mediumspringgreen = (0, 0.98, 0.604) +mediumturquoise = (0.282, 0.82, 0.8) +mediumvioletred = (0.78, 0.0824, 0.522) +midnightblue = (0.098, 0.098, 0.439) +mintcream = (0.961, 1, 0.98) +mistyrose = (1, 0.894, 0.882) +moccasin = (1, 0.894, 0.71) +navajowhite = (1, 0.871, 0.678) +navy = (0, 0, 0.502) +oldlace = (0.992, 0.961, 0.902) +olive = (0.502, 0.502, 0) +olivedrab = (0.42, 0.557, 0.137) +orange = (1, 0.647, 0) +orangered = (1, 0.271, 0) +orchid = (0.855, 0.439, 0.839) +palegoldenrod = (0.933, 0.91, 0.667) +palegreen = (0.596, 0.984, 0.596) +palevioletred = (0.686, 0.933, 0.933) +papayawhip = (1, 0.937, 0.835) +peachpuff = (1, 0.855, 0.725) +peru = (0.804, 0.522, 0.247) +pink = (1, 0.753, 0.796) +plum = (0.867, 0.627, 0.867) +powderblue = (0.69, 0.878, 0.902) +purple = (0.502, 0, 0.502) +red = (1, 0, 0) +rosybrown = (0.737, 0.561, 0.561) +royalblue = (0.255, 0.412, 0.882) +saddlebrown = (0.545, 0.271, 0.0745) +salmon = (0.98, 0.502, 0.447) +sandybrown = (0.98, 0.643, 0.376) +seagreen = (0.18, 0.545, 0.341) +seashell = (1, 0.961, 0.933) +sienna = (0.627, 0.322, 0.176) +silver = (0.753, 0.753, 0.753) +skyblue = (0.529, 0.808, 0.922) +slateblue = (0.416, 0.353, 0.804) +slategray = (0.439, 0.502, 0.565) +slategrey = (0.439, 0.502, 0.565) +snow = (1, 0.98, 0.98) +springgreen = (0, 1, 0.498) +steelblue = (0.275, 0.51, 0.706) +tan = (0.824, 0.706, 0.549) +teal = (0, 0.502, 0.502) +thistle = (0.847, 0.749, 0.847) +tomato = (1, 0.388, 0.278) +turquoise = (0.251, 0.878, 0.816) +violet = (0.933, 0.51, 0.933) +wheat = (0.961, 0.871, 0.702) +white = (1, 1, 1) +whitesmoke = (0.961, 0.961, 0.961) +yellow = (1, 1, 0) +yellowgreen = (0.604, 0.804, 0.196)