备注
转到末尾 以下载完整的示例代码。或者通过 Binder 在浏览器中运行此示例。
着色灰度图像#
人工地用某种颜色给图像上色可能会有用,无论是为了突出图像的特定区域,还是可能只是为了让灰度图像更生动。这个例子通过缩放RGB值和在HSV颜色空间中调整颜色来演示图像上色。
在2D中,彩色图像通常以RGB表示——3层2D数组,其中3层分别表示图像的红色(R)、绿色(G)和蓝色(B)通道。获取着色图像的最简单方法是分别将每个RGB通道设置为灰度图像乘以每个通道的不同倍数。例如,将绿色和蓝色通道乘以0会只保留红色通道,从而生成一个亮红色图像。同样,将蓝色通道归零会只保留红色和绿色通道,它们结合形成黄色。
import matplotlib.pyplot as plt
from skimage import data
from skimage import color
from skimage import img_as_float, img_as_ubyte
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, figsize=(8, 4), sharex=True, sharey=True)
ax1.imshow(red_multiplier * image)
ax2.imshow(yellow_multiplier * image)
plt.show()
在许多情况下,处理RGB值可能并不理想。因此,有许多其他的 色彩空间 可以用来表示彩色图像。一个流行的色彩空间称为HSV,它表示色调(~颜色)、饱和度(~色彩鲜艳度)和明度(~亮度)。例如,一种颜色(色调)可能是绿色,但其饱和度表示绿色的强度——橄榄色在低饱和度端,而霓虹色在高饱和度端。
在某些实现中,HSV 中的色调从 0 到 360,因为色调在圆中环绕。然而,在 scikit-image 中,色调是 0 到 1 之间的浮点值,因此色调、饱和度和值都共享相同的刻度。
下面,我们绘制了一个色调的线性渐变,并将饱和度和值调到最大:
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 - 0.5 / len(hue_gradient), 1 + 0.5 / len(hue_gradient), 0, 0.2)
)
ax.set_axis_off()
注意最左边和最右边的颜色是相同的。这反映了色调像色轮一样环绕(参见 HSV 了解更多信息)。
现在,让我们创建一个小工具函数来处理一个RGB图像并:
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 pop!
"""
hsv = color.rgb2hsv(image)
hsv[:, :, 1] = saturation
hsv[:, :, 0] = hue
return color.hsv2rgb(hsv)
请注意,我们需要提高饱和度;饱和度为零的图像为灰度图像,因此我们需要一个非零值才能实际看到我们设置的颜色。
使用上述函数,我们绘制了六张图像,这些图像具有线性色调梯度和非零饱和度:
hue_rotations = np.linspace(0, 1, 6)
fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True)
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()
你可以将这种着色效果与 numpy 切片和花式索引结合起来,以选择性地为你的图像着色。在下面的示例中,我们使用切片设置了一些矩形的色调,并通过阈值处理找到的像素缩放 RGB 值。在实践中,你可能希望根据分割结果或斑点检测方法定义一个着色区域。
from skimage.filters import rank
# Square regions defined as slices over the first two dimensions.
top_left = (slice(25),) * 2
bottom_right = (slice(-25, None),) * 2
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 regions with interesting texture.
noisy = rank.entropy(img_as_ubyte(grayscale_image), np.ones((9, 9)))
textured_regions = noisy > 4.25
# 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).
masked_image = image.copy()
masked_image[textured_regions, :] *= red_multiplier
fig, (ax1, ax2) = plt.subplots(
ncols=2, nrows=1, figsize=(8, 4), sharex=True, sharey=True
)
ax1.imshow(sliced_image)
ax2.imshow(masked_image)
plt.show()
对于为多个区域着色,您可能也会对 skimage.color.label2rgb 感兴趣。
脚本总运行时间: (0 分钟 0.496 秒)