OpenCV-Python系列之改变颜色空间

从本次教程开始,我们正式进入基础篇的学习,OpenCV图像处理中最重要的一环就是图像的颜色空间,我们在之前已经见到过关于图像灰度化的例子,但这仅仅是其中的一种。

颜色空间

色彩/颜色空间(英语:Color space)是对色彩的组织方式。借助色彩空间和针对物理设备的测试,可以得到色彩的固定模拟和数字表示。色彩空间可以只通过任意挑选一些颜色来定义,比如像彩通系统就只是把一组特定的颜色作为样本,然后给每个颜色定义名字和代码;也可以是基于严谨的数学定义,比如 Adobe RGB、sRGB。

许多人都知道在绘画时可以使用红色、黄色和蓝色这三种原色生成不同的颜色,这些颜色就定义了一个色彩空间。我们将品红色的量定义为X 坐标轴、青色的量定义为Y坐标轴、黄色的量定义为Z坐标轴,这样就得到一个三维空间,每种可能的颜色在这个三维空间中都有唯一的一个位置。

但是,这并不是唯一的一个色彩空间。例如,当在计算机监视器上显示颜色的时候,通常使用RGB(红色、绿色、蓝色)色彩空间定义,这是另外一种生成同样颜色的方法,红色、绿色、蓝色被当作X、Y和Z坐标轴。另外一个生成同样颜色的方法是使用色相(X轴)、饱和度(色度)(Y轴)和明度(Z轴)表示,这种方法称为HSB色彩空间。另外还有许多其它的色彩空间,许多可以按照这种方法用三维(X、Y、Z)、更多或者更少维表示,但是有些根本不能用这种方法表示。

我们生活中大多数看到的彩色图片都是RGB类型,但是在进行图像处理时,需要用到灰度图、二值图、HSV、HSI等颜色制式,OpenCV提供了cvtColor()函数来实现这些功能。首先看一下cvtColor函数定义:

cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0 );

. InputArray src: 输入图像即要进行颜色空间变换的原图像,可以是Mat类

. OutputArray dst: 输出图像即进行颜色空间变换后存储图像,也可以Mat类

. int code: 转换的代码或标识,即在此确定将什么制式的图片转换成什么制式的图片,后面会详细讲述

. int dstCn = 0: 目标图像通道数,如果取值为0,则由src和code决定

函数的作用是将一个图像从一个颜色空间转换到另一个颜色空间,但是从RGB向其他类型转换时,必须明确指出图像的颜色通道,前面我们也提到过,在OpenCV中,其默认的颜色制式排列是BGR而非RGB。所以对于24位颜色图像来说,前8-bit是蓝色,中间8-bit是绿色,最后8-bit是红色。常见的R,G,B通道的取值范围为:

. 0-255 :CV_8U类型图片

. 0-65535: CV_16U类型图片

. 0-1: CV_32F类型图片

在本次教程中我们只研究几种重要的颜色空间转化方法,包括有灰度化,HSV空间转换。我们首先来看代码:

import cv2

img = cv2.imread("cat.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
hls = cv2.cvtColor(img, cv2.COLOR_BGR2HLS)
LAB = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
LUV = cv2.cvtColor(img, cv2.COLOR_BGR2LUV)

cv2.imshow("gray", gray)
cv2.imshow("hsv", hsv)
cv2.imshow("hls", hls)
cv2.imshow("LAB", LAB)
cv2.imshow("LUV", LUV)
cv2.waitKey(0)
cv2.destroyAllWindows()

我们来看效果:

image.png

image.png

image.png

image.png

image.png

image.png

我们看到了六个不同颜色的猫,当然,OpenCV内部的颜色空间转换多达150多种,在这里不可能一一演示,我们只讲最重要的两种:灰度化和HSV,灰度化就不必多说了,主要看看HSV,HSV通常用与颜色追踪,也算是一种初级的目标追踪方法,它比 BGR 更容易跟踪某种颜色的物体,常用于分割指定颜色的物体。

HSV 表达彩色图像的方式由三个部分组成:

· Hue(色调、色相)

· Saturation(饱和度、色彩纯净度)

· Value(明度)

用下面这个圆柱体来表示 HSV 颜色空间,圆柱体的横截面可以看做是一个极坐标系 ,H 用极坐标的极角表示,S 用极坐标的极轴长度表示,V 用圆柱中轴的高度表示。

image.png

Hue 用角度度量,取值范围为0~360°,表示色彩信息,即所处的光谱颜色的位置。表示如下:

image.png

颜色圆环上所有的颜色都是光谱上的颜色,从红色开始按逆时针方向旋转,Hue=0 表示红色,Hue=120 表示绿色,Hue=240 表示蓝色等等。

在 GRB中 颜色由三个值共同决定,比如黄色为即 (255,255,0);在HSV中,黄色只由一个值决定,Hue=60即可。

HSV 圆柱体的半边横截面(Hue=60):

image.png

其中水平方向表示饱和度,饱和度表示颜色接近光谱色的程度。饱和度越高,说明颜色越深,越接近光谱色饱和度越低,说明颜色越浅,越接近白色。饱和度为0表示纯白色。取值范围为0~100%,值越大,颜色越饱和。

竖直方向表示明度,决定颜色空间中颜色的明暗程度,明度越高,表示颜色越明亮,范围是 0-100%。明度为0表示纯黑色(此时颜色最暗)。

可以通俗理解为:

在Hue一定的情况下,饱和度减小,就是往光谱色中添加白色,光谱色所占的比例也在减小,饱和度减为0,表示光谱色所占的比例为零,导致整个颜色呈现白色。

明度减小,就是往光谱色中添加黑色,光谱色所占的比例也在减小,明度减为0,表示光谱色所占的比例为零,导致整个颜色呈现黑色。

HSV 对我们来说是一种比较直观的颜色模型。我们可以很轻松地得到单一颜色,即指定颜色角H,并让V=S=1,然后通过向其中加入黑色和白色来得到我们需要的颜色。增加黑色可以减小V而S不变,同样增加白色可以减小S而V不变。例如,要得到深蓝色,V=0.4 S=1 H=240度。要得到浅蓝色,V=1 S=0.4 H=240度。

HSV 的拉伸对比度增强就是对 S 和 V 两个分量进行归一化即可,H 保持不变。

注意:在 OpenCV 中 HSV 三个分量的范围为:

· H = [0,179]

· S = [0,255]

· V = [0,255]

目标颜色追踪

前面已经提到过,颜色追踪根据HSV色彩空间来实现的,首先我们需要对一个BGR值进行颜色空间转换,得到HSV值。

为了识别特定颜色的物体,获取到颜色所对应的HSV值很重要,这里我们给出一个转化表:

image.png

而要想用代码实现这些数据范围,我们需要知道OpenCV的一个函数:

cv2. inRange(InputArray src, InputArray lowerb,InputArray upperb, OutputArray dst),对于各个参数的解析:
1.src是输入的数组
2.lowerb是包含lowerb的最小值数组或分量,本教程中用于上表中的最小数值
3.upperb是包含upperb的最大值数组或分量,本教程中用于上表中的最大数值
4.输出的数组,大小和通道数与src一样,并且是CV_8V的类型

我们来看代码,该代码用于打开摄像头,识别绿色物体的移动:

import cv2
import numpy as np

cap = cv2.VideoCapture(0)

while True:
    ret, frame = cap.read()
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    lower_black = np.array([35, 43, 46])
    upper_black= np.array([77, 255, 255])

    mask = cv2.inRange(hsv, lower_black, upper_black)
    res = cv2.bitwise_and(frame, frame, mask=mask)

    cv2.imshow('frame', frame)
    cv2.imshow('mask', mask)
    cv2.imshow('res', res)
    k = cv2.waitKey(5) & 0xFF
    if k == 27:
        break

cv2.destroyAllWindows()

我们来看效果:

image.png

完美,这样用HSV跟踪物体就可以了,最重要的还是取值范围的标定,根据上面的那个表格来进行取值就完全可以。

posted @ 2021-12-03 16:55  wuyuan2011woaini  阅读(443)  评论(0编辑  收藏  举报