摄像头读取循环事件计时优化:膝部姿态检测视频冻结问题
解决腿部姿态检测计时时视频冻结的问题
你的代码中嵌套的while循环是导致视频冻结的核心原因——主循环本应逐帧处理视频、渲染画面,但嵌套循环会让程序卡在计时逻辑里8秒,期间完全不处理新的视频帧,自然会出现画面冻结。
改用状态跟踪的方式实现计时逻辑,让计时和帧处理在同一个主循环里完成,就能避免阻塞。下面是修改后的完整代码:
import cv2 import numpy as np import mediapipe as mp from datetime import datetime mp_drawing = mp.solutions.drawing_utils mp_pose = mp.solutions.pose # 读取视频 cap = cv2.VideoCapture('C:/Users/ausaf/Downloads/KneeBendVideo.mp4') counter = 0 stage = 'straight knee' # 初始状态设为伸直 is_timing = False # 是否正在计时 start_timing = None elapsed_time = 0.0 def calculate_angle(h, k, a): # h=hip, k=knee, a=ankle h = np.array(h) k = np.array(k) a = np.array(a) radians = np.arctan2(h[1] - k[1], a[0] - k[0]) - np.arctan2(h[1] - k[1], h[0] - k[0]) angle = np.abs(radians * 180.0 / np.pi) if angle > 180: angle = 360 - angle return angle with mp_pose.Pose(min_detection_confidence=0.8, min_tracking_confidence=0.5) as pose: while cap.isOpened(): ret, frame = cap.read() if not ret: break # 视频结束退出循环 # 颜色空间转换与姿态检测 image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) image.flags.writeable = False results = pose.process(image) image.flags.writeable = True image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) angle = None # 提取关键点并计算角度 try: landmarks = results.pose_landmarks.landmark hip = [landmarks[mp_pose.PoseLandmark.LEFT_HIP.value].x, landmarks[mp_pose.PoseLandmark.LEFT_HIP.value].y] knee = [landmarks[mp_pose.PoseLandmark.LEFT_KNEE.value].x, landmarks[mp_pose.PoseLandmark.LEFT_KNEE.value].y] ankle = [landmarks[mp_pose.PoseLandmark.LEFT_ANKLE.value].x, landmarks[mp_pose.PoseLandmark.LEFT_ANKLE.value].y] angle = calculate_angle(hip, knee, ankle) # 显示角度 cv2.putText(image, f"{int(angle)}°", tuple(np.multiply(knee, [854, 640]).astype(int)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2, cv2.LINE_AA) except: pass # 渲染计数面板 cv2.rectangle(image, (0, 0), (225, 73), (245, 117, 16), -1) cv2.putText(image, 'REPS', (15, 12), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv2.LINE_AA) cv2.putText(image, str(counter), (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 2, (255, 255, 255), 2, cv2.LINE_AA) cv2.putText(image, 'Knee Status', (65, 12), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv2.LINE_AA) cv2.putText(image, stage, (60, 60), cv2.FONT_HERSHEY_SIMPLEX, 2, (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)) # 核心计时与计数逻辑(无阻塞) if angle is not None: if angle > 140: stage = 'straight knee' if is_timing: # 计时未完成就伸直,提示用户 cv2.putText(image, 'Keep your knees bent!', (50, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2, cv2.LINE_AA) is_timing = False # 停止计时 elif angle < 140: if stage == 'straight knee' and not is_timing: # 刚进入弯曲状态,启动计时 is_timing = True start_timing = datetime.now() stage = 'bent knee' if is_timing: # 计算已流逝时间 elapsed_time = (datetime.now() - start_timing).total_seconds() # 显示剩余时间 remaining_time = max(0, 8 - int(elapsed_time)) cv2.putText(image, f"Time left: {remaining_time}s", (70, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2, cv2.LINE_AA) if elapsed_time >= 8: # 完成一次有效重复 counter += 1 is_timing = False # 停止计时 cv2.imshow('Mediapipe Feed', image) if cv2.waitKey(10) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()
关键改动说明
- 移除嵌套循环:所有逻辑在主帧循环中完成,保证每帧都能被处理和渲染,彻底解决画面冻结问题。
- 状态变量跟踪:新增
is_timing标记计时状态,start_timing记录计时起始时间,逐帧计算已流逝时长,而非用循环阻塞等待。 - 逻辑优化:
- 腿部弯曲且未计时时,自动启动计时
- 计时过程中实时显示剩余时间
- 完成8秒计时后自动增加重复计数
- 计时未完成就伸直腿部时,立即提示用户并停止计时
内容的提问来源于stack exchange,提问作者Below_Average
相关产品推荐
相关产品推荐

