「这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战」
何为色彩映射
在一些计算机视觉应用程序中,算法的输出结果是灰度图像。但是,人眼在感知彩色图像的变化时更加敏感,而不擅长观察灰度图像的变化。因此我们常常需要将灰度图像重新着色转换为等效的伪彩色图像。
OpenCV 中的色彩映射
为了执行这种色彩转换,OpenCV 包含多种色彩映射来增强可视化效果,cv2.applyColorMap()
函数在给定的图像上应用色彩映射,例如应用 cv2.COLORMAP_HSV
色彩映射:
img_COLORMAP_HSV = cv2.applyColorMap(gray_img, cv2.COLORMAP_HSV)
OpenCV定义的色彩映射如下(可以直接利用编号作为参数来调用相应色彩映射,类似别名):
色彩映射名 | 编号 |
---|---|
COLORMAP_AUTUMN | 0 |
COLORMAP_BONE | 1 |
COLORMAP_JET | 2 |
COLORMAP_WINTER | 3 |
COLORMAP_RAINBOW | 4 |
COLORMAP_OCEAN | 5 |
COLORMAP_SUMMER | 6 |
COLORMAP_SPRING | 7 |
COLORMAP_COOL | 8 |
COLORMAP_HSV | 9 |
COLORMAP_HOT | 11 |
COLORMAP_PINK | 10 |
COLORMAP_PARULA | 12 |
我们可以将把所有的颜色映射应用到同一个灰度图像上,并将它们绘制在同一个图形中:
def show_with_matplotlib(color_img, title, pos):
img_RGB = color_img[:, :, ::-1]
ax = plt.subplot(2, 7, pos)
plt.imshow(img_RGB)
plt.title(title, fontsize=8)
plt.axis('off')
# 加载图像并转化为灰度图像
gray_img = cv2.imread('12.png', cv2.IMREAD_GRAYSCALE)
# 色彩映射列表
colormaps = ["AUTUMN", "BONE", "JET", "WINTER", "RAINBOW", "OCEAN", "SUMMER", "SPRING", "COOL", "HSV", "HOT", "PINK", "PARULA"]
plt.figure(figsize=(12, 5))
plt.suptitle("Colormaps", fontsize=14, fontweight='bold')
show_with_matplotlib(cv2.cvtColor(gray_img, cv2.COLOR_GRAY2BGR), "GRAY", 1)
# 应用色彩映射
for idx, val in enumerate(colormaps):
show_with_matplotlib(cv2.applyColorMap(gray_img, idx), val, idx + 2)
plt.show()
程序的运行结果如下图所示:
在上图中,可以看到将所有预定义的颜色映射应用于灰度图像以增强可视化的效果。
自定义色彩映射
可以使用多种方法将自定义颜色映射应用于图像。
第一种方法是定义一个色彩映射,将 0
到 255
个灰度值映射到 256
种颜色。这可以通过创建大小为 256 x 1
的 8
位彩色图像来完成,以便存储所有创建的颜色。之后,可以以下方法通过查找表将图像的灰度强度映射到定义的颜色:
- 使用
cv2.LUT()
函数 - 使用
cv2.applyColorMap()
函数
需要注意的是,在创建大小为 256 x 1
的 8
位彩色图像用于存储图像时,如果打算使用 cv2.LUT()
,则应按如下方式创建图像:
lut = np.zeros((256, 3), dtype=np.uint8)
如果打算使用 cv2.cv2.applyColorMap()
,则应使用:
lut = np.zeros((256, 1, 3), dtype=np.uint8)
完整的代码如下:
import cv2
import numpy as np
import matplotlib.pyplot as plt
def apply_rand_custom_colormap_values(im_gray):
lut = np.random.randint(255, size=(256, 1, 3), dtype=np.uint8)
im_color = cv2.applyColorMap(im_gray, lut)
return im_color
def apply_rand_custom_colormap_values2(im_gray):
# 创建随机 LUT
lut = np.random.randint(255, size=(256, 3), dtype=np.uint8)
# 使用 cv2.LUT() 应用自定义色彩映射
s0, s1 = im_gray.shape
im_color = np.empty(shape=(s0, s1, 3), dtype=np.uint8)
for i in range(3):
im_color[..., i] = cv2.LUT(im_gray, lut[:, i])
return im_color
def show_with_matplotlib(color_img, title, pos):
img_RGB = color_img[:, :, ::-1]
ax = plt.subplot(1, 5, pos)
plt.imshow(img_RGB)
plt.title(title, fontsize=8)
plt.axis('off')
# 读取图像并转化为灰度图像
gray_img = cv2.cvtColor(cv2.imread('8.png'), cv2.COLOR_BGR2GRAY)
plt.figure(figsize=(12, 2))
plt.suptitle("Custom colormaps providing all values", fontsize=14, fontweight='bold')
show_with_matplotlib(cv2.cvtColor(gray_img, cv2.COLOR_GRAY2BGR), "gray", 1)
# 应用色彩映射
custom_rand_1 = apply_rand_custom_colormap_values(gray_img)
custom_rand_2 = apply_rand_custom_colormap_values2(gray_img)
# 可以自行创建固定值色彩映射并应用,与随机创建类似,在此不再赘述
# custom_values_1 = apply_custom_colormap_values(gray_img)
# custom_values_2 = apply_custom_colormap_values2(gray_img)
# 可视化
show_with_matplotlib(custom_rand_1, "cv2.applyColorMap()", 2)
show_with_matplotlib(custom_rand_2, "cv2.LUT()", 3)
plt.show()
自定义色彩映射的第二种方法是仅提供一些关键颜色,然后对这些值进行插值,以获得构建查找表所需的所有颜色。
编写 build_lut()
函数根据这些关键颜色构建查找表:基于 5 个预先定义的色点,调用 np.linespace()
在预定义的每个色点区间内计算均匀间隔的颜色:
def build_lut(cmap):
lut = np.empty(shape=(256, 3), dtype=np.uint8)
max = 256
# 构建查找表
lastval, lastcol = cmap[0]
for step, col in cmap[1:]:
val = int(step * max)
for i in range(3): lastval, val - lastval))
lut[lastval:val, i] = np.linspace(lastcol[i], col[i], val - lastval)
lastcol = col
lastval = val
return lut
然后应用自定义颜色映射:
def show_with_matplotlib(color_img, title, pos):
# 通道转换
img_RGB = color_img[:, :, ::-1]
ax = plt.subplot(2, 3, pos)
plt.imshow(img_RGB)
plt.title(title, fontsize=8)
plt.axis('off')
def apply_color_map_1(gray, cmap):
lut = build_lut(cmap)
s0, s1 = gray.shape
out = np.empty(shape=(s0, s1, 3), dtype=np.uint8)
for i in range(3):
out[..., i] = cv2.LUT(gray, lut[:, i])
return out
def apply_color_map_2(gray, cmap):
lut = build_lut(cmap)
lut_reshape = np.reshape(lut, (256, 1, 3))
im_color = cv2.applyColorMap(gray, lut_reshape)
return im_color
# 读取图像并转化为灰度图像
gray_img = cv2.cvtColor(cv2.imread('example.png'), cv2.COLOR_BGR2GRAY)
# 应用色彩映射
custom_1 = apply_color_map_1(gray_img, ((0, (255, 0, 255)), (0.25, (255, 0, 180)), (0.5, (255, 0, 120)),
(0.75, (255, 0, 60)), (1.0, (255, 0, 0))))
custom_2 = apply_color_map_1(gray_img, ((0, (0, 255, 128)), (0.25, (128, 184, 64)), (0.5, (255, 128, 0)),
(0.75, (64, 128, 224)), (1.0, (0, 128, 255))))
custom_3 = apply_color_map_2(gray_img, ((0, (255, 0, 255)), (0.25, (255, 0, 180)), (0.5, (255, 0, 120)),
(0.75, (255, 0, 60)), (1.0, (255, 0, 0))))
custom_4 = apply_color_map_2(gray_img, ((0, (0, 255, 128)), (0.25, (128, 184, 64)), (0.5, (255, 128, 0)),
(0.75, (64, 128, 224)), (1.0, (0, 128, 255))))
# 可视化
show_with_matplotlib(custom_1, "custom 1 using cv2.LUT()", 2)
show_with_matplotlib(custom_2, "custom 2 using cv2.LUT()", 3)
show_with_matplotlib(custom_3, "custom 3 using cv2.applyColorMap()", 5)
show_with_matplotlib(custom_4, "custom 4 using using cv2.applyColorMap()", 6)
在上图中,可以看到将两个自定义色彩映射应用于灰度图像的效果。
显示自定义色彩映射图例
最后,我们也可以在显示自定义颜色映射时提供图例。为了构建色彩映射图例,编写 build_lut_image()
:
def build_lut_image(cmap, height):
lut = build_lut(cmap)
image = np.repeat(lut[np.newaxis, ...], height, axis=0)
return image
其首先调用 build_lut()
函数以获取查找表。然后,调用 np.repeat()
以多次复制此查找表( height 次)。这是由于查找表的形状是 (256, 3),而输出图像的形状为 (height, 256, 3) ,为了增加新维度,我们还需要将 np.repeat()
与 np.newaxis()
一起使用:
image = np.repeat(lut[np.newaxis, ...], height, axis=0)
运行结果如下图所示:
在上图中,可以看到将两个自定义颜色映射应用于灰度图像并显示每个颜色映射的图例的效果。