1. 项目概述
上周自驾游的经历让我深刻意识到现有交通标志识别系统的不足——导航软件经常误判临时施工标志,导致不必要的急刹车。这促使我决定自己动手搭建一个更精准的交通标志检测系统。经过对比多个目标检测框架,最终选择了YOLOv5作为基础架构,主要基于以下考量:
- 实时性优势:YOLO系列以"只看一次"的设计理念著称,在保持较高精度的同时,推理速度远超Faster R-CNN等两阶段检测器
- 部署友好:模型支持多种硬件平台部署,从服务器到嵌入式设备(如Jetson Nano)都能流畅运行
- 社区生态:丰富的中文教程和活跃的GitHub社区,遇到问题容易找到解决方案
这个项目聚焦于三类核心交通标志的识别:禁止类(如限速标志)、警告类(如急弯提示)和指示类(如方向箭头)。下面我将详细介绍从数据准备到模型部署的全流程。
2. 数据准备与处理
2.1 数据集选择与特点分析
经过多方比较,最终选用CCTSDB数据集,这是目前国内最全面的交通标志数据集之一,具有以下特点:
- 数据规模:原始数据集包含37,770张图像,覆盖58类交通标志
- 场景多样性:包含不同天气条件(晴天、雨天、雾天)、不同时段(白天、夜间)和不同拍摄角度
- 标注质量:每张图像都提供精确的边界框标注,部分还包含遮挡程度、光照条件等辅助信息
提示:选择数据集时务必考虑实际应用场景。如果系统主要用于城市道路,就不需要过多关注高速公路特有的标志类型。
2.2 数据筛选与分类
根据项目需求,我们对原始数据集进行了以下处理:
-
类别筛选:
- 禁止类(红色圆形标志):32种→保留18种常用类型
- 警告类(黄色三角形标志):21种→保留12种
- 指示类(蓝色圆形/矩形标志):5种→全部保留
-
数据清洗:
- 移除严重模糊或过度遮挡的样本(约占总量的8%)
- 删除重复或近似的图像(通过哈希算法检测)
最终得到27,219张有效图像,按7:2:1的比例划分为训练集(19,053张)、验证集(5,444张)和测试集(2,722张)。
2.3 标注格式转换
YOLOv5要求特定的标注格式:每个图像对应一个.txt文件,每行包含一个目标的类别ID和归一化后的边界框坐标(中心x、中心y、宽度、高度)。我们使用以下转换脚本:
python复制import xml.etree.ElementTree as ET
import os
def convert_xml_to_yolo(xml_path, classes):
tree = ET.parse(xml_path)
root = tree.getroot()
size = root.find('size')
img_width = int(size.find('width').text)
img_height = int(size.find('height').text)
yolo_lines = []
for obj in root.iter('object'):
cls_name = obj.find('name').text
if cls_name not in classes:
continue
cls_id = classes.index(cls_name)
bbox = obj.find('bndbox')
x_center = (float(bbox.find('xmin').text) + float(bbox.find('xmax').text)) / 2 / img_width
y_center = (float(bbox.find('ymin').text) + float(bbox.find('ymax').text)) / 2 / img_height
width = (float(bbox.find('xmax').text) - float(bbox.find('xmin').text)) / img_width
height = (float(bbox.find('ymax').text) - float(bbox.find('ymin').text)) / img_height
yolo_lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}")
return yolo_lines
3. 模型配置与训练
3.1 YOLOv5环境搭建
建议使用Python 3.8+和PyTorch 1.7+环境。安装步骤如下:
bash复制git clone https://github.com/ultralytics/yolov5.git
cd yolov5
git checkout v7.0 # 使用稳定版本
pip install -r requirements.txt
注意:如果使用GPU训练,需要额外安装对应版本的CUDA和cuDNN。对于NVIDIA 30系列显卡,建议使用CUDA 11.3+。
3.2 配置文件定制
创建data/cctsdb_3cls.yaml配置文件,关键参数说明如下:
yaml复制# 数据集路径配置
path: ../datasets/cctsdb_3cls
train: images/train
val: images/val
test: images/test
# 类别配置
nc: 3
names: ['prohibitory', 'warning', 'mandatory']
# 数据增强配置(可选)
hsv_h: 0.015 # 色调增强幅度
hsv_s: 0.7 # 饱和度增强幅度
hsv_v: 0.4 # 明度增强幅度
flipud: 0.5 # 垂直翻转概率
3.3 训练策略优化
针对交通标志检测的特点,我们调整了以下训练参数:
bash复制python train.py \
--img 640 \
--batch 16 \
--epochs 100 \
--data ./data/cctsdb_3cls.yaml \
--weights yolov5s.pt \
--optimizer AdamW \
--cos-lr # 使用余弦退火学习率调度
关键参数选择依据:
-
输入尺寸(--img 640):
- 平衡小标志识别精度和计算开销
- 实测显示,小于512像素时小标志(如30×30像素)识别率明显下降
-
批量大小(--batch 16):
- 在6GB显存的RTX 3060上测试得出的最大值
- 更大的批量有助于稳定训练,但受限于显存
-
学习率策略:
- 初始学习率:2e-3(AdamW优化器)
- 使用余弦退火策略,最小学习率设为初始值的1/10
3.4 训练监控与评估
训练过程中主要监控以下指标:
-
损失函数:
- 目标检测损失(box_loss)
- 分类损失(cls_loss)
- 目标置信度损失(obj_loss)
-
评估指标:
- mAP@0.5(IoU阈值0.5时的平均精度)
- mAP@0.5:0.95(IoU阈值从0.5到0.95的平均精度)
典型训练曲线特征:
- 前10个epoch:各项损失快速下降
- 20-50个epoch:mAP指标平稳上升
- 50个epoch后:指标趋于稳定,可考虑早停
4. 模型测试与优化
4.1 基础测试
使用测试集评估模型性能:
bash复制python val.py \
--weights runs/train/exp/weights/best.pt \
--data data/cctsdb_3cls.yaml \
--img 640 \
--task test
在测试集上,我们的模型取得了以下成绩:
- mAP@0.5:95.7%
- mAP@0.5:0.95:72.3%
- 推理速度(RTX 3060):4.2ms/帧
4.2 常见问题分析
在实际测试中发现了以下典型问题:
-
小目标漏检:
- 现象:小于40×40像素的标志识别率较低
- 解决方案:增加小目标专用检测头(修改模型结构)
-
相似标志混淆:
- 现象:部分禁止标志与警告标志混淆
- 解决方案:增加难例样本,调整分类损失权重
-
遮挡场景表现不佳:
- 现象:被遮挡超过30%的标志容易漏检
- 解决方案:引入注意力机制,增强局部特征提取
4.3 模型优化技巧
基于测试结果,我们实施了以下优化措施:
-
自适应锚框计算:
bash复制
python utils/autoanchor.py --cfg models/yolov5s.yaml --data data/cctsdb_3cls.yaml -
分类损失调整:
修改loss.py,增加对小样本类别的权重:python复制cls_loss += F.binary_cross_entropy(pred_sigmoid, target, reduction='none') * class_weights -
测试时增强(TTA):
bash复制python detect.py --weights best.pt --source test.jpg --augment
5. 部署与应用
5.1 不同平台部署方案
-
桌面端部署:
- 使用LibTorch C++接口
- 示例代码片段:
cpp复制auto model = torch::jit::load("best.torchscript.pt"); torch::Tensor img_tensor = preprocess(image); auto outputs = model.forward({img_tensor}).toTensor();
-
嵌入式设备部署:
- Jetson Nano优化步骤:
bash复制sudo apt-get install python3-pip libopenblas-base libopenmpi-dev pip3 install torch-1.10.0-cp36-cp36m-linux_aarch64.whl
- Jetson Nano优化步骤:
-
Web服务部署:
- 使用FastAPI创建REST接口:
python复制from fastapi import FastAPI, UploadFile import torch app = FastAPI() model = torch.hub.load('ultralytics/yolov5', 'custom', path='best.pt') @app.post("/detect") async def detect(file: UploadFile): img = Image.open(file.file) results = model(img) return results.pandas().xyxy[0].to_dict()
- 使用FastAPI创建REST接口:
5.2 性能优化技巧
-
模型量化:
python复制
model = torch.quantization.quantize_dynamic( model, {torch.nn.Linear}, dtype=torch.qint8 ) -
TensorRT加速:
bash复制
python export.py --weights best.pt --include engine --device 0 -
多线程处理:
- 使用生产者-消费者模式处理视频流
- 示例架构:
code复制Camera → Frame Queue → Worker Threads → Result Queue → Display
6. 实际应用案例
6.1 行车记录仪集成
将模型集成到车载系统中,实现了以下功能:
- 实时标志识别(10fps @ Jetson Xavier NX)
- 语音提示系统
- 驾驶行为分析(如超速预警)
6.2 交通监控分析
应用于城市交通摄像头,用于:
- 统计标志设置合理性
- 检测违规行为(如禁停区停车)
- 道路安全评估
6.3 移动端应用
开发了Android应用,主要特点:
- 离线运行(模型大小优化至12MB)
- AR叠加显示识别结果
- 历史记录分析
7. 项目资源
完整项目包含以下内容:
- 预处理后的三分类数据集
- 数据增强脚本
- 训练配置文件和模型权重
- 多平台部署示例代码
- 测试视频样本
文件结构:
code复制traffic_sign_detection/
├── datasets/
│ ├── train/
│ ├── val/
│ └── test/
├── utils/
│ ├── data_augmentation.py
│ └── conversion_tools.py
├── models/
│ ├── yolov5s_custom.yaml
│ └── best.pt
└── deployment/
├── web_service/
├── android_app/
└── embedded/
这个项目从实际需求出发,通过完整的机器学习流程,构建了一个实用的交通标志识别系统。在开发过程中,特别注重模型的实用性和部署便利性,使其能够适应从服务器到嵌入式设备的各种应用场景。
