基于深度学习的交通违章检测项目实战:从数据集标注到TensorRT部署
2026/9/25 1:40:54 网站建设 项目流程

简介:目标检测是计算机视觉的核心任务之一,旨在从图像或视频中定位并识别物体。在智慧交通领域,目标检测与多目标跟踪技术相结合,可实现车辆轨迹的连续感知,为交通违章判定提供底层支撑。深度学习模型如YOLOv5,凭借较高的检测精度与实时推理能力,成为工业部署的常见选择;TensorRT等加速方案则进一步提升了模型在实际硬件上的运行效率。从数据清洗、标注规范到模型训练调优,再到规则引擎设计与端侧部署,整个链路涉及众多工程细节。以交通违章检测项目为例,完整复盘了基于YOLOv5与DeepSORT的车辆检测跟踪方案,以及压线变道、逆行等违章判断逻辑的实现过程,并分享了模型转换、性能优化与踩坑经验,可为类似视觉检测项目提供参考。 最近整理了一下手头这个基于深度学习的违章检测项目,正好把整个流程从数据准备、模型训练到最后的部署落地完整梳理一遍。这个项目做的是通过路口和卡口的监控画面,自动识别车辆压线、逆行、违章停车等行为,本质上是一个目标检测模型配合规则判定引擎的组合方案。如果你正在做类似的视觉检测项目,或者打算入门深度学习在交通场景的实战应用,这篇内容可以给你一条完整、可参考、不绕弯的落地路径。项目压缩包里的代码、模型配置和调参记录,我会按实际踩坑的顺序拆开讲,尽量把文档里查不到的细节也补上。

1. 项目整体设计与技术路线选择

1.1 违章检测到底要解决什么问题

很多人一看“违章检测”就以为是个目标检测模型跑一下就完事,实际完全不是这样。真实场景里,摄像头拍到的是一段连续视频流,我们需要从里面找到“车辆在什么位置、在做什么动作、这个动作是否符合交通规则”。拆开来看,它至少包含三个层次的任务。

第一层是目标检测,也就是把画面里的车、人、非机动车找出来,输出每个目标的类别和框。第二层是目标跟踪,需要跨帧关联同一个目标,判断车辆是静止还是移动、往哪个方向移动。第三层才是违章判定,把目标位置、运动轨迹、车道线、交通标志等信息综合起来,套用规则逻辑判断是否违章。

以压线变道为例,只看一帧画面是不够的,因为车辆可能只是暂时骑在线上,并没有完成变道动作。正确做法是:先检测车辆和车道线,再通过跟踪得到车辆连续多帧的位置,只有确认车辆从一条车道跨过实线进入另一条车道,才判定为压线变道。这就是为什么单纯依赖一个检测模型远远不够,必须配合后端的规则引擎。

1.2 技术方案选型与对比

项目选型阶段我重点对比了三种主流方案。第一种是纯传统图像处理方案,用边缘检测加轮廓分析找车辆,这种方法对光照和遮挡极其敏感,稍微阴天或者车辆密集就大面积失效,直接排除。第二种是经典目标检测加手写特征,比如HOG加SVM,这种方案在小范围固定场景勉强能用,但泛化能力太差,换一个路口就要重新调参,也不适合。

第三种就是最终采用的深度学习方案,核心是卷积神经网络(CNN)作为特征提取器,配合目标检测算法完成车辆定位。目标检测部分我在YOLO系列和Faster R-CNN之间做了权衡。Faster R-CNN是两阶段检测器,精度高但推理速度慢,在普通GPU上处理1080P视频也就十几帧每秒,难以满足多路摄像头并发检测。YOLOv5单阶段检测器在速度和精度之间平衡得最好,实测在RTX 3060上跑640分辨率的输入,单帧推理只要十几毫秒,一个GPU能同时处理好几路视频流。

最终选型是YOLOv5作为基础检测模型,配合DeepSORT做多目标跟踪,再用规则引擎做违章判定。整体架构用消息队列串联,视频帧从摄像头拉流进来,检测和跟踪模块并行处理,判定结果写入数据库并触发告警提示。

1.3 为什么选择YOLOv5而不是更新的版本

选型期间YOLOv8甚至YOLOv9都已经发布了,但我最后依然用了YOLOv5,主要原因有三个。第一是生态成熟,YOLOv5的资料、预训练权重、部署案例在GitHub上非常丰富,出现问题几乎都能搜到解决方案,对于项目周期紧张的情况,这个优势很关键。第二是工程改了太多,我自己在模型结构上做了一些定制,比如修改检测头适配小目标,YOLOv5的代码结构清晰,改起来不费劲。第三是实际精度差距并不大,在自建的违章场景数据集上,YOLOv5s和YOLOv8s的mAP差异不到两个点,但YOLOv5在TensorRT上的加速方案更成熟。

当然,如果是全新启动的项目,现在直接使用YOLOv8或者YOLOv11也是完全没问题的,训练和部署流程差异不大,关键是趁手。

2. 数据集准备与标注细节

2.1 数据来源与清洗

深度学习项目里,数据质量直接决定模型上限。这个项目的数据来源分三部分:一是公开数据集,包括UA-DETRAC、BDD100K,主要用于预训练和补充场景多样性;二是合作路口的监控视频提取关键帧,这是主力数据,覆盖白天、夜间、阴雨天气,约两万张图片;三是用车载摄像头从路面采集的视频帧,补充了一些特殊角度样本。

数据清洗这一步很多人容易忽略,但影响非常大。原始视频帧里大量是连续重复画面,如果直接拿去做训练,模型会对同一场景过拟合,严重损失泛化能力。我的做法是用感知哈希算法计算相邻帧的相似度,相似度超过0.95的直接剔除,保证训练集里同一场景的重复帧尽量少。另外还得人工过滤掉严重模糊、镜头遮挡、极端过曝的图片,这类脏样本宁可不要,也不要留到训练里影响收敛。

公开数据集和自建数据混合使用时,建议先做分布检查。我踩过的坑是直接把BDD100K的图片和自建图片混在一起训练,结果模型在自建场景下召回率反而下降了。后来把公开数据作为预训练,再用自建数据微调,效果才恢复正常。

2.2 标注规范与格式转换

标注工具用的是LabelImg和CVAT。LabelImg适合单人小规模标注,CVAT适合团队协作,支持在线多人同时标注,还能自动跟踪标注物跨帧,效率提升非常明显。由于项目主要用YOLOv5训练,最终标注格式统一转成YOLO的TXT格式,即每个目标一行,包括类别编号和归一化后的中心点坐标、宽高。

这里强烈建议在标注阶段就把规范定死,不然后续返工成本极高。我总结的标注规范如下。

  • 类别定义:car、truck、bus、motorbike、bicycle、person六个基础类别,所有车辆和行人统一按这个标准标。
  • 遮挡处理:目标被遮挡超过50%的,不标注;遮挡小于50%的,按可见部分标注,框紧贴可见区域。
  • 截断处理:目标只有一半在画面内时,按实际可见部分标注,不要脑补完整框。
  • 小目标处理:长边小于20像素的目标不标注,这类目标是纯噪声,标注了反而干扰训练。

标注完成后还需要做一致性检查,我让两个标注员分别标注同一批50张图,计算检测框的IOU一致性,IOU低于0.6的样本要重新讨论标准。这一步能有效减少标注噪声。

2.3 数据增强策略

数据增强是提升模型泛化能力最直接的手段,尤其是对于交通场景这种光照和天气变化极大的场景。我用的增强策略分两类。

一类是常规的几何增强,比如随机水平翻转、随机旋转、随机缩放和平移。交通场景中车辆左右方向都有,水平翻转不会造成语义错误,可以放心用。另一类是颜色增强,包括HSV通道的随机扰动、亮度对比度调整、高斯噪声、运动模糊模拟。这些增强可以模拟不同天气和光照条件,让模型对光线变化更鲁棒。

Mosaic增强是YOLOv5内置的策略,我把四张图片拼接成一张训练样本,这种方式能显著增加小目标的训练样本数量。因为四张图拼在一起后,每张图里的目标都会缩小,相当于变相模拟了远处小目标的效果。实测开启Mosaic增强后,小目标检测的召回率提升了4到5个百分点,效果非常明显。

不过数据增强也要适量,过强的增强会让模型学习到不真实的特征,反而掉精度。我的经验是颜色类增强概率设置在0.5左右,几何增强概率0.7左右,具体数值还是要根据验证集的表现调整。

3. 模型训练与参数调优全过程

3.1 训练环境与基础配置

训练环境我用的是双卡RTX 3090的服务器,PyTorch框架配合CUDA 11.8。关于深度学习环境的配置,这里多说一句,很多新手卡在第一步,其实安装流程固定:先装NVIDIA驱动,再装CUDA Toolkit和cuDNN,最后用conda创建虚拟环境安装PyTorch。可以重点确认一下PyTorch版本和CUDA版本是否匹配,torch.cuda.is_available()返回True就基本没问题。

训练前做了两个预处理。一个是用聚类算法对自建数据集的标注框做K-means聚类,重新计算anchor尺寸。虽然YOLOv5的默认anchor是COCO数据集上聚类出来的,但交通场景的车辆框长宽比与通用目标差异较大,重新聚类可以加快收敛速度。聚类结果我选了9个anchor,从小到大的尺寸分布覆盖了从远处的轿车到近处的大型公交车。另一个是统计类别分布,发现truck和bus类别样本明显偏少,这为后续的类别平衡策略提供了依据。

3.2 训练策略与超参数调优

训练采用迁移学习策略,加载COCO预训练权重作为初始化。这里有一个小技巧:因为自建数据集只有六个类别,我把模型的输出类别数从80改成6,然后只加载backbone部分的权重,检测头随机初始化。这样既能充分利用预训练模型学到的通用特征,又能让检测头快速适应当前任务。

超参数配置我最终确定如下。

  • 输入分辨率:640x640,训练后期用1280分辨率微调了30个epoch,小目标提升明显。
  • Batch Size:16,双卡各8
  • 优化器:SGD,初始学习率0.01,采用余弦退火调度
  • Weight Decay:0.0005,Momentum:0.937
  • Epochs:200轮,其中前5轮是warmup,学习率从0.001线性升到0.01
  • 损失函数:边框回归用CIoU Loss,分类用BCE Loss

这些参数不是我拍脑袋定的,而是基于多次实验对比后确定。学习率是最容易出问题的参数,我试过直接用0.01开局,结果前几个epoch损失直接发散,用了warmup之后才稳定下来。类别不平衡问题,我用focal loss替代了默认的BCE Loss,gamma设为1.5,truck和bus的召回率提升了约6个百分点。

3.3 训练过程监控与调优

训练过程中要时刻关注训练集损失和验证集损失的变化曲线。如果训练损失下降而验证损失上升,说明模型过拟合了,需要增加数据增强、提高Dropout概率或者减少训练轮数。如果两个损失都降不下去,大概率是学习率设置不合理或者数据标注有误,需要停下来排查。

我实际训练过程中遇到一次诡异情况,训练损失降到3.0左右就不再下降,验证集mAP也一直徘徊在0.65附近。排查了很久,最后发现是数据集中有一批标注框中心点坐标算错了,导致损失计算混乱。重新标注那一批数据后,损失直接降到1.8,mAP也恢复了正常。所以如果训练出现异常平台期,优先检查数据和标签。

评估指标方面,我不只看mAP,还重点看了各类别的precision和recall。因为交通场景中漏检比误检更严重,漏检一个目标可能导致漏判一次违章,所以操作上我会在保证precision不下降太多的前提下,尽量压低detection阈值提高recall,这样后续规则引擎有更多候选框可以分析,宁可多给几个误检框,也不漏掉真正的目标。

4. 规则引擎与违章判定逻辑实现

4.1 压线变道检测实现

模型检测出车辆后,还需要一系列后处理才能完成违章判定。以压线变道为例,整个流程分成五步。第一步是车道线检测,我并没有单独训练分割模型,而是用传统图像处理加透视变换的方式:在固定机位的画面里预先标定车道线区域,用HSL颜色过滤提取黄色和白色车道线,再做形态学闭运算和霍夫变换拟合直线。固定机位下这个方案简单可靠,如果不换机位就不需要重新配置。

第二步是目标跟踪,采用的DeepSORT在检测框基础上提取车辆外观特征,用卡尔曼滤波预测运动轨迹,并用匈牙利算法做帧间匹配。这样能保证连续帧中同一个车辆ID保持不变,这是判断变道行为的必要前提。

第三步是轨迹平滑。直接用检测框中心点计算轨迹会抖动很厉害,我用了一个滑动窗口平均来平滑轨迹,窗口大小设置为10帧,这样轨迹更稳定,减少误判。

第四步是碰撞检测,把车辆边框与车道线做几何相交计算,判断车辆是否跨过车道线。这里要特别注意判断是车辆“骑线”还是“变道完成”,骑线说明车辆正在变道过程中,需要结合后续帧判断是否真正跨越实线。

第五步是持续帧数判定。只有当车辆从一条车道完整跨越实线进入另一条车道,且整个变道动作持续超过15帧时,才判定为压线变道。这个帧数阈值要依据视频帧率调整,25帧每秒的视频中1秒的变道时间约25帧,所以15帧是一个相对严格的阈值,能有效过滤抖动造成的误判。

4.2 逆行与违停检测逻辑

逆行检测的核心是运动方向判断。通过跟踪模块可以得到车辆的运动轨迹向量,与车道正方向做夹角计算,夹角超过90度说明车辆在反向行驶。这个逻辑本身很简单,难点在于确认车道正方向。我采用的方案是在每个检测机位上人工标定一条基准方向线,系统运行时把车辆运动向量投影到基准方向线上,取正负判断是否逆行。

违章停车检测相对简单但误判率极高。最简单的方式是检测车辆连续多帧是否保持静止,即位置偏移小于某个阈值,同时持续时间超过设定值,就判定为违停。实际操作中需要做两个过滤:一是过滤掉红绿灯路口排队等待的车辆,这个必须结合信号灯状态判断;二是过滤掉临时上下客的车辆,这个需要在后续帧中判断车辆是否短时间离开。最简单的方式是检查车辆前面是否突然出现一个行人并且与车辆距离很近,如果出现则可能是上下客场景,需要暂缓判定。

4.3 多路视频并发处理的架构设计

项目最终需要同时处理8路甚至16路摄像头,检测模型推理速度再快也扛不住直接对每路视频逐帧跑。因此架构上做了分流设计:每个摄像头用一个视频流线程拉帧,帧率控制在10到15帧每秒,不满足要求的部分直接丢帧。所有帧写入一个共享环形缓冲区,由GPU推理服务从缓冲区取帧批量运行检测。

检测结果通过消息队列传给跟踪和规则引擎模块。跟踪模块按摄像头ID独立维护轨迹数据,规则引擎消费轨迹数据生成违章事件。这种解耦设计的好处是,如果检测模块延迟增大,不会影响视频拉流和展示;如果规则引擎出现故障,也不会阻塞检测流程。

部署时我还用了TensorRT对模型做了FP16量化,推理速度从原本PyTorch的约50毫秒每帧降低到约18毫秒每帧,4路视频流的实时处理完全没问题。具体的优化我在下一节详细展开。

5. 模型部署与推理性能优化

5.1 模型转换与TensorRT加速

训练好的模型不能直接用于生产环境,需要进行格式转换和加速优化。整体流程是PyTorch权重导出为ONNX,再由ONNX转为TensorRT的engine文件。这个过程中有非常多的坑,我一个个说。

导出ONNX时,我建议固定模型的输入尺寸。YOLOv5的模型输入尺寸是可变的,但导出时指定固定尺寸可以简化后续优化。导出命令里设置--dynamic参数时,会导出动态尺寸版本,方便不同分辨率推理,但TensorRT优化效果会打折扣。我最终选择导出固定640x640的静态版本,推理速度比动态版本快约15%。

转TensorRT时,最关键的步骤是选择合适的精度模式。默认是FP32,性能提升有限;FP16精度可以带来接近两倍的加速,且精度损失很小;INT8量化能进一步提升速度,但需要校准数据集,压缩比高但精度损失较大。这个项目实测FP16模式下所有类别的mAP只比FP32低0.3个百分点,完全可以直接用。INT8量化尝试过一次,mAP下降了1.5个百分点,因为有些场景精度敏感,最终没有采用。

TensorRT的engine文件是和GPU型号强相关的,在RTX 3090上生成的engine不能直接用在RTX 3060上,需要在目标机器上重新生成。这一点如果一开始没注意会导致上线现场无法运行。

5.2 推理性能瓶颈分析与优化

实际部署后发现,TensorRT推理本身已经很快,但整体流程却跑不满帧率。使用NVIDIA提供的DeepStream框架进行性能分析后发现,瓶颈居然在视频解码环节。OpenCV默认的FFmpeg软解码在4路1080P视频并发时CPU占用率极高,而且解码速度跟不上推理速度。

解决方案是使用NVIDIA的硬件解码器,通过CUDA直接解码视频流,解码后的数据直接以GPU显存格式输入TensorRT,避免CPU和GPU之间的数据拷贝。这一步优化后,4路1080P视频流的端到端处理延迟从原来的300毫秒降低到120毫秒,CPU占用率也从80%降到25%左右。

另一个容易被忽略的性能瓶颈是后处理。YOLOv5输出的原始结果是三个尺度的特征图,需要经过NMS(非极大值抑制)才能得到最终检测框。如果直接在Python代码里做NMS,4路视频流和每秒平均50个目标的情况下,NMS耗时可能超过整个推理时间。我把NMS逻辑改成了TensorRT原生的EfficientNMS插件,在GPU上直接执行,耗时从15毫秒降到2毫秒。

5.3 实际场景中的精度与速度调优

上线后遇到过一类典型问题:白天的检测效果很好,但夜间画面明显变差,车辆召回率下降严重。排查后发现,一是夜间车辆轮廓不清晰,模型特征提取困难;二是夜间画面里车灯会造成过曝,形成大量干扰。为了解决这个问题,我采用了夜间专用的图像预处理方案:先做自适应直方图均衡化,增强对比度,再对高光区域做局部抑制。预处理后加入模型输入,夜间召回率从78%提升到86%。

此外还发现,远端小目标漏检明显。单独针对这个问题,我在推理时做了多尺度测试增强,即把同一图像缩放成640、960、1280三个尺寸分别推理,再将结果融合。检测精度提升约3个百分点,但推理耗时增加了约2.5倍。实际使用中,只有在重点路口才开启多尺度推理,常规路口还是用单尺度保证速度。

6. 典型踩坑记录与排查经验

6.1 标注与数据问题

整个项目过程中,我记录了大量的踩坑记录,整理成了一张速查表,这里分享最典型的几个。

第一个是数据集类别不平衡严重。项目初期训练的模型,truck和bus的召回率只有不到60%,因为这两个类别在自建数据集中占比不到8%。解决策略有三个,一是从BDD100K里专门抽取了truck和bus的样本补充到训练集中,二是对这两类目标使用过采样策略,三是在损失函数上应用focal loss权重,最终把这两类的召回率提升到了80%以上。

第二个是图像样本中存在大量强相关连续帧,如果不去重直接训练,模型会对一个场景过度记忆,测试集是真实场景时会明显表现不佳。使用感知哈希去重后,训练集减少了将近40%,但验证集精度反而提升了约2个百分点,这个反直觉的结果说明了去重的重要性。

6.2 模型推理和部署问题

第三个是TensorRT引擎在FP16模式下偶尔出现通道顺序错误。由于YOLOv5在PyTorch中使用的通道顺序是CHW,而一些TensorRT版本默认按NHW或NCHW处理,若不显式指定通道顺序,可能造成推理结果异常。排查结果是推理结果整体下移了大约10个像素,对检测框位置影响极大。解决方案是在转engine时显式设置输入格式为NCHW,并在后处理时保持与训练时一致的数据预处理方式。

第四个是部署机器的GPU显存不足问题。公司在低成本服务器上使用GTX 1660,显存只有6GB,原本的FP16模型推理甚至无法加载。后来源码级精简了模型结构,将backbone的通道数减半,同时将输入分辨率从640降到480,最终在6GB显存上跑到了约25ms每帧,精度损失控制在可接受范围内。

6.3 规则引擎导致的误报问题

第五个是规则引擎误报频发。上线初期,压线变道的误报率高达30%,主要原因是雨天夜间路面反光,车道线检测模块把地面反光误识别为车道线。解决办法是加入车道线置信度过滤,在霍夫变换后对拟合的直线求置信度,置信度过低的直接丢弃,同时加入车道线在时间上的稳定性判断。经过处理后,误报率降到6%左右。

第六个问题是多个摄像头画面存在时间不同步。由于网络摄像头传输延迟,不同摄像头的帧对应时间不一致,导致在多摄像头接续追踪车辆时出现轨迹断裂。解决方案是引入统一的时钟戳,所有视频流按时间戳重新对齐后再进入检测和跟踪模块。实际操作中,我把所有输入帧都放在一个时间缓冲区中,按时间戳排序后统一处理,虽然增加了一点内存占用,但轨迹连续性明显改善。

7. 实操经验总结与项目扩展方向

做完整套系统后,我最大的感受是算法模型只占项目的一部分,数据和工程化能力才是决定项目成败的关键。模型训练和调参花的时间大约占总时间的40%,剩下的时间全部用在了数据清洗、标注规范、后处理逻辑和部署性能优化上。如果你是第一次接触类似项目,建议把大部分精力放在数据和后期调试上,不要执着于换新模型试新架构,一个调好的YOLOv5在工程上的价值远超一个没调好的大模型。

另外一个小建议是,所有检测结果和中间数据一定要落盘保存。我开发了一个简单的日志系统,把每帧图像的检测结果、跟踪轨迹、规则判定中间状态全部记录成JSON文件。这样做的好处非常明显,一是规则引擎出现误报后能快速回放定位问题;二是模型更新后可以用历史数据做回归测试,确保精度没有回退。

这个项目后续如果继续扩展,我计划做两件事。一是加入基于强化学习的自适应阈值调节,让模型概率阈值和帧数阈值能够根据每个路口的实时拥堵情况动态调整。二是加入跨摄像头车辆追踪,实现车辆轨迹的全城串联,这样可以对嫌疑车辆实现连续跟踪,同时也能更准确地判断车辆是否在禁行区域内长时间停留。

如果大家在做类似项目时遇到具体问题,欢迎交流讨论。尤其是数据标注规范和TensorRT转换这两个环节,每个人踩的坑可能都不一样,多交流能少走很多弯路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询