ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于YOLOv8的收费站ETC跟车逃费识别系统:从检测到跟踪的完整实现

基于YOLOv8的收费站ETC跟车逃费识别系统:从检测到跟踪的完整实现 简介这份资源面向计算机、人工智能、通信工程等专业的在校学生与教师提供一套基于YOLOv8的交通收费站ETC跟车逃费识别系统完整方案可用于毕业设计、课程设计或大作业。压缩包共8个文件约15.91MB包含3个Python脚本、3个模型权重文件与2个说明文本分别对应可视化界面、模型训练、视频检测推理及部署说明结构清晰、拿来即用。项目已完整测试运行可生成核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果与标签分布图便于答辩展示与结果分析。目前已有46人学习下载。读者可直接获得可运行的源码、数据集、可视化页面与部署教程既能快速复现完整流程也能在此基础上修改扩展功能适合作为毕设或课设的保底方案。1. 收费站跟车逃费这件事为什么用 YOLOv8 做识别系统最省事收费站 ETC 车道最头疼的场景不是设备故障而是前车刷了 ETC 抬杆通过、后车一脚油门贴着尾巴蹭过去。这种跟车逃费在监控录像里就是两辆车前后距离极近、几乎同时通过栏杆人工翻录像一天也查不出几起。基于 YOLOv8 的交通收费站 ETC 跟车逃费识别系统核心思路就是用目标检测把每一帧里的车辆框出来再通过车辆 ID 跟踪和车道区域判定自动标记出「同一 ETC 交易对应多辆车通过」的异常事件。它解决的是从海量过车数据里自动捞出逃费嫌疑记录的问题适合做毕设或课程设计的同学也适合想快速验证检测跟踪业务判定这条链路的工程师。整套方案包含源码、可视化界面、完整数据集和部署教程简单部署即可运行不需要你从零标注几千张图。下面我把这套系统从环境搭建到逃费判定逻辑拆开讲参数怎么设、坑在哪都给你说清楚。2. 环境搭建与 YOLOv8 最小推理跑通CPU 版本也能先验证2.1 为什么选 YOLOv8 而不是 YOLOv5 或 Faster R-CNN做收费站场景的目标检测选型时主要看三点小目标召回、推理速度、部署便利性。收费站监控画面里车辆在远处时像素面积不大YOLOv8 的 C2f 结构和解耦头在小目标上比 YOLOv5 的 C3 结构更稳尤其是车辆被栏杆部分遮挡时。Faster R-CNN 精度够但推理慢收费站一个车道每天几万帧用两阶段检测器跑不动。YOLOv8 的另一个好处是 Ultralytics 把训练、验证、导出、推理封装成统一接口你不需要自己写 NMS 和后处理这对毕设节奏很关键。数据集方面这套系统一般会提供标注好的收费站场景图片类别通常是 car、bus、truck 或者更细的 etc_car、normal_car。如果你要自己补充数据用 labelme 标注后转 YOLO 格式即可转换脚本后面会给。提示如果你手头只有 CPU 机器比如 Ubuntu 20.04 的云主机或者没独显的笔记本YOLOv8n 模型 CPU 推理单帧大约 80-150ms验证逻辑够用训练就别想了。2.2 用 conda 建环境并装 ultralytics先确认 Python 版本YOLOv8 要求 3.8 以上推荐 3.10。下面这套命令在 Ubuntu 20.04 和 Windows 上都能跑Windows 把 apt 那行去掉即可。# 创建独立环境避免和系统 Python 冲突 conda create -n etc_yolo python3.10 -y conda activate etc_yolo # 安装 PyTorchCPU 版本这样装 pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu # 安装 ultralytics 和可视化依赖 pip install ultralytics opencv-python pandas matplotlib装完后验证from ultralytics import YOLO # 加载预训练权重第一次会自动下载 yolov8n.pt model YOLO(yolov8n.pt) # 对单张图推理conf 设 0.25 是常用起点 results model.predict(sourcetest.jpg, conf0.25, iou0.45, saveTrue) print(results[0].boxes.xyxy) # 打印检测框坐标这段代码的逻辑是YOLO(yolov8n.pt)加载官方在 COCO 上训练的权重predict对图片做前向推理conf0.25表示置信度低于 0.25 的框直接丢弃iou0.45控制 NMS 合并重叠框的阈值。saveTrue会把画好框的图存到runs/detect/predict目录。如果你要检测的是收费站专用类别这一步只是验证环境真正要用的是后面自己训练的权重。2.3 用自定义数据集训练收费站车辆检测模型假设你已经拿到了数据集目录结构应该是这样dataset/ images/ train/ val/ labels/ train/ val/ data.yamldata.yaml内容path: ./dataset train: images/train val: images/val nc: 3 names: [car, bus, truck]训练命令yolo detect train datadataset/data.yaml modelyolov8n.pt epochs100 imgsz640 batch16 device0参数说明epochs100对收费站场景一般够收敛imgsz640是 YOLOv8 默认输入尺寸batch16在 8G 显存上比较稳device0指定第一块 GPUCPU 训练改成devicecpu但会非常慢。训练完权重在runs/detect/train/weights/best.pt。如果你只有 labelme 标注的 json用下面脚本转 YOLO 格式import json import os from PIL import Image def labelme_to_yolo(json_path, output_dir, class_map): with open(json_path, r, encodingutf-8) as f: data json.load(f) img Image.open(json_path.replace(.json, .jpg)) w, h img.size lines [] for shape in data[shapes]: label shape[label] if label not in class_map: continue cls_id class_map[label] points shape[points] xs [p[0] for p in points] ys [p[1] for p in points] # 转成 YOLO 的归一化中心点宽高格式 cx (min(xs) max(xs)) / 2 / w cy (min(ys) max(ys)) / 2 / h bw (max(xs) - min(xs)) / w bh (max(ys) - min(ys)) / h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) out_name os.path.basename(json_path).replace(.json, .txt) with open(os.path.join(output_dir, out_name), w) as f: f.write(\n.join(lines)) # 类别映射按你的数据集改 labelme_to_yolo(sample.json, labels/train, {car: 0, bus: 1, truck: 2})转换时注意三个边界坑图片尺寸要读原图而不是标注文件里的 imageWidth否则缩放后坐标全错多边形标注要取外接矩形YOLO 只支持矩形框类别名必须和 data.yaml 里 names 顺序一致差一个位置训练就全乱。3. 跟车逃费判定逻辑从检测框到业务事件的完整链路3.1 车辆跟踪与车道区域划分光有检测框还不够逃费判定需要知道「哪辆车先过、哪辆车后过、它们是不是在同一 ETC 交易周期内」。常见做法是用 ByteTrack 或 BoT-SORT 做多目标跟踪给每辆车分配稳定 ID。Ultralytics 内置了跟踪接口from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) # 用内置 ByteTrack 跟踪persistTrue 表示视频流连续跟踪 results model.track(sourceetc_lane.mp4, trackerbytetrack.yaml, persistTrue, conf0.3) for r in results: if r.boxes.id is not None: ids r.boxes.id.cpu().numpy() boxes r.boxes.xyxy.cpu().numpy() for tid, box in zip(ids, boxes): print(f车辆ID {int(tid)} 位置 {box})persistTrue是关键参数视频逐帧推理时必须开否则每帧 ID 会重置。conf0.3比单帧检测略高减少误检导致的 ID 跳变。车道区域划分用多边形 ROI 实现在画面里把 ETC 车道和栏杆区域框出来import cv2 import numpy as np # 定义 ETC 车道区域多边形坐标按你的摄像头画面调 lane_polygon np.array([[200, 400], [800, 400], [900, 700], [100, 700]], np.int32) def in_lane(box, polygon): # 用检测框底边中心点判断是否在车道内 cx (box[0] box[2]) / 2 cy box[3] return cv2.pointPolygonTest(polygon, (float(cx), float(cy)), False) 0用底边中心点而不是框中心是因为车辆在画面里透视变形底边更接近实际接地点。3.2 逃费事件判定时间窗口 车辆计数核心逻辑是一次 ETC 抬杆交易对应一个时间窗口窗口内如果有多辆车通过栏杆线就判定为跟车逃费。实现上维护一个状态机from collections import defaultdict import time class EtcFraudDetector: def __init__(self, window_sec3.0, line_y500): self.window_sec window_sec # 交易时间窗口 self.line_y line_y # 栏杆线 y 坐标 self.crossed defaultdict(float) # 记录每辆车过线时间 self.events [] def update(self, track_id, box, etc_signal_time): cy box[3] # 车辆底边越过栏杆线 if cy self.line_y and track_id not in self.crossed: self.crossed[track_id] time.time() # 检查窗口内是否已有其他车过线 for tid, t in self.crossed.items(): if tid ! track_id and abs(t - self.crossed[track_id]) self.window_sec: self.events.append({ car_a: tid, car_b: track_id, time: self.crossed[track_id], type: follow_fraud }) return self.eventswindow_sec3.0是经验值正常 ETC 交易抬杆到落杆大约 2-4 秒跟车车辆通常在这个窗口内通过。设太小会漏判设太大会把正常排队车辆误判。line_y要根据你的摄像头安装高度和角度标定一般取画面高度的 60%-70% 位置。注意这套逻辑假设 ETC 交易信号能通过外部接口传入。如果做纯视觉方案可以用栏杆状态检测替代但精度会下降。3.3 可视化界面怎么接毕设和课程设计通常要求有界面常见做法是 PyQt5 或 Gradio。PyQt5 适合做本地桌面应用Gradio 适合快速搭 Web 界面。用 Gradio 的话核心代码很短import gradio as gr from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) def detect_video(video_path): results model.track(sourcevideo_path, trackerbytetrack.yaml, persistTrue) out_path output.mp4 # 这里省略逐帧写视频的代码实际项目里用 cv2.VideoWriter return out_path demo gr.Interface( fndetect_video, inputsgr.Video(label上传收费站监控视频), outputsgr.Video(label检测结果), titleETC跟车逃费识别系统 ) demo.launch()界面部分的关键是把检测结果、跟踪 ID、逃费事件列表三个信息都展示出来只画框不标 ID 的话答辩时老师看不出跟踪逻辑在哪。4. 避坑与排查训练和部署中最容易翻车的五个点4.1 损失不下降mAP 卡在 0.1 不动现象训练跑了 50 个 epochbox_loss 和 cls_loss 几乎不降验证集 mAP 一直在 0.1 附近。原因通常是 data.yaml 里的路径写错YOLO 找不到图片但没报错拿空数据在训。解决训练前先跑yolo detect train datadataset/data.yaml modelyolov8n.pt epochs1看输出里train: Scanning...那行显示的图片数量是不是 0。如果是 0检查 path 是相对路径还是绝对路径相对路径的基准是 ultralytics 的 datasets 目录而不是你的项目目录建议直接写绝对路径。4.2 跟踪 ID 频繁跳变同一辆车被分配多个 ID现象视频里一辆车从进入到离开ID 从 1 变成 5 又变成 12。原因是检测框在连续帧之间抖动太大ByteTrack 的匹配阈值跟不上。解决把conf从 0.25 提到 0.4 以上减少低质量检测框同时在bytetrack.yaml里把track_high_thresh调到 0.5track_buffer从默认 30 调到 60给跟踪器更多帧来恢复丢失目标。如果还不行检查视频帧率低于 15fps 的监控视频跟踪效果会明显变差。4.3 CPU 推理速度太慢视频处理卡成幻灯片现象用 CPU 跑 YOLOv8n一帧要 200ms 以上处理一分钟视频要十几分钟。原因是默认输入尺寸 640 对 CPU 来说计算量偏大。解决推理时把imgsz降到 416 或 320速度能提升 2-3 倍精度损失在收费站场景可接受。另外用halfFalse明确关掉半精度CPU 不支持 FP16 反而会报错。如果还是慢考虑用 ONNX Runtime 导出后推理CPU 上比 PyTorch 原生快 30% 左右。4.4 逃费判定误报太多正常排队也被标记现象系统把正常排队的两辆车判成跟车逃费。原因是window_sec设太大或者栏杆线位置不对导致前车还没完全通过就触发了后车计数。解决先把window_sec从 3 秒降到 1.5 秒观察误报是否减少然后检查line_y用一段正常通行视频回放看车辆底边越过栏杆线的时刻是否和实际抬杆落杆时间对齐。如果摄像头角度导致车辆底边被遮挡改用检测框中心点过线判定但要把线往下移。4.5 换一台机器部署就报错依赖版本对不上现象在自己电脑上跑得好好的拷到同学电脑或服务器上就报ImportError或CUDA error。原因是 PyTorch 版本和 CUDA 驱动不匹配或者 ultralytics 版本差异导致 API 变了。解决导出pip freeze requirements.txt在目标机器上pip install -r requirements.txt。如果目标机器没有 GPU把 torch 换成 CPU 版本重装。ultralytics 建议锁版本比如ultralytics8.0.200不同小版本之间model.track的参数名可能不一样。5. 把逃费识别做成可演示的毕设三个提分技巧第一个技巧是加逃费事件回放功能。答辩时老师最想看的是「你怎么证明这辆车逃费了」光在视频上画框不够。我的做法是把每次逃费事件的起止帧号、车辆 ID、过线时间存成 JSON界面上加一个事件列表点击某条记录就跳转到对应视频片段循环播放。这个功能代码量不大但演示效果直接拉满。第二个技巧是做一个简单的统计面板。用 pandas 把逃费事件按小时、按车道聚合画一张柱状图显示哪个时段逃费高发。数据不用真实用你测试视频跑出来的结果就行。老师看到有数据分析维度会觉得你不只是调了个模型。第三个技巧是准备一份「误报分析」文档。主动列出你的系统在哪些情况下会误判比如夜间车牌反光导致检测框偏移、摩托车跟车因为类别不在训练集里被漏检。然后给出你的缓解方案比如夜间单独调低 conf 阈值、把摩托车加进训练类别。这份文档比多跑 20 个 epoch 更能体现工程思维。最后一个习惯每次改完判定逻辑一定用同一段测试视频跑一遍把逃费事件数量和人工数出来的对比。我吃过亏调完window_sec觉得逻辑更合理了结果漏掉了两起真实逃费因为窗口调太小把跟车车辆隔到窗口外了。后来我固定用三段视频做回归测试一段正常通行、一段跟车逃费、一段排队缓行每次改参数都跑这三段误报和漏报数量记在表格里。这个习惯帮我省了很多返工时间。希望帮到你。本文还有配套的精品资源点击获取
返回列表