YOLOv8行人检测实战:从数据集标注到模型部署的完整链路
简介本资源为基于YOLOv8的行人检测完整项目包面向计算机、人工智能、通信工程、自动化等专业的在校学生、教师及企业员工可用于课程设计、毕业设计、大作业或项目初期立项演示也适合具备一定基础的学习者进阶实践。压缩包共6个文件约15.89MB包含3个pt权重文件、2个py脚本和1个txt说明文档分别对应模型权重、训练与视频检测代码以及数据集说明下载后可从README.dataset.txt入手了解整体结构。项目代码均经过实际运行验证并附带核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果和标签分布图便于直观评估模型表现。目前已有36人学习读者可在此基础上修改代码以扩展功能或直接用于答辩与课设场景快速获得可复现的行人检测方案。1. 拆开一个行人检测压缩包YOLOv8 项目从跑通到落地的真实路径拿到一个名为「基于YOLOv8的行人检测项目.rar」的压缩包多数人的第一反应是解压、找train.py、装依赖、跑起来看效果。但真正做过几个落地项目的人会先问三个问题这个项目用的是官方 COCO 预训练权重还是自建行人数据集推理是 PyTorch 原生还是导出成 ONNX 再上板子检测头有没有针对小目标行人做改动行人检测和通用目标检测最大的区别在于行人属于典型的「高长宽比 密集遮挡 尺度跨度大」目标COCO 上 mAP 很高的模型直接搬到路口监控场景漏检率可能翻倍。这个项目标题背后实际要解决的是从数据集组织、YOLOv8 训练调参、到模型导出部署的完整链路。适合刚接触 YOLOv8 想拿行人检测练手的同学也适合手里有 RK3588、Orin 这类板子、想把模型真正跑起来的工程师。下面按我实际做项目的顺序把这条路径拆开讲。2. 行人数据集怎么整从标注格式到 YOLOv8 能吃的目录结构2.1 为什么行人数据集不能直接拿 COCO 凑合COCO 里 person 类大概有 6 万多张图、25 万个实例听起来够用但它的行人分布极度不均衡大量是远景小人、运动场景、室内站立的人缺少监控视角下的近景、遮挡、夜间行人。我试过直接用 COCO 预训练权重在路口视频上推理白天近距离行人召回还行一到傍晚逆光或者人群密集处漏检肉眼可见。所以如果项目目标是特定场景自建数据集是绕不开的。自建数据集的第一步是标注。常见做法是用 labelme 标多边形或矩形框然后转成 YOLO 格式。labelme 默认输出 JSON每个 JSON 对应一张图里面shapes数组存了每个框的label和points。转 YOLO 格式的核心是把绝对像素坐标转成归一化的中心点加宽高。import json import os from PIL import Image def labelme_to_yolo(json_dir, output_dir, class_map): json_dir: labelme 标注文件目录 output_dir: 输出 YOLO txt 的目录 class_map: {person: 0} 类别名到 id 的映射 os.makedirs(output_dir, exist_okTrue) for fname in os.listdir(json_dir): if not fname.endswith(.json): continue with open(os.path.join(json_dir, fname), r, encodingutf-8) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] lines [] for shape in data[shapes]: label shape[label] if label not in class_map: continue points shape[points] xs [p[0] for p in points] ys [p[1] for p in points] xmin, xmax min(xs), max(xs) ymin, ymax min(ys), max(ys) # 归一化中心点和宽高 cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h # 过滤掉宽高为 0 的异常框 if w 0 or h 0: continue lines.append(f{class_map[label]} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) txt_name os.path.splitext(fname)[0] .txt with open(os.path.join(output_dir, txt_name), w) as f: f.write(\n.join(lines)) labelme_to_yolo(./labels_json, ./labels_yolo, {person: 0})这段脚本里有两个容易翻车的点。一是points如果是多边形标注直接取 min/max 会得到一个外接矩形对于行人这种近似矩形的目标够用但如果标的是不规则形状框会偏大。二是归一化前一定要确认imageWidth和imageHeight是原图尺寸labelme 有时会因为图片旋转信息导致宽高对调。转换完建议随机抽 10 张用可视化脚本画框检查一遍别等到训练 loss 不降才回头查。2.2 YOLOv8 要求的目录结构和 data.yamlYOLOv8 对目录结构有固定要求常见做法是dataset/ images/ train/ val/ labels/ train/ val/图片和标签文件名必须一一对应只是扩展名不同。然后写一个data.yamlpath: /home/user/dataset train: images/train val: images/val nc: 1 names: [person]nc是类别数行人检测通常就是 1。names的顺序必须和标注时 class_map 的 id 一致否则训练出来的模型会把行人预测成别的类。我见过有人把names写成[pedestrian]但标注 id 是 0 对应 person结果推理时类别名对不上排查了半天。2.3 数据增强参数怎么设才不帮倒忙YOLOv8 训练时自带增强关键参数在data.yaml同级通过命令行或配置文件传入。行人检测里我一般会调这几个参数默认值行人场景建议原因mosaic1.00.5~1.0拼接增强对小目标友好但行人长宽比大过度拼接会引入畸形框degrees0.00.0行人通常垂直旋转增强反而制造不真实样本translate0.10.1~0.2位置偏移有助于遮挡鲁棒性scale0.50.3~0.5尺度变化对远近行人都有用fliplr0.50.5左右翻转安全行人对称hsv_h0.0150.015色调扰动别太大衣服颜色是行人特征之一注意mosaic设太高时四张图拼一起行人可能被切成两半标签框也跟着变形。如果发现训练前期 loss 震荡厉害先把 mosaic 降到 0.5 试试。3. 训练与调参让 YOLOv8 在行人检测上真正收敛3.1 环境搭建与预训练权重选择环境这块Ubuntu 20.04 上 CPU 版本也能跑通但训练基本没法看推理一张图几秒。有 GTX 1660 Ti 这类 6G 显存的卡用yolov8s或yolov8n比较稳yolov8m以上容易 OOM。安装就是标准的conda create -n yolov8 python3.10 -y conda activate yolov8 pip install ultralytics预训练权重建议用yolov8s.pt官方在 COCO 上训过person 类本身就有迁移到行人检测收敛快。如果场景特别窄比如只有俯视行人yolov8n也够速度还快。下载权重直接from ultralytics import YOLO; model YOLO(yolov8s.pt)会自动拉不用手动找。3.2 训练命令与关键参数含义yolo detect train \ modelyolov8s.pt \ data./data.yaml \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ patience20 \ device0 \ project./runs \ namepedestrian_v1逐个说imgsz640是输入分辨率行人检测如果目标普遍偏小可以提到 960 或 1280但显存和速度代价大。batch16在 6G 卡上跑 640 分辨率差不多是上限OOM 就降到 8。lr0初始学习率默认 0.01如果 loss 一开始就炸降到 0.001。lrf是最终学习率因子余弦退火到lr0 * lrf。patience20表示 20 轮没提升就早停省时间。device0指定第一块 GPUCPU 就写cpu。训练过程中想看损失曲线YOLOv8 会自动在runs/detect/pedestrian_v1/下生成results.csv用 pandas 画一下import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/detect/pedestrian_v1/results.csv) df.columns df.columns.str.strip() plt.plot(df[epoch], df[train/box_loss], labelbox_loss) plt.plot(df[epoch], df[val/box_loss], labelval_box_loss) plt.xlabel(epoch) plt.ylabel(loss) plt.legend() plt.savefig(loss_curve.png)重点看val/box_loss有没有持续下降如果训练 loss 降但验证 loss 抬头就是过拟合加数据或加增强。metrics/mAP50是主要指标行人检测一般能到 0.85 以上算可用。3.3 推理与导出从 PyTorch 到 ONNX 再到板端训练完先本地验证from ultralytics import YOLO model YOLO(runs/detect/pedestrian_v1/weights/best.pt) results model(test.jpg, conf0.25, iou0.45) results[0].save(output.jpg)conf0.25是置信度阈值行人检测如果漏检多就降到 0.15误检多就提到 0.4。iou0.45是 NMS 的 IoU 阈值人群密集时调低到 0.3 能减少框重叠。导出 ONNXyolo export modelbest.pt formatonnx imgsz640 opset12 simplifyTrueopset12兼容性好simplifyTrue会做图优化。导出后可以用onnxruntime验证输出是否和 PyTorch 一致。如果要上 RK3588 或 Orin还得再转 RKNN 或 TensorRT那是另一套工具链核心是确保导出时的输入尺寸和归一化参数与训练一致。4. 避坑与排查行人检测项目里最容易翻车的 5 个地方4.1 现象训练 loss 正常下降但 mAP 一直卡在 0.3 以下原因通常是标注格式有问题。YOLO 格式要求坐标归一化到 0~1如果转换脚本里忘了除宽高或者宽高写反模型学到的就是错框。另一个可能是data.yaml里names和标注 id 对不上模型把所有类都当背景学。解决随机抽 20 张训练图用cv2.rectangle把标签画出来叠加在原图上肉眼确认框位置和类别。再检查data.yaml的nc是否等于实际类别数。4.2 现象推理时同一行人出现多个重叠框原因NMS 的 IoU 阈值设太高或者模型对遮挡行人输出了多个高置信框。行人长宽比大两个框稍微错位 IoU 就低于阈值NMS 去不掉。解决把iou从 0.45 降到 0.3~0.35同时开agnostic_nmsTrue如果只有一类其实无所谓。如果还不行说明模型本身没学好遮挡样本回去补数据。4.3 现象导出 ONNX 后推理结果和 PyTorch 不一致原因导出时imgsz和推理时输入尺寸不一致或者预处理归一化方式不同。YOLOv8 默认输入是 RGB、0~1 归一化如果 ONNX 推理时用了 BGR 或 0~255结果全乱。解决导出和推理用同一个imgsz预处理严格按letterbox加/255.0。用onnxruntime跑一张图和 PyTorch 输出逐元素对比误差应在 1e-3 以内。4.4 现象板端推理速度远低于预期原因RK3588 或 Orin 上如果没用量化或没走 NPU纯 CPU 跑 ONNX 当然慢。另一个常见问题是模型输入分辨率设太高640 提到 1280 计算量翻四倍。解决确认模型转成了 RKNN 或 TensorRT 并启用了 INT8 量化。行人检测 INT8 量化后 mAP 掉 1~2 个点通常可接受速度能翻倍。输入分辨率根据实际目标大小选不是越高越好。4.5 现象夜间或逆光场景漏检严重原因训练集里夜间样本太少模型没学到低照度下的行人特征。或者摄像头本身动态范围不够行人变成剪影。解决补夜间数据哪怕只有几百张也能明显改善。增强里加hsv_v扰动模拟亮度变化。如果硬件允许换宽动态摄像头比调模型更直接。5. 把行人检测推到可用几个我反复验证过的技巧训练完一个能跑的模型只是起点真正上线还要过几关。第一个技巧是用验证集做阈值扫描不要拍脑袋定conf。写个循环把conf从 0.05 到 0.9 步进 0.05分别算召回和误检率画成曲线找拐点。行人检测里我通常选召回优先的点因为漏检一个行人的代价远大于多检一个。from ultralytics import YOLO import numpy as np model YOLO(best.pt) confs np.arange(0.05, 0.95, 0.05) for c in confs: metrics model.val(datadata.yaml, conffloat(c), iou0.45) print(fconf{c:.2f} mAP50{metrics.box.map50:.4f} fprecision{metrics.box.mp:.4f} recall{metrics.box.mr:.4f})第二个技巧是切片推理处理大图。监控画面 1920x1080 直接缩到 640远处行人只剩几个像素。常见做法是把大图切成有重叠的小块每块单独推理再合并框。重叠区域设 20% 能避免边缘目标被切断。这个思路在 SAHI 这类工具里有现成实现但自己写也不复杂核心就是滑窗加 NMS 合并。第三个技巧是用跟踪补检测。单帧漏检的行人如果前后帧都检到了用 ByteTrack 这类跟踪器能把中间帧的框补上。行人运动连续跟踪补帧对召回提升很明显代价是引入几毫秒延迟。最后一个习惯每次改完参数或数据固定用同一段测试视频跑一遍把结果视频存下来对比。我吃过亏调完参看指标涨了就上线结果实际画面里框抖得厉害指标根本反映不出来。后来养成了存视频对比的习惯肉眼过一遍再决定要不要推。希望帮到你。本文还有配套的精品资源点击获取