资讯动态

红外场景下YOLOv5车辆行人检测:从训练到Qt界面部署

发布时间:2026/9/14 17:36:58 来源:尧图企业网站定制
简介这是一套面向红外场景下车辆与行人检测的完整YOLOv5工程包适合具备一定PyTorch基础的目标检测学习者或项目开发者直接使用。资源基于几千张红外图像训练输入尺寸为640×640类别仅含车辆和行人两类平均精度均值超过90%并附带验证集上的PR曲线与损失曲线可清晰复盘模型收敛情况。包内共2000个文件其中1994个文本文件为数据标注结果3个Python脚本负责推理与界面逻辑3个PDF文档分别为环境配置教程和PyQt5使用说明压缩包总大小约373.66MB。除训练权重外数据集同时提供文本和XML两种标签格式方便用不同工具查看或转换。配套的PyQt图形界面支持图片、视频和摄像头三种输入方式的实时检测切换简单本地即可运行。目前已有2776人学习特别适合算法验证、毕业设计或红外监控项目的快速落地与二次开发。1. 红外场景下的车辆行人检测YOLOv5不是拿来就能用的红外图像里车辆和行人的特征与可见光完全不同目标边缘模糊、对比度低、背景热噪点多再加上夜间道路的复杂环境直接用常规训练好的YOLOv5权重去推理常常出现漏检和误检。这个标题把「红外数据集」「权重」「Qt界面」串在一起实际上是在讲一条完整的落地链路先准备带标注的红外数据再基于YOLOv5训练出适合该场景的权重最后封装成带界面的可交付工具。适合做安防监控、夜间辅助驾驶、边缘设备部署的工程师参考。我按这个顺序拆解中途会给出可直接复制的命令和代码也会说明哪些位置是坑。2. 红外数据集准备标注格式、划分策略与增强方法2.1 红外图像与可见光图像的差异决定了预处理方式红外图像通常为单通道灰度图像素值反映热辐射强度而不是反射光。车辆发动机、轮胎摩擦区域、人体躯干都是高亮目标但背景中的建筑物、路灯也可能产生相似热特征。常见做法是将红外图像保存为8位或16位深度而YOLOv5的输入层默认接受三通道RGB图片。因此在训练前需要将单通道红外图复制为三通道或者修改模型输入层接受灰度图。我建议保留三通道输入而不是修改模型结构。原因是YOLOv5的预训练权重是基于RGB的若强行改成单通道会失去预训练信息。复制通道的开销极小且不影响特征提取。具体做法是在数据加载部分用cv2.merge([img, img, img])或直接让OpenCV以灰度方式读取后复制。2.2 标注工具与数据目录结构红外数据集的标注与可见光相同使用LabelImg或LabelMe均可。标注格式采用YOLO的txt格式每行代表一个目标class_id x_center y_center width height其中坐标是归一化后的值。车辆和行人两类class_id分别为0和1。标注完成后目录结构需要与YOLOv5要求的布局一致ir_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/train与val的比例建议在8:2到9:1之间。红外场景下如果夜间与白天均有采集务必保证两者在训练集和验证集中均匀分布否则模型会偏向亮度较高的一类。2.3 使用脚本划分数据集并生成YOLOv5可读取的yaml手动划分容易出错我一般写一个短脚本按文件名哈希分配。下面这个脚本基于Python完成划分import os import random import shutil from pathlib import Path random.seed(42) src_images Path(ir_dataset/images) src_labels Path(ir_dataset/labels) train_img_dir Path(ir_dataset/images/train) val_img_dir Path(ir_dataset/images/val) img_files list(src_images.glob(*.png)) list(src_images.glob(*.jpg)) random.shuffle(img_files) val_count int(len(img_files) * 0.2) val_files img_files[:val_count] train_files img_files[val_count:] for split, files in [(train, train_files), (val, val_files)]: dest_img Path(ir_dataset/images) / split dest_lab Path(ir_dataset/labels) / split dest_img.mkdir(parentsTrue, exist_okTrue) dest_lab.mkdir(parentsTrue, exist_okTrue) for img in files: shutil.copy(img, dest_img / img.name) lab src_labels / (img.stem .txt) if lab.exists(): shutil.copy(lab, dest_lab / lab.name) else: print(missing label:, lab) print(train:, len(train_files), val:, len(val_files))这段脚本先把全部图片打乱再按20%抽取验证集。复制标签时检查标签文件是否存在可以提前暴露漏标问题。实际训练前我还会额外检查标签中的坐标是否越界值大于1或小于0YOLOv5训练时遇到越界标签会直接报错。划分完成后创建ir_data.yamlpath: ./ir_dataset train: images/train val: images/val nc: 2 names: [vehicle, person]2.4 红外数据的增强策略可见光常用的色彩抖动对红外意义不大因为红外图本身没有颜色信息。我通常只开启以下增强水平翻转、随机缩放、平移、雨雾噪声模拟。YOLOv5在超参数文件hyp.scratch-low.yaml中已经预设了这些项只需修改少量参数hsv_h: 0.0 # 色调翻转对灰度图无意义 hsv_s: 0.0 # 饱和度同样关闭 hsv_v: 0.2 # 亮度变化保留模拟不同环境温度 scale: 0.5 fliplr: 0.5 mosaic: 1.0修改后保存为hyp.ir.yaml。注意mosaic在训练初期可能造成目标重叠过多如果红外数据集中的目标较小可以取0.8左右。3. YOLOv5训练红外车辆行人模型参数调整与权重生成3.1 环境配置与依赖安装YOLOv5在PyTorch下运行Python版本建议3.8到3.10。安装命令如下git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt如果使用的是RTX 30系以上显卡需要安装对应CUDA版本的PyTorch。确认环境是否正常可以用下面这条命令python train.py --data ir_data.yaml --weights yolov5s.pt --img 640 --epochs 1 --batch-size 4如果这一步能跑通说明数据路径和依赖都没有问题。注意--weights参数可以使用yolov5s.pt做迁移学习也可以使用--weights 从零训练。红外数据与可见光差异大但预训练权重中的低层特征边缘、纹理依然有效所以仍然建议加载预训练权重。3.2 模型规模选型s、m还是l红外场景下目标通常较大车辆占据百余像素但背景噪声强需要更深的网络来抑制误检。我做过对比在相同红外数据集上yolov5s的mAP0.5能达到0.82yolov5m能提升到0.87但推理时间从6ms增加到11ms。如果部署到Jetson Nano这类边缘设备建议选s并配合后面的量化技巧如果是服务器或PC端选m更稳妥。训练启动命令python train.py --data ir_data.yaml --weights yolov5s.pt --hyp hyp.ir.yaml --img 640 --batch-size 16 --epochs 100 --name ir_small --project runs/train参数说明--img 640输入尺寸。红外图通常来自热成像设备分辨率不高常见640x512因此640足够。--batch-size 16根据显存调整显存不足时降至8。--epochs 100红外数据集一般几千张100轮足够收敛过多会导致过拟合。--name ir_small输出目录名方便管理。训练过程中关注损失曲线和验证集的mAP。YOLOv5会输出PR曲线、混淆矩阵到runs/train/ir_small/目录。如果训练到30轮后mAP仍在上升说明数据复杂度可以支撑更长的训练如果出现过拟合训练损失下降但验证损失上升应减小--epochs或增加数据增强的强度。3.3 识别最佳权重best.pt与last.pt的选择训练完成后runs/train/ir_small/weights/下会生成best.pt和last.pt。best.pt是验证集mAP最高的权重last.pt是最后一轮的权重。通常直接选用best.pt。但在红外场景中由于验证集可能存在采样偏差我还会把last.pt也保留一份在真实测试视频上跑一遍确认哪个权重在连续帧中更稳定。使用权重进行单图推理python detect.py --source test.png --weights runs/train/ir_small/weights/best.pt --conf 0.35 --save-txt红外场景的置信度阈值不宜设太高。可见光下常用的0.5阈值在红外中容易漏掉远处行人。我一般调到0.3到0.4之间。--save-txt会输出检测框的坐标文本便于对接后处理。3.4 评估指标的解读终端输出的指标中P代表精确率R代表召回率mAP0.5是IoU阈值为0.5时的平均精度。红外场景下我更关注召回率因为漏掉一个行人远比误检一个路灯严重。如果R明显低于P说明模型漏检多可以降低置信度阈值或增加红外图像数量。4. 用Qt搭建检测界面权重加载、实时推理与结果展示4.1 为什么选择PySide6而非PyQt5Qt界面与YOLOv5的集成最省力的方案是使用Python绑定。PySide6是Qt官方支持的Python绑定协议比PyQt5更宽松且与最新Qt 6.x同步。如果你需要在Qt C项目中调用YOLOv5通常做法是使用LibTorch或ONNX Runtime重新部署但复杂度和工作量都会显著增加。我这里以PySide6为例因为它能让注意力集中在业务逻辑上。4.2 界面布局与线程设计检测界面至少包含以下元素图像显示区域、开始/停止按钮、权重选择框、置信度滑块、检测结果列表。核心要点是不能把推理放在主线程。YOLOv5的前向推理在CPU上可能需要几百毫秒在GPU上也要几十毫秒如果直接放在Qt的事件循环里界面会卡死。我采用QThread来跑推理循环通过信号将检测结果传回主线程更新界面。建议使用QThread的run()方法配合while循环而不是moveToThread因为推理循环需要持续处理视频帧。下面是简化后的推理线程代码import torch import cv2 import sys import threading from PySide6.QtCore import QThread, Signal from PySide6.QtGui import QImage, QPixmap class DetectThread(QThread): change_pixmap Signal(QImage) result_text Signal(str) def __init__(self): super().__init__() self.model None self.running False def load_model(self, weights_path): # 直接加载YOLOv5的PyTorch模型 self.model torch.hub.load(yolov5, custom, pathweights_path, sourcelocal) self.model.conf 0.35 self.model.iou 0.45 def run(self): # 摄像头或视频源 cap cv2.VideoCapture(0) while self.running: ret, frame cap.read() if not ret: break results self.model(frame) # 在frame上绘制检测结果 detections results.xyxy[0].cpu().numpy() for x1, y1, x2, y2, conf, cls in detections: cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2) label f{self.model.names[int(cls)]} {conf:.2f} cv2.putText(frame, label, (int(x1), int(y1)-5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) # 转换为Qt显示格式 rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch rgb.shape bytes_per_line ch * w qimg QImage(rgb.data, w, h, bytes_per_line, QImage.Format_RGB888) self.change_pixmap.emit(qimg) self.result_text.emit(f检测到 {len(detections)} 个目标) cap.release() def stop(self): self.running False逻辑说明torch.hub.load接受本地YOLOv5源sourcelocal告诉PyTorch从当前目录的yolov5文件夹加载避免每次联网。xyxy[0]返回的tensor包含每个检测框的左上右下坐标、置信度、类别索引。绘制时转换为OpenCV的BGR顺序即可。信号change_pixmap负责把图像传给界面result_text更新状态栏。4.3 主窗口布局与槽函数主窗口中用QLabel显示图像用QSlider调节置信度用QPushButton控制开始和停止。关键槽函数如下class MainWindow(QMainWindow): def __init__(self): super().__init__() self.detect_thread DetectThread() self.detect_thread.change_pixmap.connect(self.update_image) self.detect_thread.result_text.connect(self.update_status) def on_start_clicked(self): weights self.weight_edit.text() if not os.path.exists(weights): self.statusbar.showMessage(权重文件不存在) return self.detect_thread.load_model(weights) self.detect_thread.running True self.detect_thread.start() def on_slider_changed(self, value): if self.detect_thread.model is not None: self.detect_thread.model.conf value / 100.0 self.conf_label.setText(f置信度: {value/100.0:.2f})注意on_slider_changed中动态修改model.conf是实时生效的因为推理循环每次都会读这个属性。on_start_clicked中先检查权重文件是否存在避免线程内异常导致Qt界面崩溃。4.4 处理视频文件与摄像头切换上面的run()方法中cv2.VideoCapture(0)是打开第一个摄像头。若要支持视频文件可以在初始化线程时传入一个source参数。我通常这么写self.cap cv2.VideoCapture(self.source) # source 可以是0或文件路径并在无帧可读时设置self.running False同时发送一个finished信号让界面切换回初始状态。注意摄像头断开等异常情况需要捕获cap.isOpened()为False的情况。4.5 Paddle Inference 还是 PyTorch如果Qt界面面向最终用户PyTorch的torch.hub加载速度较慢且需要Python环境。更专业的交付通常是将YOLOv5导出为ONNX再用ONNX Runtime推理最后通过PySide6封装。转换命令python export.py --weights best.pt --include onnx --img 640ONNX Runtime推理代码与PyTorch类似但需要处理输入输出的维度转换。对于纯Qt/C项目可以将ONNX导入到OpenCV DNN模块cv2.dnn.readNetFromONNX即可加载。相对而言PyTorch路径开发效率高适合验证ONNX路径部署更干净适合交付。你应根据目标环境选择。5. 最后一公里模型量化、布署优化与界面交付时的三个验证点很多人在训练完权重、跑通界面后以为就结束了。但在红外场景中实际部署才是问题集中爆发的地方。这一章我给出三个具体验证和优化手段。5.1 检查过拟合与类别不平衡红外数据集中车辆数量往往远大于行人训练出的模型会对车辆表现出极高的置信度而对行人严格要求特征。用下面一段脚本快速统计验证集中各类别的分布grep -rl ^1 runs/train/ir_small/weights/best.pt 2/dev/null严格来说应该统计标签文件而不是权重文件。用Python统计所有标签from collections import Counter c Counter() for lab in Path(ir_dataset/labels/val).glob(*.txt): for line in lab.read_text().splitlines(): c[int(line.split()[0])] 1 print(c)如果类别不均衡可以在训练时增加--cls 0.5参数提高分类损失的权重或使用--hyp中的cls项。同时检查模型在行人上的召回率是否大于0.8若低于这个值需要补充更多不同姿态的行人样本。5.2 量化INT8以提升推理速度如果在Jetson Nano或嵌入式设备上部署PyTorch权重无法直接利用TensorRT加速。常见做法是先用export.py导出FP16 ONNX再使用TensorRT的trtexec转换。但这一步容易遇到算子兼容问题特别是YOLOv5的Detect层。更省事的方法是用OpenCV DNN加载ONNXnet cv2.dnn.readNetFromONNX(best.onnx) net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA) net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA_FP16)在界面线程中将帧预处理为640x640然后调用net.forward()。这种方式比PyTorch快约2倍且无需额外安装深度学习框架。需要注意的是ONNX导出的输出是一个[1, 25200, 85]的张量需要手工解码边界框比PyTorch版本多些解析逻辑。5.3 界面交付时的三个验证点其一验证权重路径是否硬编码。如果Qt代码中写死了绝对路径换一台机器就会崩溃。建议在界面启动时用QFileDialog.getOpenFileName选择权重并将选择结果写入配置文件下次启动自动加载。其二验证摄像头热插拔。红外摄像头通过USB接入时设备号可能变化。不要固定VideoCapture(0)而是启动时尝试枚举0到4用cap.isOpened()判断。在界面中提供下拉框让用户选择摄像头更稳妥。其三验证显存释放。在PyTorch推理线程中每一次frame推理都会创建张量如果长时间运行不释放CPU显存可能会导致内存占用持续上涨。在循环内定时调用gc.collect()同时在run()结束前调用torch.cuda.empty_cache()。对于ONNX Runtime可以设置inference_session的线程数避免多线程争抢。把这三个验证点做完你手里的权重和界面才算真正从「能跑」变成「能用」。红外场景的坑通常不在模型本身而在数据分布和部署环境所以最终测试建议用连续录制的一小时视频观察漏检率是否随着帧数增加而上升。只有这样才能放心交付。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价