文章目录
前言
坐姿检测是计算机视觉中的一个应用,可以通过分析人体姿态来判断是否保持正确坐姿。下面我将介绍使用Python实现坐姿检测的方法和完整代码。
一、方法概述
使用OpenCV和MediaPipe
使用OpenCV和MediaPipe:MediaPipe提供了现成的人体姿态估计模型
关键点检测
关键点检测:检测身体关键点(如肩膀、耳朵、臀部等)
角度计算
角度计算:计算关键点之间的角度来判断坐姿
姿态评估
姿势评估:根据角度阈值判断坐姿是否正确
二、完整代码实现
import cv2
import mediapipe as mp
import numpy as np
import time
class PostureDetector:
def __init__(self, mode=False, upBody=False, smooth=True,
detectionCon=0.5, trackCon=0.5):
"""
初始化姿势检测器
参数:
mode: 是否静态图像模式 (False表示视频流)
upBody: 是否只检测上半身
smooth: 是否平滑处理
detectionCon: 检测置信度阈值
trackCon: 跟踪置信度阈值
"""
self.mode = mode
self.upBody = upBody
self.smooth = smooth
self.detectionCon = detectionCon
self.trackCon = trackCon
self.mpDraw = mp.solutions.drawing_utils
self.mpPose = mp.solutions.pose
self.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 = 0
self.bad_posture_time = 0
self.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 img
def 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.shape
cx, cy = int(lm.x * w), int(lm.y * h)
self.landmarks.append([id, cx, cy, lm.z])
return self.landmarks
def 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 - angle
return angle
def evaluate_posture(self, img, draw=True):
"""
评估坐姿是否正确
参数:
img: 输入图像
draw: 是否在图像上绘制评估结果
返回:
图像和坐姿评估结果
"""
current_time = time.time()
posture_changed = False
if 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 = True
self.last_posture_change = current_time
self.posture_status = new_status
else:
if new_status == "Good":
self.good_posture_time += 1
else:
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_status
def main():
cap = cv2.VideoCapture(0) # 使用摄像头
detector = PostureDetector()
while True:
success, img = cap.read()
if not success:
break
img = 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'):
break
cap.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
调整摄像头位置,确保能清晰看到上半身
四、改进方向
- 添加更多评估标准(如肩膀是否前倾)
- 实现坐姿历史记录和统计分析
- 添加声音提醒功能
- 优化性能(如降低图像分辨率)
- 添加校准功能,适应不同体型
这个实现提供了基本的坐姿检测功能,你可以根据需要进一步扩展和完善。