用Python进行多人姿态估计
多人姿势估计是一个为体育和运动类应用设计的模型。该模型可以同时检测图像或视频中的六个人,每个人有17个关键点的关节。
本教程将使用一种被称为多人姿势估计的技术来预测图像帧中人的关节位置。
最受欢迎的用例之一是[运动学],它分析身体和身体内的所有不同角度和关节。
前提条件
要理解本教程,你需要熟悉以下内容。
- [机器学习]。
- OpenCV库。
- Python编程语言。
- Jupyter笔记本或Google Colab。为了贯彻执行,请使用Google Colab。
- TensorFlow和TensorFlow Hub。TensorFlow Hub是一个由训练好的机器学习模型组成的资源库,你可以下载并在你的任何项目中使用。
你需要从这个谷歌驱动器帐户下载
footballers.mp4视频文件,并将其上传到你的谷歌Colab。为了这个教程,我把它上传到了我的Google Colab上,但是运行后它就被删除了。所以,你需要自己下载并上传,以避免错误。
简介
多人姿态估计是谷歌在其闪电模型基础上建立的最新模型之一。它是对MoveNet.SinglePose模型的改进,后者只能检测单一姿势。该模型包括三个模型。
主干网络使用MobileNetV2网络构建,特征提取层由特征金字塔网络组成,而输出关键点的层由CenterNet模型组成。
多人姿势估计是一个为体育和运动型应用设计的模型。它的目的是在离你的相机或网络摄像头三到六英尺之间使用。如果你的工作距离超过六英尺,这个模型可能不是最适合你的。
该模型只能同时检测图像/视频中的六个人,每个人有17个关键点关节,即鼻子、左眼、右眼、右耳、左耳等。
这个模型的一些用例是。
- 在瑜伽课上确定瑜伽班成员的姿势的正确性。
- 在游泳课上确定哪些游泳者有最好的泳姿,哪些人需要改进。
- 在监督网球课的过程中。该模型将有助于分析具有正确和不正确划水姿势的人。
- 在医疗背景下,识别病人的异常姿势。
为了使用多人姿势估计模型,我们需要执行三个过程。
- 安装TensorFlow和TensorFlow Hub。
- 加载多人物运动网的闪电模型。
- 从视频中进行检测。
让我们开始吧!
安装和导入依赖项
!pip install tensorflow==2.4.1 tensorflow-gpu==2.4.1 tensorflow-hub opencv-python matplotlib
import tensorflow as tf
import tensorflow_hub as hub
import cv2
from matplotlib import pyplot as plt
import numpy as np
numpy将用于帮助绘制关键点和边缘cv2将使我们能够利用OpenCV库进行计算机视觉。在本教程中,它将在使用网络摄像头和运行视频时帮助我们。tensorflow_hub将使我们能够使用预先训练好的多人Movenet模型。
如果你使用的是GPU,考虑限制你的GPU的内存增长,以避免收到内存不足的错误。这限制了TensorFlow使用你机器上所有的V-RAM。
gpus = tf.config.experimental.list_physical_devices('GPU')
for gpu in gpus:
tf.config.experimental.set_memory_growth(gpu, True)
从TF Hub加载模型
model = hub.load('https://tfhub.dev/google/movenet/multipose/lightning/1')
movenet = model.signatures['serving_default']
第一个变量,model 是下载模型,而第二个变量,movement 是设置一个新的变量来继续使用该模型。
使用视频或网络摄像头进行检测
cap = cv2.VideoCapture(0)
while cap.isOpened():
ret, frame = cap.read()
cv2.imshow('Multi-Person Pose Estimation', frame)
if cv2.waitKey(10) & 0xFF==ord('q'):
break
cap.release()
cv2.destroyAllWindows()
上面的代码是一个标准的OpenCV代码,我们在以前的OpenCV教程中使用过。
这段代码建立了与我们的网络摄像头的连接,读取了我们的图像/视频中的帧,并在我们的屏幕上渲染了这些帧。最后一段代码告诉我们如何在完成后退出我们的应用程序。
请注意,
VideoCapture(0)中的数值0可能会改变,这取决于你的视频设备的数量。如果0不起作用,你可以尝试改变这个数字。
我们将把我们捕获的frame 传递给模型,以便用我们的模型使用这些帧。
这样做的方法如下。
from google.colab.patches import cv2_imshow
cap = cv2.VideoCapture('footballers.mp4')
while cap.isOpened():
ret, frame = cap.read()
# Resize image
img = frame.copy()
img = tf.image.resize_with_pad(tf.expand_dims(img, axis=0), 384,640)
input_img = tf.cast(img, dtype=tf.int32)
# Detection section
results = movenet(input_img)
keypoints_with_scores = results['output_0'].numpy()[:,:,:51].reshape((6,17,3))
# Render keypoints
loop_through_people(frame, keypoints_with_scores, EDGES, 0.1) #0.1 is our confidence_threshold
cv2_imshow(frame)
if cv2.waitKey(10) & 0xFF==ord('q'):
break
cap.release()
cv2.destroyAllWindows()
在文档中,为了在输入的图像上运行模型推理,建议调整图像的大小和填充(如果大小是奇数,则添加0),以便。
- 高度/宽度都是32的倍数。
- 高度和宽度的比例应该足够接近原始图像的长宽比。
- 较大的一面应该做成256px。例如,一个720p的图像(即720x1280(HxW))应该被调整大小并填充为160x256的图像。
这就是该附加代码的作用。然后我们使用movenet 模型进行检测,最后渲染关键点。
输出是一个float32张量,形状为[1, 6, 56] 。1 代表批处理维度,6 代表模型可以检测的最大人数,56 代表预测的边界框/关键点位置和分数。
前51个元素(17*3)是关键点位置和分数。最后5个元素代表边界框的区域和实例的信心分数。
我们用NumPy[:,:,:51] 来抓取所有的批次维度,所有的最大人数,只抓取51个关键点的位置和分数,因为这就是我们渲染图像所需要的。reshape((6,17,3) 告诉我们,我们重塑了关键点,有6 人,每个人有17 关节,每个人有3 值;x、y、和置信度分数。
17个关键点关节的顺序是。[鼻子,左眼,右眼,左耳,右耳,左肩,右肩,左肘,右肘,左腕,右腕,左髋,右髋,左膝,右膝,左踝,右踝]。
下面是循环浏览每个人的检测和渲染的函数。
def loop_through_people(frame, keypoints_with_scores, edges, confidence_threshold):
for person in keypoints_with_scores:
draw_connections(frame, person, edges, confidence_threshold)
draw_keypoints(frame, person, confidence_threshold)
confidence_threshold 告诉模型,如果达到阈值,就只画关键点和边缘。例如,如果置信度为0.2 ,但置信度_score被设置为0.5 ,那么该关节将不会被绘制。
剩下的就是绘制关键点和边缘了。
绘制关键点和边缘
我们将创建draw_keypoints 和draw_connections ,这将有助于我们在检测后渲染我们的视频。
def draw_keypoints(frame, keypoints, confidence_threshold):
y, x, c = frame.shape
shaped = np.squeeze(np.multiply(keypoints, [y,x,1]))
for kp in shaped:
ky, kx, kp_conf = kp
if kp_conf > confidence_threshold:
cv2.circle(frame, (int(kx), int(ky)), 6, (0,255,0), -1)
def draw_connections(frame, keypoints, edges, confidence_threshold):
y, x, c = frame.shape
shaped = np.squeeze(np.multiply(keypoints, [y,x,1]))
for edge, color in edges.items():
p1, p2 = edge
y1, x1, c1 = shaped[p1]
y2, x2, c2 = shaped[p2]
if (c1 > confidence_threshold) & (c2 > confidence_threshold):
cv2.line(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0,0,255), 4)
EDGES = {
(0, 1): 'm',
(0, 2): 'c',
(1, 3): 'm',
(2, 4): 'c',
(0, 5): 'm',
(0, 6): 'c',
(5, 7): 'm',
(7, 9): 'm',
(6, 8): 'c',
(8, 10): 'c',
(5, 6): 'y',
(5, 11): 'm',
(6, 12): 'c',
(11, 12): 'y',
(11, 13): 'm',
(13, 15): 'm',
(12, 14): 'c',
(14, 16): 'c'
}
上面的数值告诉我们如何连接这些关节点。记得我们提到过17个关节点的读取顺序。因此,例如,第一个值,(0, 1): 'm', 告诉我们鼻子如何连接到左眼,而最后一个值,(14, 16): 'c' 告诉我们右膝如何连接到右脚踝。
总结
总结一下,我们安装并导入了我们的依赖项,加载了模型,使用网络摄像头或视频进行检测,最后绘制了关键点和边缘。
如果你没有得到准确绘制的关键点和边缘,或者它在不应该绘制的物体上绘制,你可以尝试调整信心分数和比例值,以获得正确的长宽比。
你通过的图像越大,检测的速度就会越慢。反过来也是如此。