YOLOv5+HRnet姿态估计实战:人体关键点检测与调参全指南
发布时间:2026/10/1 1:59:28来源:尧图网络
简介一套将YOLOv5与HRnet、SimDR结合的人体关键点检测工程包适合目标检测、姿态估计学习者也可用于图片、视频和摄像头实时关键点识别与骨骼绘制。压缩包约841.53MB共2000个文件以1867个Python脚本为主另有C/C源码、txt配置、h头文件及md说明等方便查看逻辑和参数。已有1748人学习下载工程可直接替换路径后运行省去配置权重和参数的工作。内容覆盖项目准备、YOLOv5目标检测、姿态估计、照片/视频/实时演示并整理了路径、functional.py警告、matplotlib.use(Agg)、Upsample recompute_scale_factor、gbk解码等常见报错分析便于复现与排错。1. YOLOv5姿态估计HRnet实时检测人体关键点先跑通再调参做人体姿态估计最怕的不是模型选型而是环境没配好、权重没下对、路径没改对卡在第一步。这套基于YOLOv5 HRnet SimDR的方案把目标检测和关键点回归拆成两条清晰线索先用YOLOv5框出人体位置再用HRnet在框内回归17个关键点支持图片、视频和摄像头实时检测。资源里权重、配置、源码都齐了拿到的原工程文件里主要工作是改路径而不是搭模型。适合三种人做课设或毕业设计需要快速出效果的学生、要在树莓派或边缘设备上部署YOLOv5的开发者、想理解姿态估计pipeline但不想从零训模型的人。正文会按环境配置、目标检测、姿态估计、报错排查、统一验证的顺序展开每一段都是可以直接抄作业的操作。2. 环境与工程落地conda配置、路径改造和权重文件放置2.1 从克隆到conda环境一版不会翻车的配置拿到原工程后第一步不是急着跑而是把环境固定成和工程作者一致的版本。YOLOv5的代码对PyTorch版本不挑但HRnet和SimDR的依赖里包含Cython源码编译torch版本太新或太旧都会在编译阶段报错。这里给出我反复装过多次的组合。git clone 原工程仓库地址 # 或直接解压作者分享的zip cd 工程目录 conda create -n pose python3.8 -y conda activate pose conda install pytorch1.8.0 torchvision0.9.0 cudatoolkit10.2 -c pytorch -y pip install -r requirements.txtclone命令里把仓库地址替换成你手头的工程地址没有GPU的机器把cudatoolkit那行去掉只装CPU版torch也能跑推理只是实时摄像头检测会卡。Python 3.8是稳妥选择3.10及以上在编译Cython文件比如ObjectHandling.c、CythonFunction.c这些时更容易触发gbk编码报错。requirements.txt里如果缺pycocotools单独装一次pip install pycocotools-windowsWindows或pip install pycocotoolsLinux/macOS。这一个包是后面绘制骨骼时计算COCO骨架索引的依赖漏装会导致绘图脚本import阶段直接失败。2.2 路径改造把别人的工程变成自己的原工程里作者用了自己的绝对路径比如D:/PoseProject/weights/、C:/Users/xxx/Desktop/...你拿过来必须全局替换成自己的目录。常见做法是统一改成相对路径这样换机器不用二次修改。# 在项目根目录执行Windows用户可以用编辑器全局替换macOS/Linux用sed grep -r D:/PoseProject --include*.py --include*.yaml -l | xargs sed -i s|D:/PoseProject|$(pwd)|g上面的命令会把所有Python和yaml文件里的D:/PoseProject替换成当前工作目录。注意sed里的管道符|是定界符Windows路径带盘符冒号时用它避免转义问题。替换完后跑一次python main.py --help如果程序能打印帮助信息说明路径已经找对了。我一般会再手动检查datasets相关的yaml文件确认root:字段指向的目录真实存在。姿态估计的数据加载器比较死板路径不存在时不会报具体文件缺失而是直接抛FileNotFoundError排查起来很费时间。2.3 权重文件与目录结构黑匣子打开后的样子原工程包含的权重文件有两组YOLOv5目标检测权重yolov5x.pt用于图片检测或yolov5s.pt用于实时视频以及HRnet人体关键点权重hrnet_w32.pth。目录结构按下面的树形摆放就不会出错。工程根目录/ ├── weights/ │ ├── yolov5s.pt │ ├── yolov5x.pt │ └── hrnet_w32.pth ├── models/ │ ├── yolo.py │ └── hrnet.py ├── utils/ ├── configs/ │ └── coco_pose.yaml ├── detect.py ├── pose_estimation.py └── train.py权重文件是姿态估计的“黑匣子”——yolov5s.pt负责把人框出来hrnet_w32.pth负责在框内回归关键点坐标作者在原工程里已经把这层封装好了。你要做的只是确认这三个文件存在且大小合理yolov5s.pt约14MByolov5x.pt约240MBhrnet_w32.pth约280MB。如果从release下载的权重被git lfs截断成几个KB加载时会报EOFError直接删掉重新下。3. 目标检测底座权重加载、边界框输出与SPPF模块3.1 添加权重文件官方权重和自定义权重的区别YOLOv5的目标检测权重有两类官方预训练权重yolov5s.pt/yolov5m.pt/yolov5l.pt/yolov5x.pt和自定义训练权重。做姿态估计时检测器只用来框出人体所以直接用官方权重效果就很好——COCO数据集上yolov5s.pt对person类别的AP已经够用速度还快。# models/yolo.py 中的加载逻辑简化版 import torch def load_detector(weights_pathweights/yolov5s.pt, devicecpu): model torch.hub.load(ultralytics/yolov5, custom, pathweights_path) model.classes [0] # 只保留person类别过滤其他80类 model.conf 0.4 # 置信度阈值 model.iou 0.45 # NMS的IoU阈值 return modelmodel.classes [0]是姿态估计场景的关键过滤条件COCO数据集中类别0就是person。如果不加这行检测器会把猫、狗、车都框出来后续HRnet会对这些框强行回归关键点输出一堆无意义的坐标。conf0.4是速度和精度的折中点实时视频场景可以放到0.3减少人体漏检。实验验证时我建议把conf分别设成0.3和0.5跑同一段视频观察检测框数量变化找到你设备上的最优值。这一步很多人跳过直接导致后面骨骼绘制“跳变”——检测框一帧有、一帧没有关键点自然跟着抖。3.2 获取图片边界框从检测结果到xyxy坐标YOLOv5的输出是一个Results对象里面封装了xyxy左上右下坐标、conf置信度、cls类别、xywh中心点宽高四种格式。HRnet需要的是xyxy因为关键点回归是在矩形框区域内做的。import cv2 import torch # 加载模型 detector load_detector(weights/yolov5s.pt) frame cv2.imread(test.jpg) # 推理并解析结果 results detector(frame) boxes results.xyxy[0].cpu().numpy() # shape: (N, 6) 分别是 x1,y1,x2,y2,conf,cls for box in boxes: x1, y1, x2, y2, conf, cls box if cls 0 and conf 0.4: cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)results.xyxy[0]取第一张图的检测结果N是检测到的人数每行六列。注意box里的坐标是float类型cv2画矩形必须转int否则OpenCV直接抛TypeError: an integer is required。多人的时候这个for循环会依次框出每个人每个人后续都会送进HRnet单独做关键点回归。很多初学者在这里容易搞混YOLOv5检测的是整个图片的目标拿到的是“人的位置”HRnet做的是单人关键点输入是一张裁剪好的人体框。两者中间有一个“裁剪”动作这个动作在pose_estimation.py里实现本质就是frame[y1:y2, x1:x2]的numpy切片。3.3 添加SPPF模块从SPP到SPPF的改动与作用原工程里的YOLOv5是基于5.0版本改造的所以检测头里自带SPP模块。新版本YOLOv56.0及以上把这个模块替换成了SPPF目的是用三次MaxPool2d串联替代原来的一次MaxPool2d大核池化计算量减少但感受野几乎不变。# 添加在 models/common.py 中的SPPF模块实现 import torch import torch.nn as nn class SPPF(nn.Module): def __init__(self, c1, c2, k5): super().__init__() c_ c1 // 2 self.cv1 nn.Conv2d(c1, c_, 1, 1) self.cv2 nn.Conv2d(c_ * 4, c2, 1, 1) self.m nn.MaxPool2d(kernel_sizek, stride1, paddingk // 2) def forward(self, x): x self.cv1(x) y1 self.m(x) y2 self.m(y1) y3 self.m(y2) return self.cv2(torch.cat([x, y1, y2, y3], 1))这段代码里k5是池化核大小paddingk//2保证特征图尺寸不变。forward里把原始特征和三次池化结果拼起来输出的通道数是c_ * 4。替换到yolo.py的检测头时只需要把SPP的实例化改为SPPF(c1, c2, k5)并确保common.py里能import到新类。很多人自己改的时候会漏掉paddingk//2这一项导致特征图尺寸对不上模型直接报尺寸不匹配的RuntimeError。这个值不是随便写的stride1时只有设置paddingk//2才能保持输入输出分辨率一致这属于YOLOv5源码里的默认约定。4. 姿态估计管线HRnet权重、yaml修改与关键点绘制4.1 HRnet权重与yaml修改理解通道数、关键点数量和骨架连接HRnet的核心特点是保持高分辨率特征图通过并行分支不断融合低分辨率信息对关键点定位比单纯下采样再上采样的网络更准。原工程里用的hrnet_w32是指最后一个高分辨率分支有32个通道。修改configs/coco_pose.yaml是接入自己数据的关键跳板。# coco_pose.yaml 关键参数说明 DATASET: NUM_CLASSES: 17 # COCO数据集的17个关键点 SKELETON: [ # 骨架连接索引用于绘制骨骼 [0, 1], [0, 2], [1, 3], [2, 4], # 鼻子→左右眼→左右耳 [3, 5], [4, 6], [5, 7], [6, 8], # 耳朵→肩膀→手肘 [7, 9], [8, 10], [5, 11], [6, 12], # 手腕→髋部 [11, 13], [12, 14], [13, 15], [14, 16] # 髋部→膝盖→脚踝 ] FLIP_INDICES: [0, 2, 1, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 16, 15] MODEL: PRETRAINED: weights/hrnet_w32.pthNUM_CLASSES: 17对应COCO标注规范鼻子、左右眼、左右耳、左右肩、左右肘、左右腕、左右髋、左右膝、左右踝。SKELETON是画骨骼用的连接对索引顺序不能乱否则画出来的人体骨架交叉错位。FLIP_INDICES是数据增强时水平翻转用到的关键点映射表比如左右眼互换、左右肩互换这个表是训练时才用到的纯推理时不影响。修改yaml时常见的错误是改了NUM_CLASSES但没改输出层的卷积通道数。如果换成自定义数据集比如14个关键点的手势数据hrnet.py里最后的nn.Conv2d(32, NUM_CLASSES, 1)会自动接受新数字但对预训练权重而言输出层的权重shape对不上加载时会报size mismatch。此时需要保留预训练权重的前面层只随机初始化最后一层。4.2 从边界框到关键点热图解码与SimDRHRnet输出的不是直接的关键点坐标而是一组热图heatmap。每个关键点对应一张64×64的热图图上峰值位置就是关键点在框内坐标系下的位置。SimDRSimplicial Distance Regression是对热图解码的一种简化直接回归每个关键点到顶点的距离省去了额外解码步骤。def get_keypoints(heatmaps, box, scale64): heatmaps: HRnet输出的热图shape (17, 64, 64) box: 检测框坐标 (x1, y1, x2, y2) import numpy as np keypoints [] for heatmap in heatmaps: # 找到热图最大响应的位置 h, w np.unravel_index(np.argmax(heatmap), heatmap.shape) # 归一化到0~1区间 y_norm, x_norm h / scale, w / scale # 映射回原图坐标 x_orig box[0] x_norm * (box[2] - box[0]) y_orig box[1] y_norm * (box[3] - box[1]) keypoints.append((x_orig, y_orig)) return np.array(keypoints)这段代码是把64×64的热图坐标映射回原图的关键步。np.argmax找热图上响应最强的像素位置h/scale和w/scale把坐标归一化到0~1最后乘上检测框的宽高映射回原图。如果没有这一步所有关键点都会集中在一张小尺寸图片上绘制出来完全错位。SimDR在工程里的实际作用是选择了更简洁的后处理——不解析热图的分布方差只取最大响应点速度更快实时视频场景下每帧能省几毫秒。代价是轻微抖动后续可以通过时序滤波优化。4.3 绘制骨骼关键点从关键点到人形骨架拿到17个关键点的坐标后绘制骨骼需要两步先画点再按SKELETON里的连接对画线。def draw_skeleton(frame, keypoints, skeleton, conf_thres0.3): # 绘制关键点 for i, (x, y) in enumerate(keypoints): cv2.circle(frame, (int(x), int(y)), 3, (0, 255, 255), -1) # 绘制骨骼连接 for idx1, idx2 in skeleton: x1, y1 keypoints[idx1] x2, y2 keypoints[idx2] # 过滤置信度过低的连接可选 cv2.line(frame, (int(x1), int(y1)), (int(x2), int(y2)), (255, 0, 0), 2) return frame绘制时两个细节值得注意一是点的半径和线的粗细实时视频建议点半径2、线宽1或2否则闪烁明显二是如果做了conf过滤还要把每个关键点的置信度传进来低于阈值的点不画线避免画面出现“飘浮”的线条。COCO骨架的标准配色没有硬性要求但一般头和躯干用暖色、四肢用冷色便于肉眼追踪。5. 避坑与排查五个高频报错的现象、原因和解决5.1 路径问题FileNotFoundError和ModuleNotFoundError同时出现现象运行pose_estimation.py时先报ModuleNotFoundError: No module named utils改完import路径后又报FileNotFoundError: weights/hrnet_w32.pth不存在。原因原工程作者写的是绝对路径你的工程根目录和作者不一致。utils找不到是Python的sys.path没包含项目根目录权重找不到是文件实际位置和代码里的相对/绝对路径不匹配。解决第一步在工程根目录创建__init__.py如果已有就忽略然后在pose_estimation.py顶部加两行import sys, os sys.path.append(os.path.dirname(os.path.abspath(__file__)))第二步统一把所有权重路径改为weights/下并用第2章的sed命令全局替换。如果还报错用os.path.exists(weights/hrnet_w32.pth)打印一下确认当前工作目录到底在哪。5.2 YOLOv5、YOLOvx训练过程警告functional.py:1339现象加载YOLOv5权重后控制台输出一堆functional.py:1339: UserWarning: Detecting the angle of the tensor is not implemented...推理正常但每次启动都刷屏。原因PyTorch 1.9版本里torch.nn.functional的实现改动导致旧版YOLOv5源码里的某些调用触发了DeprecationWarning。这个警告不影响输出结果纯属“噪音警告”。解决在代码里显式忽略警告或者把torch降到1.8.0。推荐前者因为1.8.0有原生Cython编译问题。在脚本开头加import warnings warnings.filterwarnings(ignore, categoryUserWarning)注意过滤条件要精确到UserWarning不要粗暴warnings.filterwarnings(ignore)把别的有用警告也吞了。5.3 matplotlib.use(Agg)图像保存正常但弹不出窗口现象按照原工程说明设置matplotlib.use(Agg)后关键点可视化图能保存成文件但没有交互式窗口弹出实时预览完全看不到效果。原因Agg是matplotlib的无头后端专为写文件设计不渲染GUI。原工程做结果演示时保存图片到磁盘没问题但你要做摄像头实时演示时必须换成TkAgg或Qt5Agg。解决在import matplotlib.pyplot as plt之前按你的系统选择import matplotlib matplotlib.use(TkAgg) # Windows/Linux通用 # 或 matplotlib.use(Qt5Agg) # 如果TkAgg在特定环境无效 import matplotlib.pyplot as plt判断标准很简单能弹窗且不闪退就用当前后端弹窗后卡死就换另一个。5.4 AttributeError: Upsample object has no attribute recompute_scale_factor现象用新版PyTorch加载原工程的HRnet权重时报AttributeError错误指向nn.Upsample的某个属性。原因PyTorch 1.11版本中调整了Upsample的内部实现recompute_scale_factor属性被移除或改变了语义。HRnet里用了nn.Upsample(scale_factor2)做上采样老代码访问了这个不存在的属性。解决两步走。第一步改hrnet.py里所有的上采样写法把nn.Upsample(scale_factor2)替换成nn.Upsample(scale_factor2, recompute_scale_factorFalse)兼容old或nn.Upsample(size(H*2, W*2))新写法。第二步同时检查torchvision版本pip install torchvision0.12.0可以配对torch 1.11。如果不想动模型文件用torch 1.8.0环境跑推理这个报错不会出现。5.5 gbk codec cant decode byte读取图片或标注文件编码冲突现象训练或推理时读取COCO标注json或自定义数据集txt时报UnicodeDecodeError: gbk codec cant decode byte 0x...文件读不完整。原因Windows系统下Python默认用gbk编码读文件而COCO的json标注文件是UTF-8编码。原工程里如果作者在Linux/macOS上开发代码里的open()没有指定encodingutf-8拿到Windows上就会崩。解决凡是open()打开文本/标注的地方统一加encodingutf-8with open(annotations.json, r, encodingutf-8) as f: data json.load(f)如果文件的编码本身混乱既有UTF-8又有ANSI先用记事本打开另存为UTF-8格式再跑程序。这里提醒一下不要用errorsignore会跳过解码失败的内容轻则漏标注重则后续数组长度对不上直接崩溃。6. 照片/视频/摄像头统一验证跑通一条检测命令的技巧6.1 同一条命令切换输入源三行命令覆盖全部演示场景原工程的结果演示分成照片、视频、实时三种场景很多初学者以为要写三套代码其实detect.py和pose_estimation.py只需要一个source参数切换输入源。# 图片传入文件路径即可 python detect.py --source test.jpg --weights weights/yolov5s.pt --save-txt # 视频传入mp4文件路径 python detect.py --source test.mp4 --weights weights/yolov5s.pt --save-vid # 实时摄像头数字0表示第一个摄像头 python detect.py --source 0 --weights weights/yolov5s.pt --view-img--source 0是OpenCV的摄像头索引笔记本可能有内置和外接两个摄像头外接的索引通常是1。如果传0后窗口是黑的换--source 1测试。--save-txt会把每帧检测到的关键点坐标写成txt这个文件可以用来做后续的精度评估或关键点轨迹分析。6.2 手头没有现成资源时的验证清单没有摄像头和视频素材时不用干等用网络上的公开测试图就能验证模型加载是否正常。验证顺序建议按表格逐项排查避免模型没问题却误判成代码bug。检查项命令/操作期望结果权重加载python -c import torch; modeltorch.load(weights/yolov5s.pt, map_locationcpu); print(ok)打印ok不报错图片推理python detect.py --source test.jpg生成runs/detect/exp/test.jpg画有人体框关键点输出python pose_estimation.py --source test.jpg --export-kpts控制台打印17个关键点坐标数值在图片尺寸范围内视频流畅度python pose_estimation.py --source test.mp4 --view-imgFPS能上10以上画面不卡成幻灯片多人场景找一张两三个人站一起的合照每个人都被框出并绘制独立骨架多人场景是避不开的检验点YOLOv5检测出三个人HRnet就必须有三套关键点坐标。如果发现只有一个人有骨架大概率是pose_estimation.py里对检测框的循环提前break了。检查for box in boxes:这段代码后面有没有多余的break或return。我从第一次跑这个工程栽了跟头之后每次换机器或换数据集都会强制走一遍上述清单先权重、后图片、再视频最后才上摄像头。整个过程不超过十分钟但能节省下来调bug的往往是以小时计的。这套工程文件的价值不在于模型多复杂而在于整个检测→裁剪→关键点回归→绘制的链路完整且可跑通希望你拿到后也能顺利复现。本文还有配套的精品资源点击获取
网站建设高端定制企业官网