HSV是根据颜色的直观特性由A.R.Smith在1978年创造的一种颜色空间,也称六角锥体模型。这个模型中颜色的参数分别是:色调(H)、饱和度(S)、明度(V)。HSV比传统的RGB颜色空间更能准确的感知颜色,并仍保持在计算上的简单。
HSV色彩分离的基本步骤为:转换HSV表示,设定目标阈值,设置掩膜,过滤目标颜色。
RGB色彩模式是工业界的一种颜色标准,是通过对红( R )、绿( G )、蓝( B )三种颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是运用最广的颜色系统之一。
HSV是根据颜色的直观特性由A.R.Smith在1978年创造的一种颜色空间,也称六角锥体模型。这个模型中颜色的参数分别是:色调(H)、饱和度(S)、明度(V)。
色调H:用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,紫色为360°。
饱和度S:饱和度S表示颜色接近光谱色的程度。一种颜色,可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例越大,颜色接近光谱色的程度就越高,颜色的饱和程度也就越高,饱和度高,颜色则深而艳。光谱色的白光成分为0,饱和度达到最高。通常取值范围为0%~100%,值越大,颜色越饱和。
明度V:明度表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。通常取值范围为0%(黑)到100%(白)。
设 (r, g, b) 分别是一个颜色的红、绿和蓝坐标,它们的值是在 0 到 1 之间的实数。设 max 等价于 r, g 和 b 中的最大者。设 min 等于这些值中的最小者。要找到在 HSV空间中的 (h, s, v) 值,这里的 h ∈ [0, 360)是角度的色相角,而 s, v ∈ [0,1] 是饱和度和亮度
HSV对用户来说是一种直观的颜色模型。我们可以从一种纯色彩开始,即指定色彩角H,并让V=S=1,然后我们可以通过向其中加入黑色和白色来得到我们需要的颜色。增加黑色可以减小V而S不变,同样增加白色可以减小S而V不变。例如,要得到深蓝色,V=0.4 S=1 H=210度。要得到淡蓝色,V=1 S=0.4 H=210度。
一般说来,人眼最大能区分128种不同的色彩,130种色饱和度,23种明暗度。如果我们用16Bit表示HSV的话,可以用7位存放H,4位存放S,5位存放V,即745或者655就可以满足我们的需要了。
由于HSV是一种比较直观的颜色模型,所以在许多图像编辑工具中应用比较广泛,如Photoshop(在Photoshop中叫HSB)等等,但这也决定了它不适合使用在光照模型中,许多光线混合运算、光强运算等都无法直接使用HSV来实现。
顺便提一下,另外一种直观颜色模型是HSL模型,该模型中前两个参数和HSV一样,而L表示亮度。它的三维表示为一双棱锥。
各颜色具体数值如下:
数字图像处理中的掩膜概念是借鉴于PCB制版的过程,在半导体制作中,许多芯片工艺步骤采用光刻技术,用于这些步骤的图形“底片”称为掩膜,其作用是:在硅片上选定的区域中对一个不透明的图形模板掩盖,继而下面的腐蚀或扩散只影响选定区域以外的区域。
图像掩膜与其类似,用选定的图像、图形或物体,对处理的图像进行遮挡,来控制图像处理区域或处理过程。
数字图像处理中,掩膜为―维矩阵数组有时也用多值图像,图像掩膜主要用于:
①提取感兴趣区,用预先制作的感兴趣区掩膜与待处理图像相乘.得到感兴趣区图像,感兴趣区内图像值保持不变,而区外图像值都为0。
②屏蔽作用,用掩膜对图像上某些区域作屏蔽使其不参加处理或不参加处理参数的计算.或仅对屏蔽区作处理或统计。
③结构特征提取,用相似性变量或图像匹配方法检测和提取图像中与掩膜相似的结构特征。
④特殊形状图像的制作。
import numpy as np
import cv2
cap = cv2.VideoCapture('green.mp4') #打开同一目录下的视频
while(cap.isOpened()):
ret, frame = cap.read() #frame保存视频每一帧
if ret==True: #当读取成功时
cv2.imshow('frame',frame)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
else:
break
cap.release()
cv2.destroyAllWindows()
为方便浏览,本文所有视频均转换为gif格式后上传。
转换到hsv颜色空间需要使用函数cv2.cvtColor(input_image, flag)
参数 | 描述 | 返回值 | ||||||
---|---|---|---|---|---|---|---|---|
|
|
|
||||||
|
|
转换的类型:
类型 | 描述 |
---|---|
cv2.COLOR_BGR2GRAY | BGR -> Gray |
cv2.COLOR_BGR2RGB | BGR -> RGB |
cv2.COLOR_BGR2HSV | BGR -> HSV |
具体代码为:
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
转换后结果为:
计算掩膜,首先需要先根据确定颜色的各项阈值,然后使用cv2.inRang函数设置掩膜,只保留绿色的部分。其中第四行的矩阵拓展只是为了能将这一步可视化成视频,在实际操作中并不需要。
lower = np.array([35, 43, 46])
upper = np.array([77, 255, 255]) #设定绿色的hsv阈值
mask2 = cv2.inRange(hsv, lower, upper)#设置掩模 只保留绿色部分
mask=np.stack([mask2] * 3, axis=2) #矩阵拓展
求得掩膜以后,使用cv2.bitwise_and函数将掩膜与原图像做“与”操作 过滤出绿色,得到最终结果。
res = cv2.bitwise_and(frame, frame, mask = mask2)
过滤后结果为:
import cv2
cap = cv2.VideoCapture('green.mp4') #打开原视频
fourcc = cv2.VideoWriter_fourcc(*'mp4v') #设置输出视频格式
fps =cap.get(cv2.CAP_PROP_FPS) #设置输出视频帧数
size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))) #视频尺寸
out2 = cv2.VideoWriter('green_hsv.mp4',fourcc, fps, size) #设置输出hsv视频
out3 = cv2.VideoWriter('green_mask.mp4',fourcc, fps, size) #设置输出mask视频
out4 = cv2.VideoWriter('green_res.mp4',fourcc, fps, size) #设置输出最终过滤视频
while(cap.isOpened()):
ret, frame = cap.read()
if ret==True:
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) #rgb通道难以分离颜色 需要先转化到hsv色彩空间
lower = np.array([35, 43, 46])
upper = np.array([77, 255, 255]) #设定绿色的hsv阈值
mask2 = cv2.inRange(hsv, lower, upper)#设置掩模 只保留绿色部分
res = cv2.bitwise_and(frame, frame, mask = mask2 #利用掩模与原图像做“与”操作 过滤出绿色
mask=np.stack([mask2] * 3, axis=2) #mask矩阵拓展
out2.write(hsv) #保存hsv视频到本地
out3.write(mask) #保存mask视频到本地
out4.write(res) #保存最终视频到本地
cv2.imshow('frame',frame) #显示原视频
cv2.imshow('hsv',hsv) #显示hsv视频
cv2.imshow('mask',mask) #显示mask视频
cv2.imshow('res',res) #显示最终视频
if cv2.waitKey(10) & 0xFF == ord('q'):
break
else:
break
cap.release()
out.release()
out2.release()
out3.release()
out4.release()
cv2.destroyAllWindows()
通过hsv颜色分离,我们可以识别出视频中的绿色物体,因此我们可以进一步通过这种方法,对视频中的绿色物体进行跟踪。具体思路如下:
1.利用形态学中的开运算,去除视频中的绿色噪点。开运算详解。
2.根据掩膜所得到的二维(0-255)矩阵,得到物体的范围。
3.根据物体的范围绘制矩形框。
涉及代码如下:
kernel = np.ones((10,10), np.uint8) #设置开运算所需核
opening = cv2.morphologyEx(mask2, cv2.MORPH_OPEN, kernel) # 对得到的mask进行开运算
rectangle = np.where(opening == 255) #找出开运算后矩阵中为255的部分,即物体范围
cv2.rectangle(frame, (min(rectangle[1]), min(rectangle[0])), (max(rectangle[1]), max(rectangle[0])), (0, 0, 255), 3) #根据每一帧中物体的左上角坐标以及右下角坐标绘制矩形框
最终结果为: