?
通過 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()