【youcans 的图像处理学习课】12. 彩色图像的处理

专栏地址:『youcans 的图像处理学习课』
文章目录:『youcans 的图像处理学习课 - 总目录』


【youcans 的图像处理学习课】12.彩色图像的处理

1. 图像的颜色空间转换

图像的色彩空间基础

色彩空间是指通过多个(通常为 3个或4个)颜色分量构成坐标系来表示各种颜色的模型系统。色彩空间中的每个像素点均代表一种颜色,各像素点的颜色是多个颜色分量的合成或描述。

彩色图像可以根据需要映射到某个色彩空间进行描述。在不同的工业环境或机器视觉应用中,使用的色彩空间各不相同。

常见的色彩空间包括:GRAY 色彩空间(灰度图像)、XYZ 色彩空间、YCrCb 色彩空间、HSV 色彩空间、HLS 色彩空间、CIELab 色彩空间、CIELuv 色彩空间、Bayer 色彩空间等。

计算机显示器采用 RGB 色彩空间,数字艺术创作经常采用 HSV/HSB 色彩空间,机器视觉和图像处理系统大量使用 HSl、HSL色彩空间。各颜色分量的含义分别为:

  • RGB:红色(Red)、绿色(Green)、蓝色(Blue);
  • HSV/HSB:色调(Hue)、饱和度(Saturation)和明度(Value/Brightness);
  • HSl:色调(Hue)、饱和度(Saturation)和灰度(Intensity);
  • HSL:包括色调(Hue)、饱和度(Saturation)和亮度(Luminance/Lightness)。

RGB 模型是一种加性色彩系统,色彩源于红、绿、蓝三基色。用于CRT显示器、数字扫描仪、数字摄像机和显示设备上,是当前应用最广泛的一种彩色模型。


图像的颜色空间转换公式

  1. RGB ⟷ \longleftrightarrow GRAY
    GRAY 表示灰度图像,通常指 cv_8U 灰度图,有256个灰度级:0-255。
    RGB → GRAY: g r a y = 0.299 ∗ R + 0.587 ∗ G + 0.114 ∗ B gray = 0.299*R + 0.587*G + 0.114*B gray=0.299R+0.587G+0.114B

  2. RGB ⟷ \longleftrightarrow HSV

V ← max ⁡ ( R , G , B ) S ← { [ V − m i n ( R , G , B ) ] / V , V ≠ 0 0 , V = 0 H ← { 60 ( G − B ) / [ V − m i n ( R , G , B ) ] , V = R 120 + 60 ( B − R ) / [ V − m i n ( R , G , B ) ] , V = G 240 + 60 ( R − G ) / [ V − m i n ( R , G , B ) ] , V = B 0 , R = G = B \begin{aligned} V & \leftarrow \max{(R,G,B)} \\ S & \leftarrow \begin{cases} [{V-min{(R,G,B)}}]/V, &V \neq 0\\ 0, &V=0 \end{cases}\\ H &\leftarrow \begin{cases} 60(G-B)/[{V-min{(R,G,B)}}], &V =R\\ 120+60(B-R)/[{V-min{(R,G,B)}}], &V =G\\ 240+60(R-G)/[{V-min{(R,G,B)}}], &V =B\\ 0, & R=G=B \end{cases} \end{aligned} VSHmax(R,G,B){[Vmin(R,G,B)]/V,0,V=0V=0 60(GB)/[Vmin(R,G,B)],120+60(BR)/[Vmin(R,G,B)],240+60(RG)/[Vmin(R,G,B)],0,V=RV=GV=BR=G=B

更多颜色空间转换公式,详见 OpenCV官方文档: OpenCV: Color conversions


图像的颜色空间转换

色彩空间类型转换,是指将图像从一个色彩空间转换到另一个色彩空间。例如,在进行图像的特征提取、距离计算时,往往先将图像从 RGB 色彩空间转换为灰度色彩空间。

函数 cv.cvtColor() 将图像从一个颜色空间转换为另一个颜色空间。

cv.cvtColor(src, code [, dst, dstCn]]) → dst

参数说明:

  • src:输入图像,nparray 多维数组,8位无符号/ 16位无符号/单精度浮点数格式
  • code:颜色空间转换代码,详见 ColorConversionCodes
  • dst:输出图像,大小和深度与 src 相同
  • dstCn:输出图像的通道数,0 表示由src和code自动计算。

注意事项:

  1. 如果使用 RGB 表示方法,要明确指定各通道的顺序为 RGB 或 BGR。
    OpenCV,PyQt5 和 Matplotlib 中都使用 RGB 模型表示彩色图像,数据格式为 Numpy 多维数组。
    但 OpenCV 中是 BGR 顺序,按照蓝/绿/红的次序排列;而 PyQt5、Matplotlib 中是 RGB 格式, 按照红/绿/蓝的次序排序。
    因此使用 plt.imshow() 显示 OpenCV 彩色图像时,先要进行颜色空间转换,使 Numpy 多维数组按照 RGB 格式排序。
    PyQt5 也使用 RGB 格式,在 PyQt5 中显示 OpenCV 彩色图像也要先转换为 RGB 格式。
  2. 灰度图像是单通道,在 OpenCV 和 Matplotlib 中都是 Numpy 二维数组。
  3. 彩色图像中各通道的像素值范围,及灰度图像的像素值范围,由图像像素的位深度 depth决定。
    CV_8U 是8位无符号格式,取值范围 0-255,这是大多数图像和视频格式的正常范围;CV_16U 是16位无符号格式,取值范围 0-65535;CV_32F 是单精度浮点数格式,取值范围0.0-1.0。
  4. 图像格式转换通常是线性变换,像素的位深度不影响变换结果;但在进行非线性计算或变换时,需要把 RGB 输入图像归一化到适当的取值范围,才能得到正确的结果。
  5. 如果使用 8位无符号格式 CV_8U,由于数据精度较低可能丢失部分信息,使用 16位或 32位数据格式可以解决这个问题。
  6. 如果转换后添加 alpha 通道,alpha 通道的取值为相应通道范围的最大值,CV_8U 图像为 255,CV_16U 图像为 65535,CV_32F 图像为 1.0。
  7. 该函数将图像由 GRAY 转换为 RGB 时,转换规则为:R=G=B=gray 。

例程 13.1:OpenCV 颜色空间转换类型

    # 13.1 OpenCV 颜色空间转换类型
    flags = [i for i in dir(cv) if i.startswith('COLOR_')]
    print(flags)

函数 cv.cvtColor 提供了 150 多种颜色空间转换类型,本例程可以查询 OpenCV 所支持的颜色转换类型。

运行结果:

[‘COLOR_BAYER_BG2BGR’, ‘COLOR_BAYER_BG2BGRA’, ‘COLOR_BAYER_BG2BGR_EA’, ‘COLOR_BAYER_BG2BGR_VNG’, ‘COLOR_BAYER_BG2GRAY’, ‘COLOR_BAYER_BG2RGB’, ‘COLOR_BAYER_BG2RGBA’, ‘COLOR_BAYER_BG2RGB_EA’, ‘COLOR_BAYER_BG2RGB_VNG’, ‘COLOR_BAYER_BGGR2BGR’, ‘COLOR_BAYER_BGGR2BGRA’, ‘COLOR_BAYER_BGGR2BGR_EA’, ‘COLOR_BAYER_BGGR2BGR_VNG’, ‘COLOR_BAYER_BGGR2GRAY’, ‘COLOR_BAYER_BGGR2RGB’, ‘COLOR_BAYER_BGGR2RGBA’, ‘COLOR_BAYER_BGGR2RGB_EA’, ‘COLOR_BAYER_BGGR2RGB_VNG’, ‘COLOR_BAYER_GB2BGR’, ‘COLOR_BAYER_GB2BGRA’, ‘COLOR_BAYER_GB2BGR_EA’, ‘COLOR_BAYER_GB2BGR_VNG’, ‘COLOR_BAYER_GB2GRAY’, ‘COLOR_BAYER_GB2RGB’, ‘COLOR_BAYER_GB2RGBA’, ‘COLOR_BAYER_GB2RGB_EA’, ‘COLOR_BAYER_GB2RGB_VNG’, ‘COLOR_BAYER_GBRG2BGR’, ‘COLOR_BAYER_GBRG2BGRA’, ‘COLOR_BAYER_GBRG2BGR_EA’, ‘COLOR_BAYER_GBRG2BGR_VNG’, ‘COLOR_BAYER_GBRG2GRAY’, ‘COLOR_BAYER_GBRG2RGB’, ‘COLOR_BAYER_GBRG2RGBA’, ‘COLOR_BAYER_GBRG2RGB_EA’, ‘COLOR_BAYER_GBRG2RGB_VNG’, ‘COLOR_BAYER_GR2BGR’, ‘COLOR_BAYER_GR2BGRA’, ‘COLOR_BAYER_GR2BGR_EA’, ‘COLOR_BAYER_GR2BGR_VNG’, ‘COLOR_BAYER_GR2GRAY’, ‘COLOR_BAYER_GR2RGB’, ‘COLOR_BAYER_GR2RGBA’, ‘COLOR_BAYER_GR2RGB_EA’, ‘COLOR_BAYER_GR2RGB_VNG’, ‘COLOR_BAYER_GRBG2BGR’, ‘COLOR_BAYER_GRBG2BGRA’, ‘COLOR_BAYER_GRBG2BGR_EA’, ‘COLOR_BAYER_GRBG2BGR_VNG’, ‘COLOR_BAYER_GRBG2GRAY’, ‘COLOR_BAYER_GRBG2RGB’, ‘COLOR_BAYER_GRBG2RGBA’, ‘COLOR_BAYER_GRBG2RGB_EA’, ‘COLOR_BAYER_GRBG2RGB_VNG’, ‘COLOR_BAYER_RG2BGR’, ‘COLOR_BAYER_RG2BGRA’, ‘COLOR_BAYER_RG2BGR_EA’, ‘COLOR_BAYER_RG2BGR_VNG’, ‘COLOR_BAYER_RG2GRAY’, ‘COLOR_BAYER_RG2RGB’, ‘COLOR_BAYER_RG2RGBA’, ‘COLOR_BAYER_RG2RGB_EA’, ‘COLOR_BAYER_RG2RGB_VNG’, ‘COLOR_BAYER_RGGB2BGR’, ‘COLOR_BAYER_RGGB2BGRA’, ‘COLOR_BAYER_RGGB2BGR_EA’, ‘COLOR_BAYER_RGGB2BGR_VNG’, ‘COLOR_BAYER_RGGB2GRAY’, ‘COLOR_BAYER_RGGB2RGB’, ‘COLOR_BAYER_RGGB2RGBA’, ‘COLOR_BAYER_RGGB2RGB_EA’, ‘COLOR_BAYER_RGGB2RGB_VNG’, ‘COLOR_BGR2BGR555’, ‘COLOR_BGR2BGR565’, ‘COLOR_BGR2BGRA’, ‘COLOR_BGR2GRAY’, ‘COLOR_BGR2HLS’, ‘COLOR_BGR2HLS_FULL’, ‘COLOR_BGR2HSV’, ‘COLOR_BGR2HSV_FULL’, ‘COLOR_BGR2LAB’, ‘COLOR_BGR2LUV’, ‘COLOR_BGR2Lab’, ‘COLOR_BGR2Luv’, ‘COLOR_BGR2RGB’, ‘COLOR_BGR2RGBA’, ‘COLOR_BGR2XYZ’, ‘COLOR_BGR2YCR_CB’, ‘COLOR_BGR2YCrCb’, ‘COLOR_BGR2YUV’, ‘COLOR_BGR2YUV_I420’, ‘COLOR_BGR2YUV_IYUV’, ‘COLOR_BGR2YUV_YV12’, ‘COLOR_BGR5552BGR’, ‘COLOR_BGR5552BGRA’, ‘COLOR_BGR5552GRAY’, ‘COLOR_BGR5552RGB’, ‘COLOR_BGR5552RGBA’, ‘COLOR_BGR5652BGR’, ‘COLOR_BGR5652BGRA’, ‘COLOR_BGR5652GRAY’, ‘COLOR_BGR5652RGB’, ‘COLOR_BGR5652RGBA’, ‘COLOR_BGRA2BGR’, ‘COLOR_BGRA2BGR555’, ‘COLOR_BGRA2BGR565’, ‘COLOR_BGRA2GRAY’, ‘COLOR_BGRA2RGB’, ‘COLOR_BGRA2RGBA’, ‘COLOR_BGRA2YUV_I420’, ‘COLOR_BGRA2YUV_IYUV’, ‘COLOR_BGRA2YUV_YV12’, ‘COLOR_BayerBG2BGR’, ‘COLOR_BayerBG2BGRA’, ‘COLOR_BayerBG2BGR_EA’, ‘COLOR_BayerBG2BGR_VNG’, ‘COLOR_BayerBG2GRAY’, ‘COLOR_BayerBG2RGB’, ‘COLOR_BayerBG2RGBA’, ‘COLOR_BayerBG2RGB_EA’, ‘COLOR_BayerBG2RGB_VNG’, ‘COLOR_BayerBGGR2BGR’, ‘COLOR_BayerBGGR2BGRA’, ‘COLOR_BayerBGGR2BGR_EA’, ‘COLOR_BayerBGGR2BGR_VNG’, ‘COLOR_BayerBGGR2GRAY’, ‘COLOR_BayerBGGR2RGB’, ‘COLOR_BayerBGGR2RGBA’, ‘COLOR_BayerBGGR2RGB_EA’, ‘COLOR_BayerBGGR2RGB_VNG’, ‘COLOR_BayerGB2BGR’, ‘COLOR_BayerGB2BGRA’, ‘COLOR_BayerGB2BGR_EA’, ‘COLOR_BayerGB2BGR_VNG’, ‘COLOR_BayerGB2GRAY’, ‘COLOR_BayerGB2RGB’, ‘COLOR_BayerGB2RGBA’, ‘COLOR_BayerGB2RGB_EA’, ‘COLOR_BayerGB2RGB_VNG’, ‘COLOR_BayerGBRG2BGR’, ‘COLOR_BayerGBRG2BGRA’, ‘COLOR_BayerGBRG2BGR_EA’, ‘COLOR_BayerGBRG2BGR_VNG’, ‘COLOR_BayerGBRG2GRAY’, ‘COLOR_BayerGBRG2RGB’, ‘COLOR_BayerGBRG2RGBA’, ‘COLOR_BayerGBRG2RGB_EA’, ‘COLOR_BayerGBRG2RGB_VNG’, ‘COLOR_BayerGR2BGR’, ‘COLOR_BayerGR2BGRA’, ‘COLOR_BayerGR2BGR_EA’, ‘COLOR_BayerGR2BGR_VNG’, ‘COLOR_BayerGR2GRAY’, ‘COLOR_BayerGR2RGB’, ‘COLOR_BayerGR2RGBA’, ‘COLOR_BayerGR2RGB_EA’, ‘COLOR_BayerGR2RGB_VNG’, ‘COLOR_BayerGRBG2BGR’, ‘COLOR_BayerGRBG2BGRA’, ‘COLOR_BayerGRBG2BGR_EA’, ‘COLOR_BayerGRBG2BGR_VNG’, ‘COLOR_BayerGRBG2GRAY’, ‘COLOR_BayerGRBG2RGB’, ‘COLOR_BayerGRBG2RGBA’, ‘COLOR_BayerGRBG2RGB_EA’, ‘COLOR_BayerGRBG2RGB_VNG’, ‘COLOR_BayerRG2BGR’, ‘COLOR_BayerRG2BGRA’, ‘COLOR_BayerRG2BGR_EA’, ‘COLOR_BayerRG2BGR_VNG’, ‘COLOR_BayerRG2GRAY’, ‘COLOR_BayerRG2RGB’, ‘COLOR_BayerRG2RGBA’, ‘COLOR_BayerRG2RGB_EA’, ‘COLOR_BayerRG2RGB_VNG’, ‘COLOR_BayerRGGB2BGR’, ‘COLOR_BayerRGGB2BGRA’, ‘COLOR_BayerRGGB2BGR_EA’, ‘COLOR_BayerRGGB2BGR_VNG’, ‘COLOR_BayerRGGB2GRAY’, ‘COLOR_BayerRGGB2RGB’, ‘COLOR_BayerRGGB2RGBA’, ‘COLOR_BayerRGGB2RGB_EA’, ‘COLOR_BayerRGGB2RGB_VNG’, ‘COLOR_COLORCVT_MAX’, ‘COLOR_GRAY2BGR’, ‘COLOR_GRAY2BGR555’, ‘COLOR_GRAY2BGR565’, ‘COLOR_GRAY2BGRA’, ‘COLOR_GRAY2RGB’, ‘COLOR_GRAY2RGBA’, ‘COLOR_HLS2BGR’, ‘COLOR_HLS2BGR_FULL’, ‘COLOR_HLS2RGB’, ‘COLOR_HLS2RGB_FULL’, ‘COLOR_HSV2BGR’, ‘COLOR_HSV2BGR_FULL’, ‘COLOR_HSV2RGB’, ‘COLOR_HSV2RGB_FULL’, ‘COLOR_LAB2BGR’, ‘COLOR_LAB2LBGR’, ‘COLOR_LAB2LRGB’, ‘COLOR_LAB2RGB’, ‘COLOR_LBGR2LAB’, ‘COLOR_LBGR2LUV’, ‘COLOR_LBGR2Lab’, ‘COLOR_LBGR2Luv’, ‘COLOR_LRGB2LAB’, ‘COLOR_LRGB2LUV’, ‘COLOR_LRGB2Lab’, ‘COLOR_LRGB2Luv’, ‘COLOR_LUV2BGR’, ‘COLOR_LUV2LBGR’, ‘COLOR_LUV2LRGB’, ‘COLOR_LUV2RGB’, ‘COLOR_Lab2BGR’, ‘COLOR_Lab2LBGR’, ‘COLOR_Lab2LRGB’, ‘COLOR_Lab2RGB’, ‘COLOR_Luv2BGR’, ‘COLOR_Luv2LBGR’, ‘COLOR_Luv2LRGB’, ‘COLOR_Luv2RGB’, ‘COLOR_M_RGBA2RGBA’, ‘COLOR_RGB2BGR’, ‘COLOR_RGB2BGR555’, ‘COLOR_RGB2BGR565’, ‘COLOR_RGB2BGRA’, ‘COLOR_RGB2GRAY’, ‘COLOR_RGB2HLS’, ‘COLOR_RGB2HLS_FULL’, ‘COLOR_RGB2HSV’, ‘COLOR_RGB2HSV_FULL’, ‘COLOR_RGB2LAB’, ‘COLOR_RGB2LUV’, ‘COLOR_RGB2Lab’, ‘COLOR_RGB2Luv’, ‘COLOR_RGB2RGBA’, ‘COLOR_RGB2XYZ’, ‘COLOR_RGB2YCR_CB’, ‘COLOR_RGB2YCrCb’, ‘COLOR_RGB2YUV’, ‘COLOR_RGB2YUV_I420’, ‘COLOR_RGB2YUV_IYUV’, ‘COLOR_RGB2YUV_YV12’, ‘COLOR_RGBA2BGR’, ‘COLOR_RGBA2BGR555’, ‘COLOR_RGBA2BGR565’, ‘COLOR_RGBA2BGRA’, ‘COLOR_RGBA2GRAY’, ‘COLOR_RGBA2M_RGBA’, ‘COLOR_RGBA2RGB’, ‘COLOR_RGBA2YUV_I420’, ‘COLOR_RGBA2YUV_IYUV’, ‘COLOR_RGBA2YUV_YV12’, ‘COLOR_RGBA2mRGBA’, ‘COLOR_XYZ2BGR’, ‘COLOR_XYZ2RGB’, ‘COLOR_YCR_CB2BGR’, ‘COLOR_YCR_CB2RGB’, ‘COLOR_YCrCb2BGR’, ‘COLOR_YCrCb2RGB’, ‘COLOR_YUV2BGR’, ‘COLOR_YUV2BGRA_I420’, ‘COLOR_YUV2BGRA_IYUV’, ‘COLOR_YUV2BGRA_NV12’, ‘COLOR_YUV2BGRA_NV21’, ‘COLOR_YUV2BGRA_UYNV’, ‘COLOR_YUV2BGRA_UYVY’, ‘COLOR_YUV2BGRA_Y422’, ‘COLOR_YUV2BGRA_YUNV’, ‘COLOR_YUV2BGRA_YUY2’, ‘COLOR_YUV2BGRA_YUYV’, ‘COLOR_YUV2BGRA_YV12’, ‘COLOR_YUV2BGRA_YVYU’, ‘COLOR_YUV2BGR_I420’, ‘COLOR_YUV2BGR_IYUV’, ‘COLOR_YUV2BGR_NV12’, ‘COLOR_YUV2BGR_NV21’, ‘COLOR_YUV2BGR_UYNV’, ‘COLOR_YUV2BGR_UYVY’, ‘COLOR_YUV2BGR_Y422’, ‘COLOR_YUV2BGR_YUNV’, ‘COLOR_YUV2BGR_YUY2’, ‘COLOR_YUV2BGR_YUYV’, ‘COLOR_YUV2BGR_YV12’, ‘COLOR_YUV2BGR_YVYU’, ‘COLOR_YUV2GRAY_420’, ‘COLOR_YUV2GRAY_I420’, ‘COLOR_YUV2GRAY_IYUV’, ‘COLOR_YUV2GRAY_NV12’, ‘COLOR_YUV2GRAY_NV21’, ‘COLOR_YUV2GRAY_UYNV’, ‘COLOR_YUV2GRAY_UYVY’, ‘COLOR_YUV2GRAY_Y422’, ‘COLOR_YUV2GRAY_YUNV’, ‘COLOR_YUV2GRAY_YUY2’, ‘COLOR_YUV2GRAY_YUYV’, ‘COLOR_YUV2GRAY_YV12’, ‘COLOR_YUV2GRAY_YVYU’, ‘COLOR_YUV2RGB’, ‘COLOR_YUV2RGBA_I420’, ‘COLOR_YUV2RGBA_IYUV’, ‘COLOR_YUV2RGBA_NV12’, ‘COLOR_YUV2RGBA_NV21’, ‘COLOR_YUV2RGBA_UYNV’, ‘COLOR_YUV2RGBA_UYVY’, ‘COLOR_YUV2RGBA_Y422’, ‘COLOR_YUV2RGBA_YUNV’, ‘COLOR_YUV2RGBA_YUY2’, ‘COLOR_YUV2RGBA_YUYV’, ‘COLOR_YUV2RGBA_YV12’, ‘COLOR_YUV2RGBA_YVYU’, ‘COLOR_YUV2RGB_I420’, ‘COLOR_YUV2RGB_IYUV’, ‘COLOR_YUV2RGB_NV12’, ‘COLOR_YUV2RGB_NV21’, ‘COLOR_YUV2RGB_UYNV’, ‘COLOR_YUV2RGB_UYVY’, ‘COLOR_YUV2RGB_Y422’, ‘COLOR_YUV2RGB_YUNV’, ‘COLOR_YUV2RGB_YUY2’, ‘COLOR_YUV2RGB_YUYV’, ‘COLOR_YUV2RGB_YV12’, ‘COLOR_YUV2RGB_YVYU’, ‘COLOR_YUV420P2BGR’, ‘COLOR_YUV420P2BGRA’, ‘COLOR_YUV420P2GRAY’, ‘COLOR_YUV420P2RGB’, ‘COLOR_YUV420P2RGBA’, ‘COLOR_YUV420SP2BGR’, ‘COLOR_YUV420SP2BGRA’, ‘COLOR_YUV420SP2GRAY’, ‘COLOR_YUV420SP2RGB’, ‘COLOR_YUV420SP2RGBA’, ‘COLOR_YUV420p2BGR’, ‘COLOR_YUV420p2BGRA’, ‘COLOR_YUV420p2GRAY’, ‘COLOR_YUV420p2RGB’, ‘COLOR_YUV420p2RGBA’, ‘COLOR_YUV420sp2BGR’, ‘COLOR_YUV420sp2BGRA’, ‘COLOR_YUV420sp2GRAY’, ‘COLOR_YUV420sp2RGB’, ‘COLOR_YUV420sp2RGBA’, ‘COLOR_mRGBA2RGBA’]


例程 13.2:颜色空间转换

    # 13.2 OpenCV 颜色空间转换类型
    # 读取原始图像
    imgBGR = cv.imread("../images/imgLena.tif", flags=1)  # 读取为BGR彩色图像
    print(imgBGR.shape)

    imgRGB = cv.cvtColor(imgBGR, cv.COLOR_BGR2RGB)  # BGR 转换为 RGB, 用于 PyQt5, matplotlib
    imgGRAY = cv.cvtColor(imgBGR, cv.COLOR_BGR2GRAY)  # BGR 转换为灰度图像
    imgHSV = cv.cvtColor(imgBGR, cv.COLOR_BGR2HSV)  # BGR 转换为 HSV 图像
    imgYCrCb = cv.cvtColor(imgBGR, cv.COLOR_BGR2YCrCb)  # BGR转YCrCb
    imgHLS = cv.cvtColor(imgBGR, cv.COLOR_BGR2HLS)  # BGR 转 HLS 图像
    imgXYZ = cv.cvtColor(imgBGR, cv.COLOR_BGR2XYZ)  # BGR 转 XYZ 图像
    imgLAB = cv.cvtColor(imgBGR, cv.COLOR_BGR2LAB)  # BGR 转 LAB 图像
    imgYUV = cv.cvtColor(imgBGR, cv.COLOR_BGR2YUV)  # BGR 转 YUV 图像

    # 调用matplotlib显示处理结果
    titles = ['BGR', 'RGB', 'GRAY', 'HSV', 'YCrCb', 'HLS', 'XYZ', 'LAB', 'YUV']
    images = [imgBGR, imgRGB, imgGRAY, imgHSV, imgYCrCb,
              imgHLS, imgXYZ, imgLAB, imgYUV]
    plt.figure(figsize=(10, 8))
    for i in range(9):
        plt.subplot(3, 3, i + 1), plt.imshow(images[i], 'gray')
        plt.title(titles[i])
        plt.xticks([]), plt.yticks([])
    plt.tight_layout()
    plt.show()

在这里插入图片描述


3. 伪彩色图像处理

什么是伪彩色图像?

伪彩色图像是指对单色图像进行处理,结果转换得到颜色分量,构造为彩色效果的图像。伪彩色图像在形式和视觉表现为彩色图像,但其所呈现的颜色并非图像的真实色彩重现,仅仅是各颜色分量的像素值合成的结果。

(1)一类伪彩色图像是对灰度图像的增强,形成彩色效果。

伪彩色图像增强是指按照特定的准则对灰度图像进行处理,将不同的灰度级按照某种映射关系变换为不同的颜色分量。例如,天气预报中的气象云图,红外测温图像,一般都是伪彩色图像。

人眼的视觉特性,只能分辨 20 级左右的灰度,但可以分辨几千种色调和亮度。通过伪彩色图像增强,可以让灰度图像看起来更清楚,更容易分辨。

将灰度图像进行伪彩色增强,通常是基于一个设定的颜色查找表,将图像像素的灰度值替换为颜色查找表中对应的颜色值。这显然是典型的 LUT 应用场景。

(2)另一类伪彩色图像,是多光谱图像的编码合成图像。

光谱图像可以是可见光谱,也可以是红外、紫外、X光或其它信号。这些非可见光谱图像实际上既不是彩色图像,也不是灰度图像,“像素值”往往反映某种检测信号的强度。合成为彩色图像进行显示,只是为了便于观察和分析。

这在天文学观测中十分常用。NASA 公布的绚烂迷人的太空照片,并不是真实世界的色彩还原,而是将多种光谱信号图像进行编码组合和特效处理后,构造出的彩色图像。


函数原型

函数 cv.applyColorMap() 根据色彩映射表,将灰度图像变换为伪彩色图像。

cv.applyColorMap(src, colormap[, dst]) → dst
cv.applyColorMap(src, userColor[, dst]) → dst

参数说明:

  • src:输入图像,8 位灰度图像或彩色图像,cv_8U
  • dst:输出图像,大小和通道数与 src 相同
  • colormap:色彩映射表,OpenCV 自带色彩风格类型的颜色查找表
  • userColor:用户自定义的色彩映射表, 256个元素

注意事项:

  1. 输入图像可以是彩色图像。根据作者的测试,先将输入彩色图像转换为灰度图像,再按色彩映射表进行变换。
  2. 用户自定义的色彩映射表,是 256*3 数组。系统提供的 22种色彩映射表一般已经够用,就别折腾了。
  3. 例程中没有出现 cv.LUT 查表替换,在 cv.applyColorMap 内核中已经应用了查表替换方法。

色彩映射表:

  • OpenCV 提供了 22 种色彩风格类型,类型描述关键字与色彩效果如下图所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-52zKWfiW-1671353688902)(D:\OpenCV项目实战\images\colormap.png)]

  • OpenCV 提供的色彩风格类型与 Matlab、Matplotlib 热图的颜色映射是类似的,描述关键字也是一致的。
    参见:http://matplotlib.org/examples/color/colormaps_reference.html

例程 13.5:灰度图像转换为伪彩色图像

    # 13.5 灰度图像转换为伪彩色图像    
    gray = cv.imread("../images/Fig0525a.tif", flags=0)  # 读取灰度图像
    h, w = gray.shape[:2]  # 图片的高度, 宽度

    # 伪彩色处理
    pseudo1 = cv.applyColorMap(gray, colormap=cv.COLORMAP_HOT)
    pseudo2 = cv.applyColorMap(gray, colormap=cv.COLORMAP_PINK)
    pseudo3 = cv.applyColorMap(gray, colormap=cv.COLORMAP_RAINBOW)
    pseudo4 = cv.applyColorMap(gray, colormap=cv.COLORMAP_HSV)
    pseudo5 = cv.applyColorMap(gray, colormap=cv.COLORMAP_TURBO)

    plt.figure(figsize=(9, 6))
    plt.subplot(231), plt.axis('off'), plt.title("GRAY"), plt.imshow(gray, cmap='gray')
    plt.subplot(232), plt.axis('off'), plt.title("cv.COLORMAP_HOT")
    plt.imshow(cv.cvtColor(pseudo1, cv.COLOR_BGR2RGB))
    plt.subplot(233), plt.axis('off'), plt.title("cv.COLORMAP_PINK")
    plt.imshow(cv.cvtColor(pseudo2, cv.COLOR_BGR2RGB))
    plt.subplot(234), plt.axis('off'), plt.title("cv.COLORMAP_RAINBOW")
    plt.imshow(cv.cvtColor(pseudo3, cv.COLOR_BGR2RGB))
    plt.subplot(235), plt.axis('off'), plt.title("cv.COLORMAP_HSV")
    plt.imshow(cv.cvtColor(pseudo4, cv.COLOR_BGR2RGB))
    plt.subplot(236), plt.axis('off'), plt.title("cv.COLORMAP_TURBO")
    plt.imshow(cv.cvtColor(pseudo5, cv.COLOR_BGR2RGB))
    plt.tight_layout()
    plt.show()

在这里插入图片描述


例程 13.6:多光谱合成的伪彩色图像

蟹状星云 (Crab Nebula )的观测图像,是由钱德拉 X 射线天文台数据所形成的 X 射线图、哈勃太空望远镜拍摄的光学图像和斯必泽空间望远镜拍摄的红外图像合成得到的。

例程结果图中,第一行是 3 种天文观测图像的观测数据图像,图像中的灰度都只是观测的信号强度,而不是实际的物理世界的亮度或灰度。

第二行是分别对 3 种观测图像进行伪彩色变换的结果,如果选择不同的色彩风格可以获得不同的效果。

第三行是将 3 种观测信号合成得到的伪彩色图像,其中左图、中图是简单地将 3 种观测信号分别作为 RGB 的一个色彩通道得到的伪彩色图像,右图是 NASA 公布的多光谱合成伪彩色图像。虽然 NASA 图像的视觉效果更好,但仍然可以明显地看出,该图也是由第一行 3 种观测数据图像合成的。

    # 13.6 多光谱编码合成的伪彩色图像
    # 蟹状星云 (Crab Nebula), 图片来源:
    # https://www.nasa.gov/mission_pages/chandra/multimedia/photo09-096.html
    composite = cv.imread("../images/CrabNebula.png", flags=1)  # 读取多光谱合成图像
    nebulaOpti = cv.imread("../images/CrabNebula_Optical.jpg", flags=1)  # 读取 Optical
    nebulaXray = cv.imread("../images/CrabNebula_Xray.jpg", flags=1)  # 读取 Xray
    nebulaInfr = cv.imread("../images/CrabNebula_Infrared.jpg", flags=1)  # 读取 Infrared
    h, w = nebulaOpti.shape[:2]  # 图片的高度, 宽度

    grayOpti = cv.cvtColor(nebulaOpti, cv.COLOR_BGR2GRAY)
    grayXray = cv.cvtColor(nebulaXray, cv.COLOR_BGR2GRAY)
    grayInfr = cv.cvtColor(nebulaInfr, cv.COLOR_BGR2GRAY)

    # 伪彩色处理
    pseudoXray = cv.applyColorMap(nebulaXray, colormap=cv.COLORMAP_TURBO)
    pseudoOpti = cv.applyColorMap(nebulaOpti, colormap=cv.COLORMAP_MAGMA)
    pseudoInfr = cv.applyColorMap(nebulaInfr, colormap=cv.COLORMAP_HOT)

    # 多光谱编码合成
    compose1 = np.zeros((h, w, 3), np.uint8)  # 创建黑色图像 BGR=0
    compose1[:, :, 0] = grayOpti  # Optical -> B
    compose1[:, :, 1] = grayXray  # Xray -> G
    compose1[:, :, 2] = grayInfr  # Infrared -> R

    compose2 = np.zeros((h, w, 3), np.uint8)  # 创建黑色图像 BGR=0
    compose2[:, :, 0] = grayXray  # Xray -> B
    compose2[:, :, 1] = grayOpti  # Optical -> G
    compose2[:, :, 2] = grayInfr  # Infrared -> R

    # composite = cv.normalize(nebulaInfr + nebulaOpti, None, 0, 255, cv.NORM_MINMAX)  # 归一化为 [0,255]

    plt.figure(figsize=(9, 9))
    plt.subplot(331), plt.axis('off'), plt.title("CrabNebula-Xray")
    plt.imshow(grayXray, cmap='gray')
    plt.subplot(332), plt.axis('off'), plt.title("CrabNebula-Optical")
    plt.imshow(grayOpti, cmap='gray')
    plt.subplot(333), plt.axis('off'), plt.title("CrabNebula-Infrared")
    plt.imshow(grayInfr, cmap='gray')
    plt.subplot(334), plt.axis('off'), plt.title("Xray Pseudo")
    plt.imshow(cv.cvtColor(pseudoXray, cv.COLOR_BGR2RGB))
    plt.subplot(335), plt.axis('off'), plt.title("Optical Pseudo")
    plt.imshow(cv.cvtColor(pseudoOpti, cv.COLOR_BGR2RGB))
    plt.subplot(336), plt.axis('off'), plt.title("Infrared Pseudo")
    plt.imshow(cv.cvtColor(pseudoInfr, cv.COLOR_BGR2RGB))
    plt.subplot(337), plt.axis('off'), plt.title("Spectral composited")
    plt.imshow(cv.cvtColor(compose1, cv.COLOR_BGR2RGB))
    plt.subplot(338), plt.axis('off'), plt.title("Spectral composited")
    plt.imshow(cv.cvtColor(compose2, cv.COLOR_BGR2RGB))
    plt.subplot(339), plt.axis('off'), plt.title("Composite image")
    plt.imshow(cv.cvtColor(composite, cv.COLOR_BGR2RGB))
    plt.tight_layout()
    plt.show()

在这里插入图片描述


4. 图像的色彩风格滤镜

滤镜的原意是安装在相机镜头前过滤特定自然光的附加镜头,如紫外镜、偏光镜、渐变镜、雷登镜等。

在数字图像处理中,滤镜主要是用来实现图像的各种特殊效果,例如模仿在相机镜头前面加彩色滤镜,以便调整通过镜头传输的光的色彩平衡和色温。

Photoshop 提供的滤镜内容丰富,具有非常神奇的作用,可以为图片创造出绚目的效果。使用 OpenCV 也可以实现各种滤镜风格,本节介绍色彩风格变换滤镜。


4.1 使用 OpenCV 色彩风格滤镜

函数 cv.applyColorMap() 不仅可以将灰度图像变换为伪彩色图像,也可以应用于彩色图像,根据色彩映射表,对彩色图像进行颜色变换,实现不同的色彩风格。

cv.applyColorMap(src, colormap[, dst]) → dst
cv.applyColorMap(src, userColor[, dst]) → dst

输入图像是彩色图像时,先将彩色图像转换为灰度图像,再按色彩映射表进行变换。

参数说明:

  • src:输入图像,8 位灰度图像或彩色图像,cv_8U
  • dst:输出图像,大小和通道数与 src 相同
  • colormap:色彩映射表,OpenCV 自带色彩风格类型的颜色查找表
  • userColor:用户自定义的色彩映射表, 256个元素

色彩映射表:

  • OpenCV 提供了 22 种色彩风格类型,类型描述关键字与色彩效果如下图所示。
ColorMaps[] = { 
    "Autumn", "Bone", "Jet", "Winter", "Rainbow", "Ocean", "Summer", "Spring",
    "Cool", "HSV", "Pink", "Hot", "Parula", "Magma", "Inferno", "Plasma", "Viridis",
    "Cividis", "Twilight", "Twilight Shifted", "Turbo", "Deep Green"};

在这里插入图片描述


例程 13.8:图像特效之滤镜风格

函数 cv.applyColorMap() 的输入图像可以是彩色图像。

根据作者的测试,彩色图像将先被转换为灰度图像,再按色彩映射表进行变换。

    # 13.8 图像特效之色彩风格
    img = cv.imread("../images/imgLena.tif", flags=1)  # 读取彩色

    # 伪彩色处理
    pseudo1 = cv.applyColorMap(img, colormap=cv.COLORMAP_PINK)
    pseudo2 = cv.applyColorMap(img, colormap=cv.COLORMAP_CIVIDIS)
    pseudo3 = cv.applyColorMap(img, colormap=cv.COLORMAP_TWILIGHT_SHIFTED)
    pseudo4 = cv.applyColorMap(img, colormap=cv.COLORMAP_RAINBOW)
    pseudo5 = cv.applyColorMap(img, colormap=cv.COLORMAP_HOT)

    plt.figure(figsize=(9, 6))
    plt.subplot(231), plt.axis('off'), plt.title("Origin")
    plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
    plt.subplot(232), plt.axis('off'), plt.title("cv.COLORMAP_PINK")
    plt.imshow(cv.cvtColor(pseudo1, cv.COLOR_BGR2RGB))
    plt.subplot(233), plt.axis('off'), plt.title("cv.COLORMAP_CIVIDIS")
    plt.imshow(cv.cvtColor(pseudo2, cv.COLOR_BGR2RGB))
    plt.subplot(234), plt.axis('off'), plt.title("TWILIGHT_SHIFTED")
    plt.imshow(cv.cvtColor(pseudo3, cv.COLOR_BGR2RGB))
    plt.subplot(235), plt.axis('off'), plt.title("cv.COLORMAP_RAINBOW")
    plt.imshow(cv.cvtColor(pseudo4, cv.COLOR_BGR2RGB))
    plt.subplot(236), plt.axis('off'), plt.title("cv.COLORMAP_HOT")
    plt.imshow(cv.cvtColor(pseudo5, cv.COLOR_BGR2RGB))
    plt.tight_layout()
    plt.show()

在这里插入图片描述


例程 13.9:OpenCV 色彩方案全集

OpenCV 提供了 22 种色彩风格类型,类型描述关键字与色彩效果如下图所示。

ColorMaps[] = { 
    "Autumn", "Bone", "Jet", "Winter", "Rainbow", "Ocean", "Summer", "Spring",
    "Cool", "HSV", "Pink", "Hot", "Parula", "Magma", "Inferno", "Plasma", "Viridis",
    "Cividis", "Twilight", "Twilight Shifted", "Turbo", "Deep Green"};
    # 13.9 色彩风格变换之 OpenCV ColorMaps
    img = cv.imread("../images/imgLena.tif", flags=1)  # 读取彩色

    plt.figure(figsize=(12, 9))
    plt.subplot(4,6,1), plt.axis('off'), plt.title("Origin")
    plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
    plt.subplot(4,6,2), plt.axis('off'), plt.title("Gray")
    plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2GRAY), cmap='gray')

    # 色彩映射表类型描述
    ColorMaps = ["AUTUMN", "BONE", "JET", "WINTER", "RAINBOW", "OCEAN", "SUMMER", "SPRING",
        "COOL", "HSV", "PINK", "HOT", "PARULA", "MAGMA", "INFERNO", "PLASMA", "VIRIDIS",
        "CIVIDIS", "TWILIGHT", "TWILIGHT_SHIFTED", "TURBO", "DEEP_GREEN"]

    for i in range(len(ColorMaps)):
        cvmap = "cv.COLORMAP_"+ColorMaps[i]
        pseudo = cv.applyColorMap(img, colormap=i)
        print(cvmap)
        plt.subplot(4, 6, i+3), plt.axis('off'), plt.title(ColorMaps[i])
        plt.imshow(cv.cvtColor(pseudo, cv.COLOR_BGR2RGB))

    plt.tight_layout()
    plt.show()

在这里插入图片描述


4.2 使用 Matplotlib 中的色彩方案

OpenCV 提供的色彩风格类型与 Matlab、Matplotlib 热图的颜色映射是类似的。

Matplotlib 内置了很多 colormap。参见:http://matplotlib.org/examples/color/colormaps_reference.html

能否使用 Matplotlib 中的定义的色彩方案,实现色彩风格变换呢?

'Perceptually Uniform Sequential': # 亮度变化,饱和度增量
    'viridis', 'plasma', 'inferno', 'magma', 'cividis'
'Sequential': # 亮度变化,单一颜色
    'Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds',
    'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu',
    'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn'
'Sequential (2)': # 亮度变化,单一颜色
    'binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', 'pink',
    'spring', 'summer', 'autumn', 'winter', 'cool', 'Wistia',
    'hot', 'afmhot', 'gist_heat', 'copper'
'Diverging': # 亮度变化,两种颜色饱和度变化
    'PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu',
    'RdYlBu', 'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic'
'Cyclic': # 两种不同颜色亮度变化,饱和度循环,首尾颜色相同
    'twilight', 'twilight_shifted', 'hsv'
'Qualitative': # 离散颜色,没有顺序关系
     'Pastel1', 'Pastel2', 'Paired', 'Accent',
    'Dark2', 'Set1', 'Set2', 'Set3',
    'tab10', 'tab20', 'tab20b', 'tab20c'
'Miscellaneous': # 特定用途,如海洋地形等
    'flag', 'prism', 'ocean', 'gist_earth', 'terrain', 'gist_stern',
    'gnuplot', 'gnuplot2', 'CMRmap', 'cubehelix', 'brg',
    'gist_rainbow', 'rainbow', 'jet', 'turbo', 'nipy_spectral',
    'gist_ncar'

例程 13.10:色彩风格变换之使用 matplotlib 色彩方案

能否使用 Matplotlib 中的定义的色彩方案,实现色彩风格变换呢?

    # 13.10 色彩风格变换之使用 matplotlib 色彩方案
    img = cv.imread("../images/imgLena.tif", flags=1)  # 读取彩色
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

    plt.figure(figsize=(9, 6))
    plt.subplot(231), plt.axis('off'), plt.title("origin")
    plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))

    #  由 matplotlib 生成自定义色彩映射表
    from matplotlib import cm
    cmList = ["cm.copper", "cm.hot", "cm.YlOrRd", "cm.rainbow", "cm.prism"]
    for i in range(len(cmList)):
        cmMap = eval(cmList[i])(np.arange(256))
        # RGB(matplotlib) -> BGR(OpenCV)
        lutC3 = np.zeros((1, 256, 3))  # BGR(OpenCV)
        lutC3[0,:,0] = np.array(cmMap[:, 2] * 255).astype("uint8")  # B: cmHot[:, 2]
        lutC3[0,:,1] = np.array(cmMap[:, 1] * 255).astype("uint8")  # G: cmHot[:, 1]
        lutC3[0,:,2] = np.array(cmMap[:, 0] * 255).astype("uint8")  # R: cmHot[:, 0]

        cmLUTC3 = cv.LUT(img, lutC3).astype("uint8")
        print(img.shape, cmMap.shape, lutC3.shape)
        plt.subplot(2,3,i+2), plt.axis('off'), plt.title(cmList[i])
        plt.imshow(cv.cvtColor(cmLUTC3, cv.COLOR_BGR2RGB))

    plt.tight_layout()
    plt.show()

在这里插入图片描述


4.3 自己动手调节色彩平衡

色彩平衡是通过对颜色的调整使图像达到颜色平衡,可以用于调节颜色缺陷或表现效果。

使用色彩平衡更改图像中使用的色彩混合比例,可以创建生动的效果。调节色彩平衡是人们对图片色彩的主观喜好,并不需要遵循任何标准,是艺术性的实现。

在 Photoshop 中调节色彩平衡,只要拖动青色/红色、洋红/绿色或黄色/蓝色滑块,移向要增强的颜色。滑块上方的值可以在 -100~+100 调节,表示红色、绿色和蓝色通道的颜色变化。

本节用 OpenCV 程序,实现调节色彩平衡的功能。该例程也用于说明应用 LUT 对彩色图像进行颜色替换时构造多通道查找表的方法。

函数 cv.LUT() 中的查找表 lut,可以与输入彩色图像的通道数量相同,分别适用于输入图像的对应通道。多通道查找表 lut,是一个形状为 (1,256,3) 的 Numpy 数组,数据类型为 uint8。


例程 13.11:使用 LUT 调节色彩平衡

调节色彩平衡,可以通过对不同颜色分量分别进行对比度拉伸来实现。

简单地,设置各通道的最大值 maxG(<=255),将某颜色通道的色阶从 0-255 映射到 0-maxG,就可以使该颜色通道的色彩衰减。

容易想到,使用 OpenCV GUI 模块中提供的滚动条,交互地调节 R/G/B 通道的色彩强度。本系列例程为了使核心知识点更加简单易懂,并不采用较为复杂的综合性方法。

    # 13.11 使用 LUT 调节色彩平衡
    img = cv.imread("../images/imgGaia.tif", flags=1)  # 读取彩色

    maxG = 128  # 修改颜色通道最大值,0<=maxG<=255
    lutHalf = np.array([int(i * maxG/255) for i in range(256)]).astype("uint8")
    lutEqual = np.array([i for i in range(256)]).astype("uint8")

    lut3HalfB = np.dstack((lutHalf, lutEqual, lutEqual))  # (1,256,3), B_half/BGR
    lut3HalfG = np.dstack((lutEqual, lutHalf, lutEqual))  # (1,256,3), G_half/BGR
    lut3HalfR = np.dstack((lutEqual, lutEqual, lutHalf))  # (1,256,3), R_half/BGR

    blendHalfB = cv.LUT(img, lut3HalfB)  # B 通道衰减 50%
    blendHalfG = cv.LUT(img, lut3HalfG)  # G 通道衰减 50%
    blendHalfR = cv.LUT(img, lut3HalfR)  # R 通道衰减 50%

    print(img.shape, lutHalf.shape, lut3HalfB.shape, blendHalfB.shape)
    plt.figure(figsize=(9, 5))
    plt.subplot(131), plt.axis('off'), plt.title("B half decayed")
    plt.imshow(cv.cvtColor(blendHalfB, cv.COLOR_BGR2RGB))
    plt.subplot(132), plt.axis('off'), plt.title("G half decayed")
    plt.imshow(cv.cvtColor(blendHalfG, cv.COLOR_BGR2RGB))
    plt.subplot(133), plt.axis('off'), plt.title("R half decayed")
    plt.imshow(cv.cvtColor(blendHalfR, cv.COLOR_BGR2RGB))
    plt.tight_layout()
    plt.show()

在这里插入图片描述


例程 13.12:使用 LUT 调节饱和度、明度

调节色彩平衡,可以通过对不同颜色分量分别进行对比度拉伸来实现。

显然,不仅可以在 RGB 色彩空间调节色彩平衡,也可以在其它色彩空间对颜色通道的强度进行调节。

HSV 模型是针对用户观感的一种颜色模型,可以直观的表达色彩的色调明暗、及鲜艳程度,HSV 的含义分别为:色调(Hue)、饱和度(Saturation)和明度(Value)。

将图像从 RGB 色彩空间转换到 HSV 色彩空间后,用 LUT 对特定通道进行对比度拉伸,就可以调节图像的饱和度、明度。

    # 13.12 使用 LUT 调节饱和度和明度
    img = cv.imread("../images/imgGaia.tif", flags=1)  # 读取彩色
    hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)  # 色彩空间转换, BGR->HSV

    # 调节通道强度
    lutWeaken = np.array([int(0.6*i) for i in range(256)]).astype("uint8")
    lutEqual = np.array([i for i in range(256)]).astype("uint8")
    lutRaisen = np.array([int(102+0.6*i) for i in range(256)]).astype("uint8")
    # 调节饱和度
    lutSWeaken = np.dstack((lutEqual, lutWeaken, lutEqual))  # Saturation weaken
    lutSRaisen = np.dstack((lutEqual, lutRaisen, lutEqual))  # Saturation raisen
    # 调节明度
    lutVWeaken = np.dstack((lutEqual, lutEqual, lutWeaken))  # Value weaken
    lutVRaisen = np.dstack((lutEqual, lutEqual, lutRaisen))  # Value raisen

    blendSWeaken = cv.LUT(hsv, lutSWeaken)  # 饱和度降低
    blendSRaisen = cv.LUT(hsv, lutSRaisen)  # 饱和度增大
    blendVWeaken = cv.LUT(hsv, lutVWeaken)  # 明度降低
    blendVRaisen = cv.LUT(hsv, lutVRaisen)  # 明度升高

    plt.figure(figsize=(9, 6))
    plt.subplot(231), plt.axis('off'), plt.title("Saturation weaken")
    plt.imshow(cv.cvtColor(blendSWeaken, cv.COLOR_HSV2RGB))
    plt.subplot(232), plt.axis('off'), plt.title("Normal saturation")
    plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
    plt.subplot(233), plt.axis('off'), plt.title("Saturation raisen")
    plt.imshow(cv.cvtColor(blendSRaisen, cv.COLOR_HSV2RGB))
    plt.subplot(234), plt.axis('off'), plt.title("Value weaken")
    plt.imshow(cv.cvtColor(blendVWeaken, cv.COLOR_HSV2RGB))
    plt.subplot(235), plt.axis('off'), plt.title("Normal value")
    plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
    plt.subplot(236), plt.axis('off'), plt.title("Value raisen")
    plt.imshow(cv.cvtColor(blendVRaisen, cv.COLOR_HSV2RGB))
    plt.tight_layout()
    plt.show()

在这里插入图片描述


4.4 Photoshop 色阶自动调整算法(Auto Levels)

色阶调整算法

色彩平衡是通过对颜色的调整使图像达到颜色平衡,可以用于调节颜色缺陷或表现效果。

Photoshop 的色阶调整分为输入色阶调整和输出色阶调整。

输入色阶调整有 3 个调节参数:黑场阈值、白场阈值和灰场值:

  • S i n S_{in} Sin,输入图像的黑场阈值,input shadows
  • H i n H_{in} Hin,输入图像的白场阈值,input hithlight
  • M M M,中间调,灰场调节值,midtone

输入图像中低于黑场阈值的像素置 0 (黑色),高于白场阈值的像素置 255(白色)。灰场调节值默认值 1.0,调节范围 [0.01, 9.99]。灰场调节值增大的效果是加灰降对比度,减小的效果是减灰加对比度。

输出色阶调整有 2个调节参数:黑场阈值 S o u t S_{out} Sout、白场阈值 H o u t H_{out} Hout ,分别对应着输出图像的最小像素值、最大像素值。

在进行色阶调整时,Photoshop 显示图像的灰度直方图,为用户设置调节参数提供参考。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hYpz2LX9-1671353776776)(D:\OpenCV项目实战\images\PSsetup01.png)]

输入色阶调整算法,先根据黑场阈值和白场阈值对 RGB 颜色通道的动态范围进行线性拉伸,再根据灰场调节值进行幂律变换(伽马变换),对发白(曝光过度)或过暗(曝光不足)的图片进行矫正。

V 1 = { 0 , V i n < S i n 255 , V i n > H i n 255 ∗ ( V i n − S i n ) / ( H i n − S i n ) , e l s e V 2 = 255 ∗ ( V 1 / 255 ) 1 / M \begin{aligned} & V_1 = \begin{cases} 0 &, V_{in}<S_{in} \\ 255 &, V_{in}>H_{in} \\ 255 * {(V_{in}-S_{in})}/{(H_{in}-S_{in})} &, else \end{cases} \\ \\ & V_2 = 255 * (V_1 / 255)^{1/M} \end{aligned} V1= 0255255(VinSin)/(HinSin),Vin<Sin,Vin>Hin,elseV2=255(V1/255)1/M

输出色阶调整方法是基于动态范围进行线性拉伸:

V o u t = { 0 , V 2 < 0 255 , V 2 > 255 S o u t + ( H o u t − S o u t ) ∗ V 2 ∗ / 255 , e l s e V_{out} = \begin{cases} 0 &, V_{2}<0 \\ 255 &, V_{2}>255 \\ S_{out} + {(H_{out}-S_{out})} * V_2 */255 &, else \end{cases} Vout= 0255Sout+(HoutSout)V2/255,V2<0,V2>255,else

对彩色图像的各个颜色通道可以设置统一的白场、黑场和灰场参数;也可以对 R/G/B 各颜色通道分别设置白场、黑场和灰场参数,对各通道进行独立的色阶调节。但这会导致各通道的拉伸曲线不同,因此可能导致偏色。

色阶自动调整算法

除了手动设置参数调节色彩平衡, Photoshop 还提供了自动色阶(Auto Levels)功能。系统可以根据图像的曝光程度、明暗程度自动调节色彩平衡以达到最佳状态。自动色阶和自动对比度功能算法简单,对于一些图像的处理效果非常显著,具有很强的实用性。

Enhance Per Channel Contrast
Maximizes the tonal range in each channel to produce a more dramatic correction. Because each channel is adjusted individually, Enhance Per Channel Contrast may remove or introduce color casts. The Auto Tone command uses this algorithm.

参考文献: Set Auto adjustment options (adobe.com)

自动色阶调整的实现方法是,系统基于灰度直方图统计结果,自动设置色阶调整所需的参数,对 R/G/B 各通道的动态范围分别进行拉伸。

首先设置修剪比例,白场截断比 C l o w C_{low} Clow 和黑场截断比 C h i g h C_{high} Chigh 。默认值 0.1%,通常取 0.0~1.0%。修剪比例的作用是剔除一定比例的最小、最大灰度的像素,以排除个别异常噪声点的干扰。排除异常干扰后的最小、最大灰度值被设为图像中的黑场、白场基准。

具体地,将图像中灰度值最小的、比例为 C l o w C_{low} Clow 的像素剔除后的最小灰度值作为黑场阈值,将图像中灰度值最大的、比例为 C h i g h C_{high} Chigh 的像素剔除后的最大灰度值作为白场阈值。

例如,一个尺寸 100*100 的图像的像素灰度值从小到大排序的结果是:{75, 77,…,240,241},按 0.1%的修剪比例分别剔除最小、最大灰度值后的结果是:{77, …, 240},则设黑场阈值为 77,白场阈值为 240。

为了提高算法效率,可以先将图像转为灰度图像后计算得到灰度直方图,然后按修剪比例查找得到黑场阈值、白场阈值。

灰场调节值 midtone 实际上是实现 Gamma 变换,可以由灰度均值或中间值得到。

在这里插入图片描述


例程 13.13:Photoshop 色阶调整算法

本例程实现 Photoshop 的色阶调整算法,包括输入动态线性拉伸、伽马变换和输出线性拉伸 。

    # 13.13 Photoshop 色阶调整算法
    def levelsAdjust(img, Sin=0, Hin=255, Mt=1.0, Sout=0, Hout=255):
        Sin = min(max(Sin, 0), Hin-2)  # Sin, 黑场阈值, 0<=Sin<Hin
        Hin = min(Hin, 255)  # Hin, 白场阈值, Sin<Hin<=255
        Mt  = min(max(Mt, 0.01), 9.99)  # Mt, 灰场调节值, 0.01~9.99
        Sout = min(max(Sout, 0), Hout-2)  # Sout, 输出黑场阈值, 0<=Sout<Hout
        Hout = min(Hout, 255)  # Hout, 输出白场阈值, Sout<Hout<=255

        difIn = Hin - Sin
        difOut = Hout - Sout
        table = np.zeros(256, np.uint16)
        for i in range(256):
            V1 = min(max(255 * (i-Sin)/difIn,0), 255)  # 输入动态线性拉伸
            V2 = 255 * np.power(V1/255, 1/Mt)  # 灰场伽马调节
            table[i] = min(max(Sout+difOut*V2/255, 0), 255)  # 输出线性拉伸

        imgTone = cv.LUT(img, table)
        return imgTone

    img = cv.imread("../images/buddha01.png", flags=1)  # 读取彩色
    equ1 = levelsAdjust(img, 10, 225, 1.0, 10, 245)
    equ2 = levelsAdjust(img, 10, 225, 1.2, 10, 245)

    plt.figure(figsize=(9, 6))
    plt.subplot(131), plt.title("origin"), plt.axis('off')
    plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
    plt.subplot(132), plt.title("colorEqu1"), plt.axis('off')
    plt.imshow(cv.cvtColor(equ1, cv.COLOR_BGR2RGB))
    plt.subplot(133), plt.title("colorEqu2"), plt.axis('off')
    plt.imshow(cv.cvtColor(equ2, cv.COLOR_BGR2RGB))
    plt.tight_layout()
    plt.show()

在这里插入图片描述


例程 13.14:Photoshop 色阶自动调整算法

本例程实现 Photoshop 的色阶调整算法,自动设置色阶调整参数,对 R/G/B 各通道的动态范围分别进行拉伸。

    # 13.14 Photoshop 自动色阶调整算法
    def autoLevels(img, cutoff=0.1):
        channels = img.shape[2]  # h,w,ch
        table = np.zeros((1,256,3), np.uint8)
        for ch in range(channels):
            # cutoff=0.1, 计算 0.1%, 99.9% 分位的灰度值
            low = np.percentile(img[:,:,ch], q=cutoff)  # ch 通道, cutoff=0.1, 0.1 分位的灰度值
            high = np.percentile(img[:,:,ch], q=100 - cutoff)  # 99.9 分位的灰度值, [0, high] 占比99.9%
            # 输入动态线性拉伸
            Sin = min(max(low, 0), high - 2)  # Sin, 黑场阈值, 0<=Sin<Hin
            Hin = min(high, 255)  # Hin, 白场阈值, Sin<Hin<=255
            difIn = Hin - Sin
            V1 = np.array([(min(max(255*(i-Sin)/difIn, 0), 255)) for i in range(256)])
            # 灰场伽马调节
            gradMed = np.median(img[:,:,ch])  # 拉伸前的中值
            Mt = V1[int(gradMed)] / 128.  # 拉伸后的映射值
            V2 = 255 * np.power(V1/255, 1/Mt)  # 伽马调节
            # 输出线性拉伸
            Sout, Hout = 5, 250  # Sout 输出黑场阈值, Hout 输出白场阈值
            difOut = Hout - Sout
            table[0, :, ch] = np.array([(min(max(Sout + difOut*V2[i]/255, 0), 255)) for i in range(256)])
        return cv.LUT(img, table)

    # Photoshop 自动色阶调整算法
    img = cv.imread("../images/Fig0310b.tif", flags=1)  # 读取彩色图像
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)  # 转换为灰度图像
    print("cutoff={}, minG={}, maxG={}".format(0.0, gray.min(), gray.min()))

    # 色阶手动调整
    equManual = levelsAdjust(img, 63, 205, 0.8, 10, 245)  # 手动调节
    # 色阶自动调整
    cutoff = 0.1  # 截断比例, 建议范围 [0.0,1.0]
    equAuto = autoLevels(img, cutoff)

    plt.figure(figsize=(9, 6))
    plt.subplot(131), plt.title("Origin"), plt.axis('off')
    plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
    plt.subplot(132), plt.title("ManualTuned"), plt.axis('off')
    plt.imshow(cv.cvtColor(equManual, cv.COLOR_BGR2RGB))
    plt.subplot(133), plt.title("AutoLevels"), plt.axis('off')
    plt.imshow(cv.cvtColor(equAuto, cv.COLOR_BGR2RGB))
    plt.tight_layout()
    plt.show()

在这里插入图片描述


在这里插入图片描述

从本图可以看出,由于 R,G,B 三个通道单独进行调整,出现了明显的色偏问题。


4.5 Photoshop 对比度自动调整算法(AutoContrast)

对比度是指图像中明暗区域最亮的白和最暗的黑之间不同亮度层级的测量,差异范围越大代表对比越大。 当对比率达到 120:1 就可以容易地显示生动、丰富的色彩,对比率高达 300:1 时就可支持各阶的颜色。

对比度对视觉效果的影响非常关键。高对比度对于图像的清晰度、细节表现、灰度层次表现都有很大帮助。

对比度调整的目的通常是增强对比度,形成清晰的图像效果和醒目的视觉冲击力。

Photoshop 提供了自动对比度调整功能(AutoContrast),通过自动将图像最深的颜色加强为黑色,最亮的部分加强为白色,以增强图像的亮度和暗度的对比度。

Photoshop 中的自动对比度调整算法,与自动色阶调整算法基本相同,区别在于对比度自动调整不是对三个通道分别调整,而是对各通道按统一的比例进行调整。首先获取图像的亮度信息,然后根据修剪比例对亮度进行动态范围的拉伸,同比例调整 R,G,B 三个通道,因此不会出现色偏问题。

Enhance Monochromatic Contrast
Clips all channels identically. This preserves the overall color relationship while making highlights appear lighter and shadows appear darker. The Auto Contrast command uses this algorithm.

参考文献: Set Auto adjustment options (adobe.com)

输入色阶调整,先根据黑场阈值和白场阈值对图像的动态范围进行线性拉伸,再根据灰场调节值进行伽马变换,对发白(曝光过度)或过暗(曝光不足)进行矫正。

V 1 = { 0 , V i n < S i n 255 , V i n > H i n 255 ∗ ( V i n − S i n ) / ( H i n − S i n ) , e l s e V 2 = 255 ∗ ( V 1 / 255 ) 1 / M \begin{aligned} & V_1 = \begin{cases} 0 &, V_{in}<S_{in} \\ 255 &, V_{in}>H_{in} \\ 255 * {(V_{in}-S_{in})}/{(H_{in}-S_{in})} &, else \end{cases} \\ \\ & V_2 = 255 * (V_1 / 255)^{1/M} \end{aligned} V1= 0255255(VinSin)/(HinSin),Vin<Sin,Vin>Hin,elseV2=255(V1/255)1/M

输出色阶调整是基于动态范围进行线性拉伸:

V o u t = { 0 , V 2 < 0 255 , V 2 > 255 S o u t + ( H o u t − S o u t ) ∗ V 2 ∗ / 255 , e l s e V_{out} = \begin{cases} 0 &, V_{2}<0 \\ 255 &, V_{2}>255 \\ S_{out} + {(H_{out}-S_{out})} * V_2 */255 &, else \end{cases} Vout= 0255Sout+(HoutSout)V2/255,V2<0,V2>255,else


例程 13.15:Photoshop 对比度自动调整算法

本例程实现 Photoshop 的对比度自动调整算法,对各通道同时调整。

    # 13.15 Photoshop 对比度自动调整算法
    def autoLevels(img, cutoff=0.1):  # 自动色阶调整
        channels = img.shape[2]  # h,w,ch
        table = np.zeros((1,256,3), np.uint8)
        for ch in range(channels):
            # cutoff=0.1, 计算 0.1%, 99.9% 分位的灰度值
            low = np.percentile(img[:,:,ch], q=cutoff)  # ch 通道, cutoff=0.1, 0.1 分位的灰度值
            high = np.percentile(img[:,:,ch], q=100 - cutoff)  # 99.9 分位的灰度值, [0, high] 占比99.9%
            # 输入动态线性拉伸
            Sin = min(max(low, 0), high - 2)  # Sin, 黑场阈值, 0<=Sin<Hin
            Hin = min(high, 255)  # Hin, 白场阈值, Sin<Hin<=255
            difIn = Hin - Sin
            V1 = np.array([(min(max(255*(i-Sin)/difIn, 0), 255)) for i in range(256)])
            # 灰场伽马调节
            gradMed = np.median(img[:,:,ch])  # 拉伸前的中值
            Mt = V1[int(gradMed)] / 128.  # 拉伸后的映射值
            V2 = 255 * np.power(V1/255, 1/Mt)  # 伽马调节
            # 输出线性拉伸
            Sout, Hout = 5, 250  # Sout 输出黑场阈值, Hout 输出白场阈值
            difOut = Hout - Sout
            table[0, :, ch] = np.array([(min(max(Sout + difOut*V2[i]/255, 0), 255)) for i in range(256)])
        return cv.LUT(img, table)

    def autoContrast(img, cutoff):  # 自动对比度调整
        gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)  # 转换为灰度图像
        # 计算 0.1%, 99.9% 分位的灰度值
        Sin = np.percentile(gray, q=cutoff)  # cutoff=0.1, 0.1 分位的灰度值
        Hin = np.percentile(gray, q=100 - cutoff)  # 99.9 分位的灰度值, [0, per999] 占比99.9%
        # 输入动态线性拉伸
        difIn = Hin - Sin
        V1 = np.array([(min(max(255 * (i-Sin)/difIn,0), 255)) for i in range(256)])
        # 灰场伽马调节, Mt: 0.01~9.99
        gradMed = np.median(gray)  # 拉伸前的中值
        Mt = V1[int(gradMed)] / 160.  # 拉伸后的映射值
        V2 = 255 * np.power(V1/255, 1/Mt)  # 伽马调节
        # 输出线性拉伸
        Sout, Hout = 5, 250  # Sout 输出黑场阈值, Hout 输出白场阈值
        difOut = Hout - Sout
        table = np.array([(min(max(Sout + difOut*V2[i]/255, 0), 255)) for i in range(256)]).astype("uint8")
        imgTone = cv.LUT(img, table)
        return imgTone

    # Photoshop 自动对比度调整算法
    img = cv.imread("../images/Fig0310b.tif", flags=1)  # 读取彩色图像
    # img = cv.imread("../images/demist02.png", flags=1)  # 读取彩色图像

    # 色阶自动调整
    cutoff = 0.1  # 截断比例, 建议范围 [0.0,1.0]
    levelsAuto = autoLevels(img, cutoff)
    # 对比度自动调整
    cutoff = 0.1  # 截断比例, 建议范围 [0.0,1.0]
    contrastAuto = autoContrast(img, cutoff)

    plt.figure(figsize=(9, 6))
    plt.subplot(131), plt.title("Origin"), plt.axis('off')
    plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
    plt.subplot(132), plt.title("AutoLevels"), plt.axis('off')
    plt.imshow(cv.cvtColor(levelsAuto, cv.COLOR_BGR2RGB))
    plt.subplot(133), plt.title("AutoContrast"), plt.axis('off')
    plt.imshow(cv.cvtColor(contrastAuto, cv.COLOR_BGR2RGB))
    plt.tight_layout()
    plt.show()

在这里插入图片描述


在这里插入图片描述

例程运行结果的上图接近灰度图像,色阶自动调整与对比度自动调整的效果类似,没有明显的区别。而在下图中出,色阶自动调整由于对 R/G/B 三个通道单独进行调整,出现了明显的色偏问题;而对比度自动调整则不会发生色偏。



版权声明:
youcans@xupt 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/127148909)
Copyright 2022 youcans, XUPT

欢迎关注 『youcans 的 OpenCV 学习课』 系列,持续更新
文章目录:『youcans 的图像处理学习课 - 总目录』

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

youcans_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值