计算机视觉(二)——HSV色彩分离及目标跟踪
HSV是一种基于颜色直观特性的三维空间模型,在1978年由A.R.Smith提出,并被广泛应用于图像处理领域。该模型通过三个基本参数——色调(H)、饱和度(S)以及明度(V)——来描述一种特定的颜色,并且其名称也来源于其几何结构上的特点——六棱锥体模型。与传统的RGB色彩空间相比,在准确反映人类对色彩的感受方面表现更为出色,并且在计算复杂度上具有较高的简洁性。
HSV色彩分离的具体流程主要包括以下四个步骤:首先将图像从RGB空间转换为HSI(或其他相关)表示;其次设定一个目标阈值范围;接着构建一个掩膜以识别目标区域;最后通过滤波技术提取出目标颜色。
文章目录
-
一、RGB颜色模型
-
二、HSV颜色模型
-
- 1.颜色模型
- 2.转换算法
-
第三章 遮罩技术概述
-
第四章 基于HSV颜色空间的视频分割代码实现(Python)
-
第1步 导入必要的库模块
- 第2步 读取原始视频文件
- 第3步 将原始视频信号转换为HSV颜色空间表示
- 第4步 根据特定条件生成目标区域的遮罩图
- 第5步 应用滤波器以提取所需颜色成分
- 第6步 输出完整的分割处理流程代码
-
五、目标跟踪
-
一、RGB颜色模型
基于工业界广泛认可的标准...通过改变R/G/B通道的状态并进行叠加运算生成不同色彩...即代表红/绿/蓝三个通道的颜色...几乎涵盖了人类视觉系统所能感知的所有色光(视网膜能检测到大约600种不同的光线)并以这种形式被广泛应用

二、HSV颜色模型
1.颜色模型
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%(白)。

2.转换算法
令 (r, g, b) 分别代表一种颜色的红、绿、蓝分量,并且它们都在 0 到 1 的范围内取值。其中最大值即为 r、g 和 b 中的最大者;而最小值则取自这些数值的最小者。进而可求得 HSV 空间中的 (h, s, v) 值,在此定义中 h 属于 [0°, 360°),s 和 v 则均属于 [0.0, 1.0] 区间内



对于大多数用户而言,HSV是一种直观且易于理解的颜色模型。我们可以从一种纯色基底开始,并通过设定H值并将V和S参数设为1来构建基础色调。随后通过添加黑色或白色元素来实现色调的明暗调节:在加入黑色时会降低亮度而不影响色调;同样地,在加入白色时会降低色调饱和度而不影响明暗度。例如,在H=210度时调节S为0.4并使V值为1即可得到淡蓝色;反之调节S为0.4并使V值为0.4则可获得深蓝色等不同色调组合。

三、掩膜
在数字信号处理领域中,滤波器的概念源自电子电路设计的发展,它在电子系统开发过程中扮演着重要角色
四、HSV颜色分离代码实现(python)
1.引入库
import numpy as np
import cv2
2.导入原视频
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格式后上传。

3.将原视频转换到hsv颜色空间
转换到hsv颜色空间需要使用函数cv2.cvtColor(input_image, flag)
| 参数 | 描述 | 返回值 |
|---|---|---|
| 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)
转换后结果为:

4.求得掩膜
进行掩膜计算。
基于预设的颜色阈值。
使用 OpenCV 的 inRange 函数生成掩膜以提取出绿色区域。
其中第四行的矩阵拓展仅用于可视化展示,在实际应用中无需进行扩展。
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) #矩阵拓展
得到的掩膜结果为:

5.过滤目标颜色
获得掩码后,并非直接作用于原图进行处理而是通过调用函数实现这一目标
res = cv2.bitwise_and(frame, frame, mask = mask2)
过滤后结果为:

6.完整代码
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()
五、目标跟踪
通过Hue-Saturation-Value(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) #根据每一帧中物体的左上角坐标以及右下角坐标绘制矩形框
最终结果为:

