☰
Python+OpenCV+OpenPose人体形态识别与跌倒检测实战
2026/10/10 16:24:59 网站建设 项目流程

简介:一套基于Python+OpenCV+OpenPose的人体形态识别工程包,面向计算机视觉初学者、运动分析及人机交互开发者,可用于实时视频流与摄像头中的人体关键点检测。压缩包共40个文件,主体为19个Python源码、12个编译后的pyc模块,另含2个Markdown说明文档、预训练模型相关配置、演示视频及示例图片,整体约8.12MB,结构上按models、modules、scripts等目录划分,便于直接阅读与二次开发。已有7028人学习下载,具备较高参考价值。其中不仅包含train.py、demo.py等核心训练与演示代码,还提供coco.py、transformations.py等数据处理工具、ONNX转换脚本及自定义数据集训练指南,可帮助读者快速跑通姿态识别流程,并在此基础上扩展动作识别、健身指导等实际应用。

1. 视频里的动作识别,为什么先卡在视频流和关键点抖动上

把摄像头画面交给 Python 之后,大多数人遇到的第一个坎不是模型不够聪明,而是cv2.VideoCapture根本读不出画面、读出来之后 OpenPose 关键点在原地抖。视频 + 摄像头 使用 Python+OpenCV+OpenPose 实现人体形态算法识别,这条链路里 OpenPose 负责从单帧图像中找关节,OpenCV 负责把摄像头和视频文件转成帧,Python 负责把两者串起来。真正能落地的产出不是“画出骨架”,而是跌倒预警、健身计数、体态矫正、动作标准度分析这些形态判断。适合有 Python 和 OpenCV 基础、不想从零训练姿态模型的开发者,在自己机器上先跑出一个能看的最小系统。下文按环境依赖、视频接入、骨架绘制、角度计算、踩坑排查和落地验证六个部分展开,都是实际项目中反复用过的路径。

2. 安装不是 pip install openpose:模型结构、依赖选型与编译前的准备

2.1 先搞明白 OpenPose 输出什么:COCO 18 点和 BODY_25 骨架

OpenPose 不是魔法黑匣子,它的输出是一组带置信度的关键点坐标。用 COCO 模型时,单个人返回 18 个点,编号顺序固定:0 鼻子,1 脖子,2 右肩,3 右肘,4 右手腕,5 左肩,6 左肘,7 左手腕,8 右髋,9 右膝,10 右踝,11 左髋,12 左膝,13 左踝,14 右眼,15 左眼,16 右耳,17 左耳。每个点是一个三元组[x, y, confidence],x 和 y 是像素坐标,confidence 表示这个点被网络认为“确实可见”的程度,范围 0 到 1,但实际分布受遮挡影响很大,不能当作严格的概率来用。

BODY_25 模型则输出 25 个点,在 COCO 基础上增加了脚趾、脚跟以及骨盆中心等关键点。如果你要做步态分析、需要脚部落地角度的判断,BODY_25 更合适;如果只是上半身体态或者简单的健身动作识别,COCO 18 点已经够用,而且它对应的连接关系在现有教程里最容易找到。选模型时不要盲目追新,先看后续要计算什么指标。例如“膝盖超伸”必须依赖膝关节点,COCO 18 点已经有了,不需要升级到 25。

从算法原理看,OpenPose 走的是自底向上的路线:先检测全图所有人的关键点,再用 Part Affinity Fields(PAF)把这些点拼接成一个个完整的人体骨架。这和先检测人体框、再对框内单人做姿态估计的自顶向下方案是两条路。自底向上的好处是多人场景不会因为互相遮挡导致漏检整具人体,坏处是计算开销更大,而且人物越多,PAF 需要处理的关系组合越复杂。最近很多人在讲 ControlNet 的 OpenPose 骨架图如何控制人物姿态,其实正是因为它能把人体抽象成一组紧凑、稳定的骨架线,这种表达天然适合后续的几何计算。

2.2 依赖链:Python 3.8 虚拟环境、opencv-python 与 numpy

先把最基础的依赖装好。我一般建议用 conda 建一个独立虚拟环境,而不是直接往系统 Python 里堆包,否则会出现“昨天还能跑、今天 import 报错”的版本冲突。

conda create -n pose_recog python=3.8 -y conda activate pose_recog pip install opencv-python numpy

选择 Python 3.8 不是怀旧,而是 OpenPose 的很多预编译依赖和社区教程都停留在 3.6 到 3.8;Python 3.10 以上要重新编译匹配 C++ ABI,容易在 CMake 阶段出错。opencv-python安装后导入名是cv2,不是opencv。很多新手看到ModuleNotFoundError: No module named 'opencv'就以为没装成功,其实只是 import 名字写错了。numpy 是 OpenPose 的 Python API 里处理关键点数组的底层库,后续所有角度计算都会用到,不要落下。

这里有一个非常重要的提示:如果在 Ubuntu 上已经通过apt安装过 OpenCV,再装 pip 版opencv-python,很容易出现两个 OpenCV 同时存在的情况。表现特征是程序能启动,但一旦调用高层接口就崩溃,或者 pyopenpose 加载时直接报动态库冲突。考虑到网上大量教程还停留在 OpenCV 3.4.1 加 mingw64 的时代,不要照搬老帖子的编译参数。统一做法是:在虚拟环境内只认 pip 安装的 opencv-python,把系统里的/usr/lib/x86_64-linux-gnu/libopencv_*.so从LD_LIBRARY_PATH中摘出去,避免交叉污染。

2.3 CMake 编译与 PYTHONPATH:把 OpenPose 装进当前 Python

OpenPose 官方没有提供干净利落的pip install openpose,最常见的落地方式是获取源码后,用 CMake 编译 Python API。在 Ubuntu 上,先安装系统级编译依赖:

sudo apt update sudo apt install -y cmake build-essential libprotobuf-dev protobuf-compiler \ libgoogle-glog-dev libgflags-dev libboost-all-dev libopenblas-dev liblapack-dev

这些包的作用分别是:CMake 做构建编排,protobuf 处理模型读取,glog/gflags 是 Caffe 和 OpenPose 的日志与参数库,Boost 提供智能指针和文件系统支持,OpenBLAS/LAPACK 提供底层矩阵运算。缺了任何一项,CMake 配置阶段可能不报错,但make到一半会消失找不到头文件。接下来进入 OpenPose 源码目录,创建 build 目录并配置:

cd openpose mkdir -p build && cd build cmake -DBUILD_PYTHON_API=ON \ -DPYTHON_EXECUTABLE=$(which python) \ -DPYTHON_INCLUDE_DIR=$(python -c "import sysconfig; print(sysconfig.get_paths()['include'])") \ -DBUILD_EXAMPLES=OFF \ .. make -j4

关键点是-DPYTHON_EXECUTABLE=$(which python),确保 CMake 找到的是你当前 conda 环境里的 Python,而不是/usr/bin/python。如果这里指错了,后续 Python API 会装到系统环境里,import openpose依然失败。编译时间取决于机器和依赖,慢的时候一两个小时很正常,我会用-j4而不是-j8,因为 OpenPose 编译时内存峰值较高,核心太多容易把机器拖垮。

编译完成之后,build/python目录下会出现openpose模块。使用前需要把这个路径加进PYTHONPATH,否则会报ModuleNotFoundError: No module named 'openpose'。常见做法是在每个脚本开头写:

import sys sys.path.append("/path/to/openpose/build/python")

这句要放在from openpose import pyopenpose as op之前,并且建议在导入cv2之后、导入 openpose 之前保持顺序固定。为什么后面再细说,这里只需要知道动态库冲突是最难排查的一类问题。

3. 视频流跑通 OpenPose:从 cv2.VideoCapture 到第一根骨架线

3.1 摄像头与视频文件的接入:设备索引、分辨率设置与帧循环

OpenCV 的摄像头接口在不同的平台上有少许差异,但核心逻辑一致。

import cv2 cap = cv2.VideoCapture(0) if not cap.isOpened(): raise RuntimeError("camera 0 unavailable") cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) print(cap.get(cv2.CAP_PROP_FRAME_WIDTH), cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

VideoCapture(0)中的0是设备索引,通常对应笔记本内置摄像头或第一个 USB 摄像头。isOpened()只表示管道建立成功,并不代表read()真的能读到数据;摄像头被其他程序占用时,isOpened()也会返回 True,但后续循环里ret会一直是 False。设置分辨率后一定要打印实际值,很多摄像头不支持 1280x720,会静默地退回 640x480,代码里不检查的话,后续关键点坐标的比例全都会偏移。

接着是标准的读取循环:

while True: ret, frame = cap.read() if not ret: break # 这里暂时只显示画面 cv2.imshow("pose recog", frame) if cv2.waitKey(1) & 0xFF == ord("q"): break cap.release() cv2.destroyAllWindows()

waitKey(1)的含义是等待 1 毫秒,并处理显示窗口的键盘事件;没有这句,imshow画面可能不刷新。在无桌面的 Linux 服务器上,如果根本没有显示环境,imshow会直接抛异常,需要删掉这两行,或者把处理结果保存成视频文件。读取视频文件时,把VideoCapture(0)替换成视频文件路径即可,其他逻辑不变。文件不存在时isOpened()为 False,所以同样的检查仍然有效。

3.2 初始化 OpenPose 并逐帧推理:WrapperPython 的参数与输出结构

初始化 OpenPose 的常见做法是用官方 Python API 里的WrapperPython。初始化只需要一次,不要把它放在循环里重复创建,否则光是模型加载就会把系统拖死。

import sys import cv2 import numpy as np sys.path.append("/path/to/openpose/build/python") from openpose import pyopenpose as op params = { "model_folder": "/path/to/openpose/models/", "model_pose": "BODY_25", "net_resolution": "-1x368", "number_people_max": 1, "disable_multi_thread": True, } op_wrapper = op.WrapperPython() op_wrapper.configure(params) op_wrapper.start()

这里几个参数决定运行表现。model_folder必须指向 OpenPose 权重文件所在目录,首次运行会尝试加载权重,没有权重时会联网下载,所以第一次执行要保持网络可用。model_pose选择模型类型,BODY_25 和 COCO 对应不同的输出维度。net_resolution是网络输入分辨率,-1x368表示高度 368,宽度根据输入图像宽高比自动计算;这个值是精度和速度之间最关键的一个旋钮,调大后关节定位更准,但推理耗时几乎线性上升。number_people_max设为 1 表示只保留置信度最高的一个人;如果是多人场景,这个值要调大,但代价是 PAF 匹配变慢。disable_multi_thread在容器环境和部分嵌入式设备上能避免 OpenMP 线程崩溃,普通桌面机器可以注释掉。

初始化完成后,在读取循环里对每一帧执行推理:

while True: ret, frame = cap.read() if not ret: break datum = op.Datum() datum.cvInputData = frame op_wrapper.emplaceAndPop(op.VectorDatum([datum])) keypoints = datum.poseKeypoints if keypoints is not None: print("detected persons:", keypoints.shape[0]) print("joints per person:", keypoints.shape[1]) cv2.imshow("pose recog", frame) if cv2.waitKey(1) & 0xFF == ord("q"): break

emplaceAndPop是同步调用,它会阻塞到推理完成,然后返回填充好的datum。每次循环创建新的Datum对象是最稳妥的做法,虽然理论上可以复用,但不同 OpenPose 版本对Datum的生命周期处理不一致,复用导致过内存错乱。keypoints是一个三维数组,形状为(人数, 关节数, 3);用 BODY_25 模型时第二维是 25,用 COCO 模型时是 18。没有人出现时,这个数组可能是空数组,代码里一定要判空,否则keypoints[0]直接索引越界。

3.3 画骨架:置信度阈值与关键点连接

画骨架时,不要把所有关键点都画出来。被遮挡关节的 confidence 很低,画出来就是满屏乱飞的点。我一般设置一个阈值,只有在两侧关键点置信度都超过阈值时才连线。以 COCO 18 点为例,连接关系如下:脖子到右肩、脖子到左肩、右肩到右肘、右肘到右手腕、左肩到左肘、左肘到左手腕、脖子到右髋、脖子到左髋、右髋到右膝、右膝到右踝、左髋到左膝、左膝到左踝、脖子到鼻子、鼻子到右眼、鼻子到左眼、右眼到右耳、左眼到左耳,一共 17 条骨架线。

skeleton_coco = [ (1, 2), (1, 5), (2, 3), (3, 4), (5, 6), (6, 7), (1, 8), (1, 11), (8, 9), (9, 10), (11, 12), (12, 13), (1, 0), (0, 14), (0, 15), (14, 16), (15, 17), ] def draw_skeleton(img, keypoints, pairs, threshold=0.3): if keypoints.shape[0] < 1: return img person = keypoints[0] for a, b in pairs: pa, pb = person[a], person[b] if pa[2] > threshold and pb[2] > threshold: cv2.line( img, (int(pa[0]), int(pa[1])), (int(pb[0]), int(pb[1])), (0, 255, 0), 2, ) return img

threshold的取值需要现场调。0.3 是相对稳定的起点;如果整个画面逆光,关键点置信度普遍偏低,可以降到 0.1。但要注意,阈值降得太低会把遮挡产生的错误点也画出来,导致骨架线出现“倒挂”的怪异姿态。另一个常用操作是同时画出关键点圆点,方便肉眼看是哪条连接线出了问题。这一步做完,你已经能从摄像头画面里看到实时骨架,已经具备了形态识别的基础。

3.4 摄像头实时性和帧率匹配:先接受推理耗时

emplaceAndPop是阻塞接口,所以整个循环的帧率约等于1 / 推理耗时。在 GPU 上使用 BODY_25 且输入分辨率 368 时,单人推理通常 30 到 80 毫秒;CPU 上则可能 300 毫秒以上。这意味着摄像头画面会明显卡顿,这是正常现象,不是代码死循环。第一版不要急着优化,先把骨架画出来,确认输入输出链路正确,再谈帧率。优化方式会在第 6 章展开。

4. 从关键点到“人体形态”:连接关系、关节角度与特征规则

4.1 骨架连接只是第一步,形态语言在角度里

画出一根根骨架线能给人看,但不能交给程序判断“手抬起来了还是放下”。人体形态算法识别的重点是把骨架线翻译成可计算的几何量。关节角度是最稳定的形态特征:肘关节的角度能区分手臂伸直和弯曲,膝关节角度能区分站立和下蹲,肩髋连线相对水平面的角度可以判断躯干倾斜。这些量不依赖人的身高、离摄像头远近,同一动作在不同人体上的角度值大致一致,所以适合做规则判断。

角度计算本质是向量夹角。给定三个关键点 A、B、C,比如肩、肘、腕,需要计算以 B 为顶点的角 ABC。具体做法是构造向量 AB 和 CB,用点积公式求夹角。

import numpy as np def joint_angle(a, b, c): a = np.asarray(a, dtype=np.float32) b = np.asarray(b, dtype=np.float32) c = np.asarray(c, dtype=np.float32) ba = a - b bc = c - b denom = np.linalg.norm(ba) * np.linalg.norm(bc) if denom < 1e-6: return float("nan") cos_val = np.dot(ba, bc) / denom cos_val = max(-1.0, min(1.0, cos_val)) return float(np.degrees(np.arccos(cos_val)))

这里有两个细节。第一,denom < 1e-6表示两个向量里有一个长度为 0,说明三个点中有两个坐标重叠,这时角度没有意义,返回nan比返回 0 更好,因为后续统计能识别出非法值。第二,arccos的输入必须夹在 -1 和 1 之间,浮点计算可能产生 1.0000001,不夹的话arccos返回nan。

4.2 用置信度过滤脏数据再算角度

直接从关键点数组取坐标算角度,结果里会混入大量低置信度的点。实际操作中,我给角度计算包一层带置信度过滤的封装函数:

def filtered_angle(keypoints, joint_indexes, threshold=0.3): person = keypoints[0] points = [] for idx in joint_indexes: x, y, conf = person[idx] if conf < threshold: return float("nan") points.append((x, y)) return joint_angle(points[0], points[1], points[2])

调用时传入三个人体关键点编号,例如 COCO 模型下右肘角度是filtered_angle(kp, (2, 3, 4)),因为 2 是右肩、3 是右肘、4 是右手腕。膝关节角度是filtered_angle(kp, (8, 9, 10)),对应右髋、右膝、右踝。这里的threshold与画骨架时的阈值保持一致,否则会出现画面里画了一条线,但角度计算却返回空值的分裂感。这一层过滤是人体形态识别里最容易漏掉的部分,很多半途而废的项目都是因为角度曲线频繁跳变,然后误以为是模型不准,其实是没过滤低置信度点。

4.3 直接可用的形态规则:跌倒、下蹲、抬手和身体倾斜

有了角度和关键点坐标,形态规则就是一组阈值判断。常见做法是把规则封装成独立的判断函数,每个函数只接收当前帧的keypoints数组和上一帧状态,输出一个离散动作标签。

跌倒检测是形态识别里最热门的方向,常用规则是:头部关键点 y 坐标急剧下降,同时髋部中心点高度在一段连续时间内迅速下移。由于单目摄像头没有真实深度,像素高度会受距离影响,所以要特别小心。我通常先用关键点归一化:把头部坐标、髋部坐标除以肩宽或脖子到髋部的长度,消除一部分距离变化的影响。下蹲判断则更简单,膝关节角度小于某个阈值并持续若干帧,就认为进入下蹲状态,例如膝盖角度小于 100 度。

抬手动作可以通过腕部相对肩膀的 y 坐标判断,也可以看肘角。但绝对坐标有一个隐患:检测目标靠近摄像头时,手腕像素 y 坐标自然变小,看起来像是在抬手。因此我会优先选择角度,比如手臂伸直判定为肩、肘、腕三点夹角超过 160 度,然后再配合腕部相对肩膀的高度做二次确认。身体倾斜则用左肩和右肩连线的角度:肩连线与水平方向的夹角超过 10 度,说明躯干侧倾。这个角度在摄像头与人正面相对时最准,斜侧视角会引入投影误差,属于物理上的限制。

必须承认的是,OpenPose 在单目二维图像上没有任何深度信息,所谓“形态”只能是二维投影形态。摄像头稍微转到侧面,左右肩的相对关系会变化,角度值也会失真。做规则的时候要限定摄像头角度,或者干脆只做正面和斜前方的人体形态判断。

5. 摄像头姿态识别的踩坑检查:打不开、抖点、显存不足与版本错配

5.1 摄像头打不开和画面花屏:索引、占用与编码格式

现象:cap.read()一直返回 False,cap.isOpened()却是 True。原因是摄像头被其他程序独占,或者索引选错。笔记本自带的摄像头默认是 0,但部分 USB 摄像头会被识别成 1 甚至 2。解决:依次用VideoCapture(0)、VideoCapture(1)、VideoCapture(2)试探,并打印isOpened()结果。如果系统里装了多个采集设备,不要依赖默认索引,最好在启动时加一个设备选择参数。

现象:画面能出来,但颜色偏绿或出现大量横纹。原因是摄像头输出格式不是 OpenCV 默认的格式。解决:先设置 MJPG 编码,再设置分辨率。很多 USB 摄像头在 YUYV 格式下只支持 640x480,切成 MJPG 后才支持 1280x720 或更高。

cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc("M", "J", "P", "G")) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)

还有一个常见场景是虚拟机里接入摄像头。如果VideoCapture(0)在宿主机正常,但在虚拟机里黑屏,多半是虚拟机的 USB 摄像头直通没生效。解决:关闭虚拟机,在虚拟机设置里把摄像头设备直通给访客机,而不是插上 USB 后发现没反应。

现象:读取本地视频正常,但 RTSP 网络摄像头延迟大、黑屏。原因是 OpenCV 的 RTSP 拉流在弱网环境下默认走 TCP 不够稳。解决:降低采集分辨率,设置较为合理的缓冲区,或者干脆用命令行工具拉流成本地文件再处理。不要指望模型能纠正输入画面的花屏,前端的脏数据会让关键点置信度集体降低。

5.2 模型加载和推理崩溃:No module named 'openpose'、显存不足与 OpenCV 冲突

现象:import openpose直接报ModuleNotFoundError: No module named 'openpose'。原因多半是PYTHONPATH没设置,或者设置了但指向的目录不对。解决:先确认编译生成的模块路径是否存在openpose目录,然后在脚本开头sys.path.append该路径。这里有个经验,路径不要写相对路径,因为代码运行时的工作目录往往会变化,最好用环境变量或启动参数传入。

现象:显存充足的机器上运行一段时间后,报cudaErrorMemoryAllocation。原因不是全局显存不够,而是 OpenPose 会在当前时刻为该帧分配大量中间显存,比如输入分辨率太高、同时处理的人员太多。解决:把net_resolution从-1x368降到-1x256,把number_people_max设为 1,把每隔几帧推理一次改成隔帧推理。这些参数在推理精度上会有点损失,但换来了稳定性,对于形态识别原型完全够用。

现象:程序能运行,但一旦执行op_wrapper.emplaceAndPop(...)就崩溃,或者偶然性地退出时抛出cv2.error。原因常见于系统里同时存在多个 OpenCV 版本,pyopenpose 内部加载的是系统库,而 Python 侧import cv2加载的是 pip 库,两者版本不同导致内存布局冲突。解决:在启动脚本里显式清理LD_LIBRARY_PATH,把系统/usr/lib下的 OpenCV 路径摘除,只保留虚拟环境的动态库路径。

现象:按网上旧教程在 Windows 上配置 OpenCV 3.4.1 加 mingw64 之后,编译 OpenPose 总是失败。原因是 OpenPose 官方分支的默认编译链是 MSVC,mingw64 会带来 ABI 不兼容,包括 protobuf、opencv 都可能对不上。解决:Windows 下优先使用官方文档推荐的 MSVC 和 CMake 预设,或者干脆在 Ubuntu 虚拟机里跑,省掉这些底层的兼容性折腾。

5.3 关键点抖动和漏检:置信度阈值、平滑与多人 ID 不稳定

现象:一个人站在原地,肘关节点每帧跳变 5 到 10 个像素,画出来的骨架在正常和异常姿态之间来回闪。原因是网络在遮挡、快速移动和大尺度变形下输出的关键点置信度不稳定,加上没有做时间维度的平滑。解决:每一帧都不直接使用原始坐标,而是用指数移动平均来处理关键点。

smoothed = 0.4 * observed_coord + 0.6 * previous_smoothed_coord

这个公式对每个关键点的 x、y、confidence 分别做。这里的权重 0.4 表示新观测值占的比重,需要看实际效果微调。抖动严重时降到 0.25,反应灵活时调到 0.55。但有一个例外:当关键点置信度已经很低时,不要继续用原始observed_coord更新,而是保持上一帧的平滑值,否则会把明显错误的点引入。

现象:本来只有一个人在场景里,但骨架突然跳到另一个人身上。这通常是因为场景里短暂出现了另一个人,而 OpenPose 不负责跨帧的 ID 关联,每一帧都是独立推测人员。解决:在单人场景里把number_people_max固定为 1,并只取keypoints[0]。如果一定要多人,必须在代码里自己根据髋部中心点位置做最近邻匹配,否则无法保持身份。

现象:画面中人物轻微遮挡,某几个关键点连续几十帧消失。原因是在 2D 视角下,被挡住的关节没有可观测像素,网络只能靠上下文猜测。解决:如果应用场景允许,调整摄像头高度和角度,让躯干和四肢正对镜头。比如跌倒检测需要较高机位,下蹲检测机位不能太低,否则膝盖点被大腿挡住。遮挡不是代码能完全解决的问题,物理上改善视角才是正途。

6. 从原型到工具:抓帧线程、关键点平滑与固定视频回归

6.1 摄像头采集与推理解耦

同步循环里emplaceAndPop耗时多少,摄像头采集就停顿多久,画面会越来越卡。常见做法是拆两个线程:一个只负责抓帧,一个只负责推理,中间用一个有界队列缓冲。队列满的时候丢掉最旧的帧,保证推理线程永远拿到最新的画面。

import threading import queue frame_queue = queue.Queue(maxsize=2) def capture_worker(cap): while True: ret, frame = cap.read() if not ret: frame_queue.put(None) break if not frame_queue.full(): frame_queue.put(frame)

推理线程从frame_queue.get()取帧,然后执行 OpenPose 推理。队列容量限制为 2,可以避免抓帧线程积压大量旧帧导致延迟持续增大。实测中这个结构能把画面延迟压缩到一帧推理耗时左右,是摄像头姿态识别最直接有效的优化。

6.2 固定视频回归验证

不要在摄像头画面上一遍遍“看起来还行”就当完成测试。我习惯录一段固定场景的视频,包含站立、行走、下蹲、抬起手臂等动作,把它作为回归样本。每一轮改完参数后,对这段视频重新跑一遍,记录三个指标:推理耗时、关键点平滑后的抖动幅度、以及角度曲线是否符合人工预期。只有固定在同一个输入上,才能对比优化前后的效果。

参数推荐起点调整方向
net_resolution-1x368抖动大就降低到 -1x256
number_people_max1多人场景按需提升
平滑权重0.4越抖越小,越糊越大
推理间隔每 2 帧推理 1 次卡顿就增加间隔

6.3 一个翻车的教训

有次在客户现场做演示,一接上会议室大屏画面就花,我反复调模型参数,最后才发现是 USB 摄像头供电不足,换了个接口就正常了。从那以后我养成了一个习惯:任何改动都要录一段固定视频保存下来,模型代码、摄像头、分辨率全部写进配置,先跑回归,再拿回现场。人体形态识别算法本身并不玄学,真正让人翻车的往往是视频接入和环境问题了那一层。希望帮到你。

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

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

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

立即咨询