文章目錄
- 前言
- 一、方法概述
- 使用OpenCV和MediaPipe
- 關鍵點檢測
- 角度計算
- 姿態評估
- 二、完整代碼實現
- 三、代碼說明
- PostureDetector類
- find_pose()
- get_landmarks()
- cakculate_angle()
- evaluate_posture()
- 坐姿評估標準(可進行參數調整):
- 可視化功能:
- 如何使用
- 安裝依賴庫:
- 運行腳本:
- 四、改進方向
前言
坐姿檢測是計算機視覺中的一個應用,可以通過分析人體姿態來判斷是否保持正確坐姿。下面我將介紹使用Python實現坐姿檢測的方法和完整代碼。
一、方法概述
使用OpenCV和MediaPipe
使用OpenCV和MediaPipe:MediaPipe提供了現成的人體姿態估計模型
關鍵點檢測
關鍵點檢測:檢測身體關鍵點(如肩膀、耳朵、臀部等)
角度計算
角度計算:計算關鍵點之間的角度來判斷坐姿
姿態評估
姿勢評估:根據角度閾值判斷坐姿是否正確
二、完整代碼實現
import cv2
import mediapipe as mp
import numpy as np
import timeclass PostureDetector:def __init__(self, mode=False, upBody=False, smooth=True, detectionCon=0.5, trackCon=0.5):"""初始化姿勢檢測器參數:mode: 是否靜態圖像模式 (False表示視頻流)upBody: 是否只檢測上半身smooth: 是否平滑處理detectionCon: 檢測置信度閾值trackCon: 跟蹤置信度閾值"""self.mode = modeself.upBody = upBodyself.smooth = smoothself.detectionCon = detectionConself.trackCon = trackConself.mpDraw = mp.solutions.drawing_utilsself.mpPose = mp.solutions.poseself.pose = self.mpPose.Pose(static_image_mode=self.mode,model_complexity=1,smooth_landmarks=self.smooth,enable_segmentation=False,smooth_segmentation=self.smooth,min_detection_confidence=self.detectionCon,min_tracking_confidence=self.trackCon)# 坐姿評估參數self.good_posture_time = 0self.bad_posture_time = 0self.posture_status = "Unknown"self.last_posture_change = time.time()def find_pose(self, img, draw=True):"""檢測圖像中的姿勢關鍵點參數:img: 輸入圖像 (BGR格式)draw: 是否繪制關鍵點和連接線返回:帶標注的圖像和姿勢關鍵點"""img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)self.results = self.pose.process(img_rgb)if self.results.pose_landmarks and draw:self.mpDraw.draw_landmarks(img, self.results.pose_landmarks, self.mpPose.POSE_CONNECTIONS)return imgdef get_landmarks(self, img):"""獲取所有姿勢關鍵點的坐標參數:img: 輸入圖像返回:關鍵點坐標列表 (x,y,z) 或 None"""self.landmarks = []if self.results.pose_landmarks:for id, lm in enumerate(self.results.pose_landmarks.landmark):h, w, c = img.shapecx, cy = int(lm.x * w), int(lm.y * h)self.landmarks.append([id, cx, cy, lm.z])return self.landmarksdef calculate_angle(self, a, b, c):"""計算三個點之間的角度參數:a, b, c: 三個點的坐標 (x,y)返回:角度 (degrees)"""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)if angle > 180.0:angle = 360 - anglereturn angledef evaluate_posture(self, img, draw=True):"""評估坐姿是否正確參數:img: 輸入圖像draw: 是否在圖像上繪制評估結果返回:圖像和坐姿評估結果"""current_time = time.time()posture_changed = Falseif not self.landmarks or len(self.landmarks) < 33:return img, "No person detected"# 獲取需要的關節點left_shoulder = self.landmarks[11][1:3] # 11: 左肩right_shoulder = self.landmarks[12][1:3] # 12: 右肩left_ear = self.landmarks[7][1:3] # 7: 左耳right_ear = self.landmarks[8][1:3] # 8: 右耳left_hip = self.landmarks[23][1:3] # 23: 左髖right_hip = self.landmarks[24][1:3] # 24: 右髖# 計算肩膀中點shoulder_mid = ((left_shoulder[0] + right_shoulder[0]) // 2,(left_shoulder[1] + right_shoulder[1]) // 2)# 計算耳朵中點ear_mid = ((left_ear[0] + right_ear[0]) // 2,(left_ear[1] + right_ear[1]) // 2)# 計算髖部中點hip_mid = ((left_hip[0] + right_hip[0]) // 2,(left_hip[1] + right_hip[1]) // 2)# 計算脊柱角度 (肩膀-髖部-垂直線)spine_angle = self.calculate_angle((shoulder_mid[0], shoulder_mid[1] - 100), # 肩膀上方一點shoulder_mid,hip_mid)# 計算頸部角度 (耳朵-肩膀-水平線)neck_angle = self.calculate_angle((ear_mid[0] - 100, ear_mid[1]),ear_mid,shoulder_mid)# 坐姿評估標準good_spine = 160 < spine_angle < 200 # 脊柱應該接近垂直good_neck = 70 < neck_angle < 110 # 頸部應該接近垂直# 判斷坐姿new_status = "Good" if good_spine and good_neck else "Bad"# 更新姿勢狀態時間if new_status != self.posture_status:posture_changed = Trueself.last_posture_change = current_timeself.posture_status = new_statuselse:if new_status == "Good":self.good_posture_time += 1else:self.bad_posture_time += 1# 在圖像上繪制結果if draw:# 繪制關鍵點和連接線cv2.circle(img, ear_mid, 8, (255, 0, 0), cv2.FILLED)cv2.circle(img, shoulder_mid, 8, (255, 0, 0), cv2.FILLED)cv2.circle(img, hip_mid, 8, (255, 0, 0), cv2.FILLED)cv2.line(img, ear_mid, shoulder_mid, (255, 0, 0), 3)cv2.line(img, shoulder_mid, hip_mid, (255, 0, 0), 3)# 顯示角度信息cv2.putText(img, f"Spine Angle: {int(spine_angle)}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)cv2.putText(img, f"Neck Angle: {int(neck_angle)}", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)# 顯示坐姿狀態color = (0, 255, 0) if new_status == "Good" else (0, 0, 255)cv2.putText(img, f"Posture: {new_status}", (10, 90), cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2)# 顯示時間統計cv2.putText(img, f"Good Time: {self.good_posture_time//10}s", (10, 120), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)cv2.putText(img, f"Bad Time: {self.bad_posture_time//10}s", (10, 140), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)# 如果姿勢不良,添加警告if new_status == "Bad":cv2.putText(img, "WARNING: Bad Posture!", (img.shape[1]//2 - 150, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)return img, new_statusdef main():cap = cv2.VideoCapture(0) # 使用攝像頭detector = PostureDetector()while True:success, img = cap.read()if not success:breakimg = detector.find_pose(img)landmarks = detector.get_landmarks(img)if landmarks:img, posture = detector.evaluate_posture(img)cv2.imshow("Posture Detection", img)if cv2.waitKey(1) & 0xFF == ord('q'):breakcap.release()cv2.destroyAllWindows()if __name__ == "__main__":main()
三、代碼說明
PostureDetector類
PostureDetector類:核心坐姿檢測類
find_pose()
find_pose(): 檢測圖像中的人體姿勢
get_landmarks()
get_landmarks(): 獲取姿勢關鍵點坐標
cakculate_angle()
calculate_angle(): 計算三個關鍵點之間的角度
evaluate_posture()
evaluate_posture(): 評估坐姿是否正確
坐姿評估標準(可進行參數調整):
脊柱角度應在160-200度之間(接近垂直)
頸部角度應在70-110度之間(接近垂直)
滿足以上條件判斷為"Good"坐姿,否則為"Bad"
可視化功能:
- 繪制關鍵點和連接線
- 顯示角度數值
- 顯示坐姿狀態和時間統計
- 不良坐姿時顯示警告
如何使用
安裝依賴庫:
pip install opencv-python mediapipe numpy
運行腳本:
python posture_detection.py
調整攝像頭位置,確保能清晰看到上半身
四、改進方向
- 添加更多評估標準(如肩膀是否前傾)
- 實現坐姿歷史記錄和統計分析
- 添加聲音提醒功能
- 優化性能(如降低圖像分辨率)
- 添加校準功能,適應不同體型
這個實現提供了基本的坐姿檢測功能,你可以根據需要進一步擴展和完善。