四、OpenCV颜色空间——HSV颜色模型

教程汇总:python基础入门系列

该章节主要介绍两种颜色空间RGB与HSV,HSV将作为我们主要使用的颜色空间。

RGB: 在计算机体系中,最常用的颜色空间是RGB模型,常用于颜色显示和图像处理,三维坐标的模型形式,主要是易于实现RGB三原色的组合表达各种颜色方便屏幕显示。学过物理的我们应该知道,可见光谱是连续的,而三原色RGB混合能形成其他的颜色,并不是说物理上其他颜色的光是由三原色的光混合形成的,每种单色光都有自己独特的光谱,如黄光是一种单色光,但红色与绿色混合能形成黄色,原因是人的感官系统所致,因为人眼感光细胞就是由红绿蓝三种感光细胞组成的。
只能说“将三原色光以不同的比例复合后,对人的眼睛可以形成与各种频率的可见光等效的色觉。”

HSV: 而HSV模型,是针对用户观感的一种颜色模型,侧重于色彩表示,什么颜色、深浅如何、明暗如何。

RGB颜色空间

示意图:
四、OpenCV颜色空间——HSV颜色模型_第1张图片
原点到白色顶点的中轴线是灰度线,r、g、b三分量相等,强度可以由三分量的向量表示。RGB是通过红绿蓝三原色来描述颜色的颜色空间。是图像处理中最基本、最常用、面向硬件的颜色空间。我们采集到的彩色图像,一般就是被分成R、G、B的成分加以保存的。RGB色彩空间采用物理三基色表示,因而物理意义很清楚,适合电子显示屏工作。然而这一体制并不适应现实世界里人对于颜色的描述。因而,产生了其它不同的色彩空间表示法。

RGB 的局限:

  • RGB 颜色空间利用三个颜色分量的线性组合来表示颜色,任何颜色都与这三个分量有关,而且这三个分量是高度相关的,所以连续变换颜色时并不直观,想对图像的颜色进行调整需要更改这三个分量才行。

  • 自然环境下获取的图像容易受自然光照、遮挡和阴影等情况的影响,即对亮度比较敏感。而 RGB 颜色空间的三个分量都与亮度密切相关,即只要亮度改变,三个分量都会随之相应地改变,而没有一种更直观的方式来表达。

  • 人眼对于这三种颜色分量的敏感程度是不一样的,在单色中,人眼对红色最不敏感,蓝色最敏感,所以 RGB 颜色空间是一种均匀性较差的颜色空间。如果颜色的相似性直接用欧氏距离来度量,其结果与人眼视觉会有较大的偏差。对于某一种颜色,我们很难推测出较为精确的三个分量数值来表示。

所以,RGB 颜色空间适合于显示系统,却并不适合于图像处理。

HSV颜色空间

HSV颜色模型常用一个倒锥体或者圆柱体来描述。
示意图:
四、OpenCV颜色空间——HSV颜色模型_第2张图片
四、OpenCV颜色空间——HSV颜色模型_第3张图片
基于上述理由,在图像处理中使用较多的是 HSV 颜色空间,它比 RGB 更接近人们对彩色的感知经验。非常直观地表达颜色的色调、鲜艳程度和明暗程度,方便进行颜色的对比。
在 HSV 颜色空间下,比 BGR 更容易跟踪某种颜色的物体,常用于分割指定颜色的物体。

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

  • Hue(色调、色相)
  • Saturation(饱和度、色彩纯净度)
  • Value(明度)

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

Hue 用角度度量,取值范围为0~360°,表示色彩信息,即所处的光谱颜色的位置。表示如下:
四、OpenCV颜色空间——HSV颜色模型_第4张图片
颜色圆环上所有的颜色都是光谱上的颜色,从红色开始按逆时针方向旋转,Hue=0 表示红色,Hue=120 表示绿色,Hue=240 表示蓝色等等。

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

HSV 圆柱体的半边横截面(Hue=60):
四、OpenCV颜色空间——HSV颜色模型_第5张图片
其中水平方向表示饱和度,饱和度表示颜色接近光谱色的程度。饱和度越高,说明颜色越深,越接近光谱色饱和度越低,说明颜色越浅,越接近白色。饱和度为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 两个分量进行归一化(min-max normalize)即可,H 保持不变。

通过语言来描述毕竟比较空洞,下面我们来写个小程序方便更好的认识HSV调整对颜色的拾取影响。
四、OpenCV颜色空间——HSV颜色模型_第6张图片
这是一张色环图,通过HSV颜色空间的操作应当能线性拾取其中的部分色彩。代码如下:

import cv2
import numpy as np

def nothing(x):
    pass
#通过Opencv读取图片信息
#src = cv2.imread('image.jpg')
img = cv2.imread('hsv.jpg')
rows,cols,channels = img.shape
cv2.imshow("src", img)
cv2.namedWindow('img2',1)
#cv2.resizeWindow("img2", 400, 200) #创建一个500*500大小的窗口

# 创建6个滑条用来操作HSV3个分量的上下截取界限
cv2.createTrackbar('Hlow','img2',62,180,nothing)
cv2.createTrackbar('Hup','img2',99,180,nothing)
cv2.createTrackbar('Slow','img2',198,255,nothing)
cv2.createTrackbar('Sup','img2',255,255,nothing)
cv2.createTrackbar('Vlow','img2',150,255,nothing)
cv2.createTrackbar('Vup','img2',255,255,nothing)

# lower_red = np.array([55,30,30])
# upper_red = np.array([99,255,255])
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
while(1):
    # mask = cv2.inRange(hsv, lower_red, upper_red)
    #将制定像素点的数据设置为0, 要注意的是这三个参数对应的值是Blue, Green, Red。
    hlow = cv2.getTrackbarPos('Hlow', 'img2')
    hup = cv2.getTrackbarPos('Hup', 'img2')
    slow = cv2.getTrackbarPos('Slow', 'img2')
    sup = cv2.getTrackbarPos('Sup', 'img2')
    vlow = cv2.getTrackbarPos('Vlow', 'img2')
    vup = cv2.getTrackbarPos('Vup', 'img2')
    lower_red = np.array([hlow, slow, vlow])
    upper_red = np.array([hup, sup, vup])
    mask = cv2.inRange(hsv, lower_red, upper_red)
    img2 = cv2.bitwise_and(img, img, mask=mask)

   # cv2.imshow("src", src)
    cv2.imshow("img2", img2)
    k = cv2.waitKey(1)&0xFF
    if k == 27: #esc exit
        break
#cv2.waitKey(0)
cv2.destroyAllWindows()

需要注意的是在OpenCV中 HSV的取值范围分别是 H:(0-180),S:(0-255),V:(0-255)。

下图是程序运行后调整H从0-180全色彩截取显示
四、OpenCV颜色空间——HSV颜色模型_第7张图片
比如我们要截取一段蓝色出来,调整H low 与H up 在 110-120之间即可。
四、OpenCV颜色空间——HSV颜色模型_第8张图片
关于SV分量的影响观察,可以保持H在0-180,改变S或V的截取上下限,自己可以进行测试体验。

通过上面的工具代码也能发现我们使用了cv2.cvtColor(img, cv2.COLOR_BGR2HSV)函数实现了BGR图到HSV图的转化,转换后的hsv图 像素数组则都是hsv分量来表示了。

你可能感兴趣的:(python,opencv)