5.5 基于深度学习的智能交通违章检测系统
本项目利用计算机视觉和深度学习技术开发了一个交通违章检测系统,能够实时监测道路交通情况,识别车辆车牌并进行文本识别,检测交通违章行为如闯红灯等,并将违章信息记录到数据库中,最终提供用户友好的界面显示检测结果和操作功能。
实例5-8:基于深度学习的智能交通违章检测系统(codes/5/red-light-detection.ipynb)
5.5.1 项目介绍
随着城市交通的不断发展和车辆数量的增加,交通管理成为城市管理的重要组成部分。然而,许多城市面临着交通违章问题,如闯红灯、逆行等,这些违章行为不仅影响了交通秩序,也增加了交通事故的风险。因此,建立一个自动化的交通违章检测系统对于提高交通管理的效率和质量至关重要。
本项目通过实时闭路电视(CCTV)监控摄像头捕捉视频,并使用经典的数字图像处理技术来检测红灯违规行为。传统数字图像处理技术在这种情况下的应用确实是非常有意义的,因为它们通常被视为深度学习方法的替代方案,但在资源受限的情况下,这些技术可能是更可行的选择。尤其是在夜间等条件下,深度学习模型可能需要更多的计算资源和数据来训练,而传统的数字图像处理技术可能会更有效地应对这些挑战。
本项目的成功实施可能会对城市交通安全和执法有着积极的影响,因为它可以帮助自动识别红灯违规行为,并确保违规者受到惩罚,从而提高交通规则的执行力度。本项目旨在利用计算机视觉和深度学习技术,开发一个交通违章检测系统,可以实时监测道路交通情况,并记录违章行为。通过该系统,交通管理部门可以更好地管理道路交通,提高交通安全水平。
本项目的功能非常丰富,包括如下所示的功能模块。
- 实时交通灯颜色识别:使用传统的数字图像处理技术来实现实时交通灯颜色识别,这有助于在资源受限的情况下快速准确地检测红灯违规行为。
- 夜间停车线检测和颜色相关性处理:采用自适应和稳定的数字图像处理技术,有效地检测夜间的停车线,并将其与交通灯状态相关联,以提高违规行为检测的准确性。
- 夜间交通帧中的车牌提取:通过数字图像处理技术实现了对夜间交通帧中车牌的稳健提取,这对于后续的车牌识别非常重要。
- 使用 PyTesseract OCR 进行车牌文本识别:利用 PyTesseract OCR(光学字符识别)工具对车牌上的文本进行识别,以便进一步处理违规行为。
- 动态定位在视频帧上显示处罚的车牌:将违规行为的车牌动态地定位到视频帧上显示,以增强监测结果的可视化效果。
- 数据库集成记录违规车牌:使用 MySQL 数据库进行违规车牌的记录和管理,有助于对违规行为进行有效地跟踪和管理。
本项目能够有效地检测并记录红灯违规行为,为城市交通管理和执法提供了重要的技术支持。
5.5.2 导入需要的库
在这一步中,需要导入项目所需的所有库和依赖项,为后续的步骤做好准备。
(1)通过如下命令安装名为 mysql-connector-python 的 Python 包,这是一个用于连接和操作 MySQL 数据库的官方驱动程序。在本项目中,使用这个Python 包将违规车牌记录到 MySQL 数据库中。
pip install mysql-connector-python
(2)导入了需要的库和模块,包括警告控制、科学计算、图像处理、文件操作、HTTP请求、文本识别、正则表达式、数据库连接等。通过过滤警告消息,使得警告消息不会打印在输出中,提高代码的可读性。然后准备了图像处理、文本识别和数据库连接所需的基础设施,为后续实现交通违规监控系统的各个功能做好了准备。
import warnings
warnings.filterwarnings('ignore')
import numpy as np
import matplotlib.pyplot as plt
import cv2
import os
import requests
import pytesseract
import easyocr
import re
import mysql.connector
import pytesseract
from PIL import Image
from collections import deque
from mysql.connector import Error
(3)定义与MySQL数据库连接所需的一些关键参数,这些参数需要根据我们的实际数据库配置进行相应的更改,以确保能够成功连接到您的MySQL数据库,并且在项目中使用这些参数来进行数据库操作。
DB_HOST = 'localhost'
DB_USER = 'your_username'
DB_PASSWORD = 'your_password'
DB_NAME = 'traffic_violations_db'
对上述代码的具体说明如下所示:
- DB_HOST:数据库服务器的主机地址,通常是 'localhost',表示本地主机。
- DB_USER:用于连接数据库的用户名。
- DB_PASSWORD:用于连接数据库的密码。
- DB_NAME:要连接的数据库的名称,这里是 'traffic_violations_db'。
5.5.3 实时交通灯颜色识别
在本项目中,需要在给定的视觉图像帧中实时检测交通灯的颜色,具体实现步骤如下所示。
- 感兴趣区域 (ROI):首先,在图像中定义一个感兴趣的区域,这个区域是我们期望交通灯所在的位置,我们将其与其余部分隔离开来,以便可以集中分析他们。
- HSV 转换:然后,将ROI从RGB颜色空间转换为HSV(色调、饱和度、亮度)颜色空间。HSV通常更适合进行基于颜色的操作,因为它将色调与亮度内容分开。
- 定义颜色范围:分别定义红色和黄色对应的色调值范围,这些值对于检测交通灯是否显示红色、黄色或绿色至关重要。
- 颜色掩码:使用先前定义的范围创建掩码(二进制图像),突出显示了ROI中检测到红色和黄色的区域。
- 颜色识别:然后,开始检查掩码。如果在红色掩码中有任何非零值,则推断交通灯为红色。如果黄色掩码中有任何非零值,则推断交通灯为黄色。如果未检测到红色或黄色,则推断交通灯为绿色。
- 叠加信息:最后,我们在主图像上叠加了一个文本消息,指示检测到的交通灯状态。这将直观地告知信号是否指示“停止”、“警告”或“前进”。
定义函数detect_traffic_light_color ,用于检测给定图像中交通灯的颜色。detect_traffic_light_color 函数使我们能够在实时中自动检测并指示交通灯的颜色,为进一步处理提供了关键信息,特别是在红灯违规检测中。
def detect_traffic_light_color(image, rect):
# 提取矩形的尺寸
x, y, w, h = rect
# 从图像中基于矩形提取感兴趣的区域(ROI)
roi = image[y:y+h, x:x+w]
# 将 ROI 转换为 HSV 色彩空间
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
# 定义红色的 HSV 色彩范围
red_lower = np.array([0, 120, 70])
red_upper = np.array([10, 255, 255])
# 定义黄色的 HSV 色彩范围
yellow_lower = np.array([20, 100, 100])
yellow_upper = np.array([30, 255, 255])
# 创建二进制掩码,用于检测 ROI 中的红色和黄色
red_mask = cv2.inRange(hsv, red_lower, red_upper)
yellow_mask = cv2.inRange(hsv, yellow_lower, yellow_upper)
# 文字叠加所需的字体和参数
font = cv2.FONT_HERSHEY_TRIPLEX
font_scale = 1
font_thickness = 2
# 根据掩码检测颜色,确定交通灯的状态
if cv2.countNonZero(red_mask) > 0:
text_color = (0, 0, 255)
message = "Detected Signal Status: Stop"
color = 'red'
elif cv2.countNonZero(yellow_mask) > 0:
text_color = (0, 255, 255)
message = "Detected Signal Status: Caution"
color = 'yellow'
else:
text_color = (0, 255, 0)
message = "Detected Signal Status: Go"
color = 'green'
# 在主图像上叠加检测到的交通灯状态信息
cv2.putText(image, message, (15, 70), font, font_scale+0.5, text_color, font_thickness+1, cv2.LINE_AA)
# 添加分隔线
cv2.putText(image, 34*'-', (10, 115), font, font_scale, (255,255,255), font_thickness, cv2.LINE_AA)
# 返回修改后的图像和检测到的颜色
return image, color
5.5.4 自适应停车线检测
在这一步中,将开发自适应的停车线检测算法,以在夜间条件下准确地检测停车线。在这部分将定义类LineDetector,这个类是在交通和道路计算机视觉任务中检测和可视化特定线条的基石。类LineDetector的主要功能是检测视频帧中的停车线,一旦识别出停车线,就希望根据检测到的交通灯状态(红色、黄色或绿色)来突出显示该线。
class LineDetector:
def __init__(self, num_frames_avg=10):
# 初始化两个deque队列,用于在帧之间保持y坐标值
self.y_start_queue = deque(maxlen=num_frames_avg)
self.y_end_queue = deque(maxlen=num_frames_avg)
def detect_white_line(self, frame, color,
slope1=0.03, intercept1=920, slope2=0.03, intercept2=770, slope3=-0.8, intercept3=2420):
# 将颜色名称映射到BGR值的函数
def get_color_code(color_name):
color_codes = {
'red': (0, 0, 255),
'green': (0, 255, 0),
'yellow': (0, 255, 255)
}
return color_codes.get(color_name.lower())
frame_org = frame.copy()
# 用于定义感兴趣区域(ROI)的线方程
def line1(x): return slope1 * x + intercept1
def line2(x): return slope2 * x + intercept2
def line3(x): return slope3 * x + intercept3
height, width, _ = frame.shape
# 创建一个遮罩以突出显示线的感兴趣区域
mask1 = frame.copy()
# 将第一条线下方的像素设置为黑色
for x in range(width):
y_line = line1(x)
mask1[int(y_line):, x] = 0
mask2 = mask1.copy()
# 将第二条线上方的像素设置为黑色
for x in range(width):
y_line = line2(x)
mask2[:int(y_line), x] = 0
mask3 = mask2.copy()
# 将第三条线左侧的像素设置为黑色(最终遮罩)
for y in range(height):
x_line = line3(y)
mask3[y, :int(x_line)] = 0
# 将遮罩转换为灰度图像
gray = cv2.cvtColor(mask3, cv2.COLOR_BGR2GRAY)
# 对感兴趣区域应用高斯模糊
blurred_gray = cv2.GaussianBlur(gray, (7, 7), 0)
# 应用CLAHE进行直方图均衡化
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
gray_clahe = clahe.apply(blurred_gray)
# 执行边缘检测
edges = cv2.Canny(gray, 30, 100)
# 进行膨胀和腐蚀以关闭对象边缘之间的间隙
dilated_edges = cv2.dilate(edges, None, iterations=1)
edges = cv2.erode(dilated_edges, None, iterations=1)
# 执行霍夫线变换
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100, minLineLength=160, maxLineGap=5)
# 计算线的起点和终点的x坐标
x_start = 0
x_end = width - 1
if lines is not None:
for line in lines:
x1, y1, x2, y2 = line[0]
# 计算线的参数
slope = (y2 - y1) / (x2 - x1 + np.finfo(float).eps) # 添加一个小数避免除以零
intercept = y1 - slope * x1
# 计算对应的y坐标
y_start = int(slope * x_start + intercept)
y_end = int(slope * x_end + intercept)
# 将y_start和y_end值添加到队列中
self.y_start_queue.append(y_start)
self.y_end_queue.append(y_end)
# 计算平均y_start和y_end值
avg_y_start = int(sum(self.y_start_queue) / len(self.y_start_queue)) if self.y_start_queue else 0
avg_y_end = int(sum(self.y_end_queue) / len(self.y_end_queue)) if self.y_end_queue else 0
# 绘制线条
line_start_ratio=0.32
x_start_adj = x_start + int(line_start_ratio * (x_end - x_start)) # 调整后的x_start
avg_y_start_adj = avg_y_start + int(line_start_ratio * (avg_y_end - avg_y_start)) # 调整后的avg_y_start
# 创建一个与帧大小相同且全部为零的(黑色)的遮罩
mask = np.zeros_like(frame)
# 在遮罩上绘制线条
cv2.line(mask, (x_start_adj, avg_y_start_adj), (x_end, avg_y_end), (255, 255, 255), 4)
# 根据颜色参数确定要更改的颜色通道
color_code = get_color_code(color)
if color_code == (0, 255, 0): # 绿色
channel_indices = [1]
elif color_code == (0, 0, 255): # 红色
channel_indices = [2]
elif color_code == (0, 255, 255): # 黄色
# 黄色在BGR中是绿色和红色通道的组合。
# 在这里我们同时修改绿色和红色通道。
channel_indices = [1, 2]
else:
raise ValueError('Unsupported color')
# 更改遮罩为白色的地方的指定颜色通道
for channel_index in channel_indices:
frame[mask[:,:,channel_index] == 255, channel_index] = 255
# 计算平均绿色线的斜率和截距
slope_avg = (avg_y_end - avg_y_start) / (x_end - x_start + np.finfo(float).eps)
intercept_avg = avg_y_start - slope_avg * x_start
# 创建一个遮罩,将线上方的像素设置为黑色
mask_line = np.copy(frame_org)
for x in range(width):
y_line = slope_avg * x + intercept_avg - 35
mask_line[:int(y_line), x] = 0 # 将线上方的像素设置为黑色
return frame, mask_line
对上述代码的具体说明如下所示:
- 类初始化:初始化了两个deque队列,用于跟踪停车线的起点和终点在帧之间的y坐标,以获得更平滑的线条表示。
- detect_white_line 方法:根据提供的斜率和截距值定义了三条线方程,创建了一个遮罩以突出显示停车线的感兴趣区域。然后,通过灰度转换、模糊处理、直方图均衡化和边缘检测对遮罩进行图像处理。接着,利用霍夫线变换检测处理图像中的边缘,并根据检测到的线的参数更新队列。最后,将检测到的线绘制在原始帧上,并根据交通灯的颜色修改相应的通道。另外,生成一个掩码,将停车线上方的像素设置为黑色。