俯卧撑计数器(Python)

 

通过 MediaPipe 检测人体姿态,计算俯卧撑角度和计数,并在图像上进行可视化展示

需要有cv2库和mediapipe库

mediapipe库:

MediaPipe是Google开源的机器学习框架,用于构建实时音频、视频和多媒体处理应用程序。它提供了一组预训练的模型和工具,帮助开发人员快速构建和部署计算机视觉和音频处理应用。MediaPipe库的特点包括实时性能、多平台兼容性、灵活性和易用性。

MediaPipe库的主要功能包括:

1. 视频和图像处理:提供了各种预训练的模型和工具,用于视频流分析和处理,例如人脸检测、姿态估计、手势识别等。

2. 音频处理:提供了模型和工具,用于音频流的实时处理,例如语音识别、语音分割、声音增强等。

3. 数据流图:使用数据流图构建和组合多个模块,以实现复杂的音频、视频和多媒体处理应用程序。

4. 跨平台支持:支持多种平台,包括Android、iOS、Linux、Windows等。

5. 开发者工具:提供了一些工具,用于开发和调试MediaPipe应用程序,例如模型训练和调优、性能分析等。

总之,MediaPipe库是一个功能强大的机器学习框架,用于实时音频、视频和多媒体处理应用程序的开发和部署。它提供了丰富的预训练模型和工具,使开发人员能够快速搭建高性能的应用程序。

目录

定义计算角度的函数:

初始化MediaPipe Pose实例: 

 打开视频:

读取视频帧:

计算个数:

 绘制图像:

完整代码: 

定义计算角度的函数:

def calculate_angle(a, b, c):
    # 将输入点转换为numpy数组
    a = np.array(a)
    b = np.array(b)
    c = np.array(c)

    # 计算两个向量的角度差(弧度)
    radians = np.arctan2(c[1] - b[1], c[0] - b[0]) - np.arctan2(a[1] - b[1], a[0] - b[0])

    # 转换为角度(度)
    angle = np.abs(radians * 180.0 / np.pi)

    # 确保角度在0到360度之间
    if angle > 180.0:
        angle = 360 - angle

    return angle

初始化MediaPipe Pose实例: 

# 初始化MediaPipe Pose实例
pose = mp_pose.Pose(min_detection_confidence=0.5, min_tracking_confidence=0.5)
'''
min_detection_confidence:表示检测到人体姿态的最小置信度阈值。当检测到的姿态置信度低于该阈值时,可能会被视为无效检测。
min_tracking_confidence:表示跟踪人体姿态的最小置信度阈值。在跟踪过程中,如果姿态的置信度低于该阈值,可能会重新进行检测。
'''

 打开视频:

cap = cv2.VideoCapture("D:\\桌面\\1.mp4")

读取视频帧:

ret, frame = cap.read()

计算个数:

 # 尝试获取姿态关键点
    try:
        landmarks = results.pose_landmarks.landmark

        # 获取左肩、左肘和左腕的坐标
        shoulder = [landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value].x,
                    landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value].y]
        elbow = [landmarks[mp_pose.PoseLandmark.LEFT_ELBOW.value].x, landmarks[mp_pose.PoseLandmark.LEFT_ELBOW.value].y]
        wrist = [landmarks[mp_pose.PoseLandmark.LEFT_WRIST.value].x, landmarks[mp_pose.PoseLandmark.LEFT_WRIST.value].y]

        # 计算并显示肘部到肩部的角度
        angle = calculate_angle(shoulder, elbow, wrist)
        cv2.putText(image, str(angle),
                    tuple(np.multiply(elbow, [640, 480]).astype(int)),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2, cv2.LINE_AA)
        print(angle)

        # 根据角度更新俯卧撑计数
        if angle > max_angle:
            stage = "down"
        if angle < min_angle and stage == 'down':
            stage = "up"
            counter += 1
            print(counter)

    except:
        pass

 

 绘制图像:

 # 在图像上绘制矩形框,用于显示计数和阶段
    cv2.rectangle(image, (0, 0), (225, 73), (245, 117, 16), -1)

    # 在矩形框内显示计数和阶段
    cv2.putText(image, 'COUNTER', (15, 22),
                cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv2.LINE_AA)
    cv2.putText(image, str(counter),
                (35, 60),
                cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA)

    cv2.putText(image, 'STAGE', (135, 22),
                cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv2.LINE_AA)
    cv2.putText(image, stage,
                (130, 60),
                cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA)

    # 在图像上绘制关键点和连接线
    mp_drawing.draw_landmarks(image, results.pose_landmarks, mp_pose.POSE_CONNECTIONS,
                              mp_drawing.DrawingSpec(color=(245, 117, 66), thickness=2, circle_radius=2),
                              mp_drawing.DrawingSpec(color=(245, 66, 230), thickness=2, circle_radius=2)
                              )

    # 显示处理后的图像
    cv2.imshow('Mediapipe Feed', image)

    # 检查是否按下'q'键退出
    if cv2.waitKey(10) & 0xFF == ord('q'):
        break

完整代码: 

#coding:utf-8
# 导入必要的库
import cv2
import mediapipe as mp  #通过 MediaPipe 检测人体姿态,计算俯卧撑角度和计数,并在图像上进行可视化展示
import numpy as np
import logging

# 配置日志记录
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# 记录日志信息
logging.info('这是一条信息日志')
logging.warning('这是一条警告日志')
logging.error('这是一条错误日志')

# 定义计算角度的函数
"""
    计算三个点之间的角度

    参数:
    a (list):第一个点的坐标
    b (list):第二个点的坐标
    c (list):第三个点的坐标

    返回:
    float:三个点之间的角度(度)
    """
def calculate_angle(a, b, c):
    # 将输入点转换为numpy数组
    a = np.array(a)
    b = np.array(b)
    c = np.array(c)

    # 计算两个向量的角度差(弧度)
    radians = np.arctan2(c[1] - b[1], c[0] - b[0]) - np.arctan2(a[1] - b[1], a[0] - b[0])

    # 转换为角度(度)
    angle = np.abs(radians * 180.0 / np.pi)

    # 确保角度在0到360度之间
    if angle > 180.0:
        angle = 360 - angle

    return angle

# 导入MediaPipe的绘图工具和Pose解决方案
mp_drawing = mp.solutions.drawing_utils
mp_pose = mp.solutions.pose

# 初始化MediaPipe Pose实例
pose = mp_pose.Pose(min_detection_confidence=0.5, min_tracking_confidence=0.5)
'''
min_detection_confidence:表示检测到人体姿态的最小置信度阈值。当检测到的姿态置信度低于该阈值时,可能会被视为无效检测。
min_tracking_confidence:表示跟踪人体姿态的最小置信度阈值。在跟踪过程中,如果姿态的置信度低于该阈值,可能会重新进行检测。
'''

# 打开视频
cap = cv2.VideoCapture("D:\\桌面\\1.mp4")

# 计数器变量
counter = 0
# 当前动作阶段
stage = None
# 完成俯卧撑的最大角度
max_angle = 160
# 准备开始俯卧撑的最小角度
min_angle = 60

while cap.isOpened():
    # 读取视频帧
    ret, frame = cap.read()

    # BGR图像转为RGB,便于MediaPipe处理
    image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    image.flags.writeable = False

    # 使用MediaPipe进行姿态检测
    results = pose.process(image)

    # 重新转为BGR
    image.flags.writeable = True
    image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)

    # 尝试获取姿态关键点
    try:
        landmarks = results.pose_landmarks.landmark

        # 获取左肩、左肘和左腕的坐标
        shoulder = [landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value].x,
                    landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value].y]
        elbow = [landmarks[mp_pose.PoseLandmark.LEFT_ELBOW.value].x, landmarks[mp_pose.PoseLandmark.LEFT_ELBOW.value].y]
        wrist = [landmarks[mp_pose.PoseLandmark.LEFT_WRIST.value].x, landmarks[mp_pose.PoseLandmark.LEFT_WRIST.value].y]

        # 计算并显示肘部到肩部的角度
        angle = calculate_angle(shoulder, elbow, wrist)
        cv2.putText(image, str(angle),
                    tuple(np.multiply(elbow, [640, 480]).astype(int)),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2, cv2.LINE_AA)
        print(angle)

        # 根据角度更新俯卧撑计数
        if angle > max_angle:
            stage = "down"
        if angle < min_angle and stage == 'down':
            stage = "up"
            counter += 1
            print(counter)

    except:
        pass

    # 在图像上绘制矩形框,用于显示计数和阶段
    cv2.rectangle(image, (0, 0), (225, 73), (245, 117, 16), -1)

    # 在矩形框内显示计数和阶段
    cv2.putText(image, 'COUNTER', (15, 22),
                cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv2.LINE_AA)
    cv2.putText(image, str(counter),
                (35, 60),
                cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA)

    cv2.putText(image, 'STAGE', (135, 22),
                cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv2.LINE_AA)
    cv2.putText(image, stage,
                (130, 60),
                cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA)

    # 在图像上绘制关键点和连接线
    mp_drawing.draw_landmarks(image, results.pose_landmarks, mp_pose.POSE_CONNECTIONS,
                              mp_drawing.DrawingSpec(color=(245, 117, 66), thickness=2, circle_radius=2),
                              mp_drawing.DrawingSpec(color=(245, 66, 230), thickness=2, circle_radius=2)
                              )

    # 显示处理后的图像
    cv2.imshow('Mediapipe Feed', image)

    # 检查是否按下'q'键退出
    if cv2.waitKey(10) & 0xFF == ord('q'):
        break

# 释放视频资源,关闭所有OpenCV窗口
cap.release()
cv2.destroyAllWindows()

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值