
简介面向车辆检测开发者的YOLOv8多类别车辆检测资源包整合6类车辆检测权重、1000张已标注图片数据集和PyQt图形界面适合需要快速上手YOLO系列训练或构建可视化演示工具的算法工程师、研究生与竞赛选手。数据集涵盖自行车、汽车、卡车、三轮车、面包车和公交车已划分train/val/test并附带data.yamltxt格式标签无需转换即可直接用于YOLOv5、YOLOv7、YOLOv8、YOLOv9等算法训练同时带有PyQt界面源码、ui文件和若干脚本可用于加载模型完成图片或视频检测展示。整个压缩包共2000个文件以jpg图像、txt标注、py脚本和yaml配置为主另有pt权重、说明文档、辅助脚本等体积约176MB目录结构清晰便于查阅。使用这套资源可完成从数据集准备、模型训练到结果可视化展示的完整流程尤其适合做算法对比、界面二次开发或毕业设计参考。目前已有605人学习下载是一份实用性较强的车辆检测方向资源包。 做车辆相关的视觉项目最常被问到的就是“有没有现成的检测权重”。有但多半不好用。我整理了一套 YOLOv8 多类别车辆检测的完整方案从数据集怎么选、标注怎么转、权重怎么训练到最后的 PyQt 可视化界面怎么搭一次讲完。这套东西拿来当毕设、课设或者公司内部做一个车辆识别计数工具都能直接套用。如果你是第一次接触目标检测看完至少能少走两个月的弯路。1. 项目需求分析与技术选型1.1 这个项目到底要解决什么问题先想清楚需求再动手。这类车辆检测项目常见的真实场景有这么几种监控画面里的车流量统计、停车场出入口的车型识别、路口红绿灯区域的违章抓拍辅助再就是自动驾驶仿真里的感知模块。它们的共性是“从视频或图像里把车找出来并区分类型”注意是区分类型不是单纯找出车。你要把轿车、公交车、卡车、摩托车分开这才叫多类别车辆检测。很多人上来就找代码找到代码再找权重权重跑起来发现识别效果一团糟于是卡住。真正的问题是需求没拆干净。我的习惯是先列四条检测类别有哪些共几类彼此像不像数据来源是什么是固定摄像头还是移动端分辨率大概多少部署环境有没有 GPU显存多大要不要实时检测结果怎么用是画框给人看还是后续接入统计、告警、控制这四个问题直接决定了数据集方案、模型大小和界面功能。比如你是固定机位俯拍停车场那目标基本都是中小尺寸就得考虑小目标检测优化如果是车载摄像头那大尺寸目标和运动模糊又是重点。我这个项目按通用监控场景做默认类别选 car、bus、truck、motorcycle 四类图片分辨率 640部署端至少要有 4GB 显存界面提供图片、视频、摄像头三种输入。1.2 为什么是 YOLOv8 而不是其他模型YOLOv8 在这类项目里的优势不是“最准”而是“最稳”。你搜模型时可能看到 YOLOv5、YOLOv9 甚至 RT-DETR说实话都能做但 YOLOv8 有个不可替代的生态优势Ultralytics 官方把训练、验证、导出、部署的闭环做得极完整代码风格统一文档对新手极其友好网上参考案例又多到离谱。做课设或毕设最怕的就是卡在某个环境细节上没人问选 YOLOv8 等于默认有了一个几万人踩过坑的社区。从网络结构上讲YOLOv8 用了 Anchor-Free 的检测头不再像 YOLOv5 那样先预设一堆锚框而是让模型直接预测目标中心点到四条边的距离。这个改动让训练收敛更稳定对小目标的召回也更好。Backbone 部分是 C2f 结构它把梯度分流做得更细在同样 FLOPs 下比 YOLOv5 的 C3 模块提了点精度。再加上 TaskAlignedAssigner 动态标签分配正负样本划分更聪明整体训练难度反而比老版本低。这些改进凑在一起就是“同样的数据YOLOv8 更容易训出能用的模型”。1.3 为什么界面用 PyQt 而不是 Web 方案检测模型做完只是算法离“能给人用”还差一个壳。常见的选择是 Flask/FastAPI 做 Web 服务或者 PyQt 做桌面客户端。我选 PyQt原因很简单车辆检测系统通常接的是本地摄像头或本地视频文件桌面程序可以直接调用 OpenCV 的 VideoCapture延迟低、不折腾网络传输。而且 PyQt5 的 QThread 多线程模型和信号槽机制很适合接实时推流这种任务主界面不会卡。Web 方案也不是不行但你得额外处理浏览器端的视频流协议、后端推流服务、部署服务器复杂度直接翻倍。做毕设或者内部工具PyQt 是性价比最高的方案打包成 exe 拷到 Windows 机器上就能跑。界面选 PyQt5 而不是 PyQt6因为 PyQt5 的生态资料最多遇到问题随便一搜就有答案。2. 数据集准备从公开数据到自有数据2.1 公开数据集怎么选训练车辆检测模型数据集决定了精度的天花板。我见过有人用 COCO 的 car 类直接当训练集效果在特定场景下稀烂因为 COCO 里的车太杂、小目标太多、分布和实际监控场景差太远。做多类别车辆检测建议优先考虑下面几个数据集特点适合场景UA-DETRAC国内城市道路监控视角轿车/公交车为主标注质量高交通监控、车流量统计BDD100K多路况、多天气含 car/bus/truck 等类别数据量大自动驾驶、复杂场景泛化KITTI车载前视视角类别含 car/van/truck/pedestrian车载感知、自动驾驶仿真自采集数据完全贴合自己的摄像头视角和类别分布定制化项目、毕设加分项我的建议是主体用 BDD100K 或 UA-DETRAC再混一小部分自采数据。BDD100K 类别细到 car、bus、truck、motorcycle正好符合四类需求但原始标注是 JSON 格式训练前要转换。UA-DETRAC 是监控视角车型分类里甚至区分了 sedan、suv、van但它的标注 XML 结构和 YOLO 格式差别较大转换脚本要自己写。2.2 标注格式转换VOC/COCO 转 YOLOYOLO 系列训练的标注格式是纯文本每一行对应一个目标class_id cx cy w h后四个值都是归一化后的比例。所以不管原始数据是 XMLVOC还是 JSONCOCO最终都要转成这种 txt 格式。转换的核心是坐标换算公式x_center (xmin xmax) / 2 / img_width y_center (ymin ymax) / 2 / img_height box_width (xmax - xmin) / img_width box_height (ymax - ymin) / img_height我用一个脚本对 UA-DETRAC 的 XML 做了批处理把目标类型映射到自定义的类别编号比如 car 映射成 0bus 是 1truck 是 2motorcycle 是 3。这里有个注意点UA-DETRAC 里还有 van 和 others 类别我统一归到了 truck 或直接忽略避免类别太杂导致模型学不干净。忽略的框不要留空 txt而是对应删除否则训练时 FileNotFoundError 或空标注文件会报警告。转完后验证数据最关键的一步随机抽几张图把标注框画回去肉眼看对不对。我写了个几行的可视化脚本用 OpenCV 把 txt 解析出来画框发现过好几次坐标系写反或者宽高算错的问题。这一步不检查直接训练训出来模型框全是偏的后面全白干。2.3 数据增强与类别均衡车辆数据集的通病是类别极不均衡car 可能有几万张motorcycle 可能只有几百张。直接训练的话模型对车学习得很充分摩托车基本学不到特征推理时漏检率极高。我这边先做了三个处理。第一是数据增强YOLOv8 训练时自带 mosaic、flip、hsv 扰动等增强策略默认开启这能缓解数据量不足的问题。如果摩托车样本太少我会在预处理阶段单独对包含摩托车的图片做离线增强比如水平翻转、随机旋转 10 度、亮度对比度变化把样本数量补到至少 car 类别的三分之一。第二是类别权重在训练时给样本少的类别更高的 loss 权重。Ultralytics 没有直接开放这个参数但可以在 dataset.yaml 的配置文件层面做样本重采样简单点就是在训练前把包含稀有类别的图片复制几份混进数据集相当于手工过采样。第三是 dataset.yaml 的写法千万别搞错路径path: datasets/vehicle train: images/train val: images/val nc: 4 names: [car, bus, truck, motorcycle]path是数据集根目录的绝对路径train和val是相对路径指向包含图片的文件夹。YOLOv8 会自动在同级目录下找对应的labels文件夹。这个对应关系是绝对的images/train里的每张图片必须在labels/train里有同名 txt否则训练结果会缺框。3. 模型训练实操与参数调优3.1 环境配置与 GPU 最低要求训练环境这块网上说法让人很焦虑什么“必须 24G 显存”“没有 A100 别碰深度学习”。实际上车辆检测这种单类任务对算力的要求没那么离谱。我用一台 GTX 1660Ti6GB 显存跑 YOLOv8s 模型batch size 设 8图片尺寸 640训练 150 轮毫无压力一整个流程跑下来大约 6 到 8 小时。如果你只有 CPU也不是完全不能跑但 150 轮可能要两三天建议直接考虑 Google Colab 或租个云 GPU。安装环境最稳的方式是 conda 隔离避免污染其他项目conda create -n yolo python3.9 conda activate yolo pip install ultralytics torch torchvisionCUDA 要提前装好用nvidia-smi看驱动支持的 CUDA 版本再安装对应版本的 PyTorch。我做项目时踩过一个坑驱动是 11.8 的结果 pip 默认装了 CUDA 12.1 的 torch训练时报CUDA error: no kernel image is available重装 torch 才解决。版本匹配这个事建议训练前先跑一段验证import torch print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0))3.2 训练参数怎么设置训练命令本身不长核心参数就几个。我的建议是先从官方预训练权重开始不要在 ImageNet 预训练之外再从头训练除非你的数据集和通用场景差异极大。预训练权重能省下大量时间而且精度更高。yolo detect train datavehicle.yaml modelyolov8s.pt epochs150 imgsz640 batch8 device0几个参数逐个说。model选 yolov8s 还是 yolov8n取决于你的部署端。如果后续要在 RK3588 或 Jetson 上跑选 n 或 s如果只在本机做 demo选 m 也可以。imgsz建议固定 640太大显存不够太小小目标检测效果差。batch按显存来6GB 显存用 8如果报 OOM 就降到 4。epochs100 到 200 之间我建议先跑 100 轮看验证集曲线如果 loss 还在下降就续训。训练中还有一个容易忽略的选项patience。它控制早停默认 50意思是验证集指标连续 50 轮没提升就自动停止。如果你的数据集本身不太难可能训练到 70 轮就停这是正常的不代表训练失败。我看到很多新手在这个地方困惑实际上早停是保护模型不被过拟合的机制。3.3 小目标检测从默认头到 P2 检测头监控场景里车辆往往离摄像头远目标框只有几十个像素默认的 YOLOv8 检测头在这类目标上表现一般。默认情况下 YOLOv8 有三个检测头分别负责大、中、小目标最小特征图是 40x40对应到 640 的输入图上小于 8x8 像素的目标基本检测不到。如果你发现漏检的主要是远处的小车有两个改进方向。第一个是开启模型 YAML 中额外的 P2 检测头让模型在 80x80 的特征图上多预测一层。Ultralytics 在 v8.2 之后支持自定义 YAML 加检测头做法是复制一份yolov8.yaml增加一层 C2f 和对应 Detect。但要注意加了 P2 头后显存占用和计算量都会增加1660Ti 这类卡可能得把 batch 降到 4。第二个更省事的方案是 SAHI 切片推理就是把大图切成小块对每一块分别推理再合并结果。这个方案不改模型但对 PyQt 实时场景来说速度偏慢更适合离线图片分析。我在实际项目里优先尝试第一种调模型结构效果不够再上 SAHI两者各有适用场景。3.4 训练结果怎么看别只盯 mAP训练结束后runs/detect/expXX/目录下能看到一张results.png里面画出了 train/loss、val/loss、mAP50、mAP50-95、precision、recall 共六条曲线。我的习惯是优先看 val 的 mAP50 和 recall 曲线。mAP50 衡量的是框和类别综合精度recall 反映的是有没有漏检——对车辆检测来说漏检比误检更让人头疼因为计数场景漏一辆车数据就错了。权重文件里有两个best.pt和last.pt。best.pt是根据验证集指标选出的最优模型last.pt是最后一轮权重。推理和部署都优先用best.pt。如果你的训练过程出现过 loss 剧烈震荡可以对比两个文件的差异如果 best 明显优于 last说明后半段在过拟合可以适当增加数据增强强度或者减小学习率。4. PyQt 界面开发从检测逻辑到桌面应用4.1 界面功能规划PyQt 界面不是为了炫技是为了让检测结果“可操作”。一个完整的车辆检测界面至少要有三个输入入口本地图片、视频文件、摄像头实时画面。对应的输出是检测画面、类别统计、保存功能。我做的界面布局大致是左侧控制区、中间视频显示区、右侧检测列表区。控制区放打开图片、打开视频、打开摄像头、开始检测、停止检测、保存结果六个按钮中间用 QLabel 显示画面右边用 QTableWidget 显示当前帧的检测类别和置信度。界面不要一开始就做复杂先跑通核心链路打开文件、显示画面、绘制检测框。后续再加统计和保存功能。把每个按钮的功能独立成方法方便测试和排查问题。4.2 多线程架构QThread 信号槽这是整个 PyQt 项目最容易翻车的地方。如果直接在界面主线程里跑模型推理视频一播放界面立刻假死鼠标都动不了。原因很简单推理是耗时操作默认占用主线程GUI 的事件循环被阻塞。解决方案是用 QThread 把推理放到后台线程。我写了一个DetectionThread类继承 QThread在run方法里循环读取视频帧并调用模型推理每处理完一帧就通过信号把结果发回主线程。信号槽的关键代码大致长这样class DetectionThread(QThread): frame_ready pyqtSignal(object, list) def __init__(self, model_path, source): super().__init__() self.model YOLO(model_path) self.source source self.running True def run(self): cap cv2.VideoCapture(self.source) while self.running and cap.isOpened(): ret, frame cap.read() if not ret: break results self.model(frame, verboseFalse) boxes results[0].boxes self.frame_ready.emit(frame, boxes) cap.release() def stop(self): self.running False主线程里连接信号然后在槽函数里绘图并更新 QLabelself.thread.frame_ready.connect(self.update_frame) def update_frame(self, frame, boxes): for box in boxes: x1, y1, x2, y2 map(int, box.xyxy[0].tolist()) conf float(box.conf[0]) cls int(box.cls[0]) label f{self.names[cls]} {conf:.2f} cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(frame, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch rgb.shape img QImage(rgb.data, w, h, ch * w, QImage.Format_RGB888) self.label_video.setPixmap(QPixmap.fromImage(img))所有耗时操作都在线程里做主线程只负责显示界面就不会卡。强调一点不要在子线程里直接操作 UI 控件Qt 的 UI 不是线程安全的必须通过信号槽转回主线程更新。4.3 界面美化与打包发布默认的 PyQt 界面真的丑写个 QSS 样式表能让整个项目看上去专业很多。我一般把按钮、表格、面板的背景色、圆角、hover 效果统一写在一个 qss 文件里加载一次全局应用。核心就几行app.setStyleSheet( QPushButton { background-color: #2d8cf0; color: white; border: none; border-radius: 4px; padding: 8px 16px; } QPushButton:hover { background-color: #57a3f3; } QPushButton:pressed { background-color: #1e72c8; } QLabel#videoLabel { border: 1px solid #ccc; background-color: black; } )打包发布用 PyInstaller注意两件事模型权重文件要用--add-data一起打包不要写死绝对路径YOLO 相关的动态库有时需要--collect-all ultralytics才能完整收集。我第一次打包时漏了权重文件exe 打开后直接报找不到模型排查了半天。建议打包命令用pyinstaller --onefile --windowed --add-data best.pt;. --collect-all ultralytics main.py还有一个细节摄像头画面的显示区需要固定宽高比否则画面拉伸变形。我在 QLabel 里用setScaledContents(True)加setMinimumSize处理实测可用。5. 常见问题与排查记录5.1 环境与训练报错速查我把做这个项目实际遇到的典型问题整理成一张表照着排查基本都能解决现象可能原因解决办法训练报 CUDA no kernel imagePyTorch 的 CUDA 版本与驱动不匹配重装对应 CUDA 版本的 PyTorch训练时显存不足 OOMbatch 太大或图片尺寸太大降低 batch或改小 imgsz验证时 mAP 一直为 0标注框与图片不匹配、标签格式错了可视化检查标注确认归一化公式推理时模型什么都检测不到模型类别索引与推理代码不一致检查 names 列表顺序是否和训练时一致loss 训练几轮就变 NaN学习率过大或数据集有损坏图片降低 lr删除异常图片重新训练5.2 PyQt 摄像头与视频播放坑摄像头打不开是高频问题。USB 摄像头用cv2.VideoCapture(0)RTSP 流用cv2.VideoCapture(rtsp://...)但很多摄像头默认编码格式 OpenCV 不认可以先设置cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(M, J, P, G))。实测大部分 USB 摄像头切到 MJPG 格式后能正常读取。另一个坑是关闭摄像头时程序崩溃。原因是子线程还在读帧主线程先销毁了界面。解决办法是在关闭窗口事件里先调用thread.stop()再thread.wait()等线程真正退出最后才cap.release()。OpenCV 和 PyQt 的 Qt 插件冲突也遇到过症状是程序启动时报qt.qpa.plugin: could not load the qt platform plugin xcb或者运行过程中崩溃。处理方式是把 OpenCV 从opencv-python换成opencv-contrib-python-headless或者反过来做到只保留一个 Qt 绑定冲突基本能解决。5.3 检测效果调优经验用训练好的模型部署到实际场景最常见的是检测效果和训练集有差距。如果发现漏检优先看是不是小目标问题因为监控画面主体的尺寸分布和公开数据集差异很大。这里我的经验是先多采集实际场景的视频跑一遍模型看漏检样例确认是尺寸问题还是类别问题再针对性地标注补充。如果发现同一个目标在相邻帧被反复识别两次这不是模型 bug而是没有跟踪模块。车辆计数场景建议接一个 ByteTrack 或 DeepSORT 跟踪器在同一目标的多个检测框之间建立 ID 关联计数时按 ID 去重。这个功能做增量开发的时候可以考虑。写在最后这套项目做完我的最大感受是目标检测本身已经不是瓶颈瓶颈在数据、工程化整合和排坑能力。YOLOv8 训练出一个能用的模型并不难难点是把数据集整理干净、把推理代码写得健壮、把界面做得不崩溃。对一个毕设或者内部工具来说能跑通、能演示、能应对真实输入就已经赢了大多数项目。最后分享一个我在实际项目里一直用的小技巧把整个项目的配置文件集中在一个config.py里包括模型路径、类别列表、置信度阈值、输入源类型等。调试的时候改一处就行不用在界面代码里翻来翻去找参数。这个习惯帮我省了无数时间。你按这套流程做完替换成自己的数据就能复现后面想往上加跟踪、加统计、接串口控制架构也都是现成的。本文还有配套的精品资源点击获取