☰
YOLOv8人体姿态识别实战:预训练模型与Python推理代码全解析
2026/10/4 22:55:13 网站建设 项目流程

简介:面向Python开发者与计算机视觉初学者的YOLOv8人体姿势识别资源包,可直接用于图片或视频中的人体关键点检测,也可作为基础预训练模型继续微调,帮助快速建立属于自己的姿态估计流程。压缩包共4个文件,整体约31.33MB,内部包含一个预训练权重文件、一个完整的Python推理脚本,以及两张分别用于原图对比和效果验证的PNG图片,兼顾了模型权重复现与运行示例。目前已有559人浏览学习,内置的唐朝诡事录经典站位图识别演示展示了多人体同时检测能力,能够准确识别面部与躯体关键点,方便使用者直观评估模型精度。得益于开箱即用的脚本设计和紧凑的包体结构,用户下载后只需准备基础Python环境即可快速运行并查看识别结果,还可以参考代码结构将识别能力接入运动分析、医疗康复或虚拟现实等项目;若需特定动作识别,还能进一步使用自定义数据对现有模型进行再训练,以适配不同场景需求。这一设计同时适用于快速原型验证与初步部署,为个人学习或团队开发节约大量调试验证时间。

1. 人体姿势识别选型:为什么是 YOLOv8 预训练模型而不是从头训练

做人体姿势识别,最容易被绕进去的一个念头是「我要自己搭网络、自己找数据、自己训练」。作为跑过几轮完整训练流程的人,我得先泼一盆冷水:如果你不是要发论文、不是有特殊骨骼点定义,只是想把「图片/视频里的人的姿势」稳定识别出来,直接用 YOLOv8 预训练模型 + Python 推理代码,是投入产出比最高的路线。YOLOv8 官方提供的 pose 预训练权重在 COCO 关键点数据集上训过,覆盖 17 个身体关键点,单张图片推理在 CPU 上也能跑到百毫秒级,换 GPU 更是快到可以按帧处理视频。这个资源的核心就是把这条路线完整打包好了:模型权重文件、整套可运行的 Python 推理代码,图片和视频两条输入路径都能直接跑通,不需要你再碰训练流程。

适合谁用?一类是刚接触姿态识别的 Python 开发者,想先看到一个能出结果的项目;另一类是做安防、健身计数、人机交互原型的工程师,需要一个能快速集成到现有 Python 工程里的推理模块。适合的前提是你懂基础 Python 语法,会装依赖。下面我从环境准备讲起,把模型加载、图片推理、视频推理和排错全部过一遍。

2. 环境准备与模型加载:Python 侧依赖安装和 pose 权重文件

2.1 为什么依赖集中在 ultralytics 这一个库上

YOLOv8 的官方实现在 ultralytics 这个 Python 包里。跟早期 YOLO 系列要手动拼一堆 OpenCV 和 PyTorch 代码不同,YOLOv8 把模型定义、权重加载、前处理、后处理、NMS、关键点解码全部封装在库里了,对外暴露的接口非常薄。这对做应用的工程师来说是个大好事:你不用关心 17 个关键点的热力图是怎么解码出来的,只要把图片传进去,拿回来的结果里就有每个检测框、每个关键点的坐标和置信度。

安装上,老手可能直接 pip install ultralytics,但我建议新手先确认 Python 版本。这个库对 Python 3.8 以上支持比较稳,3.7 以下容易遇到依赖冲突。另外 ultralytics 会依赖 PyTorch,如果你机器上有 NVIDIA 显卡,建议先装好 CUDA 版 PyTorch 再装 ultralytics,否则它会默认拉 CPU 版 torch,后面视频按帧跑会很吃力。

# 先确认 Python 版本,3.8 ~ 3.11 之间最稳 python --version # 有 NVIDIA GPU 的话,先装 CUDA 版 PyTorch(以 cu118 为例) pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 再装 ultralytics,它会自动带上依赖的 opencv-python、numpy 等 pip install ultralytics

这段逻辑里有两个关键决定:先装 torch 是为了避免 ultralytics 安装时把 CPU 版 torch 当依赖拉进来;用 cu118 的 index-url 是因为 PyTorch 官方源把不同 CUDA 版本的 wheel 分开存放了,不加这个参数在 Windows 上很容易装成 CPU 版本。装完后可以用 python -c "import torch; print(torch.cuda.is_available())" 验证 GPU 是否可用,输入 True 说明显卡被正确识别。

2.2 模型文件到底长什么样:yolov8n-pose.pt 与自动下载机制

姿势识别用的权重文件和普通目标检测不一样,文件名带 pose 标记,常见的几个规格是 yolov8n-pose.pt、yolov8s-pose.pt、yolov8m-pose.pt,n 是 nano 最小版,m 是中等精度版。n 版权重只有 6MB 左右,CPU 上跑得快;m 版精度更高但推理时间翻几倍。

这个资源里默认用的是 yolov8n-pose.pt。你第一次调用 YOLO('yolov8n-pose.pt') 时,如果本地不存在这个文件,ultralytics 会自动去官方 GitHub 下载。这个机制在联网顺畅时很省事,但有两个隐患:一是网络差的地方会卡住不报错,二是下载到哪个目录你不知道的话排查困难。本地缓存路径是 ~/.cache/ultralytics(Windows 上是 C:\Users\你的用户名\AppData\Local\ultralytics\),确认文件是否存在可以用 ls 看一下。

from ultralytics import YOLO # 模型文件若不存在会自动下载到本地缓存目录 model = YOLO('yolov8n-pose.pt') # 打印模型结构,确认是 pose 模型而不是 detect 模型 print(model.task) # 输出应该是 'pose'

这里 model.task 输出 pose 是重要自检点。如果你下错成普通检测模型,task 字段会是 detect,后面拿不到关键点数据,报错方式还挺隐晦——results 对象里没有 keypoints 属性。文件命名里带 n 的版本参数量是 3.2M,对应 COCO 预训练权重;如果换 s 或 m 版本,后面推理时把模型加载路径改成对应 .pt 文件名就行,其余代码不用改。

2.3 验证推理链路最快的方法:单张图片跑通

环境装好后的第一件事,不是直接跑视频,而是先拿单张图片把推理链路打通。这里最怕的情况是模型加载成功、但推理时爆出一堆底层库错误,比如 OpenCV 解码异常或者 torch 张量设备不匹配。先跑一张图,把变量范围缩到最小。

from ultralytics import YOLO model = YOLO('yolov8n-pose.pt') results = model('test.jpg', save=True) print(results[0].keypoints.data.shape) # 期望输出形状 torch.Size([1, 17, 3])

save=True 会把标注好骨架的图片保存在 runs/pose/predict 目录下,默认命名是原文件名加下划线。keypoints.data 这个属性在后续代码里会经常用到,它存的就是每个检测到的行人对应的 17 个关键点坐标和置信度,形状是 [检测人数, 17, 3],最后一维的 3 分别是 x 坐标、y 坐标、置信度。如果这个 shape 打印出来不符合预期,要么图片里没人,要么模型权重加载错了。到这里,单张图片的推理链路就算验证完成了。

3. 图片推理代码拆解:一行代码出骨架,关键点坐标怎么读

3.1 单图片推理的完整流程:加载、推理、绘制、保存

直接调用 model('图片路径') 在代码层面只有一行,但实际落到工程里,我们需要的是能拿到「人体检测框 + 关键点坐标 + 骨架绘制图」的完整结果。下面这段代码演示了最常用的图片推理写法,带详细参数控制。

from ultralytics import YOLO model = YOLO('yolov8n-pose.pt') results = model.predict( source='input.jpg', conf=0.5, # 关键点置信度阈值,低于该值的点会被过滤 iou=0.45, # NMS 的 IoU 阈值,调大允许更多重叠框保留 device='cpu', # 没 GPU 时指定 cpu,有 GPU 可改成 0 save=True, # 保存标注后的图片 project='pose_output', # 输出目录名 name='image_result', # 子目录名 exist_ok=True # 允许重复写入同名目录 ) keypoints_data = results[0].keypoints.data boxes = results[0].boxes.xyxy print(f"检测到 {len(boxes)} 个人,关键点张量形状: {keypoints_data.shape}")

predict 方法和直接调用 model 的区别在于 predict 暴露了全部推理参数,适合工程化场景。conf 参数很关键,默认值是 0.25,但实际做姿势识别时 0.4 到 0.5 体验更好,低了会出现大量抖动点;iou 参数控制两个检测框的合并策略,默认 0.7 针对密集人群会漏检,我一般调到 0.45 到 0.5。device 参数建议显式指定,否则 ultralytics 会自己探测,在部分机器上会出现「有显卡但没装好 CUDA 导致崩掉」的情况。

3.2 关键点坐标的含义:COCO 17 点索引表与置信度过滤

拿到 keypoints_data 只是第一步,你得知道每个索引对应身体哪个部位。YOLOv8 的 pose 模型沿用 COCO 数据集的关键点定义,17 个点的索引顺序是固定的:0 鼻子、1 左眼、2 右眼、3 左耳、4 右耳、5 左肩、6 右肩、7 左肘、8 右肘、9 左腕、10 右腕、11 左髋、12 右髋、13 左膝、14 右膝、15 左踝、16 右踝。这个顺序不少人在第一次拿数据时吃过亏,因为它既不是从头到脚的排列,也不是从左到右的排列,左右是混着来的。

实际代码里,你需要根据置信度把不可靠的点过滤掉。COCO 数据集中标记为不可见的点,模型输出的置信度会极低,如果不过滤直接用于距离计算,算出来的关节角度会非常离谱。

import torch keypoints = results[0].keypoints.data # [人数, 17, 3] for person_idx in range(keypoints.shape[0]): person_kpts = keypoints[person_idx] for kpt_idx in range(17): x, y, conf = person_kpts[kpt_idx] if conf < 0.5: print(f"行人 {person_idx} 的 {kpt_idx} 号点(左肩)置信度过低,忽略") continue print(f"行人 {person_idx} 的 {kpt_idx} 号点坐标: ({x:.1f}, {y:.1f}), 置信度: {conf:.2f}")

这段代码的核心在 torch 张量的索引方式上:person_kpts[kpt_idx] 拿到的是一维张量,直接解包成 x、y、conf 三个变量。注意这里的坐标是原始图片像素坐标,不是归一化坐标,所以用的时候可以直接拿来在图上画点,或者换算成像素距离。部分场景下你会需要归一化坐标,可以用 results[0].keypoints.xyn 拿到,它是 xy 坐标除以图片宽高后的结果,范围在 0 到 1 之间,适合做姿态对比时消除图片尺寸影响。

3.3 骨架连线与检测框绘制:plot 方法的输出对象

上面用 save=True 保存图片,底层其实是 ultralytics 调用了 results[0].plot() 方法。这个方法返回一个 numpy 数组格式的图片,骨架连线逻辑已经内置好了,比如左肩到左肘、左肘到左腕会自动连起来。如果你想在保存之前对标注结果做二次加工——比如叠加自己的文字、画特殊的区域标注,就需要先拿到 plot() 的返回值再处理。

import cv2 from ultralytics import YOLO model = YOLO('yolov8n-pose.pt') results = model('input.jpg') annotated_frame = results[0].plot() # 返回 BGR 格式的 numpy 数组 cv2.imwrite('annotated_custom.jpg', annotated_frame) # 在图上额外叠加一个提示文字 cv2.putText(annotated_frame, 'pose detected', (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) cv2.imwrite('annotated_with_text.jpg', annotated_frame)

plot() 返回的数组就是 OpenCV 的 BGR 三通道图,可以直接用 cv2.imwrite 保存。就算你不想用 OpenCV 做额外处理,理解 plot 这个方法也有价值,因为视频推理里每一帧都要调用一次 plot(),把返回值填到 VideoWriter 里,才能生成带骨架标注的视频。

4. 视频推理代码实战:按帧处理的人体姿势识别流程与性能平衡

4.1 直接调用 predict 做视频推理的写法与它的局限

视频推理最省事的写法是直接把视频文件路径传给 model.predict,ultralytics 会自己拆帧、推理、合成输出视频。但这有个前提——你的视频文件格式是它支持的常见编码,比如 H.264 编码的 mp4。如果遇到特殊编码,或者视频很长导致内存不够,直接传路径就不够稳了。另外这种方式对每帧都做完整推理,不做任何跳帧处理,帧率低且文件特别大。

from ultralytics import YOLO model = YOLO('yolov8n-pose.pt') results = model.predict( source='input_video.mp4', conf=0.5, save=True, project='pose_output', name='video_result' )

这种写法适合快速验证模型在视频上的效果,输出文件默认在 pose_output/video_result 目录下。局限很明显:你不能在推理过程中干预单帧结果,比如视频里出现特定姿态时你想在那一帧额外叠加报警信息;也不能做跳帧处理。所以真正做项目时,我一般不用这种写法,而是用 OpenCV 自己拆帧,再逐帧喂给模型。

4.2 逐帧处理的标准循环:VideoCapture 与 VideoWriter 配合

自己拆帧的好处是每一帧的结果都在你手里,你可以做目标跟踪、计数、姿态判断或者自定义画框逻辑。核心是把 OpenCV 的读取循环和 ultralytics 的推理结果拼在一起,下面是一个完整可跑的逐帧处理模板。

import cv2 from ultralytics import YOLO model = YOLO('yolov8n-pose.pt') cap = cv2.VideoCapture('input_video.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)) fourcc = cv2.VideoWriter_fourcc(*'mp4v') out = cv2.VideoWriter('output_video.mp4', fourcc, fps, (width, height)) frame_count = 0 while cap.isOpened(): ret, frame = cap.read() if not ret: break frame_count += 1 results = model(frame, conf=0.5, device='cpu') annotated = results[0].plot() out.write(annotated) # 处理进度提示 if frame_count % 50 == 0: print(f"已处理 {frame_count} 帧") cap.release() out.release() print(f"视频处理完成,共 {frame_count} 帧")

这段代码里值得说明的参数有三个:fourcc 用 mp4v 而不是 avc1 是因为 OpenCV 自带的 H.264 编码器支持不完整,mp4v 兼容性最好,代价是输出文件体积略大;VideoWriter 的尺寸必须和输入帧尺寸一致,否则 write 会静默失败,这是最常见的坑;device='cpu' 是我故意写的,方便没显卡的人直接跑,有 GPU 改成 0 会让处理速度快一个数量级。

4.3 性能平衡策略:跳帧、降分辨率、批处理

逐帧推理在 CPU 上处理 720p 视频,nano 模型大概每帧需要 80 到 150 毫秒,视频实际帧率可能只有 7 到 10 帧每秒,实时性不够。三个常用的优化手段:

第一是跳帧处理。人体姿势识别任务里,相邻两帧的骨架变化很小,没必要每帧都推理。每 3 帧推理一次,中间两帧直接复用上一帧的骨架数据,处理速度基本可以翻三倍。代价是快速动作下骨架会比画面慢半拍。

inference_interval = 3 # 每 3 帧推理一次 last_keypoints = None while cap.isOpened(): ret, frame = cap.read() if not ret: break frame_count += 1 if frame_count % inference_interval == 0: results = model(frame, conf=0.5) last_keypoints = results[0].keypoints.data else: # 中间帧不推理,沿用上一帧的骨架 if last_keypoints is not None: pass # 这里可以执行基于骨架的自定义逻辑

第二是降分辨率。把输入帧 resize 到 640 甚至 416 宽度再喂给模型,速度提升立竿见影,代价是远距离小目标容易漏检。适用于监控画面里人比较大的场景。第三是批处理。如果视频是离线处理不是实时流,可以把多帧拼成一个 batch 传给 model.predict,在 GPU 上能显著提升吞吐量,但 CPU 上收益不大。实际项目中我一般是「跳帧 + 降分辨率」组合用,实时性要求不高的场景直接逐帧搞定。

5. 常见问题避坑:模型下载、显存、关键点索引和视频编码

5.1 模型首次加载卡住不动,几十分钟没反应

现象:执行 YOLO('yolov8n-pose.pt') 后程序停在加载阶段,不报错也不继续,像死了一样。原因:ultralytics 在本地缓存目录找不到权重文件,触发了自动下载,下载过程没有进度条展示,网络慢或者被墙时就像卡死一样。解决:自己手动下载权重文件放到指定缓存目录。具体做法是用浏览器直接访问 ultralytics 的 GitHub release 页面下载 yolov8n-pose.pt,然后放到 ~/.cache/ultralytics 目录下。不放缓存目录也行,直接把模型文件放在项目里,用绝对路径加载 YOLO('/your_path/yolov8n-pose.pt'),这样最可控,也方便后续换不同规格的模型文件。

5.2 GPU 显存溢出或程序越来越慢,LZM 爆红

现象:单张图片推理正常,跑视频时程序显存占用不断增长,最后报 CUDA out of memory;或者不报错但速度越来越慢。原因:循环里没有释放上一帧的张量引用,推理结果累积在内存里;常见情况是 results 列表不断追加没有清空。解决:确认显存是否真的不够用,yolov8n-pose 在 640 分辨率下单帧推理只需约 2GB 显存,如果报 OOM,优先查代码里有没有把历史帧的 results 全部保存下来。处理逐帧视频时,每次循环结束把不再用的变量置 None,或者用 del results,再配合 torch.cuda.empty_cache() 主动释放缓存。

import torch # 在每一帧推理后调用 del results torch.cuda.empty_cache()

如果还不行,就把输入分辨率从默认 640 降到 480,或用 nano 模型,显存占用能降一半。

5.3 关键点画出来位置错乱:左右肩膀和左右肘对不上

现象:单张图片推理结果看起来骨架线乱七八糟,比如左肘连线到了右手腕;或者自己用 keypoints 坐标画点时位置和画面明显对不上。原因:COCO 17 点的索引是固定的,但你从代码里取坐标时把索引写错了。常见误区是想当然地认为 0 是左肩、1 是右肩——实际 0 是鼻子。另一个原因是没有乘缩放系数,输入给 model 前你把图片 resize 过,但用坐标时忘了映射回原图尺寸。解决:对照 17 点索引表逐个验证,打印出坐标后用 OpenCV 在图上画圆点核对位置,不要靠猜。涉及 resize 时,保存原图尺寸,用 (原图宽/输入宽) 和 (原图高/输入高) 两个缩放系数把关键点坐标换算回去。

5.4 视频推理输出文件打不开或只有几帧

现象:模型跑完了,输出 video 文件播放器打不开,或者文件只有开头几帧后面全黑。原因:VideoWriter 的编码器选择不对,或者写入帧的尺寸和初始化时不一致。mp4v 编码器写出的文件在部分播放器上兼容性差。解决:换 fourcc 用 avc1 配合 GPU 编码器,或者输出用 .avi 格式配 MJPG 编码器,兼容性最好。另外确认 write 的帧尺寸和 VideoWriter 初始化尺寸完全一致,一旦不一致,OpenCV 不会报错但写入会失败,最终文件损坏。工程里我会在写入前打印 frame.shape 对照检查。

5.5 虚拟环境装完 import 报错,提示某底层库不匹配

现象:pip install ultralytics 装好后,import 时报 DLL load failed、numpy 版本冲突或者 cv2 属性不存在。原因:Python 版本过老,或者本地已有旧版 numpy、opencv 与新版本冲突;Windows 上常见的是 torch 的 CUDA 运行时 DLL 路径问题。解决:优先在虚拟环境里重装,不要用系统 Python;锁定依赖版本安装,用 pip install ultralytics==8.2.0 这类明确版本号,避免装到刚发布的新版本踩兼容问题。若报 numpy 相关错误,用 pip install numpy --upgrade 强制升级到 1.26 以上的版本。

6. 验证与进阶:把关键点坐标用起来前,先做三个自检

模型跑通只是起点,真正把它集成进业务前,我建议先做三个自检,能省后面大量排查时间。

第一个自检是确认关键点坐标的比例关系。找一张人站在画面中间的图片,打印出左肩(索引 5)和右肩(索引 6)的坐标,计算两点连线的水平距离,再和鼻子(索引 0)到左肩的垂直距离做比较,正常人肩宽大约是头高的两倍左右。如果这个比例明显失调,说明你用的坐标不是像素坐标而是归一化坐标,或者模型加载错了。第二个自检是置信度分布检查。截取视频里连续 30 帧,统计每帧 17 个关键点的平均置信度,如果平均置信度长期低于 0.4,说明输入画面里人太小或者模糊,需要调大输入分辨率而不是模型参数。第三个自检是稳定性验证:同一段视频连续跑两次,逐帧对比关键点坐标是否有明显差异,正常情况下两次结果应该完全一致;如果不一致,说明代码里可能用了随机采样或者输入图片有随机增强,这对推理来说属于隐患。

自检通过后,一个实用的进阶方向是根据关键点坐标做简单的姿态判断。比如检测摔倒,最直接的特征是头部关键点(鼻子或眼睛)的 y 坐标突然大幅下降,同时髋部(索引 11 和 12)的 y 坐标变化不大,且这一状态持续了若干帧。从三个关键点的夹角计算关节弯曲程度,也是健身计数类应用的常见起点。

import math def calculate_angle(a, b, c): """计算三点之间的夹角,a 和 c 是端点,b 是顶点""" ab = (a[0] - b[0], a[1] - b[1]) bc = (c[0] - b[0], c[1] - b[1]) dot = ab[0] * bc[0] + ab[1] * bc[1] norm_ab = math.sqrt(ab[0] ** 2 + ab[1] ** 2) norm_bc = math.sqrt(bc[0] ** 2 + bc[1] ** 2) if norm_ab == 0 or norm_bc == 0: return 0.0 cos_angle = dot / (norm_ab * norm_bc) cos_angle = max(-1.0, min(1.0, cos_angle)) return math.degrees(math.acos(cos_angle)) # 例:计算右肘(索引 8)的弯曲角度 # right_shoulder = keypoints[6][:2], right_elbow = keypoints[8][:2], right_wrist = keypoints[10][:2]

这段代码后面可以接业务逻辑:比如肘关节角度在 15 到 35 度之间且持续 20 帧以上,判定为手臂弯曲动作,做俯卧撑计数的基础就是它。我的血泪经验是:不管你接了多复杂的业务逻辑,先强制自己走一遍「单张图坐标自检 — 置信度过滤 — 连续帧稳定性验证」这套流程,再谈功能开发,否则模型换一个版本、换一个场景,你的坐标系就全乱了。从那以后我每次接新的姿态识别需求,都先把这套自检脚本跑一遍再动业务代码。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询