0x00 往期博文
0x01 项目介绍
之前使用yolo3实现了红绿灯识别,但是部署起来略显复杂;
本期提供Opencv识别红绿灯颜色的思路;评论区留下邮箱提供Jupyter调试文档;
0x02 实验结果
交通灯会周期性地切换颜色显示状态。
机器人识别信号灯状态,做到"红灯停,绿灯行,黄灯等一等"。
Tips: 想象一下该实验结合循迹实验,我们可以做出一些有趣的场景;
0x03 导入依赖库
import cv2
from matplotlib import pyplot as plt
import numpy as np
0x04 获取测试图片
分别准备红灯、绿灯、黄灯的照片;
打开一张亮灯和未亮灯的图像;用作对比
img = cv2.imread('./img/yellow_light2.jpg') # 亮灯时的照片
img_n_l = cv2.imread('./img/none_light.jpg') # 未亮灯时的图像
0x05 将图像转为LAB色彩空间;
使用LAB色彩空间处理的优势:
- LAB的三个分量描述和红绿灯的亮度、颜色相吻合,更容易调试出结果
为什么不采用HSV色彩空间?
- HSV的色相H有红、橙、黄、绿、青、蓝、紫多种颜色,相较于LAB的红、绿、蓝、黄,HSV复杂很多。除非有青色或紫色的交通灯, 皮皮虾可能会看到(皮皮虾有很多种色感细胞)。
- HSV的饱和度S、亮度V不好控制,不如LAB的L,一个分量识别出灯的亮灭。
img_lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
img_n_l_lab = cv2.cvtColor(img_n_l, cv2.COLOR_BGR2LAB)
0x06 调整LAB色彩空间阈值
关于 LAB 色彩空间的知识请参考往期博文:旭日X3pi :: 三原色识别
根据色彩空间轴进行调整,最终获得各颜色阈值为:
lab_data = {
'red': {'lower': (73, 159, 154), 'upper': (142, 199, 192)},
'yellow': {'lower': (168, 108, 168), 'upper': (256, 128, 256)},
'green': {'lower': (128, 0, 128), 'upper': (256, 102, 256)}
}
0x07 识别逻辑颜色标注
# 交通灯识别函数
def traffic_light_identify(_img):
global traffic_light
lab_data = {
'red': {'lower': (73, 159, 154), 'upper': (142, 199, 192)},
'yellow': {'lower': (168, 108, 168), 'upper': (256, 128, 256)},
'green': {'lower': (128, 0, 128), 'upper': (256, 102, 256)}
}
# color img dict
c_c_d = {
'red': None,
'yellow': None,
'green': None
}
img_debug = _img.copy()
# 中值滤波降噪
imt_blur = cv2.blur(_img, (9, 9))
# 转换到LAB色彩空间
img_lab = cv2.cvtColor(imt_blur, cv2.COLOR_BGR2LAB)
# 遍历lab颜色特征
for _c in lab_data:
# 图像掩膜
_img_mask = cv2.inRange(img_lab, lab_data[_c]['lower'], lab_data[_c]['upper'])
cv2.imshow(_c + 'inRange', _img_mask)
# 找出所有外轮廓
contours, _ = cv2.findContours(_img_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
if len(contours) == 0:
continue
# 对轮廓对象按面积进行排序, 降序, 面积最大的为序号为0
c_sorted = sorted(contours,
key=lambda x:
math.fabs(
cv2.contourArea(x)
), reverse=True)
c_0 = c_sorted[0]
if math.fabs(cv2.contourArea(c_0)) > 100: # 轮廓面积大于100时允许赋值, 否则颜色对应轮廓为None
c_c_d[_c] = c_sorted[0]
"""
c_c_d = {'red': 轮廓, 'yellow': 轮廓, 'green': 轮廓} # 轮廓 可能是 None
"""
# 处理轮廓数据
try:
set(list(c_c_d.values())) # 取唯一值
# 如果Set列表后,全是None,没有灯亮起,直接返回
traffic_light = None # 没有灯亮起
return
except TypeError:
# 如果有轮廓数据, 继续运行;
# 这里利用了, Set方法无法对None类型做出哈希运算,会抛出一个TypeError异常;
# 捕获这个异常, 直接运行即可;
pass
_l = None # 根据面积比较,找出交通灯颜色
area_max = 100
for _c in lab_data:
if c_c_d[_c] is not None:
area_tmp = math.fabs(cv2.contourArea(c_c_d[_c]))
if area_tmp > area_max:
area_max = area_tmp
_l = _c
traffic_light = _l # 取颜色值
代码写的很优美,像小恐龙;
评论区留下邮箱,提供完整的Jupyter文档;
评论(5)
您还未登录,请登录后发表或查看评论