Mediapipe三维实时人体关键点检测与追踪
1.Mediapipe动作计数
前面上文,我们已经知道了,人体姿态的动作,是通过3个关节点加二个人体支干,组成的关节角度,来判断动作的。
所以识别某一个具体的动作,我们只需要找出人体做出指定动作的最明显的肢体部位,比如说,人体做下蹲的时候,最明显的特征可以识别出这个动作的肢体就是大腿和小腿。
等我们找到对面的肢体部位,将对应的部位,映射到mediapipe的具体关节点,比如说引体向上,对应的肢体就是我们的手臂。
手臂对应到Mediapipe中的索引号是16,14,12(左臂)11,13,15(右臂)。可以看下,做引体向上,角度(16-14-12)的夹角,角度(11-13-15)的夹角会在引体向上过程中发生变化。
具体动作计数步骤:
- 先识别出人体的姿态
- 计算关键肢体位置的角度
- 我们通过记录肢体角度的变化,来对动作进计数
; 2.动作计数
2.1 俯卧撑
要想做好不同动作识别,最关键就是找到做动作,肢体变化最明显的部位。
🐵比如说俯卧撑,可以看出人的手臂和躯干在变化
对应到mediapipe的部位编号就是16,14,12(左臂),15,13,11(右臂),12,24,26(躯干)
有了动作计数,我们还需要有一个动作完成进度,因为每一个动作都是从初始动作一点点,变化到标准动作位置。对应的肢体角度也是一点点的变化的。
因此我们需要一个动作进度条。这里使用一种函数np.interp()线性插值。
函数解释:
np.interp(angle,(x1,y1),(x2,y2))
- angle:就是对应我们通过mediapipe得到的肢体夹角,角度
- (x1,y1):可以理解为angle的角度变化的范围
- (x2,y2):可以理解为通过角度的数值,映射到进度条的数值的范围,类似于m=2n,n的取值范围就是角度的范围,m的取值范围就是进度条的取值范围。
最后返回一个进度条数值。
这样我们就可以通过获取实时的角度,映射到进度条中,得到实时的进度条的值。
我们这里认为手臂的角度小于50为俯卧撑撑下,角度大于125为撑上,躯干角度为一直保持在165到175之间。
import cv2
import numpy as np
from poseutil import PoseDetector
cap = cv2.VideoCapture('videos.mp4')
detector = PoseDetector()
dir = 0
count = 0
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter('videos.mp4', fourcc, 30.0, (width, height))
while True:
success, img = cap.read()
if success:
h, w, c = img.shape
img = detector.find_pose(img, draw=True)
positions = detector.find_positions(img)
if positions:
angle1 = detector.find_angle(img, 12, 24, 26)
angle2 = detector.find_angle(img, 12, 14, 16)
bar = np.interp(angle2, (45, 150), (w // 2 - 100, w // 2 + 100))
cv2.rectangle(img, (w // 2 - 100, h - 150), (int(bar), h - 100), (0, 255, 0), cv2.FILLED)
if angle2 50 and angle1 >= 165 and angle1 175:
if dir == 0:
count = count + 0.5
dir = 1
if angle2 >= 125 and angle1 >= 165 and angle1 175:
if dir == 1:
count = count + 0.5
dir = 0
cv2.putText(img, str(int(count)), (w // 2, h // 2), cv2.FONT_HERSHEY_SIMPLEX, 10, (255, 255, 255), 20, cv2.LINE_AA)
cv2.imshow('Image', img)
out.write(img)
else:
break
key = cv2.waitKey(1)
if key == ord('q'):
break
out.release()
cap.release()
cv2.destroyAllWindows()
2.2 引体向上
同样的引体向上也可以做
引体向上对应到mediapipe的部位编号就是16,14,12(左臂),15,13,11(右臂)
import cv2
import numpy as np
from poseutil import PoseDetector
cap = cv2.VideoCapture('video.mp4')
detector = PoseDetector()
dir = 0
count = 0
while True:
success, img = cap.read()
if success:
img = detector.find_pose(img, draw=True)
lmslist = detector.find_positions(img)
right_angle = detector.find_angle(img, 12, 14, 16)
right_per = np.interp(right_angle, (20, 170), (100, 0))
right_bar = np.interp(right_angle, (20, 170), (200, 400))
cv2.rectangle(img, (1200, 200), (1220, 400), (0, 255, 0), 3)
cv2.rectangle(img, (1200, int(right_bar)), (1220, 400), (0, 255, 0), cv2.FILLED)
cv2.putText(img, str(int(right_per)) + '%', (1190, 450), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 2)
left_angle = detector.find_angle(img, 11, 13, 15)
left_per = np.interp(left_angle, (20, 170), (100, 0))
left_bar = np.interp(left_angle, (20, 170), (200, 400))
cv2.rectangle(img, (500, 200), (520, 400), (0, 255, 0), 3)
cv2.rectangle(img, (500, int(left_bar)), (520, 400), (0, 255, 0), cv2.FILLED)
cv2.putText(img, str(int(left_per)) + '%', (490, 450), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 2)
if (left_per >= 80 and right_per >= 80):
if dir == 0:
count = count + 0.5
dir = 1
if (left_per 20 and right_per 20):
if dir == 1:
count = count + 0.5
dir = 0
cv2.putText(img, str(int(count)), (1000, 100), cv2.FONT_HERSHEY_SIMPLEX, 3, (0, 255, 255), 4)
cv2.imshow('Image', img)
else:
break
k = cv2.waitKey(1)
if k == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
2.3 仰卧起坐
仰卧起坐对应到mediapipe的部位编号就是11,23,25(右侧躯干),12,24,26(左侧躯干)
import cv2
import numpy as np
from poseutil import PoseDetector
cap = cv2.VideoCapture('videos.mp4')
detector = PoseDetector()
dir = 0
count = 0
while True:
success, img = cap.read()
if success:
h, w, c = img.shape
img = detector.find_pose(img, draw=True)
positions = detector.find_positions(img)
if positions:
angle = detector.find_angle(img, 11, 23, 25)
bar = np.interp(angle, (50, 130), (w // 2 - 100, w // 2 + 100))
cv2.rectangle(img, (w // 2 - 100, h - 150), (int(bar), h - 100), (0, 255, 0), cv2.FILLED)
if angle 55:
if dir == 0:
count = count + 0.5
dir = 1
if angle >= 120:
if dir == 1:
count = count + 0.5
dir = 0
cv2.putText(img, str(int(count)), (w // 2, h // 2), cv2.FONT_HERSHEY_SIMPLEX, 10, (255, 255, 255), 20, cv2.LINE_AA)
cv2.imshow('Image', img)
else:
break
key = cv2.waitKey(1)
if key == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
2.3 下蹲
下蹲对应mediapipe的部位编号就是24,26,28(左腿),23,25,27(右腿)
import cv2
import numpy as np
from poseutil import PoseDetector
cap = cv2.VideoCapture('videos.mp4')
detector = PoseDetector()
dir = 0
count = 0
while True:
success, img = cap.read()
if success:
h, w, c = img.shape
img = detector.find_pose(img, draw=True)
positions = detector.find_positions(img)
if positions:
angle = detector.find_angle(img, 24, 26, 28)
bar = np.interp(angle, (50, 170), (w // 2 - 100, w // 2 + 100))
cv2.rectangle(img, (w // 2 - 100, h - 150), (int(bar), h - 100), (0, 255, 0), cv2.FILLED)
if angle 55:
if dir == 0:
count = count + 0.5
dir = 1
if angle >= 120:
if dir == 1:
count = count + 0.5
dir = 0
cv2.putText(img, str(int(count)), (w // 2, h // 2), cv2.FONT_HERSHEY_SIMPLEX, 10, (255, 255, 255), 20, cv2.LINE_AA)
cv2.imshow('Image', img)
else:
break
key = cv2.waitKey(1)
if key == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Original: https://blog.csdn.net/weixin_42010722/article/details/121469696
Author: TES·Rooike
Title: Mediapipe三维实时人体关键点检测与追踪(二)
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/719877/
转载文章受原作者版权保护。转载请注明原作者出处!