这个项目源于我在智能驾驶领域的一次实际需求探索——如何快速准确地识别道路上的交通标志和车道线。经过多次尝试,最终选择了YOLOv8作为基础框架,结合RETT100K和BDD100K两个专业数据集,构建了一套完整的检测系统。
系统最核心的价值在于:
选择RETT100K作为交通标志数据集主要基于三个原因:
而BDD100K的车道线数据则因其多样性脱颖而出:
原始RETT100K标注格式为:
code复制class_id x_min y_min x_max y_max
需要转换为YOLO格式:
code复制class_id x_center y_center width height
转换时的关键点:
完整转换脚本示例:
python复制import os
def convert_annotation(img_width, img_height, input_path, output_path):
with open(input_path) as f:
lines = f.readlines()
with open(output_path, 'w') as f:
for line in lines:
parts = line.strip().split()
class_id = int(parts[0])
x_min, y_min = float(parts[1]), float(parts[2])
x_max, y_max = float(parts[3]), float(parts[4])
x_center = (x_min + x_max) / 2 / img_width
y_center = (y_min + y_max) / 2 / img_height
width = (x_max - x_min) / img_width
height = (y_max - y_min) / img_height
f.write(f"{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n")
# 批量处理示例
for img_file in os.listdir('images'):
if img_file.endswith('.jpg'):
img_path = os.path.join('images', img_file)
txt_path = os.path.join('labels', img_file.replace('.jpg', '.txt'))
# 获取图像尺寸
img = cv2.imread(img_path)
h, w = img.shape[:2]
convert_annotation(w, h, txt_path, txt_path)
注意:转换前务必检查图像和标注文件的对应关系,常见错误包括:
- 图像与标注文件不匹配
- 坐标值超出图像范围
- 类别ID不连续
配置文件config.yaml的关键参数:
yaml复制path: ./dataset
train: images/train # 训练集路径
val: images/val # 验证集路径
nc: 45 # 类别数
names: # 类别名称映射
0: speed_limit_30
1: stop_sign
... # 其余43个类别
训练命令参数解析:
bash复制yolo task=detect mode=train \
model=yolov8s.yaml \ # 使用小模型
data=config.yaml \
epochs=100 \ # 训练轮次
imgsz=640 \ # 输入尺寸
batch=16 \ # 批大小
workers=4 \ # 数据加载线程
optimizer='AdamW' \ # 优化器选择
lr0=0.01 # 初始学习率
在augmentation.yaml中配置:
yaml复制# 基础增强
hsv_h: 0.015 # 色调增强幅度
hsv_s: 0.7 # 饱和度增强幅度
hsv_v: 0.4 # 明度增强幅度
flipud: 0.5 # 垂直翻转概率
fliplr: 0.5 # 水平翻转概率
# 高级增强
mosaic: 0.15 # 马赛克增强概率
mixup: 0.3 # 图像混合概率
copy_paste: 0.1 # 目标复制粘贴
关键监控指标:
指标异常时的应对策略:
采用MVC模式设计:
code复制MainWindow
├── DetectionController # 控制逻辑
├── ImageViewer # 显示组件
└── ModelWrapper # 模型接口
关键代码结构:
python复制class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.init_ui()
self.model = YOLOWrapper('best.pt')
self.thread_pool = QThreadPool()
def init_ui(self):
self.image_label = QLabel()
self.detect_btn = QPushButton('开始检测')
self.detect_btn.clicked.connect(self.start_detection)
layout = QVBoxLayout()
layout.addWidget(self.image_label)
layout.addWidget(self.detect_btn)
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
def start_detection(self):
# 使用线程池避免界面卡顿
worker = Worker(self.model.predict, self.current_image)
worker.signals.result.connect(self.update_result)
self.thread_pool.start(worker)
自定义Worker类实现:
python复制class Worker(QRunnable):
def __init__(self, fn, *args, **kwargs):
super().__init__()
self.fn = fn
self.args = args
self.kwargs = kwargs
self.signals = WorkerSignals()
def run(self):
try:
result = self.fn(*self.args, **self.kwargs)
except Exception as e:
self.signals.error.emit(e)
else:
self.signals.result.emit(result)
class WorkerSignals(QObject):
result = pyqtSignal(object)
error = pyqtSignal(Exception)
重要提示:PyQt5中所有UI操作必须在主线程执行,检测结果需要通过信号槽机制传回主线程更新界面。
基础环境要求:
bash复制# CUDA 11.8环境
conda create -n yolo python=3.8
conda install pytorch==2.0.1 torchvision==0.15.2 torchaudio==2.0.2 pytorch-cuda=11.8 -c pytorch -c nvidia
# 项目依赖
pip install ultralytics==8.0.0
pip install pyqt5==5.15.7 opencv-python==4.7.0.72
常见环境问题解决方案:
bash复制nvcc --version # 查看CUDA版本
conda install cudatoolkit=11.8 -c nvidia
TensorRT加速:
bash复制yolo export model=best.pt format=engine device=0
优化效果对比:
| 设备 | 原始FPS | TensorRT FPS | 提升幅度 |
|---|---|---|---|
| RTX 3060 | 45 | 112 | 2.5x |
| Jetson Xavier | 12 | 28 | 2.3x |
量化压缩:
python复制from ultralytics import YOLO
model = YOLO('best.pt')
model.export(format='onnx', int8=True) # 8位整型量化
多尺度推理:
python复制results = model.predict(source, imgsz=[640, 1280]) # 多尺度检测
针对远距离交通标志检测:
yaml复制# yolov8s.yaml
head:
- [-1, 1, nn.Upsample, [None, 2, 'nearest']] # 新增上采样层
- [[-1, -2], 1, Concat, [1]] # 增加特征融合
雨天/夜间检测增强方案:
python复制def enhance_low_light(image):
lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)
l, a, b = cv2.split(lab)
clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8))
cl = clahe.apply(l)
limg = cv2.merge((cl,a,b))
return cv2.cvtColor(limg, cv2.COLOR_LAB2BGR)
多任务学习:
时序信息利用:
边缘设备部署:
bash复制# 树莓派优化版本
yolo export model=best.pt format=onnx opset=12 \
include=['onnx'] simplify=True dynamic=False
在实际部署中发现,模型在交叉路口等复杂场景的误检率较高。通过添加注意力机制和增加路口特定数据训练,误检率降低了37%。这提醒我们,实际路况的复杂性往往超出预期,持续的数据迭代和模型优化是保证系统可靠性的关键。