尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

YOLOv5+PyQt车辆行人检测实战:从数据集训练到桌面部署

YOLOv5+PyQt车辆行人检测实战:从数据集训练到桌面部署 简介目标检测是计算机视觉领域的基础任务之一其核心在于让模型能够同时完成目标定位与分类。YOLO系列作为单阶段检测器的代表凭借一次前向传播直接预测边界框和类别的设计在实时性要求较高的场景中展现出独特优势而YOLOv5凭借其成熟的生态和轻量级模型特性成为工业落地的热门选择。在实际工程中数据质量直接决定模型上限训练参数则影响收敛效率而最终的用户体验往往取决于界面交互的设计。将YOLOv5与PyQt结合可以构建一套完整的桌面端可视化检测工具广泛应用于车辆行人检测、智能交通监控等场景。本文从数据集处理、模型训练到PyQt界面封装系统梳理了整套流程中的关键步骤与常见问题为希望快速搭建本地检测演示系统的开发者提供实践参考。 做车辆行人检测这几年YOLOv5算是我用得最顺手的一套方案了。之前有个项目需要在桌面端快速验证检测效果我直接把YOLOv5训练好的模型封装进了PyQt界面里配合一个5000张的车辆行人数据集从训练到部署跑通整个流程。这套组合特别适合刚接触目标检测的工程师或者说想在本地快速做一个可视化演示工具的朋友。今天就把完整过程拆开讲一讲包括环境搭建、数据集处理、模型训练、PyQt界面封装以及我踩过的几个坑。1. 项目整体设计与思路拆解1.1 为什么选YOLOv5而不是YOLOv8或Faster R-CNN很多新手一上来就在纠结选哪个检测框架。我自己的判断标准很简单项目周期、硬件条件、部署难度。YOLOv5在工业界的成熟度非常高生态完整教程多遇到问题基本都能搜到答案。虽然YOLOv8在性能上有提升但YOLOv5在推理速度和模型体积上依然有优势尤其是在CPU或者低端GPU上跑的时候YOLOv5的轻量级模型如yolov5s表现相当稳定。Faster R-CNN这种两阶段检测器精度虽高但推理速度慢做实时视频流检测的时候帧率上不去。而YOLOv5属于单阶段检测器一次前向传播就能同时预测边界框和类别在车辆和行人这种实时性要求较高的场景下明显更合适。另外PyQt界面的集成需要模型能够快速响应如果检测一次要等几百毫秒用户体验会非常差。1.2 项目整体架构说明这套项目的整体链路可以拆成四个环节数据集准备、模型训练、模型导出、PyQt界面推理。数据集的标注质量直接决定模型的上限训练环节决定了模型能否收敛到理想效果导出环节把PyTorch权重转成可在推理环境中高效运行的格式最后通过PyQt把模型封装成一个可交互的桌面工具。项目目录结构我建议这样规划vehicle_pedestrian_detection/ ├── dataset/ │ ├── images/ │ │ ├── train/ │ │ └── val/ │ ├── labels/ │ │ ├── train/ │ │ └── val/ │ ├── data.yaml │ └── train.txt │ └── val.txt ├── yolov5/ │ ├── train.py │ ├── detect.py │ └── ... ├── weights/ │ └── best.pt ├── ui/ │ ├── main_window.py │ ├── detector.py │ └── main.py └── requirements.txt1.3 技术选型背后的取舍模型方面我选的是YOLOv5s作为基础版本。YOLOv5一共有n、s、m、l、x五个版本s代表small参数量大约在700万左右在精度和速度之间比较均衡。如果硬件资源非常紧张可以选n版本如果对精度要求很高且GPU足够强可以选l或x但界面推理时延迟会明显增大。PyQt方面我用的PyQt5因为它的文档多、资料全网上关于PyQt5的问题基本都有人回答过。PyQt6虽然更新但有些老代码不兼容。界面布局采用左侧控制面板、右侧实时显示区的结构按钮包括选择图片、选择视频、打开摄像头、开始检测、停止检测再加上一个置信度阈值滑块。2. 数据集准备与处理2.1 5000张数据集的构成与标注格式5000张车辆行人数据集听起来不算特别大但对于二类检测任务来说已经足够打下一个不错的基础。关键在于数据分布的均衡性。我的数据集构成大致如下城市道路场景约2500张包含十字路口、直行道、人行横道场景高速公路场景约1000张主要是车辆目标乡村道路和小区内部道路约800张行人和非机动车较多夜间、雨天、逆光等特殊光照场景约700张标注格式采用YOLO格式的txt文件每行代表一个目标格式为类别id、中心点x坐标、中心点y坐标、目标宽度、目标高度。其中坐标值都是相对于图片宽高的归一化数值取值在0到1之间。拿一张1920x1080的图片举例如果图中有一辆车边界框左上角坐标是(500, 300)右下角坐标是(800, 600)那么转换后的YOLO格式标注就是class_id 0车 x_center (500 800) / 2 / 1920 0.3385 y_center (300 600) / 2 / 1080 0.4167 width (800 - 500) / 1920 0.1563 height (600 - 300) / 1080 0.2778所以txt文件里这一行的内容是0 0.3385 0.4167 0.1563 0.27782.2 数据集划分与目录整理数据处理的第一步是把原始图片和标注文件按82的比例划分成训练集和验证集。这里要注意一个常见错误不能随机乱分要保证同一场景的连续帧图片要么全在训练集要么全在验证集否则会造成数据泄漏让验证精度虚高。我一般先用脚本过滤掉没有标注目标的图片然后按场景分组再分组内划分。简单版的划分脚本可以这么写import os import random import shutil random.seed(42) image_dir raw_images label_dir raw_labels train_img_dir dataset/images/train val_img_dir dataset/images/val train_lbl_dir dataset/labels/train val_lbl_dir dataset/labels/val os.makedirs(train_img_dir, exist_okTrue) os.makedirs(val_img_dir, exist_okTrue) os.makedirs(train_lbl_dir, exist_okTrue) os.makedirs(val_lbl_dir, exist_okTrue) images [f for f in os.listdir(image_dir) if f.endswith(.jpg)] random.shuffle(images) val_count int(len(images) * 0.2) for i, img_name in enumerate(images): src_img os.path.join(image_dir, img_name) src_lbl os.path.join(label_dir, img_name.replace(.jpg, .txt)) if i val_count: shutil.copy(src_img, val_img_dir) shutil.copy(src_lbl, val_lbl_dir) else: shutil.copy(src_img, train_img_dir) shutil.copy(src_lbl, train_lbl_dir)2.3 数据增强策略5000张数据虽然够用但想要模型泛化能力更强还得靠数据增强。YOLOv5内置了Mosaic增强、随机仿射变换、HSV色彩空间扰动、水平翻转等策略。其中Mosaic增强是YOLOv5的招牌它把4张图随机裁剪拼接成一张新图这样能显著提升模型对小目标的检测能力。训练时建议开启以下增强参数hyp[mosaic] 1.0 hyp[mixup] 0.2 hyp[hsv_h] 0.015 hyp[hsv_s] 0.7 hyp[hsv_v] 0.4 hyp[degrees] 10.0 hyp[translate] 0.1 hyp[scale] 0.5 hyp[shear] 0.0 hyp[perspective] 0.0 hyp[fliplr] 0.5另外还有一个辅助手段是离线增强就是把图片做亮度调整、加高斯噪声、旋转后存成新图片。但离线增强会增加数据集体积而且跟在线增强功能重叠我只在夜间样本不足时用离线方式补了一些低亮度图片。2.4 data.yaml配置文件数据集准备好之后需要在YOLOv5的data目录下新建一个data.yaml文件train: dataset/images/train val: dataset/images/val nc: 2 names: [vehicle, pedestrian]这里nc代表类别数量names对应类别名称。顺序必须和标注文件里的class_id保持一致0对应vehicle1对应pedestrian否则训练出来的模型会张冠李戴。3. YOLOv5环境搭建与模型训练3.1 环境安装YOLOv5对硬件有一定要求。如果你只是用CPU训练5000张图片时间会很长我建议起码有一块4GB以上显存的NVIDIA GPU。CUDA和PyTorch版本要匹配我目前用的组合是CUDA 11.8 PyTorch 1.13.1。安装流程是这样的git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txtrequirements.txt里包含torch、opencv-python、numpy、matplotlib、pandas等依赖。如果网络条件一般可以手动安装PyTorch再装其他依赖pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install -r requirements.txt装完之后跑一个测试命令能正常出结果说明环境没问题python detect.py --weights yolov5s.pt --source data/images/bus.jpg3.2 训练参数选择训练是这套流程里最花时间的环节参数设置决定了模型最终效果。我的常用训练命令如下python train.py \ --weights yolov5s.pt \ --data data.yaml \ --epochs 100 \ --batch-size 16 \ --img 640 \ --device 0 \ --workers 4 \ --cos-lr \ --cache几个关键参数解释一下--weights yolov5s.pt使用预训练权重做迁移学习比从零训练收敛快得多--epochs 100训练轮数。数据集小的时候100轮基本够如果loss还在下降可以加--batch-size 16显存不够就调小到8够大可试32--img 640输入图片尺寸。YOLOv5默认训练尺寸就是640大图如1280能提升小目标检测精度但显存消耗翻倍--cache把图片缓存到内存里省去每轮反复读盘的时间--cos-lr使用余弦退火学习率收敛更平滑3.3 训练过程中的监控训练开始后YOLOv5会在终端输出每个epoch的loss、精度、召回率、mAP等指标。这里我建议重点盯几个指标box_loss边界框回归损失一般在0.02到0.05之间算正常obj_loss置信度损失持续下降说明模型在学会区分前景和背景mAP0.5IoU阈值0.5下的平均精度车辆行人这类大目标场景应该能达到90%以上mAP0.5:0.95更严格的评价指标对边界框精度要求高训练结束后runs/train/exp目录下会生成weights/best.pt和weights/last.pt。best.pt是验证集上表现最好的权重我们后续推理就用它。3.4 超参数调整心得如果你发现训练出来的模型mAP不理想不要急着换模型结构先检查这几个东西第一是学习率。YOLOv5默认lr00.01但不同数据集上表现不同。如果loss震荡明显就把lr0调低到0.001或者把batch-size调大。第二是anchor参数。YOLOv5会自动从数据集中学习anchor尺寸但如果你的目标普遍偏大或偏小建议手动改一下data/hyps/hyp.scratch-low.yaml里的anchor参数。第三是类别不均衡问题。如果数据集中车辆数量远多于行人模型会对行人检测能力偏弱可以考虑加类权重或者用约等于采样。3.5 模型推理与导出训练好之后用best.pt做推理测试python detect.py --weights runs/train/exp/weights/best.pt --source test_images/ --conf-thres 0.5推理没问题的话需要把模型导出为TorchScript格式方便PyQt里加载import torch model torch.load(runs/train/exp/weights/best.pt, map_locationcpu)[model].float() model.eval() example torch.rand(1, 3, 640, 640) traced_script_module torch.jit.trace(model, example) traced_script_module.save(weights/best.torchscript.pt)导出TorchScript的好处是脱离原始YOLOv5代码依赖也能加载部署更干净。4. PyQt界面开发与模型封装4.1 界面整体布局PyQt界面是整个项目最终交付的形态用户不需要懂任何代码打开程序就能选图片、看视频、调阈值。我的界面布局是这样的顶部为菜单栏包含打开图片、打开视频、打开摄像头、退出等操作左侧为控制面板放置置信度滑块、检测类别勾选框、检测结果显示区域中央为QLabel充当的显示区用于展示检测结果图像底部为状态栏显示当前帧率、检测目标数量、模型名称等信息主窗口的核心代码框架from PyQt5.QtWidgets import QMainWindow, QAction, QSlider, QLabel, QVBoxLayout, QHBoxLayout, QWidget, QFileDialog, QCheckBox, QPushButton from PyQt5.QtCore import Qt from PyQt5.QtGui import QImage, QPixmap import cv2 import torch class DetectionWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle(车辆行人检测系统) self.resize(1280, 720) self.model self.load_model() self.init_ui() self.cap None self.timer None def load_model(self): model torch.jit.load(weights/best.torchscript.pt, map_locationcpu) model.eval() return model4.2 模型加载与推理逻辑在PyQt界面中做推理最关键的是处理好图像尺寸转换。YOLOv5输入需要640x640的RGB图像而cv2读出来的是BGR格式尺寸也不一定匹配。我的推理流程分四步第一步读取图像并做letterbox处理。letterbox就是把原始图像等比缩放到640x640多余的边用灰色填充避免直接resize导致目标形变。第二步图像格式转换。BGR转RGB然后转成torch.Tensor维度从HWC变成CHW再增加batch维度。第三步模型前向推理。因为PyQt界面需要考虑响应速度如果直接在主线程跑推理界面会卡死。我实际是把推理放到QThread里通过信号把结果传回主线程再刷新界面。第四步解析输出。模型输出格式是[1, 25200, 7]其中25200是三个尺度特征图的anchor总数7是[x1, y1, x2, y2, objectness, class_score, class_id]。用非极大值抑制去掉重复框再按置信度阈值过滤。推理线程的简化代码如下class DetectThread(QThread): result_ready pyqtSignal(object) def __init__(self, model, frame, conf_thres0.5): super().__init__() self.model model self.frame frame self.conf_thres conf_thres def run(self): results self.detect(self.frame) self.result_ready.emit(results) def detect(self, frame): img, ratio, dw, dh self.letterbox(frame) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img img.transpose(2, 0, 1) img torch.from_numpy(img).float().div(255.0).unsqueeze(0) with torch.no_grad(): pred self.model(img)[0] dets self.non_max_suppression(pred, self.conf_thres) boxes [] if dets is not None and len(dets): for x1, y1, x2, y2, conf, cls in dets: x1 (x1 - dw) / ratio y1 (y1 - dh) / ratio x2 (x2 - dw) / ratio y2 (y2 - dh) / ratio boxes.append((int(x1), int(y1), int(x2), int(y2), float(conf), int(cls))) return boxes4.3 绘制检测框拿到检测框坐标之后需要把结果画回到原图上。车辆我用绿色框行人用红色框这样视觉上区分度高。框上方还要标注类别名称和置信度。def draw_boxes(self, image, boxes): color_map {0: (0, 255, 0), 1: (0, 0, 255)} class_names [vehicle, pedestrian] for x1, y1, x2, y2, conf, cls in boxes: color color_map[cls] cv2.rectangle(image, (x1, y1), (x2, y2), color, 2) label f{class_names[cls]} {conf:.2f} cv2.putText(image, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2) return image4.4 视频流与摄像头支持除了静态图片检测我还在界面上接入了视频流和摄像头检测。视频流处理相对简单用OpenCV的VideoCapture循环读取每一帧丢给推理线程。摄像头则直接打开摄像头索引号逻辑相同。这里要特别注意内存管理。视频帧是连续不断的如果推理速度跟不上视频帧率队列会越积越多内存蹭蹭往上涨。我的解决办法是只保留最新一帧丢掉来不及处理的帧def update_frame(self): ret, frame self.cap.read() if not ret: return if not self.thread.isRunning(): self.thread DetectThread(self.model, frame, self.conf_thres) self.thread.result_ready.connect(self.show_result) self.thread.start()4.5 实时显示与性能优化把QLabel像素图类型转换成QImage时有个小细节很容易被忽略。cv2的图像是BGR格式而QImage默认认为RGB如果不做转换显示画面颜色全偏蓝。所以必须用rgb_image cv2.cvtColor(bgr_image, cv2.COLOR_BGR2RGB) h, w, ch rgb_image.shape bytes_per_line ch * w qt_image QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888) self.label_display.setPixmap(QPixmap.fromImage(qt_image))如果想让界面更流畅可以引入一个帧间隔控制。比如设定FPS上限为30每处理完一帧后sleep一段时间避免CPU被无意义烧满。5. 常见问题与排查技巧实录5.1 训练时loss不下降或发散的排查训练时最让人头疼的就是loss不降反升。我总结下来大概率是这三个原因第一个是学习率太大。如果loss曲线上下跳动剧烈或者直接爆表试着把lr0从0.01降到0.001同时把batch-size调大稳定性会好很多。第二个是标签严重错误。用labelImg标注时如果有人把行人的框标成了车辆模型学不到规律loss就会下不去。建议训练前用可视化脚本把所有标注画出来看一遍至少抽查100张图。第三个是数据集分布问题比如某类样本太少导致模型对该类的loss始终偏高。5.2 模型对夜间或小目标检测效果差模型的泛化能力受限于训练数据。如果你的数据集里夜间图片少模型自然对夜间场景检测差。解决办法有两个方向一是补数据从公开数据集比如BDD100K里抽取夜间车辆和行人的图片加入训练二是做针对性增强把亮度降低、对比度拉高模拟夜间效果。小目标检测差的问题我建议在训练时把img参数从640提高到960或1280。分辨率提高后小目标占的像素更多模型更容易学到特征。代价是显存占用高很多训练时间也翻了不止一倍。5.3 PyQt界面卡顿和掉帧界面卡顿通常是因为推理放在了主线程阻塞了UI事件循环。把推理移到QThread只是第一步还要确认不要把结果绘制也放到子线程中操作QLabel。Qt的规定是UI操作只能在主线程进行子线程只能通过信号槽把数据传回主线程更新界面。如果视频检测的帧率还是上不去建议检查模型加载后的float类型。默认的模型参数是float32如果你的PyTorch和CPU支持可以转成float16推理速度能提升不少model model.half()5.4 模型加载路径和依赖问题把PyQt打包成exe分发时最常见的坑是模型路径写死。编译成exe后当前工作目录可能和开发时不一样模型就加载不到。解决办法是动态获取程序运行目录import sys import os def resource_path(relative_path): if hasattr(sys, _MEIPASS): base_path sys._MEIPASS else: base_path os.path.abspath(.) return os.path.join(base_path, relative_path) model_path resource_path(weights/best.torchscript.pt)5.5 常见问题速查表症状可能原因解决方案训练loss为NaN学习率过大或数据有异常值降低lr0检查标注文件检测框偏移严重缩放时未还原letterbox偏移量使用ratio和dw/dh逆变换视频画面颜色发蓝cv2 BGR格式未转换RGB加cv2.cvtColor转换界面点了没反应推理阻塞了主线程使用QThread摄像头打不开索引错误或权限问题尝试cap.open(0)/cap.open(1)模型载入失败路径错误或格式不符检查export脚本和路径拼接6. 项目扩展建议这套车辆行人检测项目其实只是一个起步。后续扩展方向非常明确第一是更多类别把检测目标扩展到自行车、摩托车、公交车在data.yaml里加类别即可但数据集也要跟上。第二是跟踪功能引入DeepSORT或者ByteTrack就能统计车流量、行人轨迹。第三是硬件的边缘部署把模型转换到TensorRT或OpenVINO接入RK3588或Jetson之类的边缘设备实现低延迟实时检测。我个人的体验是做这类项目最重要的是把握住三个环节数据质量决定上限训练参数决定收敛速度界面交互决定最终体验。每跑通一个环节后面遇到的坑就会少一个。如果你们也在做类似的检测项目按照这个流程捋一遍基本能把大坑小坑都趟平。最后再分享一个小经验训练前先拿几十张图做一次短路实验确认数据和代码链路是通的再去跑完整训练能省下不少反复试错的时间。本文还有配套的精品资源点击获取
返回列表