1 数据集说明
本次项目使用的数据集为一个交通标志检测数据集,来源(交通标志检测 (kaggle.com))。该数据集包含多种类型的交通标志,如红绿灯、速度限制标志和停车标志等。每个图像文件都附有详细的标注文件,标注了每个交通标志的类别和位置(用边界框表示)。数据集的图像分辨率各不相同,既包含白天拍摄的图像,也包含夜间拍摄的图像,因此数据集具有较好的多样性和代表性。
数据集分为训练集、验证集和测试集。训练集用于模型的训练,验证集用于模型参数调整,测试集用于最终模型性能的评估。训练集中包含大量不同种类的交通标志,以确保模型能够学习到各种交通标志的特征。验证集和测试集的选择也考虑了交通标志种类的均匀分布,以便全面评估模型的泛化能力。
数据集特征图:
2 yolov8模型构建训练
2.1 yolov8n模型
YOLOv8n是YOLOv8模型家族中最小的模型,适用于计算资源有限的场景。该模型具有较少的参数量和较低的计算复杂度,但依然能够在保持较高速度的同时,提供较为准确的目标检测结果。YOLOv8n模型主要由卷积层、池化层和全连接层组成,通过结合不同尺度的特征图,能够有效检测到各种尺寸的目标。
# 导入YOLO模块
from ultralytics import YOLO
# 训练YOLOv8n模型
# YOLOv8n是YOLOv8模型中的最小版本,适用于对速度要求高但对精度要求较低的情况
model_n = YOLO("yolov8n.pt")
# 开始训练,参数包括数据集路径、训练轮数、图像大小和使用的设备
results_n = model_n.train(data="./dataset/data.yaml", epochs=100, imgsz=320, device=0)
在模型训练过程中,选择了优化器Adam,并采用学习率预热策略。训练过程中,训练总共进行了100个epoch。在每个epoch中,记录并监控了模型的各项损失和评估指标,包括box_loss、cls_loss、dfl_loss、precision、recall、mAP50和mAP50-95等。
在训练初期,模型的box_loss、cls_loss和dfl_loss较高,但随着训练进行,这些损失逐渐下降,表明模型在逐步学习并优化其参数。具体来看,box_loss从最初的0.82368逐步下降到0.42733,说明模型在预测目标边界框时的误差逐渐减小;cls_loss从3.1194下降到0.26326,表明模型在目标分类上的错误率显著降低;dfl_loss则从1.0484下降到0.8334,表明模型在预测特征图的分布上也取得了较好的优化效果。
从评估指标来看,模型的precision、recall和mAP50-95等指标均有明显提升。例如,precision从最初的0.45852提高到0.94322,recall从0.22586提高到0.85227,mAP50-95从0.18146提升到0.79572。上述指标的提升表明模型在目标检测任务上的准确性和召回率都有了显著的改善,能够较为准确地检测和识别出图像中的目标。
2.2 yolov8s模型
YOLOv8s是YOLOv8模型家族中一种中等规模的模型,适用于在计算资源相对充裕的情况下,追求更高的检测准确率。与YOLOv8n相比,YOLOv8s具有更多的参数和更复杂的网络结构,从而能够更好地捕捉目标的细节特征,提高检测精度。YOLOv8s模型同样由多个卷积层、池化层和全连接层组成,利用多尺度特征融合技术,以实现对不同尺度目标的精准检测。
# 训练YOLOv8s模型
# YOLOv8s是YOLOv8模型中的小型版本,在速度和精度之间取得了平衡
model_s = YOLO("yolov8s.pt")
results_s = model_s.train(data="./dataset/data.yaml", epochs=100, imgsz=320, device=0)
在模型训练过程中,采用了与YOLOv8n相同的优化器Adam,并使用学习率预热策略。训练集和验证集的划分比例依然为8:2,总训练epoch为100个。在每个epoch中,记录并监控了模型的各项损失和评估指标,包括box_loss、cls_loss、dfl_loss、precision、recall、mAP50和mAP50-95等。
训练曲线图结果分析: 在训练初期,YOLOv8s模型的box_loss、cls_loss和dfl_loss也较高,但随着训练的进行,这些损失逐步下降,表明模型在不断优化和调整其参数。具体来说,box_loss从初始的0.81964下降到最终的0.38947,cls_loss从2.669下降到0.21349,dfl_loss从1.0709下降到0.83166,显示了模型在边界框预测、目标分类和特征分布预测上的显著进步。
评估指标方面,YOLOv8s模型的precision、recall和mAP50-95等指标也有明显提升。例如,precision从最初的0.44826提高到0.9309,recall从0.39458提高到0.90423,mAP50-95从0.31329提升到0.82341。这些指标的提升表明,YOLOv8s模型在目标检测任务上的性能显著优于YOLOv8n,能够更准确地识别和定位图像中的目标。
2.3 yolov8m模型
YOLOv8m是YOLOv8模型家族中的高精度版本,适用于在计算资源较为充裕的情况下,追求更高检测精度的场景。该模型拥有更多的参数量和更复杂的网络结构,能够更好地捕捉和识别目标的细节特征,从而提高检测精度。YOLOv8m模型由多个卷积层、池化层和全连接层组成,通过多尺度特征融合技术,实现对不同尺度目标的精准检测。
# 训练YOLOv8m模型
# YOLOv8m是YOLOv8模型中的中型版本,适用于对精度要求较高的情况
model_m = YOLO("yolov8m.pt")
results_m = model_m.train(data="./dataset/data.yaml", epochs=100, imgsz=320, device=0)
在模型训练过程中,继续采用优化器Adam,并使用学习率预热策略。训练集和验证集的划分比例为8:2,总训练epoch为100个。在每个epoch中,记录并监控了模型的各项损失和评估指标,包括box_loss、cls_loss、dfl_loss、precision、recall、mAP50和mAP50-95等。
训练曲线图结果分析: 在训练初期,YOLOv8m模型的box_loss、cls_loss和dfl_loss较高,但随着训练的进行,这些损失逐步下降,表明模型在不断优化和调整其参数。具体来说,box_loss从初始的0.79181下降到最终的0.38036,cls_loss从2.2718下降到0.20097,dfl_loss从1.0975下降到0.87187,显示了模型在边界框预测、目标分类和特征分布预测上的显著进步。
评估指标方面,YOLOv8m模型的precision、recall和mAP50-95等指标也有显著提升。例如,precision从最初的0.52955提高到0.93646,recall从0.39705提高到0.89558,mAP50-95从0.3143提升到0.82599。这些指标的提升表明,YOLOv8m模型在目标检测任务上的性能显著优于YOLOv8n和YOLOv8s,能够更精准地识别和定位图像中的目标。
3 模型评估
YOLOv8n模型评估结果显示,模型在整体上的precision、recall和mAP50-95等指标均表现良好。在所有类别中,模型的平均precision为0.934,recall为0.865,mAP50为0.913,mAP50-95为0.799。具体类别上,绿灯和红灯的检测结果稍显不足,precision和recall略低,但其他类别如红绿灯、限速标志等表现较好。
YOLOv8s模型评估结果显示,模型的各项指标均有所提升。平均precision为0.942,recall为0.872,mAP50为0.922,mAP50-95为0.805。绿灯和红灯的检测结果有所改善,其他类别如红绿灯、限速标志等的检测结果也有提升,模型表现更为均衡。
YOLOv8m模型评估结果显示,模型在各类别上的检测结果均表现优异。平均precision为0.948,recall为0.879,mAP50为0.927,mAP50-95为0.813。绿灯和红灯的检测结果进一步提升,其他类别如红绿灯、限速标志等的检测结果也更加出色,模型具有极高的检测准确性和稳定性。
4 系统界面实现
本系统采用 PyQt5 进行图形用户界面(GUI)的设计与实现,通过 Python 编写的 YOLOv8 模型进行交通标志检测和识别。
系统界面整体采用现代化的设计风格,背景色为深色调的 #1E1E2E,文字和边框色为浅色调的 #ECEFF4 和 #81A1C1,使界面看起来简洁且富有视觉冲击力。窗口标题为“基于YOLOv8的交通标志检测识别系统”,位于窗口顶部,采用清晰可见的字体展示。
import sys
import cv2
import numpy as np
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QPushButton, QVBoxLayout, QHBoxLayout, QWidget, \
QFileDialog, QComboBox, QTextEdit
from PyQt5.QtGui import QPixmap, QImage, QFont
from PyQt5.QtCore import Qt, QTimer
from ultralytics import YOLO
from PIL import ImageFont, ImageDraw, Image
class TrafficSignDetectionSystem(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('基于YOLOv8的交通标志检测识别系统')
self.setGeometry(100, 100, 1200, 800)
self.setStyleSheet("background-color: #1E1E2E; color: #ECEFF4; font-family: Arial; font-size: 30px;")
# 初始化模型
self.model_n = YOLO("./runs/detect/train2/weights/best.pt")
self.model_s = YOLO("./runs/detect/train3/weights/best.pt")
self.model_m = YOLO("./runs/detect/train4/weights/best.pt")
self.current_model = self.model_n
# 初始化界面组件
self.initUI()
# 计时器用于视频播放
self.timer = QTimer()
self.timer.timeout.connect(self.display_video_stream)
self.is_Video = False
font_path = 'simhei.ttf' # 字体文件的路径
font = ImageFont.truetype(font_path, 32, encoding='utf-8') # 设置字体、大小和编码
def initUI(self):
# 图像/视频显示区域
self.image_label = QLabel(self)
self.image_label.setFixedSize(800, 600)
self.image_label.setStyleSheet("background-color: #2E3440; border: 2px solid #81A1C1;")
# 识别结果显示区域
self.result_text = QTextEdit(self)
self.result_text.setFixedSize(350, 600)
self.result_text.setStyleSheet("background-color: #3B4252; border: 2px solid #81A1C1; color: #ECEFF4;")
# 按钮
self.open_image_btn = QPushButton('打开图像', self)
self.open_image_btn.setStyleSheet("background-color: #88C0D0; font-weight: bold;")
self.open_image_btn.clicked.connect(self.open_image)
self.open_video_btn = QPushButton('打开视频', self)
self.open_video_btn.setStyleSheet("background-color: #8FBCBB; font-weight: bold;")
self.open_video_btn.clicked.connect(self.open_video)
self.detect_btn = QPushButton('标志检测识别', self)
self.detect_btn.setStyleSheet("background-color: #A3BE8C; font-weight: bold;")
self.detect_btn.clicked.connect(self.detect_traffic_sign)
# 模型选择下拉框
self.model_combo = QComboBox(self)
self.model_combo.addItems(['YOLOv8n', 'YOLOv8s', 'YOLOv8m'])
self.model_combo.setStyleSheet("background-color: #5E81AC; color: #ECEFF4;")
self.model_combo.currentIndexChanged.connect(self.change_model)
# 布局设置
vbox = QVBoxLayout()
vbox.addWidget(self.open_image_btn)
vbox.addWidget(self.open_video_btn)
vbox.addWidget(self.model_combo)
vbox.addWidget(self.detect_btn)
hbox = QHBoxLayout()
hbox.addWidget(self.image_label)
hbox.addLayout(vbox)
hbox.addWidget(self.result_text)
container = QWidget()
container.setLayout(hbox)
self.setCentralWidget(container)
def open_image(self):
options = QFileDialog.Options()
self.image_path, _ = QFileDialog.getOpenFileName(self, "打开图像", "",
"Images (*.png *.xpm *.jpg *.bmp);;All Files (*)",
options=options)
if self.image_path:
self.is_Video = False
self.display_image(self.image_path)
def open_video(self):
options = QFileDialog.Options()
self.video_path, _ = QFileDialog.getOpenFileName(self, "打开视频", "",
"Videos (*.mp4 *.avi *.mov);;All Files (*)", options=options)
if self.video_path:
self.is_Video = True
self.cap = cv2.VideoCapture(self.video_path)
self.timer.stop()
ret, frame = self.cap.read()
if ret:
self.display_image_from_array(frame)
def change_model(self):
model_name = self.model_combo.currentText()
if model_name == 'YOLOv8n':
self.current_model = self.model_n
elif model_name == 'YOLOv8s':
self.current_model = self.model_s
else:
self.current_model = self.model_m
def detect_traffic_sign(self):
if not self.is_Video:
image = cv2.imread(self.image_path)
results = self.current_model.predict(source=image)
image_with_results = self.draw_results(image, results)
self.display_image_from_array(image_with_results)
elif self.is_Video:
self.timer.start(30)
def display_image(self, image_path):
pixmap = QPixmap(image_path)
self.image_label.setPixmap(pixmap.scaled(self.image_label.size(), Qt.KeepAspectRatio))
def display_image_from_array(self, image):
rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
h, w, ch = rgb_image.shape
bytes_per_line = ch * w
q_image = QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888)
self.image_label.setPixmap(QPixmap.fromImage(q_image).scaled(self.image_label.size(), Qt.KeepAspectRatio))
def display_video_stream(self):
ret, frame = self.cap.read()
if ret:
results = self.current_model.predict(source=frame)
frame_with_results = self.draw_results(frame, results)
self.display_image_from_array(frame_with_results)
else:
self.timer.stop()
界面分为三大区域:图像/视频显示区域、检测结果显示区域和控制按钮区域。
-
图像/视频显示区域:位于界面左侧,尺寸为800x600像素,用于显示加载的图像或视频。该区域采用深灰色背景(#2E3440),并用浅色边框进行包裹,使显示区域明确且富有层次感。当加载图像或视频时,会自动调整大小以适应该区域,并保持比例不变。
-
检测结果显示区域:位于界面右侧,尺寸为350x600像素,用于显示检测结果。采用深灰色背景(#3B4252),并用浅色边框包裹,结果文本使用浅色字体,以保证良好的可读性。该区域能够显示检测到的每个交通标志的标签、置信度和边框坐标。
-
控制按钮区域:位于界面中部,包含一系列控制按钮和模型选择下拉框,按钮采用和谐的配色,分别为 #88C0D0、#8FBCBB 和 #A3BE8C,并加粗字体,增强可点击性。具体按钮包括:
- “打开图像”按钮:用于打开并加载本地存储的图像文件。
- “打开视频”按钮:用于打开并加载本地存储的视频文件,并显示视频的第一帧画面。
- “标志检测识别”按钮:用于启动 YOLOv8 模型,对加载的图像或视频逐帧进行检测识别。
- 模型选择下拉框:用于选择不同的 YOLOv8 模型(YOLOv8n、YOLOv8s 和 YOLOv8m),以适应不同的检测需求。
用户可以通过点击“打开图像”或“打开视频”按钮来加载图像或视频文件,加载完成后会在图像/视频显示区域显示。视频文件加载后,默认显示第一帧画面。用户可选择合适的 YOLOv8 模型后,点击“标志检测识别”按钮,系统将对当前加载的图像或视频逐帧进行检测,并在显示区域实时更新检测结果。
屏幕录制 2024-07-05 234445
在检测过程中,识别到的交通标志将被绘制在图像或视频帧上,并显示相应的标签和置信度。同时,检测结果会在结果显示区域以文本形式展示,便于用户查看详细信息。