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()
我们来看效果:
我们看到了六个不同颜色的猫,当然,OpenCV内部的颜色空间转换多达150多种,在这里不可能一一演示,我们只讲最重要的两种:灰度化和HSV,灰度化就不必多说了,主要看看HSV,HSV通常用与颜色追踪,也算是一种初级的目标追踪方法,它比 BGR 更容易跟踪某种颜色的物体,常用于分割指定颜色的物体。
HSV 表达彩色图像的方式由三个部分组成:
· Hue(色调、色相)
· Saturation(饱和度、色彩纯净度)
· Value(明度)
用下面这个圆柱体来表示 HSV 颜色空间,圆柱体的横截面可以看做是一个极坐标系 ,H 用极坐标的极角表示,S 用极坐标的极轴长度表示,V 用圆柱中轴的高度表示。
Hue 用角度度量,取值范围为0~360°,表示色彩信息,即所处的光谱颜色的位置。表示如下:
颜色圆环上所有的颜色都是光谱上的颜色,从红色开始按逆时针方向旋转,Hue=0 表示红色,Hue=120 表示绿色,Hue=240 表示蓝色等等。
在 GRB中 颜色由三个值共同决定,比如黄色为即 (255,255,0);在HSV中,黄色只由一个值决定,Hue=60即可。
HSV 圆柱体的半边横截面(Hue=60):
其中水平方向表示饱和度,饱和度表示颜色接近光谱色的程度。饱和度越高,说明颜色越深,越接近光谱色饱和度越低,说明颜色越浅,越接近白色。饱和度为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值很重要,这里我们给出一个转化表:
而要想用代码实现这些数据范围,我们需要知道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()
我们来看效果:
完美,这样用HSV跟踪物体就可以了,最重要的还是取值范围的标定,根据上面的那个表格来进行取值就完全可以。