Python玩人工智能:你能做几个引体向上?

软件结
• 阅读 2260

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

Python玩人工智能:你能做几个引体向上?

它提供了手势、人体姿势、人脸、物品等识别和追踪功能,并提供了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.1
numpy==1.20.2
opencv-python==4.5.1.48

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

import cv2
import mediapipe as mp
import math

class 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度(引体向上拉上去时)认定一个标准的引体向上,这样我们就可以检测标准引体向上完成个数啦。

Python玩人工智能:你能做几个引体向上?

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

import cv2
import numpy as np
from poseutil import PoseDetector

# opencv打开一个视频
cap = cv2.VideoCapture('mp4/1.mp4')
# 创建一个PoseDetector类的对象
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)
        # 以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'):
        break

cap.release()
cv2.destroyAllWindows()

运行代码,我们会看到2个手肘的角度变化以及2个进度条和完成个数,使用它就可以检测标准引体向上的完成个数啦。

Python玩人工智能:你能做几个引体向上?
Python玩人工智能:你能做几个引体向上?
Python玩人工智能:你能做几个引体向上?
Python玩人工智能:你能做几个引体向上?

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
python知道 python知道
4年前
怎么学python,学习python的正确姿势
Python是一门相对来说比较简单的编程语言,自学是非常轻松的。首先得明白python有哪些发展方向需要了解这个这门语言而不是听说这个高薪资容易学习最好的学习状态就是出于兴趣兴趣是最好的老师当然对钱感兴趣也是可以的。一、人工智能二、大数据三、网络爬虫工程师四、Pythonweb全栈工程师五、Python自动化运维六、Python自动化测试再来说
Stella981 Stella981
4年前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y
Wesley13 Wesley13
4年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这