MediaPipe人体姿态估计实战:用Python+OpenCV做个AI健身教练(附完整代码)
MediaPipe人体姿态估计实战:用Python+OpenCV打造智能健身教练系统
健身房里总能看到有人对着镜子反复调整动作,却依然不确定自己的深蹲是否标准。现在,我们完全可以用计算机视觉技术解决这个问题——通过MediaPipe的姿态估计功能,配合Python和OpenCV,打造一个能实时反馈动作标准的AI健身教练。这个系统不仅能识别33个身体关键点,还能判断动作完成质量,让居家健身也能获得专业指导。
1. 环境配置与基础姿态检测
在开始构建AI健身教练之前,我们需要准备好开发环境。MediaPipe对硬件要求并不高,普通笔记本电脑的CPU就能流畅运行基础功能,但如果需要处理更高帧率的视频流,建议使用配备独立显卡的设备。
首先安装必要的Python包:
pip install mediapipe opencv-python numpy验证安装是否成功的最快方式是运行一个简单的姿态检测脚本:
import cv2 import mediapipe as mp mp_pose = mp.solutions.pose pose = mp_pose.Pose(min_detection_confidence=0.5, min_tracking_confidence=0.5) image = cv2.imread('test_image.jpg') image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) results = pose.process(image_rgb) if results.pose_landmarks: print(f"检测到{len(results.pose_landmarks.landmark)}个身体关键点") else: print("未检测到人体姿态")MediaPipe的Pose模型会返回33个关键点,每个关键点包含以下信息:
| 属性 | 描述 | 取值范围 |
|---|---|---|
| x | 关键点水平位置 | 0.0-1.0(相对于图像宽度) |
| y | 关键点垂直位置 | 0.0-1.0(相对于图像高度) |
| z | 关键点深度 | 值越小表示离摄像头越远 |
| visibility | 关键点可见性 | 0.0-1.0(值越大越可见) |
2. 实时视频流处理与关键点可视化
要让系统真正实用,必须能够处理实时视频流。OpenCV的VideoCapture类配合MediaPipe可以轻松实现这一功能:
cap = cv2.VideoCapture(0) # 0表示默认摄像头 with mp_pose.Pose( min_detection_confidence=0.7, min_tracking_confidence=0.7) as pose: while cap.isOpened(): success, image = cap.read() if not success: continue # 转换颜色空间并处理 image.flags.writeable = False image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) results = pose.process(image) # 绘制关键点和连接线 image.flags.writeable = True image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) mp.solutions.drawing_utils.draw_landmarks( image, results.pose_landmarks, mp_pose.POSE_CONNECTIONS) cv2.imshow('AI Fitness Coach', image) if cv2.waitKey(5) & 0xFF == 27: break cap.release()这段代码会打开摄像头并实时显示带有关键点和骨骼连接线的画面。对于健身应用,我们特别关注以下几个关键点:
- 11,12号点:左右肩膀
- 23,24号点:左右髋部
- 25,26号点:左右膝盖
- 27,28号点:左右脚踝
- 29,30号点:左右脚跟
- 31,32号点:左右脚尖
3. 动作标准性判断算法
以深蹲为例,一个标准的深蹲需要满足以下几个条件:
- 下蹲时膝盖不超过脚尖(31/32号点与25/26号点的相对位置)
- 背部保持挺直(11,12号点与23,24号点形成的角度)
- 下蹲深度达到要求(髋关节低于膝关节)
实现这些判断需要一些几何计算:
def check_squat(landmarks, image_width, image_height): # 获取关键点坐标(转换为像素值) left_hip = get_pixel_coords(landmarks[23], image_width, image_height) right_hip = get_pixel_coords(landmarks[24], image_width, image_height) left_knee = get_pixel_coords(landmarks[25], image_width, image_height) right_knee = get_pixel_coords(landmarks[26], image_width, image_height) left_ankle = get_pixel_coords(landmarks[27], image_width, image_height) right_ankle = get_pixel_coords(landmarks[28], image_width, image_height) left_toe = get_pixel_coords(landmarks[31], image_width, image_height) right_toe = get_pixel_coords(landmarks[32], image_width, image_height) # 计算膝盖是否超过脚尖 knee_over_toe_left = left_knee[0] > left_toe[0] knee_over_toe_right = right_knee[0] > right_toe[0] # 计算髋关节是否低于膝关节 hip_below_knee_left = left_hip[1] > left_knee[1] hip_below_knee_right = right_hip[1] > right_knee[1] # 计算背部角度 shoulder_angle = calculate_angle(landmarks[11], landmarks[12], landmarks[23], image_width, image_height) back_straight = 160 < shoulder_angle < 200 feedback = [] if knee_over_toe_left or knee_over_toe_right: feedback.append("膝盖超过脚尖了!") if not (hip_below_knee_left and hip_below_knee_right): feedback.append("下蹲深度不够") if not back_straight: feedback.append("背部没有保持挺直") return feedback if feedback else ["动作标准!"]角度计算的辅助函数:
def calculate_angle(point1, point2, point3, image_width, image_height): # 将三个点转换为像素坐标 p1 = get_pixel_coords(point1, image_width, image_height) p2 = get_pixel_coords(point2, image_width, image_height) p3 = get_pixel_coords(point3, image_width, image_height) # 计算向量 vec1 = (p1[0]-p2[0], p1[1]-p2[1]) vec2 = (p3[0]-p2[0], p3[1]-p2[1]) # 计算角度 dot = vec1[0]*vec2[0] + vec1[1]*vec2[1] det = vec1[0]*vec2[1] - vec1[1]*vec2[0] angle = math.degrees(math.atan2(det, dot)) return angle + 360 if angle < 0 else angle4. 系统集成与用户反馈
完整的AI健身教练系统需要将姿态检测、动作分析和用户反馈集成在一起。我们可以通过视觉和听觉两种方式提供反馈:
def provide_feedback(image, feedback_text, is_good=False): # 设置显示参数 font = cv2.FONT_HERSHEY_SIMPLEX font_scale = 1 thickness = 2 color = (0, 255, 0) if is_good else (0, 0, 255) # 在图像上添加文本 y_offset = 50 for line in feedback_text: cv2.putText(image, line, (50, y_offset), font, font_scale, color, thickness, cv2.LINE_AA) y_offset += 40 # 添加语音反馈(需要pyttsx3库) try: import pyttsx3 engine = pyttsx3.init() for line in feedback_text: engine.say(line) engine.runAndWait() except ImportError: pass return image将以上所有组件整合后的主循环:
cap = cv2.VideoCapture(0) frame_count = 0 feedback_interval = 10 # 每10帧提供一次反馈 with mp_pose.Pose( min_detection_confidence=0.7, min_tracking_confidence=0.7) as pose: while cap.isOpened(): success, image = cap.read() if not success: continue frame_count += 1 provide_feedback_now = frame_count % feedback_interval == 0 # 处理图像 image.flags.writeable = False image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) results = pose.process(image) # 绘制关键点 image.flags.writeable = True image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) if results.pose_landmarks: mp.solutions.drawing_utils.draw_landmarks( image, results.pose_landmarks, mp_pose.POSE_CONNECTIONS) if provide_feedback_now: feedback = check_squat(results.pose_landmarks.landmark, image.shape[1], image.shape[0]) image = provide_feedback(image, feedback, feedback[0]=="动作标准!") frame_count = 0 cv2.imshow('AI Fitness Coach', image) if cv2.waitKey(5) & 0xFF == 27: break cap.release() cv2.destroyAllWindows()5. 扩展功能与性能优化
基础功能实现后,我们可以考虑添加更多实用功能来提升用户体验:
动作计数功能:通过检测髋关节的垂直运动轨迹来判断是否完成了一次完整的深蹲
class SquatCounter: def __init__(self): self.count = 0 self.hip_positions = [] self.down_threshold = 0.05 # 髋部下移超过5%图像高度 self.up_threshold = 0.03 # 髋部上移超过3%图像高度 self.state = "up" # or "down" def update(self, hip_y): self.hip_positions.append(hip_y) if len(self.hip_positions) < 2: return self.count # 计算移动方向 delta = self.hip_positions[-1] - self.hip_positions[-2] if self.state == "up" and delta > self.down_threshold: self.state = "down" elif self.state == "down" and delta < -self.up_threshold: self.state = "up" self.count += 1 return self.count性能优化技巧:
- 降低处理分辨率(保持检测精度同时提高帧率)
- 使用多线程处理视频流和姿态分析
- 对关键点坐标进行平滑滤波(减少抖动)
# 降低分辨率示例 def resize_and_maintain_aspect(image, target_width): h, w = image.shape[:2] ratio = target_width / float(w) dim = (target_width, int(h * ratio)) return cv2.resize(image, dim, interpolation=cv2.INTER_AREA) # 在视频循环中使用 image = resize_and_maintain_aspect(image, 640)支持更多健身动作:通过类似的方法可以实现对其他动作的检测,如:
- 俯卧撑(检测肘部角度和身体高度)
- 开合跳(检测手脚距离变化)
- 平板支撑(检测身体直线度和髋部高度)
def check_pushup(landmarks, image_width, image_height): left_shoulder = get_pixel_coords(landmarks[11], image_width, image_height) left_elbow = get_pixel_coords(landmarks[13], image_width, image_height) left_wrist = get_pixel_coords(landmarks[15], image_width, image_height) elbow_angle = calculate_angle(left_shoulder, left_elbow, left_wrist, image_width, image_height) feedback = [] if elbow_angle > 160: feedback.append("手臂没有完全伸直") elif elbow_angle < 90: feedback.append("身体可以再降低一些") return feedback if feedback else ["动作标准!"]在实际项目中,我发现MediaPipe在光照条件良好、用户穿着紧身衣物时检测效果最佳。对于健身应用,建议用户穿着与背景对比明显的服装,并在侧面放置一个辅助光源来减少阴影干扰。
