ARTICLE DETAIL

资讯详情

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

YOLOv5车辆行人检测实战:5000张数据集训练与PyQt界面集成

YOLOv5车辆行人检测实战:5000张数据集训练与PyQt界面集成 简介本资源面向计算机视觉入门与进阶开发者提供一套可直接运行的YOLOv5车辆行人检测完整方案目标类别为person与car两类。包内包含yolov5s和yolov5m两种已训练权重mAP超过90%并附PR曲线、loss曲线等训练过程记录权重基于一万余张交通场景数据训练得到便于读者直接推理或继续微调。资源共约2000个文件以jpg图像、xml与txt双格式标注、py源码、yaml配置、pt权重为主另有ui界面文件、mp4演示视频与sh脚本压缩包约640MB目录按数据集、代码、权重分模块组织。配套PyQt界面支持图片、视频与摄像头三种检测模式可自由切换输入源方便快速验证效果。随包附赠5000余张行人车辆数据集标注同时提供txt与xml两种格式省去自行整理数据的成本。目前已有5802人学习下载适合课程设计、毕业项目或算法验证场景参考使用。1. YOLOv5车辆行人检测从5000张数据集到PyQt界面的完整落地路径路上跑的车、街上走的人这两类目标撑起了智能交通和安防监控里最刚需的检测场景。你手上如果有一个标题写着「YOLOv5车辆行人检测练好的车辆行人检测模型pyqt界面5000车辆行人检测数据集」的项目它本质上是一套从数据到模型再到可视化交互的闭环方案用5000张标注好的车辆行人图片训练YOLOv5导出权重再用PyQt搭一个能加载图片、视频、摄像头流并实时画框的桌面端界面。这套东西适合谁做毕业设计的学生、需要快速验证检测效果的产品原型开发者、以及想把检测能力塞进本地工具链的一线工程师。它不追求SOTA指标追求的是「跑得通、看得见、改得动」。下面我按数据准备、模型训练、界面集成、避坑排查、进阶技巧的顺序把这条链路拆开讲清楚每一步都落到能复现的命令和参数上。2. 5000张车辆行人数据集从原始图片到YOLOv5可训练格式2.1 数据集结构设计与标注规范YOLOv5只认一种目录结构这是硬性约定绕不过去。5000张图片按8:1:1切分训练集、验证集、测试集对应三个文件夹images/train、images/val、images/test标签文件放在平行的labels/train、labels/val、labels/test下文件名与图片一一对应扩展名从.jpg换成.txt。每行标签的格式是class_id x_center y_center width height五个值全部归一化到0到1之间。车辆行人检测通常只设两个类别0代表车辆1代表行人。标注工具用LabelImg或CVAT都行导出YOLO格式即可。这里有个容易翻车的点归一化坐标是相对于图片原始宽高的不是相对于网络输入尺寸。很多人用LabelImg标完直接拿去训练发现框全偏了就是因为中途改过图片尺寸但没重新计算坐标。我一般会在标注前统一把图片短边缩到640长边按比例缩放这样后续训练不用再做一次resize减少坐标换算的误差。2.2 用脚本做数据清洗与格式校验5000张图里难免混入损坏文件、重复图片、空标签。直接开训会报各种奇怪的错不如先跑一遍清洗脚本。下面这段代码做三件事检查图片能否正常解码、删除没有对应标签的图片、统计两个类别的框数量是否严重失衡。import os import cv2 import hashlib from collections import Counter img_dir datasets/images/train lbl_dir datasets/labels/train hash_set set() class_counter Counter() removed 0 for fname in os.listdir(img_dir): img_path os.path.join(img_dir, fname) lbl_path os.path.join(lbl_dir, os.path.splitext(fname)[0] .txt) # 1. 解码检查 img cv2.imread(img_path) if img is None: os.remove(img_path) removed 1 continue # 2. 重复图片检查基于文件内容哈希 with open(img_path, rb) as f: file_hash hashlib.md5(f.read()).hexdigest() if file_hash in hash_set: os.remove(img_path) removed 1 continue hash_set.add(file_hash) # 3. 空标签检查 if not os.path.exists(lbl_path) or os.path.getsize(lbl_path) 0: os.remove(img_path) removed 1 continue # 4. 类别统计 with open(lbl_path, r) as f: for line in f: cls_id int(line.strip().split()[0]) class_counter[cls_id] 1 print(f清理完成移除 {removed} 张问题图片) print(f类别分布: {dict(class_counter)})逻辑说明哈希去重用的是文件字节的MD5能抓住完全相同的副本但对轻微裁剪或压缩的近似图无能为力那种得用感知哈希属于进阶操作。类别统计输出后如果车辆和行人的框数量比例超过5:1训练时容易出现某一类召回率极低的情况需要在损失函数里加类别权重或者对少样本类做过采样。参数方面img_dir和lbl_dir要改成你自己的路径脚本默认原地删除文件建议先备份再跑。2.3 生成训练所需的data.yamlYOLOv5通过一个yaml文件知道去哪里找数据、有几个类别。在项目根目录建一个vehicle_person.yaml内容如下path: ./datasets train: images/train val: images/val test: images/test nc: 2 names: [vehicle, person]path是数据集根目录train/val/test是相对路径。nc是类别数必须和标签里的class_id最大值加一相等否则训练时索引越界直接崩。names的顺序要和标注时的类别编号严格对应标车辆时用了0、行人用了1这里就不能写反。这个文件后面训练命令里要引用路径别写错。3. YOLOv5训练自己的数据集环境配置、超参数与模型导出3.1 环境配置与依赖安装YOLOv5对PyTorch版本有要求太新或太旧都会出兼容问题。我一般用conda建一个干净环境Python选3.8或3.9PyTorch选1.12到2.0之间的版本CUDA版本跟着显卡驱动走。下面是一套经过验证的安装流程conda create -n yolov5_vehicle python3.9 -y conda activate yolov5_vehicle # 安装PyTorch以CUDA 11.8为例 pip install torch2.0.1 torchvision0.15.2 --index-url https://download.pytorch.org/whl/cu118 # 克隆YOLOv5源码并安装依赖 git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txt装完之后跑一句python -c import torch; print(torch.cuda.is_available())输出True才算GPU可用。如果输出False先检查显卡驱动和CUDA版本是否匹配别急着改代码。requirements.txt里包含numpy、opencv-python、matplotlib这些版本冲突时优先保证torch和torchvision的匹配其他包可以适当放宽。3.2 训练命令与关键超参数设置YOLOv5的训练入口是train.py最简命令如下python train.py \ --img 640 \ --batch 16 \ --epochs 100 \ --data vehicle_person.yaml \ --weights yolov5s.pt \ --project runs/train \ --name vehicle_person_v1逐项说明--img 640是网络输入尺寸车辆行人检测里640是精度和速度的平衡点显存够可以上到1280但训练时间翻倍不止。--batch 16是批大小8G显存跑yolov5s用16比较稳爆显存就降到8。--epochs 100对5000张图来说通常够收敛看验证集mAP曲线如果80轮后还在涨就加到150。--weights yolov5s.pt是预训练权重从COCO迁移过来能明显加快收敛别从零训。--project和--name决定输出目录权重、日志、混淆矩阵都存那里。训练过程中重点盯三个指标box_loss、obj_loss、cls_loss。box_loss下降说明框回归在收敛obj_loss下降说明目标置信度在学cls_loss下降说明分类在改善。如果obj_loss震荡不降大概率是学习率太大把--lr0从默认0.01降到0.001试试。如果box_loss降但mAP不涨检查标签坐标有没有归一化错误。3.3 模型导出与推理验证训练结束后最优权重在runs/train/vehicle_person_v1/weights/best.pt。先别急着上界面用命令行验证一下python detect.py \ --weights runs/train/vehicle_person_v1/weights/best.pt \ --source datasets/images/test \ --img 640 \ --conf 0.25 \ --iou 0.45 \ --save-txt--conf 0.25是置信度阈值低于这个值的框直接丢弃。--iou 0.45是NMS的IoU阈值重叠度超过这个的框会被合并。这两个参数是后处理的核心调高conf减少误检但可能漏检调低conf增加召回但误报变多。车辆行人场景里行人目标小且密集conf建议设0.2到0.3之间iou设0.4到0.5之间。--save-txt会把检测结果存成txt方便和标注对比算指标。导出ONNX或TorchScript用于部署python export.py \ --weights runs/train/vehicle_person_v1/weights/best.pt \ --include onnx \ --img 640 \ --batch 1导出的onnx文件可以脱离PyTorch环境运行适合集成到C或C#的桌面程序里。注意--batch 1导出的模型只支持单张推理如果要批量处理得设成对应batch size。4. PyQt界面集成加载模型、实时检测与结果展示4.1 PyQt5界面框架与YOLOv5推理线程PyQt界面最怕的是推理卡住主线程导致窗口无响应。正确做法是把检测逻辑放到QThread里主线程只管刷新界面。下面是一个最小可用的界面骨架包含图片选择、视频播放、检测结果显示三个区域。import sys import cv2 import torch from PyQt5.QtWidgets import (QApplication, QMainWindow, QLabel, QPushButton, QVBoxLayout, QHBoxLayout, QWidget, QFileDialog) from PyQt5.QtGui import QImage, QPixmap from PyQt5.QtCore import QThread, pyqtSignal, Qt class DetectThread(QThread): frame_signal pyqtSignal(object) def __init__(self, model, source): super().__init__() self.model model 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 # YOLOv5推理 results self.model(frame, size640) annotated results.render()[0] self.frame_signal.emit(annotated) cap.release() def stop(self): self.running False self.wait() class MainWindow(QMainWindow): def __init__(self): super().__init__() self.model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/vehicle_person_v1/weights/best.pt) self.model.conf 0.25 self.model.iou 0.45 self.init_ui() def init_ui(self): self.setWindowTitle(车辆行人检测系统) self.image_label QLabel(等待输入...) self.image_label.setAlignment(Qt.AlignCenter) self.image_label.setMinimumSize(800, 600) btn_image QPushButton(选择图片) btn_video QPushButton(选择视频) btn_image.clicked.connect(self.load_image) btn_video.clicked.connect(self.load_video) btn_layout QHBoxLayout() btn_layout.addWidget(btn_image) btn_layout.addWidget(btn_video) main_layout QVBoxLayout() main_layout.addWidget(self.image_label) main_layout.addLayout(btn_layout) container QWidget() container.setLayout(main_layout) self.setCentralWidget(container) def load_image(self): path, _ QFileDialog.getOpenFileName(self, 选择图片, , Images (*.jpg *.png)) if not path: return frame cv2.imread(path) results self.model(frame, size640) annotated results.render()[0] self.show_frame(annotated) def load_video(self): path, _ QFileDialog.getOpenFileName(self, 选择视频, , Videos (*.mp4 *.avi)) if not path: return self.thread DetectThread(self.model, path) self.thread.frame_signal.connect(self.show_frame) self.thread.start() def show_frame(self, frame): rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch rgb.shape qimg QImage(rgb.data, w, h, ch * w, QImage.Format_RGB888) self.image_label.setPixmap(QPixmap.fromImage(qimg).scaled( self.image_label.size(), Qt.KeepAspectRatio)) if __name__ __main__: app QApplication(sys.argv) window MainWindow() window.show() sys.exit(app.exec_())逻辑说明DetectThread继承QThread在run里循环读帧、推理、发信号。frame_signal把带框的图像传给主线程的show_frame做显示。torch.hub.load直接加载本地权重conf和iou通过模型属性设置和命令行参数效果一致。show_frame里做了BGR到RGB的转换因为OpenCV读进来是BGRQt显示要RGB这个转换漏了会导致颜色发蓝。参数方面size640要和训练时的--img一致否则精度掉得厉害。self.model.conf和self.model.iou可以在界面上加滑块动态调但每次改完要重新推理才生效。视频线程里没有做帧率控制如果推理速度跟不上视频帧率画面会越来越延迟解决办法是跳帧或者用队列限制缓冲。4.2 界面上的参数调节与结果导出实际用的时候不同场景对conf和iou的偏好不一样。白天光照好conf可以设0.3傍晚或雨天目标对比度低conf得降到0.15才不漏。在界面上加两个QSlider范围分别设0.05到0.95和0.1到0.9实时更新模型的conf和iou属性。注意滑块回调里不要直接调推理只改属性值下一帧自然生效。结果导出加一个按钮把当前帧的检测框坐标和类别存成CSV。代码很简单在show_frame里把results.xyxy[0]取出来写文件就行。xyxy格式是x1, y1, x2, y2, conf, cls转成归一化坐标除以宽高即可。这个功能在需要做二次分析时很实用比如统计某段时间内车辆和行人的数量变化。4.3 打包成exe的注意事项用PyInstaller打包时YOLOv5的权重文件和模型定义文件要一起打进去。常见做法是把best.pt和yolov5目录下的models、utils文件夹加到--add-data里。打包命令示例pyinstaller --onefile --windowed \ --add-data runs/train/vehicle_person_v1/weights/best.pt;weights \ --add-data yolov5/models;models \ --add-data yolov5/utils;utils \ main.py打包后exe体积会到几百MB因为PyTorch本身很大。如果嫌大可以导出ONNX然后用onnxruntime推理体积能压到几十MB但需要改推理代码。--windowed去掉控制台窗口调试阶段建议不加留着看报错。5. 车辆行人检测的避坑与排查血泪经验五条5.1 训练loss正常但mAP为0现象训练日志里box_loss、obj_loss都在降但验证集mAP一直是0或者极低。原因标签文件里的class_id超出了nc定义的范围或者坐标没有归一化。YOLOv5在计算mAP时会过滤掉无效标签导致评估时没有正样本。解决用脚本遍历所有标签文件检查class_id最大值是否小于nc检查坐标是否都在0到1之间。发现越界就修正标注或调整nc。5.2 推理时框位置整体偏移现象检测出来的框位置和实际目标对不上整体往一个方向偏。原因训练时用了--rect矩形推理但推理时用了默认的方形letterbox两者的padding方式不一致。解决训练和推理保持相同的预处理方式要么都加--rect要么都不加。另外检查推理时的size是否和训练--img一致不一致也会导致缩放比例错误。5.3 PyQt界面卡死无响应现象点击开始检测后窗口变灰无法拖动或关闭。原因推理代码跑在主线程里阻塞了Qt的事件循环。解决把检测逻辑移到QThread子类里通过信号槽机制更新界面。注意子线程里不能直接操作UI组件所有UI更新必须通过信号发回主线程。另外在窗口关闭事件里要调用线程的stop方法并wait否则线程没退出会导致进程残留。5.4 视频检测延迟越来越大现象视频播放几秒后画面明显滞后于音频或实时时间。原因推理速度低于视频帧率帧在缓冲区里堆积。解决在读取循环里加跳帧逻辑比如每读两帧只推理一帧或者用cap.grab()快速跳过多余帧。更彻底的做法是用生产者消费者队列队列满时丢弃旧帧。参数上可以降低输入尺寸到416或320用精度换速度。5.5 导出ONNX后推理结果和PyTorch不一致现象同一个输入PyTorch和ONNX Runtime的输出框位置有细微差异。原因ONNX导出时默认做了常量折叠和算子融合某些版本的torch和onnxruntime对NMS的实现有差异。解决导出时加--dynamic支持动态尺寸推理时确保预处理和后处理与PyTorch版本完全一致。如果差异在几个像素以内属于正常数值误差如果框完全不对检查导出时的--img和推理时的输入尺寸是否匹配。6. 进阶技巧用TensorRT加速和半精度推理把帧率翻倍训练和界面都跑通之后下一步就是压榨速度。YOLOv5在PyTorch下用yolov5s跑640输入RTX 3060大概能到60到80 FPS但换成TensorRT加FP16同样硬件能到150 FPS以上。做法分三步先导出ONNX再用TensorRT的trtexec工具转成engine文件最后在Python里用pycuda或tensorrt加载推理。导出ONNX时加--dynamic和--simplifypython export.py \ --weights best.pt \ --include onnx \ --img 640 640 \ --batch 1 \ --dynamic \ --simplify转TensorRT enginetrtexec --onnxbest.onnx \ --saveEnginebest_fp16.engine \ --fp16 \ --workspace4096--fp16开启半精度速度提升明显精度损失通常在1%以内。--workspace4096是显存工作空间单位MB太小会转失败。转完之后在Python里加载engine预处理和后处理要自己写NMS可以用TensorRT自带的插件或者用CUDA核函数实现。如果不想折腾TensorRT还有一个更简单的加速手段在PyTorch推理时加model.half()和model.to(cuda)把模型和输入都转成FP16。这个改动只需要两行代码速度能提升30%到50%精度损失比TensorRT还小。我一般先在PyTorch里试半精度不够再上TensorRT。验证加速效果时别只看单帧耗时要跑100帧取平均并且用torch.cuda.synchronize()确保GPU任务真正完成。很多人测出来速度飞快其实是异步执行没同步实际帧率根本没变。这个坑我踩过不止一次后来养成习惯测速必加同步。最后说个习惯每次改完模型或界面先在小批量测试集上跑一遍确认mAP和之前比没有明显下降再上完整视频。车辆行人检测里行人的召回率比车辆更值得关注因为漏检一个行人的代价远大于漏检一辆车。调参时优先保行人召回conf可以适当降低iou适当调高来抑制重叠框。希望帮到你。本文还有配套的精品资源点击获取
返回列表