将MatplotLib或自定义的色彩地图应用到OpenCV图像上

11

OpenCV的颜色映射数量有限。MatplotLib拥有更多的颜色映射,但将这些颜色映射应用于给定的OpenCV图像并不直观。在使用Python API时如何将来自下面页面的MatplotLib颜色映射应用于OpenCV图像?这类似于将自定义颜色映射应用于给定图像。

https://matplotlib.org/examples/color/colormaps_reference.html

3个回答

11

对于Python >= 2.7, cmapy包以一种便捷的方式提供了这个功能。安装方法如下:

Python 2.7:

pip install cmapy

Python 3.x:

pip3 install cmapy

或者,对于Anaconda(来自conda-forge):

conda install -c conda-forge cmapy 

然后像这样使用:

import cv2
import matplotlib.pyplot as plt
import cmapy

# Read image.
img = cv2.imread('imgs/woman.png')

# Colorize.
img_colorized = cv2.applyColorMap(img, cmapy.cmap('viridis'))

# Display
plt.imshow(img_colorized)
plt.show()
不同的色图效果如下:

查看所有可用的色图效果,请点击此处。 免责声明:我编写了cmapy(因为我需要将其用于另一个项目中),在内部,它基本上与其他答案做的一样。

1
迄今为止最简单的方法。我花了很长时间尝试使用LUTs在cv2中定义自己的颜色映射,但是没有进展。然后我转而使用MatplotLib的cmaps和cmapy,几乎瞬间就完成了。我真的无法推荐这个方法了。 - Clay Records

6

我自己回答这个问题,因为我在StackOverflow上没有找到一个简单的解决方案:

def apply_custom_colormap(image_gray, cmap=plt.get_cmap('seismic')):

    assert image_gray.dtype == np.uint8, 'must be np.uint8 image'
    if image_gray.ndim == 3: image_gray = image_gray.squeeze(-1)

    # Initialize the matplotlib color map
    sm = plt.cm.ScalarMappable(cmap=cmap)

    # Obtain linear color range
    color_range = sm.to_rgba(np.linspace(0, 1, 256))[:,0:3]    # color range RGBA => RGB
    color_range = (color_range*255.0).astype(np.uint8)         # [0,1] => [0,255]
    color_range = np.squeeze(np.dstack([color_range[:,2], color_range[:,1], color_range[:,0]]), 0)  # RGB => BGR

    # Apply colormap for each channel individually
    channels = [cv2.LUT(image_gray, color_range[:,i]) for i in range(3)]
    return np.dstack(channels)


image_gray = cv2.imread('./lena.jpg', cv2.IMREAD_GRAYSCALE)
image_bgr = apply_custom_colormap(image_gray, cmap=plt.get_cmap('bwr'))

cv2.imshow('image with colormap', image_bgr)
cv2.waitKey(0)

生成以下图片:

在此输入图片描述


6
在OpenCV的最新版本(从3.3开始),applyColorMap有一种重载方法,允许您提供自定义的色彩映射(1或3通道)。我修改了verified.human的代码,使其生成适用于此函数的颜色映射。
我利用了更多机会来简化代码:
  • ScalarMappable.to_rgba当您将bytes参数设置为True时,可以直接返回0-255范围内的字节。
  • 我们可以使用负步长的数组索引来删除alpha通道,并将RGB切换为BGR。
代码:
import cv2
import numpy as np
from matplotlib import pyplot as plt


def get_mpl_colormap(cmap_name):
    cmap = plt.get_cmap(cmap_name)

    # Initialize the matplotlib color map
    sm = plt.cm.ScalarMappable(cmap=cmap)

    # Obtain linear color range
    color_range = sm.to_rgba(np.linspace(0, 1, 256), bytes=True)[:,2::-1]

    return color_range.reshape(256, 1, 3)


image_gray = cv2.imread('cage.png', cv2.IMREAD_GRAYSCALE)
image_bgr = cv2.applyColorMap(image_gray, get_mpl_colormap('bwr'))

cv2.imshow('image with colormap', image_bgr)
cv2.waitKey()

3
指出颜色映射应该具有形状为(256,1,3)的形状,拯救了我的一天! - hkchengrex
@hkchengrex,你救了我的命!为什么没有在文档中说明LUT的形状必须是(256,1,3)呢?我卡了三个小时。 - Moritz Seppelt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接