如何基于OpenCV改进简单交通灯检测代码实现全图检测?
问题:OpenCV简单交通灯检测仅检测图像上部,如何修改?
我希望在Python中借助OpenCV实现简单的交通灯检测算法。当然,若要获得高精度应使用预训练深度学习模型,但目前我仅需最简单的非全面方案。由于交通灯存在红、绿、黄三种颜色,我找到了一份实现三色检测的代码。
我清楚这并非精准方法,仅用于自学。我已在一段视频上测试了该代码,视频的截取帧如下:
运行代码后得到如下结果图:
可以看到,图像下部被忽略,仅检测了上部区域。
我该如何调整或修改代码,使其能检测整张图像中的真实交通灯?是否需要将图像调整为更低分辨率?或是采用其他方法?我考虑过调整帧大小,但想先听取意见。我认为核心问题出在轮廓坐标定位的代码部分,该如何修改?
测试代码
import numpy as np import cv2 import warnings warnings.filterwarnings("ignore") # Capturing video through webcam live_video = cv2.VideoCapture("traffic_light.mp4") # Start a while loop while (1): # Reading the video from the # webcam in image frames _, imageFrame = live_video .read() # Convert the imageFrame in # BGR(RGB color space) to # HSV(hue-saturation-value) # color space hsvFrame = cv2.cvtColor(imageFrame, cv2.COLOR_BGR2HSV) # Set range for red color and # define mask red_lower = np.array([136, 87, 111], np.uint8) red_upper = np.array([180, 255, 255], np.uint8) red_mask = cv2.inRange(hsvFrame, red_lower, red_upper) # Set range for green color and # define mask green_lower = np.array([25, 52, 72], np.uint8) green_upper = np.array([102, 255, 255], np.uint8) green_mask = cv2.inRange(hsvFrame, green_lower, green_upper) # Set range for blue color and # define mask blue_lower = np.array([94, 80, 2], np.uint8) blue_upper = np.array([120, 255, 255], np.uint8) blue_mask = cv2.inRange(hsvFrame, blue_lower, blue_upper) # Morphological Transform, Dilation # for each color and bitwise_and operator # between imageFrame and mask determines # to detect only that particular color kernal = np.ones((5, 5), "uint8") # For red color red_mask = cv2.dilate(red_mask, kernal) res_red = cv2.bitwise_and(imageFrame, imageFrame, mask=red_mask) # For green color green_mask = cv2.dilate(green_mask, kernal) res_green = cv2.bitwise_and(imageFrame, imageFrame, mask=green_mask) # For blue color blue_mask = cv2.dilate(blue_mask, kernal) res_blue = cv2.bitwise_and(imageFrame, imageFrame, mask=blue_mask) # Creating contour to track red color contours, hierarchy = cv2.findContours(red_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) for pic, contour in enumerate(contours): area = cv2.contourArea(contour) if (area > 300): x, y, w, h = cv2.boundingRect(contour) imageFrame = cv2.rectangle(imageFrame, (x, y), (x + w, y + h), (0, 0, 255), 2) cv2.putText(imageFrame, "Red Colour", (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 0, 255)) # Creating contour to track green color contours, hierarchy = cv2.findContours(green_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) for pic, contour in enumerate(contours): area = cv2.contourArea(contour) if (area > 300): x, y, w, h = cv2.boundingRect(contour) imageFrame = cv2.rectangle(imageFrame, (x, y), (x + w, y + h), (0, 255, 0), 2) cv2.putText(imageFrame, "Green Colour", (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0)) # Creating contour to track blue color contours, hierarchy = cv2.findContours(blue_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) for pic, contour in enumerate(contours): area = cv2.contourArea(contour) if (area > 300): x, y, w, h = cv2.boundingRect(contour) imageFrame = cv2.rectangle(imageFrame, (x, y), (x + w, y + h), (255, 0, 0), 2) cv2.putText(imageFrame, "Blue Colour", (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 0, 0)) # Program Termination cv2.imshow("Multiple Color Detection in Real-TIme", imageFrame) if cv2.waitKey(10) & 0xFF == ord('q'): live_video .release() cv2.destroyAllWindows() break
解决方案
1. 核心问题分析
下部区域检测不到的问题,并非轮廓坐标定位的问题,根源在于:
- 原代码未覆盖交通灯的黄色检测
- 预设的HSV颜色范围与视频中下部交通灯的实际颜色不匹配
- 轮廓面积阈值
300对画面中尺寸更小的下部交通灯来说过高
2. 具体修改步骤
(1)添加黄色检测逻辑
在绿色检测代码后插入黄色的HSV范围定义与形态学处理:
# Set range for yellow color and define mask yellow_lower = np.array([20, 100, 100], np.uint8) yellow_upper = np.array([30, 255, 255], np.uint8) yellow_mask = cv2.inRange(hsvFrame, yellow_lower, yellow_upper) # Morphological Dilation for yellow yellow_mask = cv2.dilate(yellow_mask, kernal) res_yellow = cv2.bitwise_and(imageFrame, imageFrame, mask=yellow_mask)
再添加黄色的轮廓检测与绘制代码:
# Creating contour to track yellow color contours, hierarchy = cv2.findContours(yellow_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) for pic, contour in enumerate(contours): area = cv2.contourArea(contour) if (area > 100): # 降低阈值适配小尺寸交通灯 x, y, w, h = cv2.boundingRect(contour) imageFrame = cv2.rectangle(imageFrame, (x, y), (x + w, y + h), (0, 255, 255), 2) cv2.putText(imageFrame, "Yellow Colour", (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255))
(2)调整绿色HSV范围适配实际场景
原绿色范围过宽易误检,修改为更精准的区间:
green_lower = np.array([40, 40, 40], np.uint8) green_upper = np.array([80, 255, 255], np.uint8)
(3)降低轮廓面积阈值
将所有area > 300的判断改为area > 100(可根据视频实际情况微调),确保小尺寸交通灯的轮廓能被捕捉到。
(4)可选:简化代码结构
将颜色检测与轮廓绘制封装为函数,避免重复代码:
def detect_color(imageFrame, mask, color, label, area_threshold=100, font_scale=0.5): contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) for contour in contours: area = cv2.contourArea(contour) if area > area_threshold: x, y, w, h = cv2.boundingRect(contour) cv2.rectangle(imageFrame, (x, y), (x+w, y+h), color, 2) cv2.putText(imageFrame, label, (x, y), cv2.FONT_HERSHEY_SIMPLEX, font_scale, color) return imageFrame
在主循环中调用该函数:
imageFrame = detect_color(imageFrame, red_mask, (0,0,255), "Red Colour") imageFrame = detect_color(imageFrame, green_mask, (0,255,0), "Green Colour") imageFrame = detect_color(imageFrame, blue_mask, (255,0,0), "Blue Colour") imageFrame = detect_color(imageFrame, yellow_mask, (0,255,255), "Yellow Colour")
3. 其他优化建议
- 无需降低分辨率:低分辨率会丢失小交通灯的细节,保持原分辨率即可。
- 添加高斯模糊预处理:减少噪声干扰,放在
cv2.cvtColor之前:imageFrame = cv2.GaussianBlur(imageFrame, (5,5), 0) - 替换膨胀为开运算:过滤小噪声点,比如:
red_mask = cv2.morphologyEx(red_mask, cv2.MORPH_OPEN, kernal)
内容的提问来源于stack exchange,提问作者AI researcher
相关产品推荐
相关产品推荐

