通过 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 - anglereturn 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 += 1print(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 - anglereturn 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 = 60while 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)# 重新转为BGRimage.flags.writeable = Trueimage = 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 += 1print(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()