常用色彩空间RGB、HSV、LAB的对比以及直方图可视化显示

常用色彩空间

在OpenCV中,正常读取的图像是BGR色彩空间,但面对不同的图像识别处理任务时,常常需要根据任务与环境需求,将图像转换为其他色彩空间。

常用的色彩空间有三种:RGB、HSV、LAB。

色彩空间介绍

RGB色彩空间

  • 人类视觉会感知到红色、绿色、蓝色三原色,三种颜色通过加色混合可以产生其他不同的颜色。

  • 三个颜色通道:

    R通道、G通道、B通道。分别为红色、绿色、蓝色通道。

    每个通道值的范围为[0,255]。

    例如,纯白色的RGB值为(255,255,255);纯黑色的RGB值为(0,0,0);纯红色的RGB值为(255,0,0);纯绿色的RGB值为(0,255,0);纯蓝色的RGB值为(0,0,255)。

HSV色彩空间

  • 人的眼睛在对色彩感知时,色调、饱和度、亮度会产生影响。这三要素即是HSV色彩空间的组成部分。

  • 三个通道

    • 色调H(Hue):与光的波长有关,决定是什么颜色。

      用角度度量,取值范围为0~360°,从红色开始按逆时针方向旋转。值范围为[0,360],在opencv中便于计算,压缩到[0,180]

在这里插入图片描述
在这里插入图片描述

  • 饱和度S(Saturation):颜色的深浅和纯度,鲜艳与暗淡。值范围在[0,1],opencv中为了便于计算,扩展到[0,255]

  • 亮度V(Value):颜色的亮与暗。值范围在[0,1],opencv中为了便于计算,扩展到[0,255]

LAB色彩空间

  • 有时候也写成CIE L*a*b*,是均匀色彩空间模型,即人所观察到的两种颜色的区别程度,与这两种颜色在该色彩空间中对应的点之间的欧式距离成正比

  • 三个通道分量

    • L**分量:像素的亮度,取值范围是[0,100],表示从纯黑到纯白*

    • a*分量:从绿色到红色的范围,取值范围是[-127,127]。负轴为绿,正轴为红

    • b*分量:从蓝色到黄色的范围,取值范围是[-127,127]。负轴为蓝,正轴为黄

    • 注意将LAB色彩空间中的图像通道分割后,若想进行进一步处理,需要将三个分量映射到对应范围

      l, a, b = cv2.split(roi)  # 将图像拆分为l、a、b三个通道
      l = l / 256 * 100
      a = (a / 256 - 0.5) * 255  # 将a、b通道值从[0,255]转换到[-127,127]
      b = (b / 256 - 0.5) * 255
      

      在这里插入图片描述

通过直方图观察不同色彩空间下的图像的特点

基本函数

先要了解一些会用到的函数。

色彩空间转换
  • dst = cv2.cvtColor( src, code [, dstCn] )

    返回值:dst:返回转换后的图像

    参数

    • src:源图像

    • code:色彩空间转换码。常用cv2.COLOR_BGR2GRAYcv2.COLOR_BGR2HSVcv2.COLOR_BGR2RGB等,表示从什么色彩空间转换到什么色彩空间

    • dstCn:输出图像的通道数。默认为0,自动计算得到

直方图
  • 直方图:统计图像中的信息。

    在这里,x轴为图像的长即每一列

    对于RGB图像和HSV图像,y轴表示图像的每一列中像素点对应通道值的和;

    对于二值图像,y轴表示图像得每一列中白色像素点的个数和。

  • 使用matplotlib.pyplot模块

    import matplotlib.pyplot as plt  
    
  • 创建窗口

    窗口用于放置图像、直方图等。

    plt.figure(num, figsize)

    参数

    • num:字符串为窗口名称,整数为窗口编号
    • figsize:窗口的大小,例如figsize=(5, 3)表示窗口大小为5英寸长,3英寸宽
  • 添加子窗口

    在大窗口中插入子窗口,便于观察与对比。

    plt.subplot(nrows, ncols, index)

    参数

    • nrows:行数
    • ncols:列数
    • index:子窗口序号

    例如,plt.subplot(2,3,4)plt.subplot(234)表示有2行3列的第四个位置添加一个子窗口

在这里插入图片描述

如果三个参数都小于10,之间的逗号可以省略。

  • 绘制直方图

    plt.bar(x, height, color)

    参数

    • x:数组,x轴的数据类别
    • height:数组,y轴的数值
    • color:条形的颜色
  • 动态画图

    灰常重要!!!用于实时画图!

    matplotlib画图有两种模式:

    • 阻塞模式:使用matplotlib显示图像后,之后的代码会阻塞不运行,这是默认模式
    • 交互模式:使用matplotlib显示图像后代码继续运行,意味着可以继续绘制下一帧图像的直方图

    要绘制视频的动态直方图,得开启交互模式。下列是动态画图的重要函数:

    • plt.ion()开启交互模式。
    • plt.ioff()关闭交互模式。
    • plt.cla()清空创建的axes轴上的内容,如果需要更新轴的信息可以使用,否则轴信息容易重叠混乱。
    • plt.clf()清空创建的figure窗口中的内容,如果需要更新整个窗口内的信息可以使用,否则窗口内的显示容易重叠混乱。由于我们的窗口中还有子窗口,使用该函数清除得彻底一点。
    • plt.pause()等待一段时间,使图像更新。

效果显示

在代码中(放在文末),开启摄像头,将实时图像转化为RGB、HSV色彩空间和二值化图像并展示。同时将RGB、HSV图像拆分通道,使用matplotlib的交互模式,绘制每个通道像素值的动态直方图。

我将摄像头对准开着灯的教室中,放置有一个蓝色盒子的带有线条的地板上,效果如下:
在这里插入图片描述

直方图会随视频实时变化。

上面四个窗口从左至右分别是源图像、RGB图像、HSV图像、二值化图像。

下面三个窗口从左至右分别是RGB三个通道的色彩直方图、HSV三个通道的色彩直方图、二值化图像的直方图。

可以看到,rgb图像中,蓝色盒子所在区域,BLUE通道的直方图对应区域突出;hsv图像中,对应区域的HUE通道和SATURATION通道突出;二值图像中,对应区域也有明显区别,线条部分亦是。

综合分析

通过摄像头识别不同的物体及观察直方图的变化,可以发现,当我改变物体的颜色,RGB三个通道的直方图会改变趋势相似,但对于不那么纯净的颜色,观察的时候不直观。hsv三个通道的直方图,改变物体颜色时色调变化明显,在我对同一物体施加不同光照时,饱和度和亮度也会有所改变。

  • RGB

    • 优点:可以组成256x256x256=16777216种颜色。应用普遍与广泛,显示图像直观。
    • 缺点:对环境光照等条件不敏感,在光线对颜色造成影响的时候判断不灵敏。观察指定颜色不方便。
    • 适用情况:在电子显示设备、一般的图像显彩中会使用RGB;在预处理图像阶段,RGB仍然是一个重要的起点
  • HSV

    • 优点:色调不易受饱和度和亮度的影响,更方便识别特定颜色。加上饱和度和亮度,可以处理一定的光照影响。
    • 缺点:若遇到极端的强光或者弱光环境,色相可能会偏移。且不适合对颜色精确度要求高的任务
  • LAB

    • 优点:具有与设备无关的特点,在不同的设备上保持一致。色域宽广。允许单独编辑亮度(L通道)和色彩平衡(a和b通道),为调色提供了更多的灵活性
    • 缺点:虽然更符合人类视觉感知,但是其值不如RGB等色彩空间直观易懂
    • 适用情况:颜色分割更细致,在检测植物叶片、水果成熟度等背景比较复杂任务中效果好

适用情况:环境会受一定程度光照的影响

  • LAB
    • 优点:具有与设备无关的特点,在不同的设备上保持一致。色域宽广。允许单独编辑亮度(L通道)和色彩平衡(a和b通道),为调色提供了更多的灵活性

    • 缺点:虽然更符合人类视觉感知,但是其值不如RGB等色彩空间直观易懂

    • 适用情况:颜色分割更细致,在检测植物叶片、水果成熟度等背景比较复杂任务中效果好

代码如下:

import cv2
import numpy as np
import matplotlib.pyplot as plt


def draw_hist(rgb, hsv, binary):
    y, x = rgb.shape[:2]  # 640,480

    # 绘制直方图
    # rgb图像
    plt.figure("RGB", figsize=(5, 3))
    plt.clf()  # 清空该窗口内的图像,重新绘制,避免图像叠加
    plt.subplot(131)
    r_pixel = np.sum(rgb[:, :, 0], axis=0)  # 计算图像中r通道每列像素点的和
    plt.bar(range(x), r_pixel, color='red')
    plt.title("RED")

    plt.subplot(132)
    g_pixel = np.sum(rgb[:, :, 1], axis=0)  # 计算图像中g通道每列像素点的和
    plt.bar(range(x), g_pixel, color='green')
    plt.title("GREEN")

    plt.subplot(133)
    b_pixel = np.sum(rgb[:, :, 2], axis=0)  # 计算图像中b通道每列像素点的和
    plt.bar(range(x), b_pixel, color='blue')
    plt.title("BLUE")

    # hsv图像
    plt.figure("HSV", figsize=(5, 3))
    plt.clf()
    plt.subplot(131)
    h_pixel = np.sum(hsv[:, :, 0], axis=0)  # 计算图像中h通道每列像素点的和
    plt.bar(range(x), h_pixel, color='yellow')
    plt.title("HUE")

    plt.subplot(132)
    s_pixel = np.sum(hsv[:, :, 1], axis=0)  # 计算图像中s通道每列像素点的和
    plt.bar(range(x), s_pixel, color='purple')
    plt.title("SATURATION")

    plt.subplot(133)
    v_pixel = np.sum(hsv[:, :, 2], axis=0)  # 计算图像中v通道每列像素点的和
    plt.bar(range(x), v_pixel, color='orange')
    plt.title("VALUE")

    white_pixel = np.sum(binary == 255, axis=0)  # 计算每一列白色像素点的总数
    plt.figure("BINARY", figsize=(5, 3))
    plt.clf()
    plt.bar(range(x), white_pixel, color='gray')
    plt.title("BINARY")

    plt.pause(1)  # 等待图像更新


if __name__ == "__main__":
    cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
    plt.ion()  # 开启交互模式

    while True:
        ret, frame = cap.read()
        if not ret:
            break

        rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        _, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

        cv2.imshow('frame', frame)
        cv2.imshow('rgb', rgb)
        cv2.imshow('hsv', hsv)
        cv2.imshow('binary', binary)
        cv2.waitKey(1)  # 摄像头获取图像更新

        draw_hist(rgb, hsv, binary)

    plt.ioff()  # 关闭交互模式
    cap.release()
    cv2.destroyAllWindows()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值