简介:面向需要快速实现图片或视频人体姿势识别功能的Python开发者,资源包提供了一套基于YOLOv8s-pose的完整可运行方案。压缩包共4个文件,包括预训练模型文件(.pt)、可直接执行的Python脚本(.py)以及两张姿态识别效果示意图(.png),整体大小仅31.33MB,结构简洁、便于快速部署。该模型能够准确识别站立、坐下、跑步、跳跃等常见人体姿态,并输出面部与躯体关键点位置;既可直接用于图片或视频推理,也可作为基础模型进行迁移学习,适配运动分析、康复训练监测、虚拟现实交互等场景。例如在运动分析中辅助教练评估动作标准度,在医疗康复中监测训练动作是否正确,在虚拟现实应用中捕捉用户身体动作以增强沉浸感。脚本中包含完整调用流程与示例,下载解压后即可运行验证,免去繁琐的环境配置。目前已有559人浏览学习,对于希望低成本上手姿态识别项目或参考YOLOv8预训练模型调用方式的开发者,这套方案具备明确的使用价值。
1. 人体姿势识别就该用 YOLOv8 的 pose 模型:先说结论
做人体姿势识别,最怕的不是算法选错,而是模型跑不起来、代码改不动、效果调不出。YOLOv8 的预训练 pose 模型正好卡在这个痛点上:官方把权重和推理代码绑在同一个库里,下载即用,图片和视频通吃,Python 代码十几行就能跑通。这套方案的真正价值在于,它把「标注骨架、训练关键点、调 NMS」这些脏活全部封装成现成接口,让做动作分析、健身纠错、安防行为识别的人不用从零造轮子。我实测下来,哪怕机器上没有显卡,CPU 跑单人视频也能到实时。这篇笔记就把从环境配置到完整运行代码、再到调参与踩坑的路径一次讲透,适合想快速验证效果又不想折腾底层的开发者和研究者。
2. YOLOv8-pose 模型到底能识别什么:关键点定义与选型理由
2.1 人体姿态估计在解决什么问题
人体姿势识别本质上是在做「关键点检测」。给定一张图片或一帧视频,模型要输出每个人体的骨架信息,通常是一组关节坐标和对应置信度。YOLOv8-pose 采用的是 COCO 的 17 个关键点定义,从鼻子、眼睛、耳朵,到双肩、双肘、双腕、双髋、双膝、双踝,覆盖了人体运动分析的主流需求。你要做的是拿到这 17 个点的坐标,再根据自己的业务去算角度、距离、动作分类,模型本身不负责理解「这个姿态是什么动作」。
不少刚开始接这个任务的人会把人脸关键点检测和人体姿态估计搞混。人脸关键点模型只关注脸部区域的几十个点,而人体姿态估计需要处理全身结构、肢体遮挡、多人交叉、尺度差异,难度不在一个量级。YOLOv8-pose 的优势是把目标检测和关键点检测放在同一个网络里端到端完成,先检测出人体框,再在框内预测 17 个关键点,这比先检框再裁图送第二个模型的做法少一次误差传播。
常见的做法是用 Ultralytics 官方开源的预训练权重直接推理,这也是目前从业者用得最多的姿势识别落地路径。官方提供了 n、s、m、l、x 五个规格的预训练模型,统一用 COCO 数据集训练,涵盖的类别就是「person」。针对可穿戴设备、边缘盒子、服务器 GPU 的不同算力,选型逻辑完全不同,规格选错会导致「能跑但太卡」或者「很流畅但骨架乱跳」的尴尬。
2.2 五个预训练模型怎么选:算力与精度的权衡表
YOLOv8 的 pose 系列预训练权重在 Ultralytics 的模型仓库里都有对应链接,文件名规则是yolov8{n,s,m,l,x}-pose.pt。下载后第一次调用时,库会自动加载权重并完成初始化,不需要手动配置网络结构。
| 模型规格 | 尺寸(像素) | 关键点数量 | 适合设备 | 我一般用它做什么 |
|---|---|---|---|---|
| yolov8n-pose | 640 | 17 | CPU / 树莓派 | 快速验证、低算力demo |
| yolov8s-pose | 640 | 17 | 入门级独显 | 实时视频流 |
| yolov8m-pose | 640 | 17 | 中端GPU | 健身动作分析 |
| yolov8l-pose | 640 | 17 | 高端GPU | 精度优先的离线批处理 |
| yolov8x-pose | 640 | 17 | 多卡服务 | 比赛级关键点精度 |
我的个人习惯是:先用yolov8n-pose.pt跑通整个代码链路,确认数据流没问题后,再按业务精度要求逐级往上换。不要一上来就追求最大模型,因为大模型在小目标、遮挡场景确实更稳,但推理延迟成倍增加,很多时候换到 m 级别就够了。关键点置信度输出在keypoints对象里,每个人体实例都有一个17×3的数组,前两列是坐标,第三列是置信度,后面写代码时你会反复用到这个结构。
2.3 推理数据流:从图像输入到 17 点骨架的完整路径
把一张图片喂给 YOLOv8-pose,内部数据流大致是:图像预处理(缩放、归一化)→ 骨干网络提取特征 → 检测头输出人体框和类别得分 → 关键点头输出每个人体的 17 个点坐标和可见度 → NMS 去除重叠框 → 输出Results对象。你在外面看到的只是一行model(img),但理解这五步对后面调参很重要,尤其是 NMS 这一步,它直接决定了拥挤场景下骨架会不会「串人」。
拿到结果后,我习惯先把result.keypoints.data的形状打印出来,确认检测到了几个人、每个点是否有效。对于单独一个人的场景,形状通常是(1, 17, 3);如果画面里没人,第一维会是 0,代码里必须做空结果判断,否则下一步绘制骨架直接报错。这个检查在视频流里尤其关键,因为视频中总有若干帧是空帧或模糊帧。
需要注意,YOLOv8-pose 输出的人体框是经过 NMS 过滤的,默认置信度阈值大概是 0.25 左右。当画面中人体大量重叠、互相遮挡时,模型会倾向于只保留高置信度的实例,低置信度的直接丢框。这时不是模型「识别不到人」,而是默认阈值把低分结果滤掉了,后面会在避坑章节详细说这个调参问题。
3. 环境准备与最小可运行代码:从零到跑通一张图
3.1 虚拟环境与依赖安装:版本选择的三个关键点
接这个项目的第一道坎不是模型原理,而是 Python 环境能不能装干净。我见过太多翻车案例:有人直接用系统 Python 装包,装到一半发现numpy版本被其他项目改掉,模型推理结果全变成 NaN;有人图省事用pip install ultralytics一把梭,结果 torch 版本和 CUDA 不匹配,GPU 不可用只能跑 CPU。这些都是环境问题,不是模型问题。
我一般会在项目根目录新建一个独立的虚拟环境,专门给这个姿势识别项目用,避免和 web 开发、爬虫等其他任务互相污染。命令如下:
python -m venv venv_pose # Windows 用户 venv_pose\Scripts\activate # macOS / Linux 用户 source venv_pose/bin/activate pip install ultralytics opencv-python这段命令做的事情是:创建名为venv_pose的虚拟环境,激活后再安装两个核心包。ultralytics会连带安装torch、torchvision、numpy、opencv-python等一堆依赖,所以后面那个opencv-python其实往往已经装好了,显式写上只是为了确保后续读写视频时不会缺编解码器。
如果你机器有 NVIDIA 显卡,建议提前用官网的 pip 命令装对应的 CUDA 版 torch,再装 ultralytics,否则 ultralytics 默认拉取的 torch 可能是 CPU 版。反过来,如果你只有 CPU,就不用折腾 CUDA 了,CPU 版 torch 跑yolov8n-pose在单人视频上也能到达 1 秒 2 到 3 帧的水平,做离线分析完全够用。
3.2 一张图片的最小推理脚本:十行代码拿到骨架坐标
环境配好之后,不要急着写业务逻辑,先用最简脚本把模型跑起来,确认权重能加载、结果能解析。我习惯在工作目录建一个quick_test.py,内容如下:
from ultralytics import YOLO # 初始化预训练模型,首次运行会自动下载权重到当前目录 model = YOLO("yolov8n-pose.pt") # 推理单张图片,保存结果到 runs/pose/predict results = model("demo.jpg") # 取出第一个结果中的关键点数据 keypoints = results[0].keypoints.data print("关键点形状:", keypoints.shape) print("第一个人左肩坐标:", keypoints[0][5])这段代码的逻辑很简单:第一行创建模型对象并加载预训练权重,第二行传入图片路径执行推理,最后打印关键点数组的形状和一个人体实例的某个关键点坐标。注意keypoints[0][5]中第二个索引对应 COCO 17 点序号,5 号点是左肩。
跑通后你应该看到类似关键点形状: torch.Size([1, 17, 3])的输出,其中第一维是检测到的人数。如果打印出来是[0, 17, 3],说明这张图没人,换张有人全身照再试。这一步验证通过,意味着你已具备继续做视频和批量处理的基础能力。首次运行会下载权重文件,网络慢的话会卡在进度条上,后面我会讲预下载的后悔药。
3.3 结果对象里有什么:可视化与坐标解析的必备字段
results这个对象是理解整个输出的钥匙,第一次接触的人经常被它绕晕。它不是简单的数组,而是一个Results列表,每个元素对应一张输入图片。每一张图的对象里有boxes、keypoints、names、speed这几个常用属性,其中boxes.xyxy保存人体框坐标,keypoints.data保存关键点坐标,names是人脸类别名称映射。
想把结果可视化存图,官方封装好的plot方法最省事,它会自动把人体框、骨架、关键点画在图上并返回 BGR 格式的图片数组。然后配合 OpenCV 的imwrite存到本地。代码如下:
import cv2 from ultralytics import YOLO model = YOLO("yolov8n-pose.pt") results = model("demo.jpg") # 绘制结果并保存 annotated = results[0].plot() cv2.imwrite("demo_annotated.jpg", annotated) # 同时保存原始尺寸图 cv2.imwrite("demo_raw.jpg", results[0].orig_img)plot()返回的图片和原图尺寸一致,不会因为模型内部把图缩放到 640 就改变输出尺寸,这一点官方处理得比较贴心。实际项目中如果要做二次开发,比如把关键点坐标传给骨骼动画程序,你会更常用keypoints.data.cpu().numpy()转成 NumPy 数组来用,因为 PyTorch 张量在 GPU 上时无法直接被普通数据处理库读取。养成转 NumPy 的好习惯,后面写视频处理会少踩很多坑。
4. 图片与视频的人体姿势识别完整代码:可直接运行的 Python 脚本
4.1 图片批处理代码:多张图一次推理并输出 JSON
很多人拿到模型后的第一个需求不是跑单张图,而是批量处理一个文件夹里的图片,并输出每张图每个人的关键点坐标用于后续分析。下面的脚本把这一需求完整实现,同时把可视化结果和结构化数据都落盘。
import cv2 import json import glob from ultralytics import YOLO model = YOLO("yolov8n-pose.pt") image_paths = glob.glob("images/*.jpg") for img_path in image_paths: results = model(img_path, conf=0.3, verbose=False) result = results[0] # 保存可视化结果 annotated = result.plot() out_path = img_path.replace("images/", "outputs/annotated_") cv2.imwrite(out_path, annotated) # 解析关键点数据并保存为 JSON keypoints = result.keypoints.data.cpu().numpy() boxes = result.boxes.xyxy.cpu().numpy() data = [] for i in range(len(boxes)): person = { "image": img_path, "box": boxes[i].tolist(), "keypoints": keypoints[i].tolist() } data.append(person) json_path = img_path.replace("images/", "outputs/keypoints_") json_path = json_path.replace(".jpg", ".json") with open(json_path, "w") as f: json.dump(data, f, indent=2) print("批量处理完成")这段代码的核心逻辑是循环读取images目录下所有 JPG 图片,对每张执行推理,然后兵分两路:一路画图存到outputs/annotated_开头的新文件,另一路把人体框和关键点转成 Python 列表,存成同名 JSON 文件。conf=0.3是置信度阈值,低于 0.3 的检测结果会被过滤,这个值在实际项目中很重要,后面会展开讲。
注意我在代码中对路径字符串做了 replace 操作,这是为了保持输入输出目录分离。如果你输入的图片是 PNG 格式,replace(".jpg", ".json")这一行就匹配不到,建议改用os.path.splitext切后缀再拼接,会更稳妥。另外,keypoints[i].tolist()对每个关键点是包含 3 个值的子列表,第三个值就是置信度,后续算夹角时可以直接穿透这个值做加权。
4.2 视频推理代码:实时处理 MP4 并保存结果视频
视频场景是姿势识别的主要落地场景,比如健身动作分析、体测视频评分、监控录像离线分析。视频推理相比图片多了一个时间维度,需要处理帧读取、累积追踪、性能优化的问题。下面是一个完整的视频处理脚本,把输入视频转换成带骨架标注的输出视频,同时控制推理频率避免 CPU/GPU 过载。
import cv2 from ultralytics import YOLO model = YOLO("yolov8n-pose.pt") cap = cv2.VideoCapture("input.mp4") # 读取视频参数 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_pose.mp4", cv2.VideoWriter_fourcc(*"mp4v"), fps, (width, height) ) frame_count = 0 while True: ret, frame = cap.read() if not ret: break frame_count += 1 # 每隔一帧推理一次,减少计算压力 if frame_count % 2 != 0: continue results = model(frame, verbose=False) annotated = results[0].plot() writer.write(annotated) # 在窗口显示,按 q 退出 cv2.imshow("pose", annotated) if cv2.waitKey(1) & 0xFF == ord("q"): break cap.release() writer.release() cv2.destroyAllWindows() print("视频处理完成,已保存 output_pose.mp4")这个脚本里最关键的优化是frame_count % 2 != 0时直接跳过推理。视频帧率通常 25 到 30,人的动作变化在相邻帧之间极小,逐帧推理浪费算力且输出视频反而会因为推理时间不均出现卡顿感。跳帧后每秒推理 12 到 15 帧,视觉上完全流畅。
cv2.VideoWriter_fourcc(*"mp4v")用的是 MP4V 编码,兼容性不错,但在部分 Linux 环境下写出的视频可能打不开,这时换成"MJPG"编码并把输出文件名后缀改为.avi是最快的解法。显示窗口部分只适合本地调试,服务器部署时建议把imshow注释掉,否则没有桌面环境的机器直接报错。
4.3 推理参数的具体作用:conf、iou、device、verbose 一次说清
处理代码里出现的几个推理参数值得单独拉出来讲透,因为它们直接影响结果质量和运行速度。conf是最重要的一个,它控制检测框置信度阈值,默认 0.25,意思是模型认为某个区域有人的概率低于 25% 就丢弃。调低到 0.1 能找回大量被遮挡的人体,但误检也会增多,比较玄学的是调参效果在不同场景差异极大,我一般先固定在 0.3 观察效果再微调。
iou是 NMS 的 IoU 阈值,默认 0.7。它决定两个高度重叠的框是合并还是保留,值越小对重叠框的抑制越强。多人密集场景,比如地铁车厢里人贴人,iouv 调低到 0.5 能减少单人出多个框的问题,但有可能把一前一后两个人误并成一个。我的习惯是保持默认,除非某种场景下明显出现「一个人两条骨架」的诡异画面才去动它。
device参数控制推理设备,device="cpu"强制用 CPU,device="0"用第一个 GPU。verbose=False可以关掉推理日志,批量跑很多文件时不至于刷屏。给一个综合调参的调用示例:
results = model( "demo.jpg", conf=0.3, iou=0.5, device="0", verbose=False )这套参数组合在单人全身照、多人稀疏、户外监控三个场景都是不错的起点。记住核心原则:先固定 conf,再调 iou,最后才考虑换更大模型。顺序反了会浪费时间在无效尝试上。
5. 避坑指南:YOLOv8-pose 跑不通的 5 个高频问题排查
5.1 装环境时 ultralytics 导入报错:Python 版本与依赖冲突
现象:按教程装完包,import ultralytics直接抛ModuleNotFoundError或OSError,有时候是numpy版本不兼容,有时候是缺lap库。最典型的场景是 A 同学在 Python 3.12 下安装,torch还没正式支持该版本,导致一系列依赖装不上。
原因:ultralytics 对 Python 版本有门槛,过新或过旧都会翻车。3.12 刚发布时很多扩展包没跟上,3.7 又太老跑不动新权重。
解决:切换到 Python 3.9 或 3.10 建虚拟环境,然后先装 torch,再装 ultralytics,顺序不能反。装完之后跑一句python -c "from ultralytics import YOLO; print('ok')"验证导入没问题再继续写代码。如果仍报错,把pip list里 numpy 卸载重装为 1.26 以下的版本。
5.2 视频推理卡顿且显存持续上涨:没有控制帧率和 batch
现象:单张图片推理很快,一上视频就卡得没法看,显卡显存占用随运行时间线性增长,最后直接 OOM。
原因:显存上涨不是因为模型变大,而是视频阅读速度跟不上推理速度,cap.read() 不断读帧塞进队列,推理端消化不掉,同时 OpenCV 的缓冲区没有自动清理,内存越堆越高。
解决:代码里加入跳帧机制,同时把输入帧 resize 到模型输入大小附近。另一个有效做法是用固定间隔读取:cap.set(cv2.CAP_PROP_POS_FRAMES, frame_count)直接跳帧,而不是cap.read()逐帧读后再抛弃。显存方面,如果用的是 GPU,在循环里把results[0].keypoints.data.cpu().numpy()及时释放引用,避免结果对象一直留在显存里。
5.3 画面里有人但模型一个框都没输出:置信度阈值误伤
现象:跑一张灯光偏暗、人体偏小或者人物处于画面边缘的图片,模型返回空结果,但人眼明明能看到人。
原因:默认conf=0.25在理想光照下没问题,一旦场景复杂度上升,推理置信度掉到 0.1 以下,框就被滤掉了。这不代表模型「看不见」,只是分数不够高。
解决:把 conf 降到 0.1 重试,观察骨架是否出现。如果低阈值下骨架抖动明显,说明确实有检测但质量不高,此时更好的解法是换yolov8m-pose或yolov8l-pose,而不是继续压低阈值。阈值降到 0.05 以下得到的通常是大量误检,骨架错乱到没法看。
5.4 输出的视频文件打不开或没有画面:编码器不兼容
现象:推理完成后输出视频文件存在,但用播放器打开黑屏,或者直接提示无法解码。Windows 上常见,Linux 上也会偶发。
原因:mp4v编码器在部分环境中不可用,或者 OpenCV 自带的编码器不支持高分辨率写帧。另一个隐蔽原因是写出的视频尺寸与输入不一致,导致播放器无法解析。
解决:把 VideoWriter 的编码换成MJPG,输出文件名改为.avi,这是最稳的组合,缺点是文件大一点。如果想保留 MP4,可以改用avc1编码(H.264),但需要系统有对应的编码器。我自己的项目里通常默认用.avi出中间结果,确认无误后再用 FFmpeg 转压成 MP4,反而少折腾。
5.5 CPU 推理模型下载卡在进度条不动:首次加载权重慢
现象:第一次执行model("demo.jpg")时,终端显示进度条停在某个百分比很长时间,看起来像死机,等了几分钟后才继续。
原因:首次运行需要下载预训练权重,yolov8n-pose.pt 大概 40 多 MB,如果网络不稳定或资源被墙,下载会反复重试,观察起来就像卡死。
解决:提前手动下载权重文件放到工作目录,再用本地路径初始化模型。具体做法是用浏览器或命令行工具把.pt文件下载到项目根目录,之后代码里写YOLO("yolov8n-pose.pt")时会直接命中本地文件,不再走下载流程。这个小习惯能省不少等待时间。
6. 进阶技巧:把姿态数据输出成结构化 JSON 并做动作角度分析
跑通基础推理后,下一步自然是把数据接进自己的业务。「输出骨架图」只是第一步,真正能用的是关键点坐标。这里我给一个实用的进阶代码模板:读取视频里每一帧的人体关键点,计算肘关节角度,并把「角度随时间的变化」保存下来。这个方案可以直接迁移到健身动作计数、康复训练评估等场景。
import cv2 import numpy as np from ultralytics import YOLO model = YOLO("yolov8s-pose.pt") cap = cv2.VideoCapture("squat.mp4") # 肩、肘、腕三个关键点的 COCO 索引 SHOULDER, ELBOW, WRIST = 5, 7, 9 def calc_angle(a, b, c): a = np.array(a[:2]); b = np.array(b[:2]); c = np.array(c[:2]) ba = a - b bc = c - b cos_angle = np.dot(ba, bc) / (np.linalg.norm(ba) * np.linalg.norm(bc)) return np.degrees(np.arccos(np.clip(cos_angle, -1.0, 1.0))) angle_history = [] while True: ret, frame = cap.read() if not ret: break results = model(frame, verbose=False, conf=0.4) if len(results[0].keypoints.data) == 0: continue kpts = results[0].keypoints.data[0].cpu().numpy() angle = calc_angle(kpts[SHOULDER], kpts[ELBOW], kpts[WRIST]) angle_history.append(angle) cap.release() print("角度序列已记录,共", len(angle_history), "帧有效数据")这段代码里的核心函数calc_angle接受三个关键点坐标,先转成二维坐标忽略置信度,然后根据向量点积算出中间关节的角度。角度随帧变化的数据如果拿来画曲线,就能很直观地看出动作节奏是否平稳。
我自己第一次拿这串代码做深蹲分析时,最大的教训是坐标抖动:即使人站在原地不动,模型输出的肩膀坐标也会在几个像素间跳动,导致角度曲线毛刺很多。后来习惯加一个滑动平均窗口,把前后 5 帧的角度平均后再绘图,曲线立刻平滑很多。这也是从「能跑」到「能用」的一次关键优化。希望这篇笔记能帮你把 YOLOv8-pose 这条技术路线快速落地,少走我走过的弯路,祝你的项目一次跑通。
本文还有配套的精品资源,点击获取