OpenCV基础教学(六):基于HSV颜色空间的目标颜色识别
本文将深入讲解HSV颜色空间的原理,以及如何利用HSV进行目标颜色识别和提取,通过Python+OpenCV代码实战演示完整的颜色识别流程。
总流程图:

一、颜色空间概述
RGB颜色模型的局限性
在之前的文章中,我们一直使用RGB(或BGR)颜色模型。虽然RGB模型直观且易于理解,但它存在一些局限性:
- 不符合人类感知:人类感知颜色是基于色调、饱和度和亮度,而不是红绿蓝三原色的强度
- 调整困难:在RGB空间调整颜色需要同时修改三个通道
- 光照敏感:RGB值对光照变化非常敏感
HSV颜色空间的特点与优势
HSV(Hue-Saturation-Value)颜色空间更符合人类对颜色的感知方式:
- Hue(色调):颜色的种类(红、绿、蓝等)
- Saturation(饱和度):颜色的纯度或鲜艳程度
- Value(明度):颜色的明亮程度
HSV的优势:
- 直观的颜色调整
- 对光照变化有一定鲁棒性
- 便于颜色分割和识别
二、HSV颜色空间详解
色调(Hue)的理解与应用
色调表示颜色的种类,使用角度表示(0°-360°):
红色:0°(或360°)
黄色:60°
绿色:120°
青色:180°
蓝色:240°
紫色:300°
在OpenCV中,Hue的取值范围被压缩到0-180(为了适应8位无符号整数)。
饱和度(Saturation)的作用
饱和度表示颜色的纯度:
- 0%:灰色,无色彩
- 100%:纯色,非常鲜艳
饱和度越高,颜色越鲜艳;饱和度越低,颜色越接近灰色。
明度(Value)的影响
明度表示颜色的明亮程度:
- 0%:纯黑色
- 100%:最亮的颜色
明度与光照强度直接相关,调整明度可以模拟不同光照条件。
HSV与RGB的对比
| 特性 | RGB颜色空间 | HSV颜色空间 |
|---|---|---|
| 颜色表示 | 红、绿、蓝三通道强度 | 色调、饱和度、明度 |
| 人类感知 | 不符合 | 符合 |
| 光照影响 | 敏感 | 相对不敏感 |
| 颜色调整 | 复杂 | 简单直观 |
三、目标颜色识别原理
HSV颜色范围的设定
在HSV空间中,每种颜色都有一个特定的范围。识别特定颜色的关键是找到该颜色在HSV空间中的最小值和最大值。
HSV范围设定原则:
- Hue(色调):确定主要颜色
- Saturation(饱和度):排除灰色和接近灰色的区域
- Value(明度):排除过暗或过亮的区域
常见颜色的HSV范围(OpenCV格式)
在OpenCV中,HSV的范围如下:
- Hue: 0-179
- Saturation: 0-255
- Value: 0-255
以下是常见颜色的HSV范围参考:
python
# 常见颜色的HSV范围(OpenCV格式)
HSV_RANGES = {
'红色': [
([0, 43, 46], [10, 255, 255]), # 红色范围1
([156, 43, 46], [180, 255, 255]) # 红色范围2(跨越0°)
],
'黄色': [([26, 43, 46], [34, 255, 255])],
'绿色': [([35, 43, 46], [77, 255, 255])],
'青色': [([78, 43, 46], [99, 255, 255])],
'蓝色': [([100, 43, 46], [124, 255, 255])],
'紫色': [([125, 43, 46], [155, 255, 255])],
'黑色': [([0, 0, 0], [180, 255, 46])],
'白色': [([0, 0, 221], [180, 30, 255])],
'灰色': [([0, 0, 46], [180, 43, 220])]
}
注意:红色在HSV中需要两个范围,因为它跨越了0°(360°)边界。
掩膜(Mask)的创建与应用

掩膜是一个二进制图像,其中白色(255)表示感兴趣区域,黑色(0)表示背景区域。
掩膜的作用:
- 隔离特定颜色区域
- 减少计算量
- 便于后续处理
按位操作提取目标区域
使用按位与操作,将原始图像与掩膜结合,只保留掩膜中白色区域对应的像素:
python
# 按位与操作:提取目标颜色区域
result = cv2.bitwise_and(src1, src2, mask=mask)
四、代码实战:目标颜色识别
基础实现代码
python
import cv2
import numpy as np
import matplotlib.pyplot as plt
def color_detection(image_path, target_color='yellow', show_steps=True):
"""
检测图像中的特定颜色
Args:
image_path: 图像路径
target_color: 目标颜色
show_steps: 是否显示处理步骤
Returns:
处理结果
"""
# 1. 读取图像
image_bgr = cv2.imread(image_path)
image_bgr = cv2.resize(image_bgr, (700, 700))
image_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB)
# 2. 转换为HSV颜色空间
image_hsv = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2HSV)
# 3. 定义目标颜色的HSV范围
if target_color == 'yellow':
# 黄色范围
lower = np.array([26, 43, 46])
upper = np.array([34, 255, 255])
elif target_color == 'red':
# 红色范围(需要两个范围)
lower1 = np.array([0, 43, 46])
upper1 = np.array([10, 255, 255])
lower2 = np.array([156, 43, 46])
upper2 = np.array([180, 255, 255])
elif target_color == 'blue':
# 蓝色范围
lower = np.array([100, 43, 46])
upper = np.array([124, 255, 255])
else:
# 默认使用黄色
lower = np.array([26, 43, 46])
upper = np.array([34, 255, 255])
# 4. 创建掩膜
if target_color == 'red':
# 红色需要两个掩膜
mask1 = cv2.inRange(image_hsv, lower1, upper1)
mask2 = cv2.inRange(image_hsv, lower2, upper2)
mask = cv2.bitwise_or(mask1, mask2)
else:
mask = cv2.inRange(image_hsv, lower, upper)
# 5. 应用掩膜提取目标颜色
result = cv2.bitwise_and(image_bgr, image_bgr, mask=mask)
result_rgb = cv2.cvtColor(result, cv2.COLOR_BGR2RGB)
# 6. 可视化结果
if show_steps:
plt.figure(figsize=(15, 10))
plt.subplot(2, 3, 1)
plt.imshow(image_rgb)
plt.title('Original Image')
plt.axis('off')
plt.subplot(2, 3, 2)
# 显示HSV的H通道
h_channel = image_hsv[:, :, 0]
plt.imshow(h_channel, cmap='hsv')
plt.title('Hue Channel')
plt.colorbar()
plt.axis('off')
plt.subplot(2, 3, 3)
# 显示HSV的S通道
s_channel = image_hsv[:, :, 1]
plt.imshow(s_channel, cmap='gray')
plt.title('Saturation Channel')
plt.colorbar()
plt.axis('off')
plt.subplot(2, 3, 4)
# 显示HSV的V通道
v_channel = image_hsv[:, :, 2]
plt.imshow(v_channel, cmap='gray')
plt.title('Value Channel')
plt.colorbar()
plt.axis('off')
plt.subplot(2, 3, 5)
plt.imshow(mask, cmap='gray')
plt.title(f'Mask for {target_color}')
plt.axis('off')
plt.subplot(2, 3, 6)
plt.imshow(result_rgb)
plt.title(f'Detected {target_color} Region')
plt.axis('off')
plt.tight_layout()
plt.show()
return mask, result_rgb
# 使用示例
mask, result = color_detection('./color.png', target_color='yellow')
多颜色同时识别
python
def detect_multiple_colors(image_path, colors=['red', 'green', 'blue']):
"""
同时检测多种颜色
"""
# 读取并预处理图像
image_bgr = cv2.imread(image_path)
image_bgr = cv2.resize(image_bgr, (700, 700))
image_hsv = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2HSV)
# 定义颜色范围
color_ranges = {
'red': [([0, 43, 46], [10, 255, 255]),
([156, 43, 46], [180, 255, 255])],
'yellow': [([26, 43, 46], [34, 255, 255])],
'green': [([35, 43, 46], [77, 255, 255])],
'blue': [([100, 43, 46], [124, 255, 255])]
}
# 为每种颜色创建掩膜
masks = {}
for color in colors:
if color in color_ranges:
color_masks = []
for lower, upper in color_ranges[color]:
lower_np = np.array(lower)
upper_np = np.array(upper)
color_masks.append(cv2.inRange(image_hsv, lower_np, upper_np))
# 合并多个范围(如红色)
if len(color_masks) > 1:
combined_mask = cv2.bitwise_or(color_masks[0], color_masks[1])
for i in range(2, len(color_masks)):
combined_mask = cv2.bitwise_or(combined_mask, color_masks[i])
masks[color] = combined_mask
else:
masks[color] = color_masks[0]
# 可视化结果
plt.figure(figsize=(15, 10))
# 显示原图
plt.subplot(2, 3, 1)
plt.imshow(cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB))
plt.title('Original Image')
plt.axis('off')
# 显示每种颜色的掩膜
for idx, (color, mask) in enumerate(masks.items(), 2):
plt.subplot(2, 3, idx)
plt.imshow(mask, cmap='gray')
plt.title(f'{color.capitalize()} Mask')
plt.axis('off')
# 显示所有颜色合并的结果
plt.subplot(2, 3, 6)
combined_result = np.zeros_like(image_bgr)
color_map = {
'red': (0, 0, 255), # BGR格式
'green': (0, 255, 0),
'blue': (255, 0, 0),
'yellow': (0, 255, 255)
}
for color, mask in masks.items():
if color in color_map:
color_mask = np.zeros_like(image_bgr)
color_mask[:, :] = color_map[color]
color_region = cv2.bitwise_and(color_mask, color_mask, mask=mask)
combined_result = cv2.add(combined_result, color_region)
plt.imshow(cv2.cvtColor(combined_result, cv2.COLOR_BGR2RGB))
plt.title('All Detected Colors')
plt.axis('off')
plt.tight_layout()
plt.show()
return masks
# 使用示例
masks = detect_multiple_colors('./color.png', colors=['red', 'green', 'blue', 'yellow'])
五 、总结与应用场景
颜色识别的实际应用
- 工业分拣:识别和分拣不同颜色的产品
- 交通标志识别:识别红绿灯、交通标志的颜色
- 医学图像分析:识别病理图像中的特定颜色区域
- 机器人视觉:引导机器人识别和抓取特定颜色的物体
- 游戏开发:颜色追踪和交互
- 农业应用:识别成熟水果的颜色
HSV颜色识别的优缺点
优点:
- 对光照变化有一定鲁棒性
- 颜色分离效果好
- 计算相对简单
- 实时性好
缺点:
- 需要预先知道目标颜色的HSV范围
- 对颜色渐变处理不够好
- 在极端光照条件下可能失效
进一步学习方向
- 机器学习方法:使用分类器进行颜色识别
- 深度学习:使用卷积神经网络进行像素级颜色分类
- 颜色恒常性:在不同光照条件下保持颜色识别的一致性
- 多光谱成像:使用超出可见光范围的光谱信息
实践建议
- 实验不同的HSV范围:使用交互式工具找到最佳范围
- 结合形态学操作:优化识别结果
- 考虑光照条件:在不同光照下测试算法
- 使用多个颜色模型:结合RGB、HSV、LAB等模型提高鲁棒性
📌 下期预告
下一期我们将学习图像的特征检测与描述(SIFT、SURF、ORB等),掌握如何在图像中寻找和描述关键特征点。
扩展思考
- 如何处理颜色渐变区域?
- 如何在没有先验知识的情况下识别未知颜色?
- 如何提高颜色识别在复杂背景下的鲁棒性?
欢迎在评论区分享你的实践经验和遇到的问题!
如果觉得本文有帮助,欢迎点赞、收藏、关注!
你的支持是我持续创作的最大动力!