OpenCV轻松入门:面向Python【1.9】

4.4.3 标记指定颜色

在 HSV 色彩空间中, H 通道(饱和度 Hue 通道)对应不同的颜色。或者换个角度理解,颜色的差异主要体现在 H 通道值的不同上。所以,通过对 H 通道值进行筛选,便能够筛选出特定的颜色。例如,在一幅 HSV 图像中,如果通过控制仅仅将 H 通道内值为 240(在 OpenCV内被调整为 120)的像素显示出来,那么图像中就会仅仅显示蓝色部分。

本节将首先通过例题展示一些实现上的细节问题,然后通过具体例题展示如何将图像内的特定颜色标记出来,即将一幅图像内的其他颜色屏蔽,仅仅将特定颜色显示出来。

1.通过inRange函数锁定特定值

OpenCV 中通过函数 cv2.inRange()来判断图像内像素点的像素值是否在指定的范围内,其语法格式为:

dst = cv2.inRange( src, lowerb, upperb )

式中:

 dst 表示输出结果,大小和 src 一致。

 src 表示要检查的数组或图像。

 lowerb 表示范围下界。

 upperb 表示范围上界。

返回值 dst 与 src 等大小,其值取决于 src 中对应位置上的值是否处于区间[lowerb,upperb]内:

 如果 src 值处于该指定区间内,则 dst 中对应位置上的值为 255。

 如果 src 值不处于该指定区间内,则 dst 中对应位置上的值为 0。

【例 4.7】 使用函数 cv2.inRange()将某个图像内的在[100,200]内的值标注出来。为了方便理解,这里采用一个二维数组模拟图像,完成操作。

根据题目要求,设计程序如下:

import cv2
import numpy as np
img=np.random.randint(0,256,size=[5,5],dtype=np.uint8)
min=100
max=200
mask = cv2.inRange(img, min, max)
print("img=\n",img)
print("mask=\n",mask)
运行程序,会显示如下所示的运行结果。
img=
[[129 155 99 51 182]
[ 57 130 235 135 110]
[232 182 194 13 26]
[111 7 136 190 55]
[ 35 144 9 255 187]]
mask=
[[255 255 0 0 255]
[ 0 255 0 255 255]
[ 0 255 255 0 0]
[255 0 255 255 0]
[ 0 255 0 0 255]]

通过本例题可以看出,通过函数 cv2.inRange()可以将数组(图像)内指定范围内的值标注出来,在返回的 mask 中,其值取决于 img 中对应位置上的值是否在 inRange 所指定的[100,200]内:

 如果 img 值位于该指定区间内,则 mask 对应位置上的值为 255。 如果 img 值不在该指定区间内,则 mask 对应位置上的值为 0。返回的结果 mask 可以理解为一个掩码数组,其大小与原始数组一致。

2.通过基于掩码的按位与显示ROI

【例 4.8】 正常显示某个图像内的感兴趣区域(ROI),而将其余区域显示为黑色。

为了方便理解,这里采用一个二维数组模拟图像,完成操作。题目中要求将不感兴趣区域以黑色显示,可以通过设置掩码的方式将该区域的值置为 0 来实现。

根据题目要求,设计程序如下:

import cv2
import numpy as np
img=np.ones([5,5],dtype=np.uint8)*9
mask =np.zeros([5,5],dtype=np.uint8)
mask[0:3,0]=1
mask[2:5,2:4]=1
roi=cv2.bitwise_and(img,img, mask= mask)
print("img=\n",img)
print("mask=\n",mask)
print("roi=\n",roi)

在本例中,通过 mask 设置了两个感兴趣区域(掩模)。后续通过在按位与运算中设置掩模的方式,将原始图像 img 内这两部分的值保留显示,而将其余部分的值置零。

运行程序,会显示如下所示的运行结果:

img=
[[9 9 9 9 9]
[9 9 9 9 9]
[9 9 9 9 9]
[9 9 9 9 9]
[9 9 9 9 9]]
mask=
[[1 0 0 0 0]
[1 0 0 0 0]
[1 0 1 1 0]
[0 0 1 1 0]
[0 0 1 1 0]]
roi=
[[9 0 0 0 0]
[9 0 0 0 0]
[9 0 9 9 0]
[0 0 9 9 0]
[0 0 9 9 0]]

3. 显示特定颜色值

【例 4.9】 分别提取 OpenCV 的 logo 图像内的红色、绿色、蓝色。

需要注意,在实际提取颜色时,往往不是提取一个特定的值,而是提取一个颜色区间。例如,在 OpenCV 中的 HSV 模式内,蓝色在 H 通道内的值是 120。在提取蓝色时,通常将“蓝色值 120”附近的一个区间的值作为提取范围。该区间的半径通常为 10 左右,例如通常提取[120-10,120+10]范围内的值来指定蓝色。

相比之下, HSV 模式中 S 通道、 V 通道的值的取值范围一般是[100,255]。这主要是因为,当饱和度和亮度太低时,计算出来的色调可能就不可靠了。

根据上述分析,各种颜色的 HSV 区间值分布在[H-10,100,100]和[H+10,255,255]之间。因此,各种颜色值的范围为:

 蓝色:值分布在[110,100,100]和[130,255,255]之间。

 绿色:值分布在[50,100,100]和[70,255,255]之间。

 红色:值分布在[0,100,100]和[10,255,255]之间。

根据前述例题的相关介绍,首先利用函数 cv2.inRange()查找指定颜色区域,然后利用基于掩码的按位与运算将指定颜色提取出来。

根据题目要求,设计程序如下:

import cv2
import numpy as np
opencv=cv2.imread("opencv.jpg")
hsv = cv2.cvtColor(opencv, cv2.COLOR_BGR2HSV)
cv2.imshow('opencv',opencv)
#=============指定蓝色值的范围=============
minBlue = np.array([110,50,50])
maxBlue = np.array([130,255,255])
#确定蓝色区域
mask = cv2.inRange(hsv, minBlue, maxBlue)
#通过掩码控制的按位与运算,锁定蓝色区域
blue = cv2.bitwise_and(opencv,opencv, mask= mask)
cv2.imshow('blue',blue)
#=============指定绿色值的范围=============
minGreen = np.array([50,50,50])
maxGreen = np.array([70,255,255])
#确定绿色区域
mask = cv2.inRange(hsv, minGreen, maxGreen)
#通过掩码控制的按位与运算,锁定绿色区域
green = cv2.bitwise_and(opencv,opencv, mask= mask)
cv2.imshow('green',green)
#=============指定红色值的范围=============
minRed = np.array([0,50,50])
maxRed = np.array([30,255,255])
#确定红色区域
mask = cv2.inRange(hsv, minRed, maxRed)
#通过掩码控制的按位与运算,锁定红色区域
red= cv2.bitwise_and(opencv,opencv, mask= mask)
cv2.imshow('red',red)
cv2.waitKey()
cv2.destroyAllWindows()

运行程序,结果如图 4-4 所示,其中:

 图(a)是原始图像。

 图(b)是从图(a)中提取得到的蓝色部分。

 图(c)是从图(a)中提取得到的绿色部分。

 图(d)是从图(a)中提取得到的红色部分。

由于本书为黑白印刷,所以为了更好地观察运行效果,请大家亲自上机运行程序。

OpenCV轻松入门:面向Python【1.9】_第1张图片

4.4.4 标记肤色

在标记特定颜色的基础上,可以将标注范围进一步推广到特定的对象上。例如,通过分析可以估算出肤色在 HSV 色彩空间内的范围值。在 HSV 空间内筛选出肤色范围内的值,即可将图像内包含肤色的部分提取出来。

这里将肤色范围划定为:

 色调值在[5, 170]之间

 饱和度值在[25, 166]之间

【例 4.10】 提取一幅图像内的肤色部分。根据题目要求,设计程序如下:

import cv2
img=cv2.imread("lesson2.jpg")
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h,s,v=cv2.split(hsv)
minHue=5
maxHue=170
hueMask=cv2.inRange(h, minHue, maxHue)
minSat=25
maxSat=166
satMask = cv2.inRange(s, minSat, maxSat)
mask = hueMask & satMask
roi = cv2.bitwise_and(img,img, mask= mask)
cv2.imshow("img",img)
cv2.imshow("ROI",roi)
cv2.waitKey()
cv2.destroyAllWindows()

运行程序,结果如图 4-5 所示,程序实现了将人的图像从背景内分离出来。其中:

 左侧是原始图像,图像背景是白色的。

 右侧是提取结果,提取后的图像仅保留了人像肤色(包含衣服)部分,背景为黑色。

由于本书是黑白印刷,无法很好地感受到颜色的变化。为了更好地观察上述效果,请大家亲自上机运行程序。

OpenCV轻松入门:面向Python【1.9】_第2张图片

4.4.5 实现艺术效果

在 HSV 色彩空间内进行分量值的调整能够生成一些有趣的效果。一些图像处理软件正是利用对 HSV 色彩空间内值的调整来实现各种艺术效果的。

在本节中,将一幅图像的 H 通道和 S 通道的值保持不变,而将其 V 通道的值都调整为 255,即设置为最亮,观察得到的艺术效果。

【例 4.11】 调整 HSV 色彩空间内 V 通道的值,观察其处理结果。

可以任意改变图像内各个通道的值,观察其最终的显示效果。本例中,我们改变 V 通道的值,让其值均变为 255,观察图像处理结果。

根据题目要求,设计程序如下:

import cv2
img=cv2.imread("barbara.bmp")
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h,s,v=cv2.split(hsv)
v[:,:]=255
newHSV=cv2.merge([h,s,v])
art = cv2.cvtColor(newHSV, cv2.COLOR_HSV2BGR)
cv2.imshow("img",img)
cv2.imshow("art",art)
cv2.waitKey()
cv2.destroyAllWindows()

运行程序,结果如图 4-6 所示。其中,左侧是原始图像,右侧是艺术效果。
OpenCV轻松入门:面向Python【1.9】_第3张图片

4.5 alpha 通道

在 RGB 色彩空间三个通道的基础上,还可以加上一个 A 通道,也叫 alpha 通道,表示透明度。 这种 4 个通道的色彩空间被称为 RGBA 色彩空间, PNG 图像是一种典型的 4 通道图像。alpha 通道的赋值范围是[0, 1],或者[0, 255],表示从透明到不透明。【例 4.12】 编写一个程序,分析 alpha 通道的值。

为了方便观察,本例中使用一个随机数组来模拟图像, 进行观察。根据题目要求,设计程序如下:

import cv2
import numpy as np
img=np.random.randint(0,256,size=[2,3,3],dtype=np.uint8)
bgra = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
print("img=\n",img)
print("bgra=\n",bgra)
b,g,r,a=cv2.split(bgra)
print("a=\n",a)
a[:,:]=125
bgra=cv2.merge([b,g,r,a])
print("bgra=\n",bgra)

在本例中,使用语句 bgra = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)将 img 从 BGR 色彩空间转换到 BGRA 色彩空间。在转换后的 BGRA 色彩空间中, A 是 alpha 通道,默认值为255。

接下来,分别使用打印语句打印原始图像 img 的值和转换后的图像 bgra 的值。

然后,使用语句 a[:,:]=125 将从 bgra 中提取的 alpha 通道的值设定为 125,并使用语句bgra=cv2.merge([b,g,r,a])构建一个新的 bgra 图像。在本步骤中,使用 cv2.merge()函数将新的 alpha通道与原有的 BGR 通道进行合并,得到一个新的图像。从另外一个角度理解就是,本步骤实现了将 bgra 图像中 alpha 通道的值更改为 125。

最后,使用 print 语句显示重构后的 bgra 图像。运行程序,结果如下所示。

img=
[[[141 62 75]
[ 64 55 238]
[ 10 167 220]]
[[ 19 29 93]
[234 219 238]
[108 33 99]]]
bgra=
[[[141 62 75 255]
[ 64 55 238 255]
[ 10 167 220 255]]
[[ 19 29 93 255]
[234 219 238 255]
[108 33 99 255]]]
a=
[[255 255 255]
[255 255 255]]
bgra=
[[[141 62 75 125]
[ 64 55 238 125]
[ 10 167 220 125]]
[[ 19 29 93 125]
[234 219 238 125]
[108 33 99 125]]]

【例 4.13】 编写一个程序,对图像的 alpha 通道进行处理。根据题目要求,设计程序如下:
 

import cv2
img=cv2.imread("lenacolor.png")
bgra = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
b,g,r,a=cv2.split(bgra)
a[:,:]=125
bgra125=cv2.merge([b,g,r,a])
a[:,:]=0
104
bgra0=cv2.merge([b,g,r,a])
cv2.imshow("img",img)
cv2.imshow("bgra",bgra)
cv2.imshow("bgra125",bgra125)
cv2.imshow("bgra0",bgra0)
cv2.waitKey()
cv2.destroyAllWindows()
cv2.imwrite("bgra.png", bgra)
cv2.imwrite("bgra125.png", bgra125)
cv2.imwrite("bgra0.png", bgra0)

在本例中,首先从当前目录下读取文件 lenacolor.png,然后将其进行色彩空间变换,将其由 BGR 色彩空间转换到 BGRA 色彩空间,得到 bgra,即为原始图像 lena 添加 alpha 通道。

接下来,分别将提取得到的 alpha 通道的值设置为 125、 0,并将新的 alpha 通道与原有的BGR 通道进行组合,得到新的 BGRA 图像 bgra125、 bgra0。

接着,分别显示原始图像、原始 BGRA 图像 bgra、重构的 BGRA 图像 bgra125 和 bgra0。

最后,将 3 个不同的 BGRA 图像保存在当前目录下。运行程序,显示的图像如图 4-7 所示。图中:

 图(a)是原始图像 lena。

 图(b)是由原始图像 lena 通过色彩空间转换得到的图像 bgra,该图像内 alpha 通道的值是默认值 255。

 图(c)是将图像 bgra 中 alpha 通道值设置为 0 得到的。

 图(d)是将图像 bgra 中 alpha 通道值设置为 125 得到的。

从图中可以看到,各个图像的 alpha 通道值虽然不同,但是在显示时是没有差别的。

OpenCV轻松入门:面向Python【1.9】_第4张图片

除此以外,程序还分别保存了不同 alpha 通道值的图像。打开当前文件夹,可以看到当前文件夹下保存了三幅图像,如图 4-8 所示,其中:

 图(a)是保存的图像 bgra,该图像由原始图像 lena 通过色彩空间转换得到,该图像内 alpha通道的值是默认值 255。

 图(b)是保存的图像 bgra125,该图像是将图像 bgra 中 alpha 通道值设置为 125 得到的。

 图(c)是保存的图像 bgra0,该图像是将图像 bgra 中 alpha 通道值设置为 0 得到的。 需要注意,在图像 bgra0 处于预览模式时,看起来可能是一幅黑色的图像,将其打开后就会看到它实际上是纯色透明的。

OpenCV轻松入门:面向Python【1.9】_第5张图片

你可能感兴趣的:(Python工程师提升计划,opencv,人工智能,计算机视觉,基于HSV色彩空间,开发语言,python,RGBA色彩空间)