# OpenCV 第14课:图像处理之颜色识别(二)
方法优点缺点适用场景固定HSV阈值简单快速光照敏感实验室环境动态滑动条可调参调试不适合自动化开发阶段多颜色识别支持复杂场景需处理重叠工业分拣结合轮廓/形状更准确计算量大交通标志识别。
🎨 实战进阶篇 —— 动态调参、多色识别与实际应用(含完整代码 + 图文详解)
📚 上节回顾 & 本课目标
在【第13课】中,我们学习了:
- HSV色彩空间基础
- 使用
cv2.inRange()提取单一颜色 - 简单的颜色分割示例
📌 本节课升级内容:
✅ 多颜色同时识别
✅ 使用滑动条动态调节HSV阈值(实时调参)
✅ 颜色识别+轮廓检测联动
✅ 实际应用场景:交通灯识别模拟
✅ 完整可运行代码 + 图解流程
🧰 准备工作
✅ 安装依赖
pip install opencv-python numpy matplotlib
✅ 测试图片准备
建议使用一张包含红、绿、蓝等明显颜色的图片。例如:
📁 test_colors.jpg
(可以是彩色积木、RGB灯带、交通信号灯等)
🎯 核心知识点:HSV 色彩空间再理解
| 通道 | 含义 | 取值范围 |
|---|---|---|
| H(Hue) | 色相(颜色种类) | 0–179(OpenCV中) |
| S(Saturation) | 饱和度 | 0–255 |
| V(Value) | 明亮度 | 0–255 |
🟢 常见颜色 HSV 近似范围(光照不同会有变化):
| 颜色 | H(低) | H(高) | S, V 下限 |
|---|---|---|---|
| 红色 | 0–10 或 170–180 | S > 100, V > 100 | |
| 绿色 | 40–80 | S > 100, V > 100 | |
| 蓝色 | 100–130 | S > 100, V > 100 | |
| 黄色 | 20–40 | S > 100, V > 100 |
⚠️ 注意:红色跨边界!需合并两个区间
🔧 第一步:创建动态HSV调节器(Trackbar)
让我们做一个“实时调色板”,方便调试!
import cv2
import numpy as np
# 加载图像
image = cv2.imread('test_colors.jpg')
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# 创建窗口
cv2.namedWindow('Trackbars')
cv2.resizeWindow('Trackbars', 600, 300)
# 创建滑动条(H, S, V 的上下限)
def nothing(x):
pass
cv2.createTrackbar("L - H", "Trackbars", 0, 179, nothing)
cv2.createTrackbar("L - S", "Trackbars", 0, 255, nothing)
cv2.createTrackbar("L - V", "Trackbars", 0, 255, nothing)
cv2.createTrackbar("U - H", "Trackbars", 179, 179, nothing)
cv2.createTrackbar("U - S", "Trackbars", 255, 255, nothing)
cv2.createTrackbar("U - V", "Trackbars", 255, 255, nothing)
while True:
# 获取滑动条当前值
l_h = cv2.getTrackbarPos("L - H", "Trackbars")
l_s = cv2.getTrackbarPos("L - S", "Trackbars")
l_v = cv2.getTrackbarPos("L - V", "Trackbars")
u_h = cv2.getTrackbarPos("U - H", "Trackbars")
u_s = cv2.getTrackbarPos("U - S", "Trackbars")
u_v = cv2.getTrackbarPos("U - V", "Trackbars")
# 构建HSV上下界
lower_bound = np.array([l_h, l_s, l_v])
upper_bound = np.array([u_h, u_s, u_v])
# 创建掩膜
mask = cv2.inRange(hsv, lower_bound, upper_bound)
result = cv2.bitwise_and(image, image, mask=mask)
# 显示结果
cv2.imshow("Original", image)
cv2.imshow("Mask", mask)
cv2.imshow("Result", result)
# 按 ESC 退出
if cv2.waitKey(1) == 27:
break
cv2.destroyAllWindows()
🖼️ 效果图示意:
+------------------+ +------------------+
| Original | | Mask (Binary) |
| | | 白色=匹配区域 |
| [彩色图像] | | [黑白图] |
+------------------+ +------------------+
+------------------+
| Result |
| 只保留目标色块 |
| [过滤后图像] |
+------------------+
👉 你可以拖动滑块,实时看到哪些像素被选中!
🎨 第二步:同时识别多种颜色(红/绿/蓝)
现在我们要一次性找出画面中的三种颜色,并分别标记。
import cv2
import numpy as np
def detect_colors(image):
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# 定义各颜色的HSV范围
color_ranges = {
'Red': [
(np.array([0, 100, 100]), np.array([10, 255, 255])),
(np.array([170, 100, 100]), np.array([180, 255, 255])) # 红色有两个区间
],
'Green': [(np.array([40, 100, 100]), np.array([80, 255, 255]))],
'Blue': [(np.array([100, 100, 100]), np.array([130, 255, 255]))]
}
output = image.copy()
for color_name, ranges in color_ranges.items():
mask = None
for lower, upper in ranges:
part_mask = cv2.inRange(hsv, lower, upper)
mask = part_mask if mask is None else cv2.bitwise_or(mask, part_mask)
# 查找轮廓
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
area = cv2.contourArea(cnt)
if area > 500: # 过滤小噪点
x, y, w, h = cv2.boundingRect(cnt)
cv2.rectangle(output, (x, y), (x+w, y+h), (0, 255, 255), 2)
cv2.putText(output, color_name, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX,
0.9, (0, 255, 255), 2)
# 可选:显示每个颜色的掩膜
# cv2.imshow(f'Mask_{color_name}', mask)
return output
🧪 测试代码
img = cv2.imread('test_colors.jpg')
result_img = detect_colors(img)
cv2.imshow('Detected Colors', result_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
🖼️ 输出效果:
[图像]
🟩 绿色方框标注绿色积木
🟥 红色标签标出红色部分
🟦 蓝色物体也被圈出
✅ 成功实现多色识别!
🚦 第三步:实战案例 —— 模拟交通灯识别
假设你有一张交通灯图像,我们要判断当前亮的是什么灯。
def detect_traffic_light(image):
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 找圆(假设交通灯是圆形)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 50,
param1=50, param2=30, minRadius=10, maxRadius=100)
if circles is None:
return image, "No traffic light detected"
circles = np.uint16(np.around(circles))
light_status = "Unknown"
for circle in circles[0, :]:
center_x, center_y = circle[0], circle[1]
radius = circle[2]
# 创建圆形掩膜
mask = np.zeros(hsv.shape[:2], dtype=np.uint8)
cv2.circle(mask, (center_x, center_y), radius, 255, -1)
# 分区检测颜色(上中下)
top_roi = mask[center_y-radius:center_y-int(radius*0.3), center_x-radius:center_x+radius]
mid_roi = mask[center_y-int(radius*0.3):center_y+int(radius*0.3), center_x-radius:center_x+radius]
bot_roi = mask[center_y+int(radius*0.3):center_y+radius, center_x-radius:center_x+radius]
# 判断每区是否有红/黄/绿
red_mask = cv2.inRange(hsv, (0,100,100), (10,255,255))
red_mask2 = cv2.inRange(hsv, (170,100,100), (180,255,255))
red_mask = cv2.bitwise_or(red_mask, red_mask2)
green_mask = cv2.inRange(hsv, (40,100,100), (80,255,255))
# 统计亮度占比
def get_color_ratio(color_mask, roi_mask):
masked = cv2.bitwise_and(color_mask, color_mask, mask=roi_mask)
return cv2.countNonZero(masked) / (cv2.countNonZero(roi_mask) + 1e-6)
top_ratio = get_color_ratio(red_mask, top_roi)
mid_ratio = get_color_ratio(green_mask, mid_roi)
if top_ratio > 0.5:
light_status = "Stop (Red)"
color = (0, 0, 255)
elif mid_ratio > 0.5:
light_status = "Go (Green)"
color = (0, 255, 0)
else:
light_status = "Caution (Yellow)" # 可扩展为黄色检测
color = (0, 255, 255)
# 绘制结果
cv2.circle(image, (center_x, center_y), radius, color, 3)
cv2.putText(image, light_status, (center_x-50, center_y-80),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, color, 2)
return image, light_status
🧪 测试交通灯识别
img_tl = cv2.imread('traffic_light.jpg')
res, status = detect_traffic_light(img_tl.copy())
cv2.imshow('Traffic Light Detection', res)
print("🚦 当前状态:", status)
cv2.waitKey(0)
cv2.destroyAllWindows()
📊 总结对比表:颜色识别方法优劣
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 固定HSV阈值 | 简单快速 | 光照敏感 | 实验室环境 |
| 动态滑动条 | 可调参调试 | 不适合自动化 | 开发阶段 |
| 多颜色识别 | 支持复杂场景 | 需处理重叠 | 工业分拣 |
| 结合轮廓/形状 | 更准确 | 计算量大 | 交通标志识别 |
💡 小贴士与避坑指南
- 光照影响极大! → 尽量在均匀光线下测试
- 避免颜色混淆:如绿色和青色接近,可加S/V过滤
- 性能优化:先缩放图像再处理
- 生产建议:结合深度学习模型(如 YOLO+颜色分类)更鲁棒
📦 完整项目结构推荐
project/
│
├── main.py # 主程序入口
├── utils/color_detector.py # 颜色识别模块
├── assets/
│ ├── test_colors.jpg # 测试图
│ └── traffic_light.jpg
└── requirements.txt
🎁 附录:常用HSV范围速查表(打印备用)
| 颜色 | H (Low) | H (High) | S/V Min |
|---|---|---|---|
| Red | 0–10 和 170–180 | S≥100, V≥100 | |
| Orange | 10–25 | S≥100, V≥100 | |
| Yellow | 25–35 | S≥100, V≥100 | |
| Green | 40–80 | S≥100, V≥100 | |
| Cyan | 80–100 | S≥100, V≥100 | |
| Blue | 100–130 | S≥100, V≥100 | |
| Purple | 130–160 | S≥100, V≥100 | |
| Pink | 160–170 | S≥100, V≥100 |
📝 建议:用自己的摄像头 + 实物校准一次最佳参数!
🎯 下一课预告
《OpenCV 第15课:图像处理之模板匹配与特征点检测》
我们将学习:
cv2.matchTemplate()匹配图标- SIFT/SURF 特征提取
- 实现“找茬游戏”或“二维码定位”
📌 点赞 + 收藏,不错过每一节硬核教程!
💬 欢迎留言:“求视频版” 或 “想要摄像头实时识别代码!” 我会持续更新!
📎 示例代码 GitHub 地址:https://github.com/example/opencv-course-14 (请自行创建)
🎯 学会颜色识别,你就掌握了机器“看懂世界”的第一步
2025年昇腾CANN训练营第二季,基于CANN开源开放全场景,推出0基础入门系列、码力全开特辑、开发者案例等专题课程,助力不同阶段开发者快速提升算子开发技能。获得Ascend C算子中级认证,即可领取精美证书,完成社区任务更有机会赢取华为手机,平板、开发板等大奖。\n报名链接:https://www.hiascend.com/developer/activities/cann20252!
更多推荐
所有评论(0)