参考这篇文章
在Windows上编译OpenPose Python Wrapper - 远处有泽细细说 (yuanze.wang)https://yuanze.wang/posts/build-openpose-python-api/
为了防止文章中用到的东西失效,也附上一份我的百度网盘,我的网盘中额外添加了一个pybind11的压缩包,我并不清楚这个是否是必要的,作者提了一嘴,但教程中未涉及。
链接:https://pan.baidu.com/s/17KfsYGyxUuqcoVYD0FGcKQ
提取码:1odt
简单说一下流程:需要提前准备:NVIDIA显卡驱动,CUDA 10.0,CMake,VisualStudio
1、下载OpenPose源代码,推荐下载并解压我百度网盘中的“openpose.tar.gz”以保持版本一致性。也可去官网自行下载最新版。
2、下载百度网盘中的"opencv_411_v14_15_2019_09_24.zip","caffe3rdparty_15_2019_03_14.zip",“caffe_15_2019_05_16.zip”到openpose\3rdparty\windows中,并解压到此处。(注意保留压缩包在此处,防止程序未检测到对应文件,重新下载。)
3、删除openpose\models文件夹,并下载百度网盘中的"models"文件夹进行替换。
4、下载并解压百度网盘中的"pybind11.zip",放在openpose\3rdparty文件夹下覆盖。(不知道这一步是否必须。)
5、打开CMake,设置源代码位置为你的openpose位置(如F:/openpose),并在该目录下新建build文件夹作为编译文件夹(如F:/openpose/build)点击Configure按钮,选择你安装的VS版本,并选择平台为x64,点击Finish即可。不出意外的话CMake会在最下面显示Configuring done。
6、勾选上方变量中的BUILD_PYTHON(请确保已经安装了64位Python),再次点击Configuring按钮。随后点击Genetate按钮,生成VS工程文件,并点击OpenProject来打开工程,并在解决方案配置中选择Release(在本地Windows调试器左边)。
7、右键点击pyopenpose项目,点击生成。看到生成成功的提示后,可以在openpose\build\python\openpose\Release目录中找到pyopenpose.cp38-win_amd64.pyd(文件名根据python版本可能不同)。
8、换个地方新建一个名字叫openpose的文件夹,将第7步中提到的pyopenpose.cp38-win_amd64.pyd复制到其中,再将openpose\build\python\openpose\__init__.py复制到其中,再将openpose\build\bin中的所有文件复制到其中,最后将openpose\build\x64\Release\openpose.dll复制到其中。至此,这个openpose便是可以被我们本机对应版本Python调用的OpenPose库了。
将openpose\models文件夹复制到新建的openpose文件夹中,并在上一级目录新建openpose_demo.py,运行此文件即可演示Python对OpenPoseAPI的调用。
(图中其他Py文件,以及media等文件夹都是后续使用时自己创建的。)
openpose_demo.py里的东西如下:
import cv2
import sys
import timeit
import openpose.pyopenpose as opparams = dict()
params["model_folder"] = 'openpose\\models'
params["net_resolution"] = '128x192'
params["render_pose"] = '1'opWrapper = op.WrapperPython()
opWrapper.configure(params)
opWrapper.start()cap = cv2.VideoCapture(0)
print('Video device Initialized.')frame_start_time = timeit.default_timer()
frame_cnt = 0while True: # Process Image
datum = op.Datum()
ret, img = cap.read() # Read camera
imageToProcess = img
datum.cvInputData = imageToProcess
opWrapper.emplaceAndPop([datum])# print("Body keypoints: \\n" + str(datum.poseKeypoints))
cv2.imshow("Openpose Python - Press Q to Exit", datum.cvOutputData)frame_end_time = timeit.default_timer()
if frame_end_time - frame_start_time > 1:
print('fps:{}'.format(frame_cnt))
frame_cnt = 0
frame_start_time = frame_end_timeframe_cnt = frame_cnt + 1
if cv2.waitKey(1) & 0xFF == ord('q'):
breakcap.release()
cv2.destroyAllWindows()
exit(0)
在openpose\include\openpose\flags.hpp中可以查阅完整参数及说明,现挑一些我觉得比较重要的翻译如下:
params["model_folder"] = "openpose/models/"#模型地址
params["video"] = "./media/help.mp4"#视频地址(不写默认使用前置摄像头)
params["net_resolution"] = '160x240'#分辨率,需要是16的倍数,降低这个参数可以以准确率为代价显著提升处理速度。
params["disable_multi_thread"] = True#稍微降低帧率以大大减少延迟,用于网络摄像头
params["frame_step"] = 2#隔几帧处理一张图片
params["process_real_time"] = False#保持视频原来的速度,如果处理速度过慢就会跳帧,过快就会减慢速度
params["disable_blending"] = False #如果为True,只显示骨骼关键点,背景为黑
params["model_pose"] = "BODY_25" #参数设置"BODY_25“表示使用25点的检测模式,CUDA版本中最快最准的模式。此外设置"COCO"使用18点的检测模式,设置"MPI"使用15点的检测模式,最不精确,但在CPU上最快。设置"MPI_4_layers"使用15点的检测模式,甚至比上一种更快,但不够准确。
经过测试,BODY_25是最快的。(使用GPU的话)
附上25点和18点的位置图:
初始化伪代码如下(完整代码在最后面):
import openpose.pyopenpose as op
parser = argparse.ArgumentParser() args = parser.parse_known_args()params = dict() params["model_folder"] = "openpose/models/"#模型地址...#设置参数
#初始化
opWrapper = op.WrapperPython() opWrapper.configure(params) opWrapper.start()cap = cv2.VideoCapture("./media/help.mp4")
while True:
datum = op.Datum()ret, img = cap.read()
然后就可以开始使用了,在while语句中使用datum.cvInputData = img的形式对img进行骨骼关键点提取。
然后跟上一句opWrapper.emplaceAndPop([datum])
获取关键点的方式:key_points = datum.poseKeypoints[0]
key_points里即为每个关键点的信息,它的shape为(25,3),其中25代表25个关键点,3代表每个关键点的x坐标,y坐标和置信度(0-1之间的浮点数)
获取处理后图片的方式:frame = datum.cvOutputData
frame即为提取了关键点并绘制后的图片。
目标:识别图像中人是否在双手挥手呼救,并与单手挥手和双手伸懒腰区分开。
思路:使用onepose提取骨骼关键点后,判断双手手臂上的关键点y坐标是否在肩膀上方,且x坐标和肩膀中心的关键点的距离是否在阈值内(挥手时手臂会贴近头部,即靠近肩膀中心,而伸懒腰多数为双手向两边展开)
代码:
import cv2
import sys
import timeit
#import openpose.pyopenpose as op
import os
import shutil
from sys import platform
import argparse
try:
import openpose.pyopenpose as op
# Flags
parser = argparse.ArgumentParser()
args = parser.parse_known_args()
# Custom Params (refer to include/openpose/flags.hpp for more parameters)
params = dict()
params["model_folder"] = "openpose/models/"#模型地址
params["video"] = "./media/help.mp4"#视频地址(不写默认使用前置摄像头)
params["net_resolution"] = '160x240'#分辨率,需要是16的倍数
params["model_pose"] = "BODY_25" #`BODY_25` (fastest for CUDA version, most accurate, and includes"
#" foot keypoints), `COCO` (18 keypoints), `MPI` (15 keypoints, least accurate model but"
#" fastest on CPU), `MPI_4_layers` (15 keypoints, even faster but less accurate)
#params["disable_multi_thread"] = True#稍微降低帧率以大大减少延迟,用于网络摄像头
params["frame_step"] = 2#隔几帧处理一张图片
params["process_real_time"] = False#保持视频原来的速度,如果处理速度过慢就会跳帧,过快就会减慢速度
params["face_detector"] = 0#脸部检测的模式
params["disable_blending"] = False #如果为True,只显示骨骼关键点,背景为黑
#初始化
opWrapper = op.WrapperPython()
opWrapper.configure(params)
opWrapper.start()
#获取视频信息
cap = cv2.VideoCapture("./media/help.mp4")
fps = cap.get(cv2.CAP_PROP_FPS)
w = int(0.5 *cap.get(cv2.CAP_PROP_FRAME_WIDTH))
h = int(0.5 *cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
frame_start_time = timeit.default_timer()
#运算中需要用到的一些东西
frame_cnt = 0#计算FPS
is_help_threshold = 100#呼救角度阈值
is_help_num = 0#判断呼救累计值
is_first_help = True#是否初次判断成呼救
fourcc = cv2.VideoWriter_fourcc('m','p','4','v')
# print(fourcc)
# print(fps)
# print(w)
# print(h)
writer = cv2.VideoWriter(r'./output/mp4/output.mp4',fourcc,fps,(w,h))
while True: # Process Image
datum = op.Datum()
ret, img = cap.read() # Read camera
imageToProcess = cv2.resize(img,(w,h))
#imageToProcess = img
datum.cvInputData = imageToProcess#提取关键点
opWrapper.emplaceAndPop([datum])
#print(type(datum.poseKeypoints))
#print(datum.poseKeypoints.shape)
key_points = datum.poseKeypoints[0]#key_points保存每个关键点。shape为25,3,25代表25个关键点,3代表每个关键点的XY坐标和置信度
frame = datum.cvOutputData#获取提取骨骼之后的图片
#判断是否为help的后处理,基本思路是手臂需要高于肩膀。且在一定角度范围内。
if key_points[2][1] > key_points[3][1] and key_points[5][1] >key_points[6][1]:
if abs(key_points[1][0] - key_points[3][0]) < is_help_threshold and abs(key_points[1][0] - key_points[6][0]) < is_help_threshold:
if is_help_num <= 50:
if is_first_help and is_help_num >19 :
is_help_num = 50
is_first_help = False
is_help_num += 3
else:
if is_help_num < 20:
is_first_help = True
is_help_num = 0
if is_help_num >= 0:
is_help_num -= 1
else:
if is_help_num < 20:
is_first_help = True
is_help_num = 0
if is_help_num >= 0:
is_help_num -= 2
print('ishelpnum:',is_help_num)
if is_help_num >= 20:
cv2.putText(frame, f'help', (round(0.75 * frame.shape[1]), round(0.15 * frame.shape[0])),
cv2.FONT_ITALIC, 1, (16, 25, 238), 2, lineType=cv2.LINE_AA)
# print("Body keypoints: \\n" + str(datum.poseKeypoints))
#写入图片
writer.write(frame)
cv2.imshow("Openpose Python - Press Q to Exit", frame)
frame_end_time = timeit.default_timer()
if frame_end_time - frame_start_time > 1:
print('fps:{}'.format(frame_cnt))
frame_cnt = 0
frame_start_time = frame_end_time
frame_cnt = frame_cnt + 1
if cv2.waitKey(1) & 0xFF == ord('1'):
break
cap.release()
cv2.destroyAllWindows()
except Exception as e:
print(e)
sys.exit(-1)