Google出了一个开源的、跨平台的、可定制化的机器学习解决方案工具包,给在线流媒体(当然也能够用于一般的视频、图像等)提供了机器学习解决方案。感兴趣的同学能够关上这个网址理解详情:https://mediapipe.dev/

它提供了手势、人体姿态、人脸、物品等辨认和追踪性能,并提供了C++、Python、JavaScript等编程语言的工具包以及iOS、Android平台的解决方案,明天咱们就来看一下如何应用MediaPipe提供的人体姿态辨认性能,应用Python编程实现一个“引体向上检测”的程序。

电脑须要装置Python3,倡议装置Python3.8.x的版本。除此之外,还须要装置Opencv-Python、MediaPipe以及numpy几个工具包,能够应用pip进行装置:

pip install mediapipe numpy opencv-python

我的电脑是Python3.8.3,各工具包版本是:

mediapipe==0.8.3.1numpy==1.20.2opencv-python==4.5.1.48

编写一个poseutil.py模块,这个postutil模块有一个PoseDetector类,提供了检测人体姿态、获取人体姿态数据以及获取人体关节的角度的办法。代码如下,具体解决看代码正文:

import cv2import mediapipe as mpimport mathclass PoseDetector():    '''    人体姿态检测类    '''    def __init__(self,                 static_image_mode=False,                 upper_body_only=False,                 smooth_landmarks=True,                 min_detection_confidence=0.5,                 min_tracking_confidence=0.5):        '''        初始化        :param static_image_mode: 是否是动态图片,默认为否        :param upper_body_only: 是否是上半身,默认为否        :param smooth_landmarks: 设置为True缩小抖动        :param min_detection_confidence:人员检测模型的最小置信度值,默认为0.5        :param min_tracking_confidence:姿态可信标记的最小置信度值,默认为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        # 创立一个Pose对象用于检测人体姿态        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):        '''        检测姿态办法        :param img: 一帧图像        :param draw: 是否画出人体姿态节点和连贯图        :return: 解决过的图像        '''        imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)        # pose.process(imgRGB) 会辨认这帧图片中的人体姿态数据,保留到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):        '''        获取人体姿态数据        :param img: 一帧图像        :param draw: 是否画出人体姿态节点和连贯图        :return: 人体姿态数据列表        '''        # 人体姿态数据列表,每个成员由3个数字组成:id, x, y        # id代表人体的某个关节点,x和y代表坐标地位数据        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):        '''        获取人体姿态中3个点p1-p2-p3的角度        :param img: 一帧图像        :param p1: 第1个点        :param p2: 第2个点        :param p3: 第3个点        :param draw: 是否画出3个点的连贯图        :return: 角度        '''        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]        # 应用三角函数公式获取3个点p1-p2-p3,以p2为角的角度值,0-180度之间        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

编写另一个posetracking.py代码,在这个代码中,调用poseutil.py的PoseDetector类提供的办法,从引体向上的视频中(或者是实时摄像头视频)获取人体左右手肘的的蜿蜒角度,假如咱们以手肘角度从170度(齐全放松时)到20度(引体向上拉上去时)认定一个规范的引体向上,这样咱们就能够检测规范引体向上实现个数啦。

从上图可知:11、13、15这3个点是右边肩膀、手肘和手段的节点,而12、14、16是右手的。残缺代码如下:

import cv2import numpy as npfrom poseutil import PoseDetector# opencv关上一个视频cap = cv2.VideoCapture('mp4/1.mp4')# 创立一个PoseDetector类的对象detector = PoseDetector()# 方向和实现次数的变量dir = 0count = 0while 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)        # 以170到20度检测右手肘蜿蜒的水平        right_per = np.interp(right_angle, (20, 170), (100, 0))        # 进度条高度数据        right_bar = np.interp(right_angle, (20, 170), (200, 400))        # 应用opencv画进度条和写右手肘蜿蜒的水平        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)        # 检测个数,我这里设置的是从20%做到80%,就认为是一个        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'):        breakcap.release()cv2.destroyAllWindows()

运行代码,咱们会看到2个手肘的角度变动以及2个进度条和实现个数,应用它就能够检测规范引体向上的实现个数啦。