☰
OpenPose人体姿态估计实战:基于OpenCV的视频流关键点检测与动作识别
2026/10/1 16:36:43 网站建设 项目流程

简介:这是一套面向人体姿态识别开发者的完整实战代码包,以Python+OpenCV+OpenPose为核心,解决视频流与摄像头场景下的实时人体关键点检测问题。包内共40个文件,以19个Python源码和12个编译后的pyc文件为主,另含Markdown说明文档、示例图片、演示视频及依赖清单等,代码工程结构清晰,适合有一定Python基础并希望快速搭建姿态识别原型的开发者。资源压缩包大小8.12MB,轻量易下载。已有7028人浏览学习。除了可直接运行的训练、推理、验证等主程序,还提供基于MobileNet的轻量化模型、自定义数据集训练说明、关键点后处理滤波、模型转换脚本等,涵盖从数据准备、模型训练、实时推理到结果可视化的完整流程。通过阅读代码与文档,读者可以掌握OpenPose在Python环境中的集成方式、OpenCV相机帧处理技巧,并扩展到运动分析、健身指导、虚拟现实等应用场景。

1. 人体形态算法识别:视频加摄像头的场景下,为什么先选 OpenPose

“人体形态算法识别”这个需求,拆到落地就是两件事:先把视频或摄像头画面里的人体骨架关键点找出来,再根据这些关键点在连续帧里的位置变化判断姿态。很多人一上来就套目标检测,但检测框只能回答“人在哪”,回答不了“人此刻是什么姿势”。OpenPose 是骨架提取这条线上最成熟的方案,Python 负责组织逻辑,OpenCV 负责读摄像头和做图像预处理,三者配合起来,一个普通 PC 加一个 USB 摄像头就能把单人姿态估计跑起来。这篇笔记适合做健身动作计数、安防姿态告警、康复评估的开发者,按环境搭建、骨架提取、形态计算、排错、加速的顺序讲,所有步骤都能直接复现。

2. 环境搭建:Python + OpenCV + OpenPose 的版本匹配是第一步

2.1 OpenPose 的两种获取方式:源码编译与预编译模型

拿到 OpenPose 有两条路,一条是用官方仓库从源码 cmake 编译,另一条是只下载官方训练好的模型权重,然后用 OpenCV 的 DNN 模块直接加载。我一般推荐后一条路,除非你的项目必须改网络结构或者要深度定制 PAF 输出层。

源码编译这条路,网上 opencv cmake 编译步骤写得很多,但 OpenPose 的坑在于它依赖 Caffe、CUDA、cuDNN 三件套,版本稍微不匹配就整页报错。Windows 上编译 OpenPose 尤其容易在 Caffe 的第三方依赖上翻车,一次编译折腾半天很正常。所以我的判断标准很简单:有 N 卡且需要跑多人实时识别,才值得走源码编译;只有 CPU 或者只需要单人姿态,用 OpenCV DNN 加载预训练模型就够了。

Python 环境这边,先把 Python 装好,3.8 到 3.10 都可以,然后用 venv 隔离项目依赖。网上 python 安装教程很多,但这里的关键是不要直接往系统 Python 里 pip install,不然之后换项目版本冲突会非常难受。VSCode 里配置 python 环境时,记得选到 venv 的解释器,否则终端里明明装了包,编辑器却一直报 ModuleNotFoundError。

python -m venv venv # Windows 下激活命令是 venv\Scripts\activate source venv/bin/activate pip install opencv-python numpy

逻辑说明:venv 创建一个独立的 Python 环境,opencv-python 装的是预编译好的 wheel,自带 FFmpeg 和一个可用的摄像头读取后端,不需要再单独装 opencv。numpy 是后面做坐标运算和角度计算的刚需。装完后可以用python -c "import cv2; print(cv2.__version__)"验证,能输出版本号就说明环境通了。

2.2 用 OpenCV 的 DNN 模块加载 OpenPose 模型:最小可跑代码

模型文件选 COCO 骨架那套,一个 prototxt 描述网络结构,一个 caffemodel 存放权重。这两个文件放在项目目录下,然后用下面这段代码验证模型能正常加载和推理。

import cv2 import numpy as np # COCO 骨架模型:18 个关键点,适合单人/双人姿态估计 proto_file = "pose_deploy_linevec.prototxt" weights_file = "pose_iter_440000.caffemodel" net = cv2.dnn.readNetFromCaffe(proto_file, weights_file) # 读一张测试图,确认模型能跑通 image = cv2.imread("sample.jpg") h, w = image.shape[:2] # 原图 BGR -> 归一化到 0~1 -> 缩放到 368x368 -> 转成 NCHW 布局 blob = cv2.dnn.blobFromImage( image, 1.0 / 255.0, (368, 368), (0, 0, 0), swapRB=True, crop=False ) net.setInput(blob) output = net.forward() print("output shape:", output.shape) # 期望输出 (1, 57, 46, 46)

逻辑说明:blobFromImage 做的是标准预处理,把 OpenCV 读进来的 BGR 图像转成网络要求的 NCHW 四维张量。368x368 是 OpenPose 官方训练时用的输入尺寸,也是速度和精度比较平衡的点。output 的 57 个通道不是乱来的,它由 19 个关键点热图(18 个关键点加 1 个背景通道)和 38 个 PAF 通道组成。PAF 的完整名字叫 Part Affinity Fields,中文一般叫部分亲和场,它编码的是相邻关键点之间的方向和连接强度,OpenPose 能在多人场景正确组装骨架,靠的就是它。

提示:如果你加载 BODY_25 模型,输出通道数会变成 79,因为关键点从 18 个涨到 25 个,PAF 连接也变多了。通道数对不上,八成是 prototxt 和 caffemodel 不是同一套。

2.3 关键参数:输入尺寸、阈值、模型精度

参数常用值作用注意事项
输入尺寸368x368决定关键点热图的分辨率尺寸越小越快,但关键点抖动越明显;656x368 精度更高,CPU 上基本跑不动
置信度阈值0.1 ~ 0.3过滤低质量关键点设太低会把背景噪点当成人手,设太高会把人手直接丢掉
骨架模型COCO / BODY_25决定关键点数量只需要上肢角度 COCO 够用,要分析步态就得上 BODY_25
后端CPU / CUDA推理执行设备CPU 上 opencv DNN 用 OpenCL 加速效果不稳定,N 卡直接开 CUDA 收益更大

输入尺寸是第一个要调的参数。固定摄像头场景下,先用 368x368 跑通,然后看单帧延迟。CPU 上如果一帧超过 300ms,可以先降到 320x240 或者 256x256,但关键点会明显变糙,需要配合后面的时序平滑一起用。置信度阈值这里,官方 demo 用的 0.1,实际项目我从 0.15 起步,人物容易侧身的场景提到 0.2。阈值不是越高越好,0.5 以上人稍微侧个身就少一个点。

3. 人体骨架提取:从单张图片到摄像头视频流的实现路径

3.1 单帧推理:COCO 与 BODY_25 两种骨架格式怎么选

COCO 骨架的 18 个关键点有固定的索引顺序,从鼻子开始,经脖子、肩膀、手肘、手腕、髋、膝、踝,到眼睛和耳朵结束。这个顺序必须记牢,因为后面取关节角度、画骨架连线全都靠索引定位,写错一个数字,画出来的骨架就是歪的。

# COCO 关键点索引顺序,写熟了这个数组后面不会乱 COCO_POINTS = [ "nose", "neck", "r_shoulder", "r_elbow", "r_wrist", "l_shoulder", "l_elbow", "l_wrist", "r_hip", "r_knee", "r_ankle", "l_hip", "l_knee", "l_ankle", "r_eye", "l_eye", "r_ear", "l_ear" ] # 从网络输出中解析关键点坐标 def parse_points(output, img_w, img_h): points = [] heatmap_h, heatmap_w = output.shape[2], output.shape[3] for i in range(18): prob_map = output[0, i, :, :] min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(prob_map) if max_val > 0.15: x = int(max_loc[0] * img_w / heatmap_w) y = int(max_loc[1] * img_h / heatmap_h) points.append((x, y)) else: points.append(None) return points

逻辑说明:每个关键点对应一张 46x46 的热图,热图上响应值最大的位置就是该关键点最可能出现的地方。minMaxLoc 一次把最大值和坐标都拿出来了,省得自己写 argmax 再换算。坐标缩放用热图尺寸和原图尺寸的比例完成,因为热图分辨率远小于原图。最大响应低于阈值时存 None,后续角度计算会跳过这个点,而不是把它当成 0 坐标参与运算。

选 COCO 还是 BODY_25,取决于你要算哪些形态特征。只做上肢角度、手部动作,COCO 完全够。要做步态分析、落地姿势评估,BODY_25 多出的脚趾和脚跟关键点就很有价值。代价是 BODY_25 输出通道从 57 涨到 79,forward 时间和后处理遍历量都变大,CPU 上会更吃力。

3.2 连续帧处理:摄像头视频流的关键点平滑

单帧解析跑通之后,接摄像头视频流就变得顺理成章。但这里有一个所有做实时姿态识别的人都会撞上的问题:单帧检测出来的关键点在连续帧之间会抖,明明人站着没动,骨架却像帕金森一样乱颤。这不是模型坏了,而是热图峰值本身有小幅浮动,加上输入尺寸压缩带来的量化误差。血泪经验是,形态识别翻车往往不是模型精度不够,而是没做时序平滑。

cap = cv2.VideoCapture(0) # 0 是默认摄像头,也可以传视频文件路径 if not cap.isOpened(): print("摄像头打开失败,检查设备占用或驱动") exit() smooth_points = [None] * 18 # 存放历史关键点 alpha = 0.35 # 平滑系数,越大越跟手,越小越稳 while True: ret, frame = cap.read() if not ret: break blob = cv2.dnn.blobFromImage( frame, 1.0 / 255.0, (368, 368), (0, 0, 0), swapRB=True, crop=False ) net.setInput(blob) output = net.forward() current_points = parse_points(output, frame.shape[1], frame.shape[0]) smoothed = [] heatmap_h, heatmap_w = output.shape[2], output.shape[3] for i in range(18): if current_points[i] is not None: x, y = current_points[i] if smooth_points[i] is not None: # 一阶低通滤波:当前帧占 alpha,历史占 1-alpha sx = int(alpha * x + (1 - alpha) * smooth_points[i][0]) sy = int(alpha * y + (1 - alpha) * smooth_points[i][1]) smoothed.append((sx, sy)) smooth_points[i] = (sx, sy) else: smoothed.append((x, y)) smooth_points[i] = (x, y) else: smoothed.append(None) smooth_points[i] = None

逻辑说明:指数移动平均是最便宜的降噪手段,alpha 取 0.35 意味着当前帧坐标只占 35%,历史占 65%,抖动会被压掉一大半。动作快的场景可以把 alpha 调到 0.5 让骨架更跟手,动作慢且稳定的场景调到 0.2 让曲线更平滑。这个参数没有绝对正确值,要在你自己的摄像头上试出来。

另一种常见做法是 Savitzky-Golay 滤波,它做滑动窗口多项式拟合,平滑效果更精致,但要维护一个长度固定的窗口,实时视频流里实现起来比 EMA 重不少。我一般先用 EMA,不够用再考虑升级。

3.3 性能优化:把推理延迟压到可用的红线

视频流形态识别能不能用,延迟说了算。OpenPose 的 Caffe 模型在 CPU 上单帧推理普遍要 200 到 500ms,直接跑摄像头画面会卡到没法看。优先做三件事:降低输入尺寸、跳帧推理、开启 CUDA 后端。

net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA) net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)

这两行只在 N 卡 + CUDA 环境可用,指定之后 OpenCV DNN 会把卷积层放到 GPU 上执行,延迟可以从几百毫秒降到几十毫秒。没有 N 卡就跳帧,每两帧推理一次,中间帧沿用上一帧的关键点坐标,视觉上几乎无差别,延迟直接减半。

infer_every = 2 # 每隔 2 帧推理一次 frame_index = 0 last_points = [None] * 18 while True: ret, frame = cap.read() if not ret: break if frame_index % infer_every == 0: blob = cv2.dnn.blobFromImage( frame, 1.0 / 255.0, (320, 240), (0, 0, 0), swapRB=True, crop=False ) net.setInput(blob) output = net.forward() last_points = parse_points(output, frame.shape[1], frame.shape[0]) # 画骨架时统一使用 last_points frame_index += 1

逻辑说明:320x240 是网络输入尺寸,不是输出画面尺寸,热图分辨率会下降,但配合 3.2 的 EMA 平滑,实际效果可以接受。跳帧本质是用时间分辨率换算力,适合深蹲、站立、抬手这类变化不剧烈的动作。如果判断的是快速挥拍、跑步摆臂,infer_every 最多设到 2,再低就跟不上了。

4. 人体形态特征计算:夹角、比例与动作判定逻辑

4.1 从关键点坐标到关节角度:向量夹角的计算方法

有了关键点坐标,形态识别就有数据了。最常用的特征是关节角度,比如说“肘关节弯曲多少度”“膝盖弯曲多少度”,它比坐标更直观,也和人体解剖学的判断标准一致。三个点确定一个角度,以中间的关节点为顶点,用两个向量夹角算出角度值。

def calculate_angle(a, b, c): """计算角 abc 的角度,b 是关节点,a、c 是它连接的两个端点""" if a is None or b is None or c is None: return None ba = np.array([a[0] - b[0], a[1] - b[1]]) bc = np.array([c[0] - b[0], c[1] - b[1]]) norm_ba = np.linalg.norm(ba) norm_bc = np.linalg.norm(bc) if norm_ba < 1e-6 or norm_bc < 1e-6: return None # 两个点重合时角度无意义 cos_theta = np.dot(ba, bc) / (norm_ba * norm_bc) cos_theta = np.clip(cos_theta, -1.0, 1.0) # 防止浮点误差导致 arccos 越界 return np.degrees(np.arccos(cos_theta))

逻辑说明:np.dot(ba, bc) / (norm_ba * norm_bc)算出来是夹角的余弦值,arccos 把它还原成弧度,degrees 转成角度。分母加 1e-6 防止除零,clip 是防止浮点计算里出现 1.0000001 这种值导致 arccos 报错。这两处都是在实际跑数据时容易被问到的点,坐标一极端就会触发。

2D 姿态估计有一个先天限制:没有深度信息。当身体平面和相机光轴接近垂直时,比如人正对镜头做深蹲,膝盖弯曲角度的误差会被放大。这种场景下角度值只能当作参考,要拿到精确的关节角必须上双目相机或者深度相机,这是方案选型时就该想清楚的。

4.2 用角度序列判断动作:深蹲与抬手的判定逻辑

动作判定不要靠单帧定结论。深蹲这个动作用膝盖角度看,正常站立时膝盖接近 180 度,下蹲到最低点时膝盖会小于 120 度,起身后回到 180 度附近。但有人在临界角度附近来回晃,单帧阈值判断会把一次深蹲数成三四次。

def detect_squat(knee_angle, state): """ 基于膝盖角度状态机判断一次深蹲 state: "up" 表示站立, "down" 表示下蹲 """ if knee_angle < 120 and state == "up": return "down", False elif knee_angle > 160 and state == "down": return "up", True # 完成一次深蹲 return state, False

逻辑说明:状态机靠角度阈值切换状态,只有在“从下蹲状态回到站立状态”这一瞬间才计一次数。这样人蹲在半空中晃多久都不会重复计数,比单纯数“角度低于阈值几次”可靠得多。阈值 120 和 160 是按我这边健身场景标定出来的,如果你的摄像头角度低,蹲得特别浅,需要重新标定这两个值。

更稳妥的做法是引入滞后窗口:连续 3 帧角度都低于 120 才进入 down 状态,连续 3 帧都高于 160 才计一次完成。这样可以滤掉偶发的单帧噪声,代价是动作判定会慢几帧,但对深蹲这种慢动作完全没问题。

抬手动作同理,用右肩(2)、右肘(3)、右手腕(4)三个点算肘关节角度,当肘角小于 30 度或者手腕关键点高于肩膀时判为抬手。注意这里有个坑:人体左右在 COCO 索引里是从画面观察者的角度定义的,摄像头如果正对人物,画面左侧是人家的右手,索引是 2 到 4 那一组;如果摄像头背后拍,就要把左右反过来,直接用索引不检查会出反。

4.3 形态识别的边界:遮挡与多人场景的处理策略

遮挡是形态识别绕不过去的边界。手被身体挡住时,手腕关键点置信度下降,parse_points 会返回 None。最简单的兜底策略是:用上一帧坐标补齐,但补位超过 5 帧就放弃,因为人可能已经走出画面,继续补出来的坐标没有意义。

MISSING_TOLERANCE = 5 # 允许连续缺失帧数 missing_count = [0] * 18 for i in range(18): if frame_points[i] is None: missing_count[i] += 1 if missing_count[i] <= MISSING_TOLERANCE: frame_points[i] = last_points[i] # 用上一帧坐标补位 else: missing_count[i] = 0

逻辑说明:补位能维持骨架连续,但它不是真实检测结果,超过容错就必须把点置为 None,让上层逻辑知道这个关节当前不可信。如果你在做动作计数,宁可少记一次,也比用脏坐标多记一次好。

多人场景是 OpenPose 真正的坎。OpenCV DNN 加载 Caffe 模型后,理论上热图输出支持多人,但要正确把关键点组装成每个人的骨架,需要按 PAF 做二分图匹配,这个算法实现起来不轻松。常见做法是退一步:先用目标检测框住每个人,然后对每个检测框单独跑一次姿态估计,逻辑简单,缺点是同一个画面里人多时 CPU 算力扛不住。如果项目有强多人实时识别需求,老老实实编译官方源码版,里面的 PAF 解析是写好的,不要自己在 OpenCV DNN 上重复造轮子。

5. OpenPose 实战避坑:编译、运行与精度问题的排查记录

5.1 模型加载失败:文件路径与网络结构不匹配

现象:readNetFromCaffe抛异常,提示解析 prototxt 失败;或者模型加载成功,但 net.forward() 的输出维度和自己预期对不上。

原因:下载的 caffemodel 和 prototxt 不是同一套模型。最常见的是把 COCO 的权重文件配到了 BODY_25 的 prototxt 上,网络层对不上,OpenCV 解析到一半就崩。COCO 那套权重文件名带440000,BODY_25 那套带584000,这两个数字是迭代次数,也是区分模型身份的最直接标记。

解决:确认两个文件是配套下载的。不要自己手动改 prototxt 里的层结构来“适配”权重,OpenCV 的 Caffe 解析器兼容性比原版 Caffe 差,手改 prototxt 很容易引入新错误。去 OpenPose 官方仓库的 model 目录下,把对应的 prototxt 和 caffemodel 放在同一文件夹,路径用相对路径,不要带中文,这个问题就基本不会碰上了。

提示:加载后可以先打印 output.shape 验证通道数,COCO 应该是 57,BODY_25 应该是 79。数字不对,直接检查文件是不是拿错了。

5.2 关键点抖动:阈值过低导致识别不稳定

现象:人站着不动,画出来的鼻子、手腕在背景区域乱跳,看起来像骨架在抽风。

原因:置信度阈值设太低,热图上的噪声峰被当成关键点。热图是模型对每个位置“这个点是关键点”的概率估计,有人的区域概率高,没人的区域概率低但不为零,阈值太低噪声就进来了。

解决:把 parse_points 里的阈值从 0.1 提到 0.2 到 0.3。提到 0.3 后,人稍微侧身或者手在身体前方交叉,关键点会丢得比较频繁,这时要配合 3.2 的 EMA 平滑和 4.3 的缺失补位一起用,不能只靠提阈值。我现在的习惯是阈值固定 0.2,平滑参数按场景调,两个一起作用比单调一个效果稳定得多。

5.3 视频流卡顿:解码与推理线程分离

现象:推理一帧要 200ms,摄像头读取也跟着卡,画面掉帧严重,姿态轨迹一段一段的。

原因:cap.read() 和 net.forward() 在同一个线程里,read 必须等 forward 返回才能执行下一次读取,摄像头的硬件缓冲区被占满,后面的新帧进不来,读出来的就是旧帧或者空帧。这是单线程串行处理的固有瓶颈,算力越差越明显。

解决:把视频读取拆到独立线程,用一个容量很小的队列保存最新帧,推理线程从队列里取。队列长度限制在 1 到 2,满了就丢弃旧帧,保证拿到的永远是最新画面。

import threading import queue import time frame_queue = queue.Queue(maxsize=2) def read_frames(cap, q): while True: ret, frame = cap.read() if not ret: break if q.full(): try: q.get_nowait() # 丢弃最旧的未处理帧 except queue.Empty: pass q.put(frame) cap = cv2.VideoCapture(0) threading.Thread(target=read_frames, args=(cap, frame_queue), daemon=True).start() # 主线程只做推理和显示 while True: try: frame = frame_queue.get(timeout=1) except queue.Empty: continue # 对 frame 做 blob 转换和 net.forward()

逻辑说明:读取线程持续从设备拿帧,推理线程专注算关键点,互不阻塞。队列 maxsize=2 是个关键细节,它让系统始终处理最新帧而不是堆积几十帧旧画面,延迟反而比大队列更低。daemon=True 保证主程序退出时读取线程自动结束,不会卡住进程。这个模式也适用于 RTSP 网络摄像头,画面中断后的恢复逻辑可以放到读取线程里统一处理。

5.4 摄像头拉流中断:重连与缓存策略

现象:USB 摄像头长时间运行后,cap.read() 一直返回 False,程序也不报错,就那么卡在原地。IP 摄像头的 RTSP 流更明显,网络抖动之后画面直接冻住。

原因:USB 带宽被其他设备抢占、摄像头固件长时间工作后驱动异常、RTSP 流服务端断开但客户端没感知。OpenCV 的 VideoCapture 对断流处理很弱,read 失败后内部状态不会自动恢复。

解决:写一个安全读取函数,read 返回 False 时 release 掉当前对象,等 1 秒重新打开,并限制最大重连次数防止死循环。USB 摄像头直接重新 VideoCapture 同一下标号,RTSP 摄像头重新传 URL。

import time MAX_RETRY = 5 def safe_read(cap, source=0): ret, frame = cap.read() if ret: return True, frame # 读取失败,释放后重建连接 cap.release() retry = 0 while retry < MAX_RETRY: time.sleep(1) cap = cv2.VideoCapture(source) if cap.isOpened(): ret, frame = cap.read() if ret: return True, frame, cap retry += 1 return False, None, cap

逻辑说明:release 会真正关闭底层设备句柄,重新 open 才会重新走驱动初始化流程。如果连续重试 5 次仍然失败,说明问题不在代码而在设备,此时应该抛出显式告警或者退出程序,而不是无限循环消耗 CPU。这个函数在长时间运行的摄像头服务里是必需品,我见过太多程序跑了一晚上,第二天早上画面冻结但进程还在占用内存的案例。

6. 把形态识别做成可用的服务:ROI 裁剪与帧率控制技巧

6.1 用 ROI 裁剪降计算量:只对有人区域跑推理

把前面章节的代码组合成一个服务时,最先要控制的是整体吞吐。一个我常用的套路是“画面里有人才做全分辨率推理,没人就降低采样频率”。对固定场景,比如健身房的深蹲区或者工位监控,可以先框定一个 ROI。ROI 内的画面送去跑 OpenPose,ROI 外的背景直接不参与计算。这样输入尺寸可以维持 368x368 的精度,但实际送入网络的像素少了很多。如果场景不是固定的,先用目标检测把人框出来,再把框裁出来单独跑姿态估计,OpenCV DNN 同时加载检测模型和 OpenPose 模型没有问题,只要显存或内存够。

6.2 参数验证的朴素方法:用录像回放代替现场调试

另一个实用技巧是按帧率换精度。摄像头 30fps 不代表姿态识别需要 30fps,把 3.3 的 infer_every 从 2 调到 3,CPU 占用能降不少,配合 EMA 平滑,视觉上骨架依然稳定。要追求极致性能,可以把 OpenPose 的 Caffe 模型转成 ONNX 再走 TensorRT,它的卷积结构对 TensorRT 很友好,但用 OpenCV DNN 读取 ONNX 时某些层会重新排序,输出通道顺序要自己写脚本验证,不能直接沿用之前 parse_points 里写死的索引。

我的习惯是每次改参数之前先录一段 30 秒的摄像头视频存成本地文件,然后拿这段视频做回放测试,对比新旧代码的输出差异,而不是直接对着摄像头调。OpenPose 的阈值、平滑系数、ROI 位置,这些参数在录像上验证一遍再上线,比在现场一遍遍试高效得多。人体形态算法识别这种实时视觉任务,最大的坑是没法稳定复现现场,而录像是唯一的后悔药,它能让你改了代码之后还知道之前的版本到底表现如何。最后提醒一句:OpenPose 在 2D 骨架上非常成熟,但遇到严重遮挡和快速出画时还是会翻车,先把缺失兜底逻辑写好,再谈精度提升。希望帮到你。

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

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

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

立即咨询