Python玩人工智能:你的仰卧起坐達標了嗎?


介紹

Google出了一個開源的、跨平台的、可定制化的機器學習解決方案工具包,給在線流媒體(當然也可以用於普通的視頻、圖像等)提供了機器學習解決方案。感興趣的同學可以打開這個網址了解詳情:https://mediapipe.dev/。它提供了手勢、人體姿勢、人臉、物品等識別和追蹤功能,並提供了C++、Python、JavaScript等編程語言的工具包以及iOS、Android平台的解決方案,今天我們就來看一下如何使用MediaPipe提供的人體姿勢識別功能,使用Python編程完成一個“仰卧起坐檢測”的程序。

准備工作

  1. 安裝Python3.8.x

  2. 創建一個Python項目,建議使用virtualenv創建一個項目專有的Python環境

  3. 安裝包:Opencv-Python、mediapipe、numpy

開始編程

  1. 創建一個人體姿勢識別模塊,在這個模塊中,我們使用mediapipe模塊來實現人體姿勢識別,並獲取姿勢數據。

 1 import cv2
 2 import mediapipe as mp
 3 import math
 4 
 5 
 6 class PoseDetector():
 7     '''
 8     人體姿勢檢測類
 9     '''
10 
11     def __init__(self,
12                  static_image_mode=False,
13                  upper_body_only=False,
14                  smooth_landmarks=True,
15                  min_detection_confidence=0.5,
16                  min_tracking_confidence=0.5):
17         '''
18         初始化
19         :param static_image_mode: 是否是靜態圖片,默認為否
20         :param upper_body_only: 是否是上半身,默認為否
21         :param smooth_landmarks: 設置為True減少抖動
22         :param min_detection_confidence:人員檢測模型的最小置信度值,默認為0.5
23         :param min_tracking_confidence:姿勢可信標記的最小置信度值,默認為0.5
24         '''
25         self.static_image_mode = static_image_mode
26         self.upper_body_only = upper_body_only
27         self.smooth_landmarks = smooth_landmarks
28         self.min_detection_confidence = min_detection_confidence
29         self.min_tracking_confidence = min_tracking_confidence
30         # 創建一個Pose對象用於檢測人體姿勢
31         self.pose = mp.solutions.pose.Pose(self.static_image_mode, self.upper_body_only, self.smooth_landmarks,
32                                            self.min_detection_confidence, self.min_tracking_confidence)
33 
34     def find_pose(self, img, draw=True):
35         '''
36         檢測姿勢方法
37         :param img: 一幀圖像
38         :param draw: 是否畫出人體姿勢節點和連接圖
39         :return: 處理過的圖像
40         '''
41         imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
42         # pose.process(imgRGB) 會識別這幀圖片中的人體姿勢數據,保存到self.results中
43         self.results = self.pose.process(imgRGB)
44         if self.results.pose_landmarks:
45             if draw:
46                 mp.solutions.drawing_utils.draw_landmarks(img, self.results.pose_landmarks,
47                                                           mp.solutions.pose.POSE_CONNECTIONS)
48         return img
49 
50     def find_positions(self, img):
51         '''
52         獲取人體姿勢數據
53         :param img: 一幀圖像
54         :param draw: 是否畫出人體姿勢節點和連接圖
55         :return: 人體姿勢數據列表
56         '''
57         # 人體姿勢數據列表,每個成員由3個數字組成:id, x, y
58         # id代表人體的某個關節點,x和y代表坐標位置數據
59         self.lmslist = []
60         if self.results.pose_landmarks:
61             for id, lm in enumerate(self.results.pose_landmarks.landmark):
62                 h, w, c = img.shape
63                 cx, cy = int(lm.x * w), int(lm.y * h)
64                 self.lmslist.append([id, cx, cy])
65 
66         return self.lmslist
67 
68     def find_angle(self, img, p1, p2, p3, draw=True):
69         '''
70         獲取人體姿勢中3個點p1-p2-p3的角度
71         :param img: 一幀圖像
72         :param p1: 第1個點
73         :param p2: 第2個點
74         :param p3: 第3個點
75         :param draw: 是否畫出3個點的連接圖
76         :return: 角度
77         '''
78         x1, y1 = self.lmslist[p1][1], self.lmslist[p1][2]
79         x2, y2 = self.lmslist[p2][1], self.lmslist[p2][2]
80         x3, y3 = self.lmslist[p3][1], self.lmslist[p3][2]
81 
82         # 使用三角函數公式獲取3個點p1-p2-p3,以p2為角的角度值,0-180度之間
83         angle = int(math.degrees(math.atan2(y1 - y2, x1 - x2) - math.atan2(y3 - y2, x3 - x2)))
84         if angle < 0:
85             angle = angle + 360
86         if angle > 180:
87             angle = 360 - angle
88 
89         if draw:
90             cv2.circle(img, (x1, y1), 20, (0, 255, 255), cv2.FILLED)
91             cv2.circle(img, (x2, y2), 30, (255, 0, 255), cv2.FILLED)
92             cv2.circle(img, (x3, y3), 20, (0, 255, 255), cv2.FILLED)
93             cv2.line(img, (x1, y1), (x2, y2), (255, 255, 255, 3))
94             cv2.line(img, (x2, y2), (x3, y3), (255, 255, 255, 3))
95             cv2.putText(img, str(angle), (x2 - 50, y2 + 50), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 255, 255), 2)
96 
97         return angle
  1. 編寫situps.py,在這個程序中我們將使用opencv讀取視頻文件,當然你也可以使用攝像頭直接拍攝。調用人體姿勢識別模塊進行視頻中人體姿勢識別並獲取姿勢數據,通過人體姿勢中3個位置點的數據:肩膀(11)、臀部(23)、膝蓋(25),計算這3個點的角度,判斷仰卧起坐是否達標。

# 導入opencv工具包
import cv2
# 導入numpy
import numpy as np
# 導入姿勢識別器
from poseutil import PoseDetector

# 打開視頻文件
cap = cv2.VideoCapture('videos/situp.mp4')
# 姿勢識別器
detector = PoseDetector()

# 方向與個數
dir = 0  # 0為躺下,1為坐起
count = 0

while True:
    # 讀取攝像頭,img為每幀圖片
    success, img = cap.read()
    if success:
        h, w, c = img.shape
        # 識別姿勢
        img = detector.find_pose(img, draw=True)
        # 獲取姿勢數據
        positions = detector.find_positions(img)

        if positions:
            # 獲取仰卧起坐的角度
            angle = detector.find_angle(img, 11, 23, 25)
            # 進度條長度
            bar = np.interp(angle, (50, 130), (w // 2 - 100, w // 2 + 100))
            cv2.rectangle(img, (w // 2 - 100, h - 150), (int(bar), h - 100), (0, 255, 0), cv2.FILLED)
            # 角度小於55度認為坐起
            if angle <= 55:
                if dir == 0:
                    count = count + 0.5
                    dir = 1
            # 角度大於120度認為躺下
            if angle >= 120:
                if dir == 1:
                    count = count + 0.5
                    dir = 0
            cv2.putText(img, str(int(count)), (w // 2, h // 2), cv2.FONT_HERSHEY_SIMPLEX, 10, (255, 255, 255), 20, cv2.LINE_AA)

        # 打開一個Image窗口顯示視頻圖片
        cv2.imshow('Image', img)
        
    else:
        # 視頻結束退出
        break

    # 如果按下q鍵,程序退出
    key = cv2.waitKey(1)
    if key == ord('q'):
        break

# 關閉攝像頭
cap.release()
# 關閉程序窗口
cv2.destroyAllWindows()

運行測試

總體感覺mediapipe識別率還是很不錯的,在使用CPU的情況下基本上能達到25幀/秒。我們可以通過調整仰卧起坐的判斷角度來使這個程序更符合你自己的仰卧起坐檢測。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM