
简介这份资源是面向计算机视觉方向毕业设计与课程设计的一套YOLO行人检测项目适合需要快速搭建目标检测实验环境的学生与开发者。包内含核心脚本与模型权重配置共24个文件以Python脚本、编译缓存pyc、类别/锚框配置txt、测试图片jpg、Shell执行脚本、说明文档md及字体文件等为主压缩包整体约261KB。通过yolo_predict.py加载预训练模型完成图片或视频中的行人预测detect.py提供简洁调用接口gen_anchors.py用于生成YOLO算法的锚框utils.py与config.py分别承担图像处理与参数配置predict.sh支持Linux环境下快速执行目录结构清晰便于二次开发与课程演示。目前已有85人学习使用既适合毕业设计、课程设计的完整方案参考也可作为入门YOLO目标检测的实操资料帮助理解锚框机制、多尺度预测思路与模型调参方法。1. 行人检测的 zip 到底值不值得解压拿到一个叫基于yolo的行人检测.zip的压缩包多数人的第一反应是解压、找README、跑 demo。但我建议你先把它当成一份「技术方案」来审而不是当成现成代码来跑——因为 YOLO 行人检测这个方向真正卡人的从来不是检测框架本身而是数据集质量、目标尺度分布和部署环境的匹配度。这个包如果组织得好应该包含四样东西可复现的环境配置、能直接推理的预训练权重、带标注的行人数据集或生成脚本、以及训练/评估的完整流程。这篇文章就按这条链路展开从选型到训练再到部署避坑讲清楚每一步怎么做、参数怎么调、翻车了怎么排查让你拿到任何同类项目都能快速判断它值不值得投入。2. 选型先行YOLO 版本与项目结构怎么定2.1 从 v5 到 v8行人检测该选哪一代行人检测属于目标检测里的中尺度目标问题不像遥感或病理切片那样极端小目标也不像工业质检那样需要像素级边界。YOLO 系列里v5 和 v8 是当前落地最主流的两个选择v5 胜在生态成熟、部署资料多v8 胜在训练收敛更稳、内置了更灵活的训练策略。如果你的 zip 里只有yolov5目录别急着嫌弃老。v5 的detect.py和train.py几十年如一日地稳定社区里改网络结构的变体几乎都以它为基础遇到报错搜一下就有答案。v8 的ultralytics包把训练和推理统一成一个 Python API代码更简洁但对自定义数据集的组织方式有自己的一套约定刚上手时会被它的数据集 yaml 配置绕一下。我的建议很直接如果是做课程设计或快速验证选包内已有的版本就行如果是自己做落地项目优先看是不是 v8 或更新版本因为 v8 对数据增强、损失函数做了不少工程化改进同等数据量下训练出来模型对小尺度行人的召回率通常比 v5 好一点。版本选型本质上是赌生态不是赌论文指标所以别只看 mAP要看你能搜到多少同版本的踩坑帖。2.2 拿到 zip 后先看这四个文件再动手不要一上来就pip install -r requirements.txt先花五分钟检查项目结构。一个组织良好的 YOLO 行人检测项目至少应该包含以下几类东西文件/目录作用缺失时的后果weights/或runs/预训练权重.pt或.onnx只能从头训练耗时成倍增加data/或datasets/行人数据集或下载脚本只能用自己的数据标注成本高train.py/detect.py训练与推理入口需要自己补脚本工作量大requirements.txt或environment.yml依赖锁定环境装完一堆版本冲突我见过不少「基于 yolo 的行人检测」压缩包解压后只有一堆.py和一个空目录。那种包不是不能用而是把最脏最累的部分——数据准备和权重获取——留给你自己做。如果你已经有一定基础这不算坏事因为自己走一遍数据流程印象更深但如果你想快速跑通看效果请优先找带权重的版本。另外留意包内是否包含标注好的行人数据。有些数据集是 VOC 格式的 XML 标注有些是 YOLO 格式的 txt 标注两者转换是大坑之一后面专门讲。先确认你的包里的标注格式再决定要不要自己写转换脚本。3. 环境部署与最小推理先把预训练权重跑起来3.1 用 conda 快速搭一套可复现环境无论包内是 v5 还是 v8我都建议先用 conda 建独立环境别往 base 环境里直接装。深度学习项目最怕的不是装不上而是装上了但把系统 Python 环境搞乱了后面排查问题全是环境原因。conda create -n yolo_ped python3.9 -y conda activate yolo_ped # 先装 PyTorch版本根据你的 CUDA 版本选 # 如果显卡是 30 系及以上建议 CUDA 11.8 pip install torch2.0.1 torchvision0.15.2 --index-url https://download.pytorch.org/whl/cu118 # 再装项目依赖注意先看 requirements.txt 里是否锁版本 cd 你的项目目录 pip install -r requirements.txt这里有一个关键点PyTorch 一定要先于其他依赖安装。YOLO 训练脚本会在导入时检测 CUDA 是否可用如果先把numpy、opencv装了再装 torch某些组合下会出现 OpenCV 与 PyTorch 的 CUDA 运行时冲突报错信息是libcudart.so: cannot open shared object file极其玄学。先装 torch 再装其他依赖这个顺序基本能避开。装完之后别急着训练先验证环境是否真的能用 GPUpython -c import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0) if torch.cuda.is_available() else CPU)如果这里输出False大概率是 torch 版本和你本机 CUDA 驱动不匹配。注意区分「驱动 CUDA 版本」和「运行时 CUDA 版本」——nvidia-smi显示的 CUDA 版本是驱动支持的不是 torch 实际使用的。解决办法是卸载 torch 重装对应 cu 后缀的版本别去改系统环境变量那是给自己挖坑。3.2 用一张图片验证模型最小推理脚本环境通了的下一步是拿一张含行人的图片跑通推理。这一步的目的是验证权重文件和模型结构是否匹配而不是追求检测效果所以用项目自带脚本或手写最小推理都可以。如果你用的是 v8最简洁的方式是这样from ultralytics import YOLO # 加载权重包内如果没有预训练权重第一次运行会自动下载 model YOLO(yolov8n.pt) # 推理source 可以是图片路径、目录、视频或摄像头序号 results model.predict( sourcetest_images/pedestrian.jpg, conf0.25, # 置信度阈值行人检测建议 0.25 起调 iou0.7, # NMS 的 IoU 阈值 saveTrue, # 保存标注后的图片 imgsz640 # 输入分辨率和训练时保持一致 )如果是 v5对应命令是python detect.py --weights yolov5s.pt --source test_images/pedestrian.jpg --conf 0.25 --iou 0.7 --imgsz 640跑完看两件事一是有没有检测出图中的行人二是检测框是否基本贴合人体轮廓。如果完全没检测出来先别怀疑权重坏了先看图片——图中的人物是不是太小是不是背面/遮挡/暗光这些场景对行人检测模型是天然压力测试后面避坑章节会细说。conf和iou这两个参数是检测效果的第一组旋钮。conf太低会引入大量误检太高会漏掉被遮挡的行人iou控制重叠框的合并程度行人密集场景下iou0.7往往不够要调到0.45左右才能避免多个框叠在同一个人身上。记住一个原则先调conf控制误检率再调iou控制重叠框两者互相牵制。3.3 检测结果怎么看置信度、NMS 与类别筛选跑通推理只是开始你得理解输出里每一列是什么否则后面调参就是盲人摸象。YOLO 的检测输出通常是一个(N, 6)的张量每一行对应一个检测框前四列是框坐标中心点 x、y 和宽高或 xyxy 格式第五列是置信度第六列是类别 ID。置信度在行人检测里有特殊意义。COCO 预训练权重里person类别的置信度普遍偏高因为训练数据里行人样本多、姿态变化大模型对「像人」的物体有很强的响应。这带来一个典型问题把雕塑、广告牌上的人形、远处模糊的人影都当成行人。所以行人检测部署时conf阈值往往要比通用检测高一些我一般从0.35起步根据误检率上下浮动。NMS 相关的坑更隐蔽。YOLO 输出的原始预测框大量重叠NMS 的作用是把同一目标的多个框合并iou阈值越低合并越激进却可能导致相邻行人被合并成一个框。反过来iou阈值越高重叠框残留越多密集行人场景下就会出现「一个人两个框」的翻车现场。调参时记住行人密度越大iou阈值应越小。4. 训练自己的行人检测模型数据集与参数是核心4.1 行人数据集怎么选公开集与自标注的取舍如果你的 zip 内自带了数据集省事很多如果没有就得自己准备。行人检测的公开数据集有不少常见的是 COCO 的 person 类、Caltech Pedestrian、CityPersons 和 WiderPerson。它们的共同点是场景以街景为主行人姿态覆盖站立、行走、骑行遮挡情况不一。但公开集有一个问题场景分布和你的实际应用大概率不一致。你在园区装监控训练集全是城市街景模型对俯视角度、夜间红外、雨天反光的行人会明显掉点。所以常见的做法是「公开集预训练 自采数据微调」。先下载公开集训练一个 base model再标注几百张你自己的场景图做 fine-tune效果远好于只用公开集或只用自采数据。行人数据集的标注规范有几个硬性要求。一是标注框要紧贴人体不要像画风景框一样留大量余白否则模型学到的行人边界是模糊的二是遮挡超过 50% 的行人建议不标否则模型会学到「半个人也是完整的人」这种错误映射三是图片里出现的小目标行人高度小于 32 像素要么放大裁剪后单独训练要么直接忽略否则它们会拉低整体训练效率。有人会问能不能直接爬图自动标注我的回答是可以用于预筛选但必须人工复核。自动标注的框经常出现「框住两条腿」「框住上半身」的问题这些噪声会让训练好的模型在推理时输出半个身位的检测框后处理很难修正。4.2 VOC 标注转 YOLO 格式转换脚本与四个边界坑很多公开数据集提供的是 VOC 格式XML 文件而 YOLO 训练需要的是每张图对应一个 txt 文件、每行一个class x_center y_center width height、坐标归一化到 0~1。转换脚本是每个行人检测项目绕不开的坎直接上代码import os import xml.etree.ElementTree as ET from glob import glob def voc_to_yolo(xml_path, out_dir, class_names, img_width, img_height): 将单个 VOC XML 转换为 YOLO txt 参数: xml_path: XML 文件路径 out_dir: 输出的 txt 目录 class_names: 类别名列表例如 [person] img_width, img_height: 图片原始尺寸 tree ET.parse(xml_path) root tree.getroot() # 注意有的 XML 里 size 节点包含宽度高度有的不包含 # 这里先用外部传入的尺寸避免读不到 size 时报错 lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in class_names: continue # 只保留目标类别 cls_id class_names.index(cls_name) bndbox obj.find(bndbox) x1 float(bndbox.find(xmin).text) y1 float(bndbox.find(ymin).text) x2 float(bndbox.find(xmax).text) y2 float(bndbox.find(ymax).text) # 边界处理把超出图片范围的框裁剪回来 x1 max(0, min(x1, img_width)) y1 max(0, min(y1, img_height)) x2 max(0, min(x2, img_width)) y2 max(0, min(y2, img_height)) # 过滤掉标注错误的框宽或高为 0 if x2 x1 or y2 y1: continue # 转归一化坐标 x_center (x1 x2) / 2 / img_width y_center (y1 y2) / 2 / img_height w (x2 - x1) / img_width h (y2 - y1) / img_height lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) # 写入 txt xml_name os.path.basename(xml_path).replace(.xml, .txt) with open(os.path.join(out_dir, xml_name), w) as f: f.write(\n.join(lines))这段代码做了三件关键的事用外部传入的图片尺寸避免 XML 里 size 缺失导致归一化算错裁剪超出边界的框处理标注软件留下的越界框过滤掉宽高为 0 的坏标注防止训练时 loss 变 nan。除了代码本身还有四个实战中很容易踩的坑。第一XML 里filename的图片名可能和实际文件名大小写不一致Linux 下大小写敏感会导致图片找不到建议转换前统一改名第二图片尺寸要以实际读取为准不能只信 XML 里的size有些数据集的 XML 尺寸和真实图片不一致最好用 PIL 或 OpenCV 实际读一遍图shape第三类别过滤不能少公开数据集里可能混入rider、bicycle等类别你需要决定是忽略还是另建类别第四生成的 txt 和图片要放在同一目录且同名YOLO 训练时按同名匹配查找稍有不一致就会「找不到标签」直接跳过该图。转换完后一定要抽查统计。写一段小脚本统计每一张图的行人数量如果出现大量「标注框数量和 txt 行数不一致」的图说明有标注被过滤了需要回头检查是越界还是尺寸错误导致的。4.3 训练命令与关键参数batch、epoch、anchor 的调法数据准备好了就可以开训。用 v5 训练自定义数据集的命令是# 假设数据集放在 datasets/person/ 下images 和 labels 两个子目录 # person.yaml 里定义 train/val 路径和类别名 python train.py --data person.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100 --device 0用 v8 则是yolo train dataperson.yaml modelyolov8s.pt imgsz640 batch16 epochs100 device0第一步是配置person.yaml它决定了 YOLO 去哪里找数据和类别定义path: datasets/person train: images/train # 训练集图片目录 val: images/val # 验证集图片目录 nc: 1 # 类别数这里只有 person 一类 names: [person] # 类别名顺序与 txt 标注里的 class id 对应三个必调参数是batch、epochs和imgsz。batch不是越大越好它受显存约束显存不够时优先减半而不是减小imgsz因为降低输入分辨率会直接影响小目标行人的检测能力epochs对于行人检测这个单类别任务从预训练权重微调时 50~100 轮足够因为行人检测不是从零学起过长的训练会过拟合到训练集的特定场景imgsz是行人检测里最值得加码的参数——同等算力下把 640 提到 768小目标行人召回率能明显提升但推理速度会下降约 20%需要你根据部署设备的能力做取舍。训练过程中还有两个容易被忽略的开关。一个是 mosaic 增强v5/v8 默认开启它把四张图拼成一张训练对小目标丰富但对行人这种中尺度目标容易导致目标被切分如果发现训练集损失一直在降、验证集损失波动很大可以尝试把mosaic关掉或在最后 10 轮关闭通常能稳住验证集表现。另一个是 pretrained 权重优先用 COCO 预训练权重而不是从头训练COCO 里 person 类占比高预训练模型已经具备行人特征提取能力从头训练往往需要 3 倍以上数据量才能达到同样效果。4.4 训练中的两个信号损失曲线与混淆矩阵训练不是把命令丢出去就完事你得学会读训练日志。YOLO 训练时每个 epoch 会打印 box loss、obj loss、cls loss 和 mAP 指标四个信号里有三个值得关注box_loss如果一直不降说明回归头学不到框的位置通常是标注框质量太差框不贴合人体或学习率过大obj_loss居高不下说明目标置信度学不好常见原因是数据里目标太小、正负样本不平衡mAP50 能到 0.8 以上但 mAP50-95 很低意味着检测框位置不够精准需要提高imgsz或检查标注精度。训练结束后生成的confusion_matrix.png是一个被大多数人忽略但极其有用的图。很多人看到混淆矩阵里数值总和不是 1 就以为代码出错其实是 YOLO 的混淆矩阵按「预测类别」做了归一化每一行代表该类别实际样本被预测到各类的比例所以行和为 1。如果你是单类别行人检测混淆矩阵会退化成 3x3person、background、miss重点关注 background 那一行如果有很多「person 被预测为 background」说明漏检严重需要降低conf或提高输入分辨率如果「background 被预测为 person」说明误检多需要提高conf或检查是否有太多与环境相似的负样本。训练完保留什么文件也有讲究。runs/train/exp/weights/下会有best.pt和last.pt两者都别删——best.pt是验证集上表现最好的权重用于最终推理last.pt是最后一轮的权重当你想继续训练时用--weights last.pt接着跑比从头跑省一半时间。很多人只留best.pt后续想加数据扩充训练时只能重新开始血泪教训。5. 行人检测部署避坑五条实测踩坑记录5.1 小目标行人漏检调 anchor 和输入分辨率现象监控画面里远处的行人完全检测不到近处的正常或检测框只有半截身体。原因YOLO 的 anchor 尺寸覆盖不够输入分辨率太低导致小目标在特征图上只剩几个像素。解决优先把imgsz从 640 提到 768 或 896观察召回率变化如果仍然漏检再考虑修改 anchor——在训练命令中加--anchor让 YOLO 根据数据集自动重新计算 anchor通常 50 轮后 anchor 会重新聚类到更匹配行人比例的尺寸。注意改 anchor 必须用--cache缓存数据否则每次训练都重新聚类结果不稳定。5.2 密集场景误检翻车NMS 阈值与置信度联动现象地铁站、商场入口这类人流密集场景一张图里出现十几个框其中好几个叠在同一个人身上甚至行人之间互相串框。原因默认 NMS 阈值iou0.7太宽松重叠 70% 的框不会被合并同时conf0.25太低放进了很多低质量预测框。解决把iou降到0.4~0.45conf提到0.35~0.5两者配合才能压住密集场景的框爆炸。还有一个容易被忽略的变量输入分辨率。密集场景下行人之间的像素间隔本来就小分辨率越高框越精细NMS 合并越容易出错所以密集场景反而建议不要过度提高imgsz640 往往是更稳的选择。5.3 训练时 loss 变成 nan学习率与 BN 层现象训练到某一步突然打印的 loss 全是nan日志里出现RuntimeError: NaN loss训练立即崩溃。原因最常见的是学习率过大导致梯度爆炸其次是标注数据里出现「框坐标超出图片范围」导致的数值异常虽然转换脚本里做了边界裁剪但有些数据集原标注本身就包含负数坐标。解决先检查数据写脚本统计所有 txt 里是否有小于 0 或大于 1 的坐标有就清洗掉如果数据没问题降低初始学习率v5 命令行加--lr0 0.001v8 在配置里设lr00.001。另外注意一个隐藏问题如果batch太小比如 8BN 层的统计量不稳定也可能诱发 loss 抖动可以把batch提到 16 以上或用--nosave先跑 20 轮观察曲线。5.4 边缘设备推理卡顿量化与推理引擎现象模型在服务器上检测 30 FPS部署到 Jetson 或 RK3588 上只剩 3 FPS完全不可用。原因PyTorch 的 GPU 推理在边缘设备上跑不出性能必须经过模型转换和量化。解决先把权重导出为 ONNX再转成对应平台引擎格式。转换时注意两个参数opset版本不能太新边缘设备上opset11或者12兼容性最好量化推荐使用 INT8 量化行人检测对精度损失容忍度较低量化后 mAP 掉 2~3 个点可以接受掉超过 5 个点要检查量化数据集是否覆盖足够多的行人场景。如果你的 zip 项目里没有提供转换脚本按这个流程走.pt - .onnx - .engineTensorRT/ .rknnRK3588每一步都要用一张实拍图验证输出框是否变化。5.5 混淆矩阵总和不是 1归一化方式搞错了现象训练生成的confusion_matrix.png里所有格子加起来不是 1强迫症犯了以为训练出错。原因YOLO 的混淆矩阵默认对每行归一化显示的是「真实类别被预测成各类别的比例」不是全矩阵归一所以行和是 1、总和不一定是 1。解决这个现象不是 bug。真正需要警惕的是对角线之外的值如果「person 被预测成 background」比例高于 10%说明漏检率偏高优先调输入分辨率和conf如果「background 被预测成 person」比例高于 5%说明误检严重优先调conf并检查训练集的负样本不包含行人的背景图是否足够。我一般会在项目中同时保留confusion_matrix.png和results.png前者看类别混淆后者看损失曲线两个图对不上时以results.png的损失曲线为准排查训练过程。6. 用一段视频把整个流程连起来调试脚本与验证技巧训练好的模型不能只看静态图效果行人检测的实际挑战在连续帧里才暴露出来——闪烁的检测框、突然丢帧的人影、镜头抖动导致的误检。我习惯在项目里单独写一个视频验证脚本把模型放到接近真实部署的环境里压测。import cv2 from ultralytics import YOLO model YOLO(runs/train/exp/weights/best.pt) video_path test_videos/street.mp4 cap cv2.VideoCapture(video_path) fps cap.get(cv2.CAP_PROP_FPS) width int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) writer cv2.VideoWriter(output_video.mp4, cv2.VideoWriter_fourcc(*mp4v), fps, (width, height)) frame_count 0 while cap.isOpened(): ret, frame cap.read() if not ret: break frame_count 1 # 每 3 帧推理一次模拟边缘设备的性能瓶颈 if frame_count % 3 ! 0: continue results model.predict( sourceframe, conf0.35, iou0.45, imgsz768, # 和训练时的分辨率保持一致不要随意改 verboseFalse ) for result in results: boxes result.boxes for box in boxes: x1, y1, x2, y2 map(int, box.xyxy[0]) cls_id int(box.cls[0]) conf float(box.conf[0]) # 只画 person 类别避免误检类别干扰观察 if cls_id 0 and conf 0.35: cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(frame, fperson {conf:.2f}, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) writer.write(frame) cv2.imshow(Pedestrian Detection, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() writer.release() cv2.destroyAllWindows() print(f视频处理完成共写入了 {frame_count // 3} 帧)这个脚本模拟了部署态的三个关键变量跳帧推理对应边缘设备算力瓶颈推理时锁定imgsz对应训练/推理分辨率不一致导致的精度跳变只输出置信度 0.35 以上的框对应实际场景里对误检率的硬性要求。逐帧播放视频时重点观察三个现象检测框是否在相邻帧之间来回跳、一个行人是否被拆成两个框、以及远处的小目标是否存在「出现几帧后消失」的闪烁——前两个问题多半要调 NMS 和置信度第三个问题直接指向输入分辨率。验证脚本跑完后我习惯再用一个只有一行的统计命令看一下整体效果python detect.py --weight best.pt --source test_videos/street.mp4 --save-txt --save-conf生成的labels里每帧的检测框数据都保存了你可以快速统计单帧最多框数、平均置信度这些数字比肉眼直观得多也是后续写部署需求文档的依据。回到开头那个问题基于 YOLO 的行人检测这个方向值不值得投入我的答案是值得但前提是你要接受一个事实YOLO 只是骨架数据集、参数、部署调优才是血肉。一个 zip 包解压跑通 demo 只需要半小时但要把它变成稳定运行的业务系统后面还有十倍的工作量在等着你。这也是我写这篇文章的原因——把链路走一遍你才知道每个环节的分量。希望帮到你。本文还有配套的精品资源点击获取