Google has come up with an open source, cross-platform, customizable machine learning solution toolkit for online streaming (as well as general video, images, etc.). For those of you who are interested, go to mediapipe.dev/
It provides gesture, body posture, face, object recognition and tracking functions, and provides C++, Python, JavaScript and other programming languages toolkit, as well as iOS, Android platform solutions. Today we will take a look at how to use MediaPipe’s body posture recognition function. Complete a “pull-up check” program in Python.
Python3 needs to be installed on the PC. Python3.8.x is recommended. In addition to installing Opencv-Python, MediaPipe, and Numpy toolkits, you can use PIP to install:
pip install mediapipe numpy opencv-python
My computer is Python3.8.3, each toolkit version is:
Mediapipe = = 0.8.3.1 numpy = = 1.20.2 opencv - python = = 4.5.1.48Copy the code
Write a poseutil.py module that has a PoseDetector class that provides methods for detecting body posture, obtaining body posture data, and obtaining the angles of human joints. The code is as follows, and the detailed solution is to see the code comment:
import cv2
import mediapipe as mp
import math
class PoseDetector() :
Human posture detection
def __init__(self,
static_image_mode=False,
upper_body_only=False,
smooth_landmarks=True,
min_detection_confidence=0.5,
min_tracking_confidence=0.5) :
Initializing :param static_image_mode: static image (default: no) :param upper_body_only: upper body (default: no) :param smooth_landmarks: Set to True to reduce jitter :param min_detection_CONFIDENCE: minimum confidence value of the staff detection model, default is 0.5 :param min_tracking_confidence: minimum confidence value of the pose trust flag, default is 0.5 ""
self.static_image_mode = static_image_mode
self.upper_body_only = upper_body_only
self.smooth_landmarks = smooth_landmarks
self.min_detection_confidence = min_detection_confidence
self.min_tracking_confidence = min_tracking_confidence
Create a Pose object to detect human body posture
self.pose = mp.solutions.pose.Pose(self.static_image_mode, self.upper_body_only, self.smooth_landmarks,
self.min_detection_confidence, self.min_tracking_confidence)
def find_pose(self, img, draw=True) :
"" Detection posture method: Param IMG: a frame image: Param draw: whether to draw the human body posture node and connection diagram :return: processed image" "
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# pose. Process (imgRGB) will recognize the human pose data in this frame and save it to self.Results
self.results = self.pose.process(imgRGB)
if self.results.pose_landmarks:
if draw:
mp.solutions.drawing_utils.draw_landmarks(img, self.results.pose_landmarks,
mp.solutions.pose.POSE_CONNECTIONS)
return img
def find_positions(self, img) :
"Get human pose data :param img: a frame image: Param Draw: whether to draw human pose nodes and link diagrams :return: list of human pose data"
# Body posture data list, each member consists of 3 numbers: ID, X, Y
# ID represents a node of the human body, x and y represent coordinate position data
self.lmslist = []
if self.results.pose_landmarks:
for id, lm in enumerate(self.results.pose_landmarks.landmark):
h, w, c = img.shape
cx, cy = int(lm.x * w), int(lm.y * h)
self.lmslist.append([id, cx, cy])
return self.lmslist
def find_angle(self, img, p1, p2, p3, draw=True) :
Param img: a frame image: Param P1: first point: Param P2: second point: Param P3: third point: Param draw: param img: a frame image: Param P1: first point: Param P2: second point: Param P3: third point: Param draw: Whether to draw a connection diagram of 3 points:
x1, y1 = self.lmslist[p1][1], self.lmslist[p1][2]
x2, y2 = self.lmslist[p2][1], self.lmslist[p2][2]
x3, y3 = self.lmslist[p3][1], self.lmslist[p3][2]
# Use the trigonometric formula to obtain the Angle values of 3 points p1-P2-p3, with Angle P2 as the value, 0-180 degrees
angle = int(math.degrees(math.atan2(y1-y2, x1-x2) - math.atan2(y3-y2, x3-x2)))
if angle < 0:
angle = angle + 360
if angle > 180:
angle = 360 - angle
if draw:
cv2.circle(img, (x1, y1), 8, (0.255.255), cv2.FILLED)
cv2.circle(img, (x2, y2), 15, (255.0.255), cv2.FILLED)
cv2.circle(img, (x3, y3), 8, (0.255.255), cv2.FILLED)
cv2.line(img, (x1, y1), (x2, y2), (255.255.255.3))
cv2.line(img, (x2, y2), (x3, y3), (255.255.255.3))
#cv2.putText(img, str(angle), (x2-50, y2+50),cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 255, 255), 2)
return angle
Copy the code
Write another posetracking.py code that calls methods provided by the PoseDetector class of PoseUtil. Py to get the bending angles of the left and right elbows of the human body from a pull-up video (or live camera video), Suppose we identify a standard pull-up at an elbow Angle from 170 degrees (when fully relaxed) to 20 degrees (when pull-up), then we can measure the number of standard pull-ups completed.
From the figure above, we can see that 11, 13 and 15 are the nodes of the left shoulder, elbow and wrist, while 12, 14 and 16 are the right hand. The complete code is as follows:
import cv2
import numpy as np
from poseutil import PoseDetector
# OpencV opens a video
cap = cv2.VideoCapture('mp4/1.mp4')
Create a PoseDetector object
detector = PoseDetector()
# Direction and completion variables
dir = 0
count = 0
while True:
# Read the video picture frame
success, img = cap.read()
if success:
# Detect human body posture in video picture frames
img = detector.find_pose(img, draw=True)
Get body posture list data
lmslist = detector.find_positions(img)
# Right elbow Angle
right_angle = detector.find_angle(img, 12.14.16)
Measure right elbow bend at 170 to 20 degrees
right_per = np.interp(right_angle, (20.170), (100.0))
Progress bar height data
right_bar = np.interp(right_angle, (20.170), (200.400))
# Use OpencV to draw the progress bar and write the degree of bending of the right elbow
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)) + The '%', (1190.450), cv2.FONT_HERSHEY_SIMPLEX, 1, (0.255.255), 2)
# Angle of left elbow
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)) + The '%', (490.450), cv2.FONT_HERSHEY_SIMPLEX, 1, (0.255.255), 2)
# Number of detection, I set here from 20% to 80%, it is considered one
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
# Display the number of completions on the video
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()
Copy the code
Running the code, we will see the two elbow angles as well as the two progress bars and the number of completions, which can be used to detect the number of completions in a standard pull-up.