mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-26 13:37:17 +08:00
Merge pull request #485 from tonysyu/image_label2rgb
ENH: Add `label2rgb`.
This commit is contained in:
@@ -160,8 +160,11 @@ individually.
|
||||
|
||||
"""
|
||||
|
||||
from skimage.color import label2rgb
|
||||
|
||||
segmentation = ndimage.binary_fill_holes(segmentation - 1)
|
||||
labeled_coins, _ = ndimage.label(segmentation)
|
||||
image_label_overlay = label2rgb(labeled_coins, image=coins)
|
||||
|
||||
plt.figure(figsize=(6, 3))
|
||||
plt.subplot(121)
|
||||
@@ -169,7 +172,7 @@ plt.imshow(coins, cmap=plt.cm.gray, interpolation='nearest')
|
||||
plt.contour(segmentation, [0.5], linewidths=1.2, colors='y')
|
||||
plt.axis('off')
|
||||
plt.subplot(122)
|
||||
plt.imshow(labeled_coins, cmap=plt.cm.spectral, interpolation='nearest')
|
||||
plt.imshow(image_label_overlay, interpolation='nearest')
|
||||
plt.axis('off')
|
||||
|
||||
plt.subplots_adjust(**margins)
|
||||
|
||||
@@ -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 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 = label2rgb(seg1, image=coins, 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 = label2rgb(seg2, image=coins, 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 = label2rgb(segj, image=coins, image_alpha=0.5)
|
||||
axes[3].imshow(color3, interpolation='nearest')
|
||||
axes[3].set_title('Join')
|
||||
|
||||
for ax in axes:
|
||||
|
||||
@@ -21,6 +21,7 @@ from skimage.filter import threshold_otsu
|
||||
from skimage.segmentation import clear_border
|
||||
from skimage.morphology import label, closing, square
|
||||
from skimage.measure import regionprops
|
||||
from skimage.color import label2rgb
|
||||
|
||||
|
||||
image = data.coins()[50:-50, 50:-50]
|
||||
@@ -37,9 +38,10 @@ clear_border(cleared)
|
||||
label_image = label(cleared)
|
||||
borders = np.logical_xor(bw, cleared)
|
||||
label_image[borders] = -1
|
||||
image_label_overlay = label2rgb(label_image, image=image)
|
||||
|
||||
fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(6, 6))
|
||||
ax.imshow(label_image, cmap='jet')
|
||||
ax.imshow(image_label_overlay)
|
||||
|
||||
for region in regionprops(label_image, ['Area', 'BoundingBox']):
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -41,6 +41,9 @@ from .colorconv import (convert_colorspace,
|
||||
is_rgb,
|
||||
is_gray)
|
||||
|
||||
from .colorlabel import color_dict, 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',
|
||||
'label2rgb']
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
import warnings
|
||||
import itertools
|
||||
|
||||
import numpy as np
|
||||
|
||||
from skimage import img_as_float
|
||||
from skimage._shared.utils import is_str
|
||||
from .colorconv import rgb2gray, gray2rgb
|
||||
from . import rgb_colors
|
||||
|
||||
|
||||
__all__ = ['color_dict', 'label2rgb', 'DEFAULT_COLORS']
|
||||
|
||||
|
||||
DEFAULT_COLORS = ('red', 'blue', 'yellow', 'magenta', 'green',
|
||||
'indigo', 'darkorange', 'cyan', 'pink', 'yellowgreen')
|
||||
|
||||
|
||||
color_dict = rgb_colors.__dict__
|
||||
|
||||
|
||||
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 label2rgb(label, image=None, 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
|
||||
----------
|
||||
label : array
|
||||
Integer array of labels with the same shape as `image`.
|
||||
image : array
|
||||
Image used as underlay for labels. If the input is an RGB image, it's
|
||||
converted to grayscale before coloring.
|
||||
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. Ignored if image is `None`.
|
||||
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]
|
||||
|
||||
if image is None:
|
||||
colorized = np.zeros(label.shape + (3,), dtype=np.float64)
|
||||
# Opacity doesn't make sense if no image exists.
|
||||
alpha = 1
|
||||
else:
|
||||
if not image.shape[:2] == label.shape:
|
||||
raise ValueError("`image` and `label` must be the same shape")
|
||||
|
||||
if image.min() < 0:
|
||||
warnings.warn("Negative intensities in `image` are not supported")
|
||||
|
||||
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
|
||||
@@ -0,0 +1,146 @@
|
||||
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)
|
||||
@@ -0,0 +1,74 @@
|
||||
import itertools
|
||||
|
||||
import numpy as np
|
||||
from numpy import testing
|
||||
from skimage.color.colorlabel import label2rgb
|
||||
from numpy.testing import assert_array_almost_equal as assert_close
|
||||
|
||||
|
||||
def test_shape_mismatch():
|
||||
image = np.ones((3, 3))
|
||||
label = np.ones((2, 2))
|
||||
testing.assert_raises(ValueError, label2rgb, image, label)
|
||||
|
||||
|
||||
def test_rgb():
|
||||
image = np.ones((1, 3))
|
||||
label = np.arange(3).reshape(1, -1)
|
||||
colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1)]
|
||||
# Set alphas just in case the defaults change
|
||||
rgb = label2rgb(label, image=image, colors=colors, alpha=1, image_alpha=1)
|
||||
assert_close(rgb, [colors])
|
||||
|
||||
|
||||
def test_alpha():
|
||||
image = np.random.uniform(size=(3, 3))
|
||||
label = np.random.randint(0, 9, size=(3, 3))
|
||||
# If we set `alpha = 0`, then rgb should match image exactly.
|
||||
rgb = label2rgb(label, image=image, alpha=0, image_alpha=1)
|
||||
assert_close(rgb[..., 0], image)
|
||||
assert_close(rgb[..., 1], image)
|
||||
assert_close(rgb[..., 2], image)
|
||||
|
||||
|
||||
def test_no_input_image():
|
||||
label = np.arange(3).reshape(1, -1)
|
||||
colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1)]
|
||||
rgb = label2rgb(label, colors=colors)
|
||||
assert_close(rgb, [colors])
|
||||
|
||||
|
||||
def test_image_alpha():
|
||||
image = np.random.uniform(size=(1, 3))
|
||||
label = np.arange(3).reshape(1, -1)
|
||||
colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1)]
|
||||
# If we set `image_alpha = 0`, then rgb should match label colors exactly.
|
||||
rgb = label2rgb(label, image=image, colors=colors, alpha=1, image_alpha=0)
|
||||
assert_close(rgb, [colors])
|
||||
|
||||
|
||||
def test_color_names():
|
||||
image = np.ones((1, 3))
|
||||
label = np.arange(3).reshape(1, -1)
|
||||
cnames = ['red', 'lime', 'blue']
|
||||
colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1)]
|
||||
# Set alphas just in case the defaults change
|
||||
rgb = label2rgb(label, image=image, colors=cnames, alpha=1, image_alpha=1)
|
||||
assert_close(rgb, [colors])
|
||||
|
||||
|
||||
def test_bg_and_color_cycle():
|
||||
image = np.zeros((1, 10)) # dummy image
|
||||
label = np.arange(10).reshape(1, -1)
|
||||
colors = [(1, 0, 0), (0, 0, 1)]
|
||||
bg_color = (0, 0, 0)
|
||||
rgb = label2rgb(label, image=image, bg_label=0, bg_color=bg_color,
|
||||
colors=colors, alpha=1)
|
||||
assert_close(rgb[0, 0], bg_color)
|
||||
for pixel, color in zip(rgb[0, 1:], itertools.cycle(colors)):
|
||||
assert_close(pixel, color)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testing.run_module_suite()
|
||||
|
||||
Reference in New Issue
Block a user