1. 先搞清楚这套组合的逻辑:为什么是OpenPose + ST-GCN
如果你能搜到这个标题,大概率已经看过前两篇关于姿态估计和动作识别的基础内容了。OpenPose负责从视频帧里提取人体关键点坐标,ST-GCN再把这些关键点序列当成图结构数据去分类,两者前后衔接,正好组成一条完整的“视频动作识别”pipeline。这篇文章不聊理论推导,只聊怎么在Win10上把OpenPose 1.7.0和ST-GCN的代码完整复现出来,包括编译、跑通demo、数据对接和踩坑记录。
我默认你是有一定Python基础的,至少会装包、改环境变量,也大概知道CUDA是干什么的。但我不默认你熟悉C++和CMake,因为OpenPose在Windows上的编译过程,确实拦住了很多人。这篇文章会把从零到一的每一步都拆开讲,命令、参数、日志现象都给你列出来,你照着操作,比看十篇零散教程都管用。
1.1 这套模型组合到底在解决什么问题
先说清楚一个概念:动作识别不是图像分类,它面对的是“一段视频里某个人在做什么动作”这个问题。输入不是单张图片,而是一段时间内的多帧图像;输出也不只是“有没有人”,而是“这个人在做什么”,比如走路、挥手、坐下、摔倒。
做这件事有两条技术路线:一条是基于RGB图像的时序模型,典型代表是SlowFast、TSN这类;另一条就是先做姿态估计,把每个人的骨骼关键点提取出来,再对关键点序列做分类,OpenPose + ST-GCN就是这条路线里的经典组合。
为什么要绕一圈去提取骨骼再分类?因为骨骼关键点去掉了背景、衣服、光照这些干扰信息,模型学的是“关节角度和位置关系的变化模式”,泛化能力更强。而且骨骼数据是低维的,计算量比直接处理视频帧小很多。做过实际项目的人都知道,工业场景里动作识别经常要跑在边缘设备上,骨骼方案的实际部署成本低得多。
OpenPose 1.7.0支持2D人体关键点检测,单人最多能出25个关键点(BODY_25模型),多人场景也能处理。ST-GCN全称是Spatial Temporal Graph Convolutional Network,它把每一帧的骨骼关键点看成图的节点,关键点之间的自然连接关系看成边,再把时间维度上的帧间连接也考虑进去,用图卷积来提取空间特征,用时序卷积来提取运动特征,最终输出动作类别概率。简单说,OpenPose负责“看到人”,ST-GCN负责“看懂动作”。
1.2 为什么选择Win10原生环境而不是WSL或虚拟机
很多教程推荐在Ubuntu下跑OpenPose和ST-GCN,毕竟这两个项目的主要测试环境都是Linux。但这篇文章的主角是Win10,而且我可以负责任地说:在Win10原生环境复现这套代码,比用WSL和虚拟机更省心。
先说虚拟机。VirtualBox这类虚拟化方案最大的问题是GPU透传。OpenPose和ST-GCN的推理和训练都要用CUDA,虚拟机里要么无法访问物理显卡,要么性能损失巨大,跑起来比CPU还慢。你想用VMware装个Win10再在里面跑CUDA,基本是给自己找麻烦。所以虚拟机方案直接排除。
再说WSL2。WSL2虽然支持CUDA转发,OpenPose也能在WSL2里通过vGPU跑,但你会遇到几个很尴尬的问题:OpenPose的demo程序要弹出GUI窗口显示检测结果,WSL2要配置Windows的X Server才能弹出图像界面;摄像头读取、视频文件路径映射也是坑;Python环境的OpenCV还要额外处理显示后端。这些都不难,但叠加在一起非常消耗耐心,刚开始复现项目的人很容易在这一步就放弃了。
相比之下,Win10原生环境的优势很明显:Visual Studio的MSVC编译器是OpenPose官方支持的构建工具链,CMake能直接识别;OpenPose官方提供了完整的Windows编译文档;Python版本、CUDA版本、cuDNN版本在Windows下都有成熟的搭配方案。只要你照着正确版本装,编译过程虽然长,但每一步都是可控的。
1.3 版本选型与软硬件要求
复现老代码,版本锁死是第一原则。OpenPose 1.7.0官方明确支持CUDA 10.x和CUDA 11.x的部分版本,但考虑到ST-GCN的官方实现是基于TensorFlow 1.x的,这里有个很重要的兼容性约束:TensorFlow 1.14到1.15版本需要CUDA 10.0或10.1,以及cuDNN 7.6。所以我把整套环境的版本都锁定在CUDA 10.1 + cuDNN 7.6上,这样OpenPose和ST-GCN都能兼顾。
硬件方面,建议至少8GB显存的NVIDIA显卡。我实测用的是GTX 1660 Super(6GB),OpenPose单帧推理大概50到80毫秒,ST-GCN推理一个动作序列不到50毫秒。如果你的显卡是RTX 20系或30系,记得要注意显卡驱动版本必须支持CUDA 10.1。RTX 30系是可用的,只是编译的时候需要额外注意算力参数,后面编译章节我会具体讲。
软件清单先放在这里,后面会逐个安装:
- Windows 10 64位系统,建议更新到较新的版本
- Visual Studio 2019(Community版即可,必须安装C++桌面开发组件)
- CMake 3.14以上版本(我用的3.20)
- Git for Windows
- Python 3.6或3.7(推荐3.6,ST-GCN的依赖更稳)
- CUDA 10.1 + cuDNN 7.6.5
- OpenPose 1.7.0源码
- ST-GCN源码(yysijie/st-gcn)
这里特别说明一下为什么不用Python 3.8以上。OpenPose 1.7.0的Python API编译时需要匹配Python的版本,Python 3.8也能编译成功,但ST-GCN官方代码依赖的TensorFlow 1.15在Python 3.8下兼容性很差,经常报“module ‘tensorflow’ has no attribute ‘random_uniform’”之类的错误。为了少踩坑,我建议你卸载高版本Python,老老实实装一个Python 3.6,用conda管理环境最省事。
2. 搭建复现环境:Win10系统准备与工具链安装
环境搭建阶段花的时间,往往比跑通代码本身还多。这个阶段急不得,每一步做完都值得停下来确认一遍结果,不然到了编译阶段,一个环境变量配置错误会让你反复横跳。
2.1 系统层面的Windows优化与安全中心处理
先说一个很多人第一次编译C++项目都会遇到的问题:Windows安全中心把编译生成的exe或dll文件当成威胁清掉了。OpenPose在编译过程中会生成几十个exe和dll文件,Windows的实时保护偶尔会把其中某些文件判定为可疑程序,特别是当你第一次运行时,Defender的云检查还没认识这些文件。
处理思路不是把实时保护全部关掉,而是把工程目录加入白名单。具体操作:打开Windows安全中心,选择“病毒和威胁防护”,点击“管理设置”,在“排除项”里把OpenPose的源码目录和STM32(开玩笑,是ST-GCN的目录)都加进去。这样既不牺牲全局安全性,又避免构建产物被误删。
另外建议你检查几个系统配置:
- 开启Windows的长路径支持。OpenPose和ST-GCN的源码目录结构很深,有些文件路径超过260字符会引发git clone失败。通过组策略开启:Win+R输入gpedit.msc,进入“计算机配置 → 管理模板 → 系统 → 文件系统 → 启用Win32长路径”,设置为“已启用”。
- 电源计划设为“高性能”。编译是吃CPU的活,笔记本用户如果不插电编译,一个项目可能要跑四十分钟以上,电源计划会明显影响编译速度。
- 关闭UAC弹窗干扰。编译过程中VS和CMake会自动弹出大量确认框,建议把UAC级别调到最低,等全部跑完再调回来。
2.2 必备工具链安装细节
Visual Studio 2019安装的时候,工作负载勾选“使用C++的桌面开发”,右侧安装详细信息里确认勾选以下组件:MSVC v142 - VS 2019 C++ x64/x86生成工具、Windows 10 SDK、C++ CMake工具。CMake工具可以不在VS里装,后面我们单独安装CMake GUI。
CUDA 10.1的安装需要注意,安装前先确认NVIDIA显卡驱动版本不要太新。这是个很反直觉的点:太新的驱动不一定兼容老版本CUDA Toolkit。如果驱动版本太新导致CUDA 10.1的固件不兼容,安装的时候会报错,个别情况装完以后运行还会出现奇怪的问题。我个人的经验是:驱动版本在441到452左右,对CUDA 10.1是最稳的。
cuDNN安装相对简单,解压后把cuda文件夹下的bin、include、lib\x64三个目录里的文件,分别复制到CUDA安装目录(C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1)对应的bin、include、lib\x64目录下。
装完以后建议验证CUDA环境。命令行输入:
nvcc --version正常会输出CUDA 10.1版本的编译信息。再写一个简单的测试脚本验证运行时是否正常,或者直接编译OpenPose的时候再验证——反正第一步过不去的话,CMake配置阶段一定会报错。
2.3 为什么版本锁定这么重要
我知道肯定有人会用最新的CUDA 12.x去试,然后跑来问为什么编译失败。道理其实很简单:OpenPose 1.7.0是2020年发布的,它内部依赖的Caffe框架和第三方库(如Caffe、OpenCV)都是按当时的CUDA版本适配的。ST-GCN官方实现更老,TensorFlow 1.15的时代是2019年,连Python 3.7都算新版本。
老代码配老版本,不是保守,是实用性考虑。你复现这个项目是为了理解动作识别的完整流程,而不是为了给开源项目做版本适配。把这套环境跑顺之后,你已经有足够经验去迁移到更新的实现上了。
还有一个小建议:所有软件安装路径、项目路径、模型路径都避免中文和空格。OpenPose的CMake脚本对空格路径的处理虽然优化过,但ST-GCN的Python代码读文件时,中文路径经常触发编码问题。我见过太多人因为用户名叫“张三”就把整个项目放到C:\Users\张三\目录下,最后在读取模型文件时各种解码报错。实在没办法的话,把项目直接放在D盘根目录,比如D:\ActionRecognition\。
3. 编译OpenPose 1.7.0:CMake配置到VS2019构建
OpenPose在Windows上的编译是这套流程里最劝退、但其实也最套路化的环节。只要版本匹配,CMake配置正确,剩下的就是等编译完成。
3.1 下载源码与模型
从GitHub克隆OpenPose源码:
git clone https://github.com/CMU-Perceptual-Computing-Lab/openpose.git cd openpose git checkout v1.7.0注意一定切到v1.7.0标签,不要用master分支。master分支经历了后续更新,和ST-GCN对接时有些API变动,但复现文章还是按照1.7.0来说更稳妥。
OpenPose在首次运行时会自动下载模型文件,但自动下载经常因为网络原因失败。我的做法是提前手动下载好所需模型,放到指定目录。需要下载的模型主要是这几个(以BODY_25为主):
- pose_iter_440000.caffemodel(BODY_25模型)
- hand_pose_iter_102000.caffemodel(手部关键点模型)
- face_pose_iter_116000.caffemodel(面部关键点模型)
把下载好的模型文件放到model目录下,OpenPose源码目录里本来就有对应的文件夹结构,比如model/pose/body_25/。放好后运行OpenPoseDemo就不会再触发自动下载了。
3.2 CMake配置参数逐项说明
打开CMake GUI,设置源码目录为OpenPose的根目录,构建目录建议设置为源码目录下的build文件夹。
第一次点击Configure之前,需要先选择生成器。选“Visual Studio 16 2019”,平台选择“x64”。这里有个常见的坑:如果你没选x64,默认可能是x86,后面编译出来的是32位程序,加载不了64位的CUDA库,直接报一堆“无法解析的外部符号”错误。
Configure完成之后,重点检查以下选项:
- BUILD_PYTHON_API:勾选,我们需要Python接口
- BUILD_EXAMPLES:勾选,方便测试demo
- BUILD_CAFFE:勾选,OpenPose自带Caffe,编译时一起编
- USE_CUDA:勾选
- USE_CUDNN:勾选
- USE_OPENCV:勾选
- GPU_MODE:选择CUDA
- CUDA_ARCH:这里要填你的显卡算力对应值。GTX 1660 Super是7.5,RTX 20系是7.5,RTX 30系是8.6。如果填错,编译能过,但运行时可能报“no kernel image is available for execution on the device”
如果你没有OpenCV,让CMake自动下载OpenCV也行,但下载速度慢且容易失败。我更推荐手动下载OpenCV 4.1或4.2版本,解压后在CMake里手动设置OpenCV_DIR为opencv/build目录。这个路径一定要精确到包含OpenCVConfig.cmake的目录。
再次点击Configure直到没有红色警告,然后点Generate生成VS解决方案。
3.3 VS2019编译与运行实测
用VS2019打开build目录下的OpenPose.sln,解决方案配置选择“Release”,平台选择“x64”,右键点击解决方案,选择“生成解决方案”。
这里提醒一下:首次编译时间很长,取决于CPU性能,一般20到50分钟。中间可能有一两次报错,先别慌,很多报错是环境问题,不是代码问题。常见的“找不到Python.h”错误,是因为CMake的Python路径没有指向正确环境;常见的“C2220: 警告被视为错误”需要改一下VS的警告设置,把警告不作为错误即可。
编译完成后,OpenPoseDemo.exe会生成在build\x64\Release目录下。测试一张图片:
cd build\x64\Release .\OpenPoseDemo.exe --image ../../../examples/media/COCO_val2014_000000000192.jpg --write_images output/如果一切正常,output目录下会生成带骨骼连线标注的图片。第一次看到输出图的时候,说明OpenPose已经跑通了。
测试视频识别:
.\OpenPoseDemo.exe --video ../../../examples/media/video.avi --write_video output_video.avi注意视频文件路径换成实际存在的文件。如果视频文件本身有问题,OpenPoseDemo会卡住不动,看起来像死机,其实是在等待视频解码库响应。建议先用OpenCV自带的视频文件或者自己用ffmpeg转成MP4再试。
3.4 调用OpenPose Python API
OpenPose的C++推理接口用起来不方便,后续果然要喂数据给ST-GCN,必然要通过Python调用。编译完Python API之后,需要在环境变量里加入OpenPose的Python绑定路径:
build/python/openpose/Release build/x64/Release第一个目录里有pyopenpose.pyd,第二个目录里有OpenPose的dll。不加入这两个路径,import pyopenpose会直接报“ModuleNotFoundError: No module named ‘pyopenpose’”。
测试Python API:
import sys import cv2 sys.path.append('D:/ActionRecognition/openpose/build/python/openpose/Release') sys.path.append('D:/ActionRecognition/openpose/build/x64/Release') # 设置环境变量 import os os.environ['PATH'] = os.environ['PATH'] + ';D:/ActionRecognition/openpose/build/x64/Release' import pyopenpose as op params = dict() params["model_folder"] = "D:/ActionRecognition/openpose/models/" params["face"] = False params["hand"] = False opWrapper = op.WrapperPython() opWrapper.configure(params) opWrapper.start() image = cv2.imread("D:/ActionRecognition/openpose/examples/media/COCO_val2014_000000000192.jpg") datum = op.Datum() datum.cvInputData = image opWrapper.emplaceAndPop([datum]) print("检测到的人体关键点数:", len(datum.poseKeypoints)) cv2.imwrite("python_output.jpg", datum.cvOutputData)运行后终端会打印检测到的人数信息,同时当前目录生成python_output.jpg。这就是OpenPose在Python里跑通的标志。
这里有个容易踩的坑:系统里有多个Python环境时,pyopenpose.pyd绑定的Python版本必须和运行环境的Python版本一致。如果你用Python 3.6编译的OpenPose,就必须用Python 3.6解释器运行,换Python 3.9会直接报错“ModuleNotFoundError”或者加载失败。
4. 复现ST-GCN:骨架动作分类模型跑通
OpenPose拿到人体关键点之后,下一步就是让ST-GCN学会识别“这段骨架序列在做什么动作”。
4.1 ST-GCN的原理与输入数据格式
ST-GCN的核心思想是把骨架序列构造成一个时空图。每一帧里,人体关键点之间的连接关系构成空间边;相邻两帧之间同一个关键点的连接构成时间边。图卷积在空间上聚合邻接节点的信息,时序卷积在时间上捕捉运动的动态变化。
ST-GCN的输入数据维度是(样本数, 通道数, 帧数, 关键点数, 人数)。通道数通常是3,对应x坐标、y坐标和置信度。帧数就是一个动作序列持续了多少帧,关键点数就是每个骨架包含多少个点,人数表示一个样本里最多有几个人。OpenPose输出的poseKeypoints数组格式是(人数, 关键点数, 3),前两维是x和y坐标,第三维是置信度。你需要把自己采集的数据转成ST-GCN的格式,这一步叫数据预处理或者packing。
4.2 安装依赖与源码准备
ST-GCN官方实现地址是https://github.com/yysijie/st-gcn,但这个仓库的代码版本比较老,直接clone下来在新环境里跑会碰到不少问题。
我的建议是clone到本地之前,先创建好独立的环境。用conda创建Python 3.6环境:
conda create -n stgcn python=3.6 conda activate stgcn然后安装依赖:
pip install tensorflow-gpu==1.15.0 pip install numpy==1.17.4 pip install scipy==1.2.1 pip install opencv-python==4.1.2.30 pip install matplotlib pip install tqdm pip install pandas注意版本,numpy的版本尤其重要。TensorFlow 1.15和numpy 1.17是配套的,如果你直接装最新版numpy,跑数据增强时会出现“cannot import name ‘imread’”或者“module ‘numpy’ has no attribute ‘math’”这类问题。
4.3 数据准备:小规模跑通与NTU数据集
ST-GCN官方支持两个数据集:NTU RGB+D和Kinetics-Skeleton。NTU RGB+D是动作识别领域的标准数据集,有60类动作、几万样本,但完整下载需要超大空间和很长的下载时间。如果是第一次复现,我不建议直接把完整数据集搬下来——你更需要先验证代码流程能跑通。
Kinetics-Skeleton数据集相对小一些,仓库的data文件夹下有它的数据划分文件,包括train和val的样本列表。把数据集下载好放到data/kinetics_skeleton目录,然后运行训练脚本验证。
如果网络下载数据也不是很方便,还有一个取巧路径:自己用OpenPose在几段包含动作的视频上提取骨架,构造一个几十个样本的小数据集。虽然准确率不会高,但足以验证整个链路是通的。具体做法:用OpenPose把每帧的关键点提取出来,保存成npy数组,然后按ST-GCN的输入格式打包。
我个人建议的流程是:先下载Kinetics-Skeleton中的一小部分数据,例如只取前10类动作、每类几十个样本,放到data目录里,修改处理脚本的路径,快速验证训练和测试都能跑通。这个流程走得通,再考虑完整数据集。
4.4 训练与测试实操
ST-GCN仓库里提供了训练和测试的入口脚本main.py。训练前先确认配置文件,在config目录下找到st_gcn.kinetics-skeleton.yaml之类的文件,把数据集路径、显卡设置、批次大小、训练轮数等参数改好。
启动训练:
python main.py --train --config config/st_gcn.kinetics-skeleton.yaml训练过程中会看到loss逐渐下降、准确率慢慢提升。这个阶段不需要急着追求高精度,重点是确认代码能完整运行一个epoch。
测试已训练模型:
python main.py --test --config config/st_gcn.kinetics-skeleton.yaml如果你只是想把整个流程跑通,甚至可以跳过训练,直接用官方提供的预训练模型。把下载好的预训练模型放到指定目录,修改配置文件指向它,然后跑测试即可。
测试完成后,输出中会打印每个动作类别的准确率、recall、f1-score等指标。看到这些指标的那一刻,说明OpenPose + ST-GCN这套链路已经完整接通了。
5. 关键报错与排查记录
写到这里,我认为最值得你保存的是这一节。下面是我在复现过程中遇到过的报错和排查思路,按阶段整理成速查表,你遇到问题时可以直接对号入座。
5.1 CMake阶段的坑
报错“CMake Error: The following variables are used in this project, but they are set to NOTFOUND”:这是某依赖库没找到。最常见是OpenCV没有正确指定OpenCV_DIR,或者CUDA找不到。逐一查看CMakeError日志,找到具体是哪个库没找到,手动指定路径。
报错“CUDA_cublas_device_LIBRARY NOTFOUND”:CUDA 10.1在较新版本CMake下会有这个识别问题。解决方法是手动设置CUDA_cublas_device_LIBRARY路径,指向C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\lib\x64\cublas_device.lib。这个坑在官方文档里就有说明,属于CMake对旧版本CUDA兼容性的历史遗留问题。
报错“Python not found”或“PythonLibs NOTFOUND”:CMake默认查找的是最新版本的Python,而我们需要的是Python 3.6。在CMake GUI里手动设置PYTHON_LIBRARY为Python 3.6安装目录下的libs\python36.lib,PYTHON_EXECUTABLE指向python3.6.exe。
5.2 编译阶段的坑
编译报错“C2220: warning treated as error - no object file generated”:VS2019默认把警告当错误,导致编译中断。解决方法是打开项目属性 → C/C++ → 常规 → “将警告视为错误”改为“否”。也可以在OpenPose的CMakeLists里调整这个选项,重新生成项目。
编译报错“LNK1104: cannot open file ‘python37.lib’”:这表明CMake混用了Python版本。你配置的OpenPose可能找到了Python 3.7的库,但转换到VS工程后某些子项目指向了错误路径。回到CMake,把PYTHON_LIBRARY改成实际安装的版本,重新Generate。
5.3 运行阶段的坑
运行OpenPoseDemo报“Failed to load the model”:模型文件路径不对。OpenPose是相对路径查找模型,源码根目录启动才行,或者用--model_folder参数显式指定。建议启动时加--model_folder D:/ActionRecognition/openpose/models/。
运行Python API报“DLL load failed”:一种原因是缺少Microsoft Visual C++运行库,另一种是OpenPose的dll文件路径没加入系统PATH。把build/x64/Release加入PATH后重启终端再试。
ST-GCN训练报“Resource exhausted: OOM when allocating tensor with shape[...]”:显存不足。降低batch_size,或者把num_worker(数据预取进程数)调小。实在不够,把输入帧数调低,比如从N=150改成N=100。
5.4 环境匹配速查表
| 组件 | 推荐版本 | 备注 |
|---|---|---|
| Windows | 10 64位 1909以上 | 开启长路径 |
| Visual Studio | 2019 16.11 | 安装C++桌面开发 |
| CMake | 3.20.x | GUI版更方便 |
| CUDA | 10.1 | 显卡驱动441.22 |
| cuDNN | 7.6.5 | 需登录NVIDIA官网下载 |
| Python | 3.6.8 | 用conda管理 |
| TensorFlow | 1.15.0 | ST-GCN依赖 |
| OpenPose | v1.7.0 | 切到tag再编译 |
| OpenCV | 4.1.2 | 手动指定路径 |
我实际用这套配置跑下来,OpenPose推理正常,ST-GCN训练和测试正常,没有遇到版本不兼容的玄学问题。再补充一个经验:如果你用的显卡是RTX 30系,CUDA 10.1在运行起来之后可能报“no kernel image available”的错误,这是因为CUDA 10.1不支持Ampere架构的算力(8.0/8.6),这时需要安装CUDA 11.1以上版本,但TensorFlow 1.15的兼容性又会下降。两条路:要么换一张20系或10系显卡来复现老项目,要么放弃ST-GCN官方老代码,改用PyTorch实现的ST-GCN复现版。从个人经验看,PyTorch版(例如microsoft的st-gcn移植)用起来更舒心,但那就不是这篇标题里说的“复现原始代码”了。建议小白先用老版本跑通流程,跑完理解了,再迁移到PyTorch版。
最后再分享一个实操中的心得体会:整套流程跑下来,真正卡住人的地方不是模型原理,而是环境匹配。当年我在Windows上编译OpenPose时,CMake配置反复失败了七八次,每次都是老老实实看日志、找依赖、改路径,最后一上午才把整个构建链路理顺。等你把这一步迈过去,后面无论是换数据集还是换识别模型,都会顺畅很多。如果你配环境的时候遇到我这里没有写到的报错,不要慌,去GitHub的issue区搜关键词,大概率有人已经问过同样的问题了。
还有一个小技巧:建议把每一步安装好的软件版本、下载链接、配置参数都记录在文档里,包括环境变量设置、CMake配置项的勾选情况。这个东西在将来重装系统、换机器的时候,价值比你想象的大得多。我自己后来换电脑,一小时就把这套环境重新搭好了,全凭当时的笔记。