使用OpenCV和MediaPipe库——驼背检测(姿态监控)

目录

驼背检测的运用

[1. 驾驶姿态与疲劳关联分析](#1. 驾驶姿态与疲劳关联分析)

[2. 行业应用案例](#2. 行业应用案例)

[1. 教育场景痛点分析](#1. 教育场景痛点分析)

[2. 智能教室系统架构](#2. 智能教室系统架构)

代码实现思路

[1. 初始化与配置](#1. 初始化与配置)

[2. MediaPipe和摄像头设置](#2. MediaPipe和摄像头设置)

[3. 主循环](#3. 主循环)

[4. 资源释放](#4. 资源释放)

RGB与BGR的区别

一、本质区别

二、OpenCV的特殊性

内存结构示意图:

三、转换必要性分析

转换流程图示:

四、常见问题场景

五、性能优化建议

六、底层原理

七、验证实验

八、现代发展趋势

整体代码

效果展示


驼背检测的运用

1. 驾驶姿态与疲劳关联分析
  • 生理机制:驼背姿势会压迫胸腔,减少氧气摄入量,加速疲劳感产生(研究显示,不良坐姿使疲劳出现时间提前30%)

  • 典型场景

    • 长途货运司机连续驾驶超过2小时后,脊柱弯曲度增加15-20度

    • 夜间驾驶时,50%的司机出现头部前倾超过安全阈值

2. 行业应用案例
  • 沃尔沃S90:配备驾驶员姿态监测系统,当检测到持续不良姿势时,自动调节座椅支撑

  • 滴滴出行:试点运用AI姿势评估,对连续工作超8小时的司机强制休息

1. 教育场景痛点分析
问题维度 传统方式缺陷 姿态监控解决方案
实时反馈 教师无法持续关注每个学生 智能课桌每15分钟震动提醒
数据追踪 家长会依赖主观描述 生成每周姿势分析报告
习惯养成 被动式口头教育 AR游戏化矫正训练
2. 智能教室系统架构
复制代码
graph TD
    A[3D摄像头矩阵] --> B(骨骼关键点提取)
    B --> C{脊柱曲度分析}
    C -->|异常| D[课桌触觉反馈]
    C -->|持续异常| E[教师端预警]
    C --> F[云端健康档案]
    F --> G[家长可视化终端]

代码实现思路

1. 初始化与配置

先导库,包括OpenCV(用于图像处理)、MediaPipe(用于人体姿势估计)、csv(用于日志记录)、datetime和time(用于时间相关操作)等。然后再定义一些全局变量和参数,比如POSTURE_THRESHOLD(头部前倾判断阈值)、ALARM_COLOR(警报颜色)、ALARM_SOUND(警报声音文件路径)等。最后还初始化了一个CSV文件用于记录姿势数据。

2. MediaPipe和摄像头设置

使用MediaPipe的Pose解决方案初始化姿势估计器,并设置摄像头为默认设备。这里设置了姿势检测和跟踪的置信度阈值(大家可以自行调整,我完整代码中给出的是我个人认为比较好的参数,但是可能由于摄像头不同的角度等问题会导致不同的结论,所以可以自己调一调),以调整灵敏度。

3. 主循环

主循环负责持续从摄像头读取视频帧,然后进行以下操作:

  • 图像预处理:将BGR格式的图像转换为RGB格式供MediaPipe处理,并禁用图像写入权限以提高效率。

  • 姿势估计:通过MediaPipe获取当前帧中的人体关键点位置。如果成功检测到关键点,则计算耳朵、肩膀和髋部的平均Y坐标(垂直位置),以此作为评估姿势的基础。

  • 姿势状态判断:基于耳肩高度差和肩髋高度差来判断用户是否处于不良姿势状态。如果满足特定条件(例如头部前倾超过一定阈值且没有弯腰动作),则认为姿势不正确。

  • 绘制和显示:根据姿势状态,在图像上绘制相应的视觉反馈(如连线的颜色变化或警示边框)。同时,也在图像上显示一些实时信息,如耳肩和肩髋的高度差。

  • 警报:当检测到不良姿势时,会播放音频警报,并确保警报不会过于频繁地播放。

  • 数据记录:将每个帧的姿势数据(包括时间戳、耳肩差、肩髋差和姿势状态)记录到CSV文件中。

4. 资源释放

当你想程序结束时,按下Q键退出(英文状态下按下Q不然不行),释放摄像头资源并关闭所有OpenCV窗口。


RGB与BGR的区别

RGB和BGR是两种不同的颜色通道排列方式,它们的核心区别在于颜色分量的顺序不同。以下是详细的技术解析:

一、本质区别

特性 RGB BGR
通道顺序 Red-Green-Blue Blue-Green-Red
内存布局 [R,G,B] [B,G,R]
典型应用领域 大部分图像处理库 OpenCV默认格式

二、OpenCV的特殊性

python 复制代码
# OpenCV的历史设计决策
cv2.imread() → BGR格式
cv2.imshow() → 期待BGR输入
内存结构示意图:
复制代码
BGR像素布局 → | B | G | R | B | G | R | ... 
RGB像素布局 → | R | G | B | R | G | B | ...

三、转换必要性分析

在代码中出现的两次转换:

python 复制代码
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)  # ← 转换1:给MediaPipe
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)  # ← 转换2:回显准备
转换流程图示:
复制代码
摄像头原始帧(BGR)
     ↓ 转换1
MediaPipe处理格式(RGB)
     ↓ 算法处理
     ↓ 转换2
OpenCV显示格式(BGR)

四、常见问题场景

  1. 颜色显示异常

    python 复制代码
    # 错误示例:直接显示未转换的MediaPipe结果
    cv2.imshow('错误演示', results_image)  # 会出现颜色失真
  2. 跨库兼容问题

    python 复制代码
    matplotlib.pyplot.imshow(cv2_image)  # 需要先做BGR→RGB转换

五、性能优化建议

python 复制代码
# 原始代码
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image.flags.writeable = False  # ← 优化点:禁止写入加速处理
results = pose.process(image)

# 高级优化方案(使用numpy视图):
rgb_image = image[..., ::-1]  # BGR→RGB通过数组倒序实现

六、底层原理

OpenCV使用BGR的根本原因可追溯到:

  1. 早期相机传感器的硬件设计

  2. Windows系统显示驱动的历史遗留问题

  3. 与Intel图像处理库(IPP)的兼容性

七、验证实验

python 复制代码
# 颜色通道分离验证
b, g, r = cv2.split(bgr_image)
print(r[0,0], g[0,0], b[0,0])  # 输出顺序为BGR

r, g, b = cv2.split(rgb_image)
print(r[0,0], g[0,0], b[0,0])  # 输出顺序为RGB

八、现代发展趋势

技术方向 说明
硬件加速转换 GPU直接处理颜色空间转换
自动格式检测 智能识别输入图像的颜色空间
统一颜色标准 DCI-P3等广色域标准的普及应用

整体代码

python 复制代码
# 导入所需库
import cv2  # OpenCV库,用于图像处理和摄像头操作
import mediapipe as mp  # MediaPipe库,提供人体姿势识别模型
import csv  # 用于CSV文件读写
import datetime  # 生成时间戳
import time  # 时间相关操作
import numpy as np  # 数值计算(虽然代码中未直接使用)
from playsound import playsound  # 播放音频文件

# 初始化MediaPipe组件
mp_pose = mp.solutions.pose
mp_drawing = mp.solutions.drawing_utils  # 绘制姿势关键点和连线的工具

# 摄像头初始化(0表示默认摄像头)
cap = cv2.VideoCapture(0)

# ================== 全局配置参数 ==================
POSTURE_THRESHOLD = -0.255  # 头部前倾判断阈值(需根据实际情况调整)
ALARM_COLOR = (0, 0, 255)  # 警报显示颜色(BGR格式-红色)
NORMAL_COLOR = (0, 255, 0)  # 正常状态颜色(BGR格式-绿色)
ALARM_SOUND = "alert.wav"  # 警报音效文件路径
LOG_FILE = "posture_log.csv"  # 日志文件名

# 初始化CSV日志文件(带异常处理)
try:
    with open(LOG_FILE, 'w', newline='') as f:
        csv.writer(f).writerow([
            'Timestamp',           # 时间戳
            'EarShoulderDiff',      # 耳-肩垂直差值
            'ShoulderHipDiff',     # 肩-髋垂直差值
            'PostureStatus'         # 姿势状态(True/False)
        ])
except Exception as e:
    print(f"文件初始化失败: {str(e)}")

last_play_time = 0  # 记录上次播放警报的时间(用于防止重复播放)

# 校准相关变量(代码中暂未实现完整校准逻辑)
calibration_values = []      # 存储校准数据
start_calibration = time.time()  # 校准开始时间

# ================== 主处理流程 ==================
with mp_pose.Pose(
        min_detection_confidence=0.5,  # 姿势检测置信度阈值(调低以提高灵敏度)
        min_tracking_confidence=0.5    # 姿势跟踪置信度阈值
) as pose:
    while cap.isOpened():  # 主循环
        success, image = cap.read()
        if not success:  # 摄像头读取失败处理
            break

        # ============= 图像预处理 =============
        try:
            image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)  # 转换颜色空间(MediaPipe需要RGB格式)
            image.flags.writeable = False  # 设为只读以提高处理效率
            results = pose.process(image)  # 使用MediaPipe处理图像获取姿势数据
            image.flags.writeable = True
            image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)  # 转换回BGR格式供OpenCV显示
        except Exception as e:
            print(f"图像处理异常: {str(e)}")
            continue

        # 初始化姿势状态变量
        posture_status = False
        ear_shoulder_diff = 0.0
        shoulder_hip_diff = 0.0

        if results.pose_landmarks:  # 如果检测到姿势关键点
            try:
                # ========== 关键点坐标获取 ==========
                landmarks = results.pose_landmarks.landmark

                # 定义安全获取关键点平均值的函数
                def get_landmark_avg(landmark1, landmark2):
                    """获取两个关键点Y坐标的平均值(归一化坐标)"""
                    try:
                        return (landmark1.y + landmark2.y) / 2
                    except:
                        return 0.0  # 异常时返回默认值

                # 计算各身体部位的平均Y坐标(归一化坐标,原点在图像左上角)
                ear_y = get_landmark_avg(
                    landmarks[mp_pose.PoseLandmark.LEFT_EAR],
                    landmarks[mp_pose.PoseLandmark.RIGHT_EAR]
                )
                shoulder_y = get_landmark_avg(
                    landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER],
                    landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER]
                )
                hip_y = get_landmark_avg(
                    landmarks[mp_pose.PoseLandmark.LEFT_HIP],
                    landmarks[mp_pose.PoseLandmark.RIGHT_HIP]
                )

                # ========== 姿势参数计算 ==========
                ear_shoulder_diff = float(ear_y - shoulder_y)   # 耳肩高度差(正值表示头部前倾)
                shoulder_hip_diff = float(shoulder_y - hip_y)   # 肩髋高度差

                # ========== 姿势状态判断 ==========
                # 判断条件:
                # 1. 耳肩高度差超过阈值(头部前倾)
                # 2. 肩髋高度差绝对值小于0.5(排除弯腰动作)
                posture_status = bool(
                    (ear_shoulder_diff > POSTURE_THRESHOLD) and
                    (abs(shoulder_hip_diff) < 0.62)
                )

                # ========== 姿势关键点绘制 ==========
                mp_drawing.draw_landmarks(
                    image,
                    results.pose_landmarks,
                    mp_pose.POSE_CONNECTIONS,  # 绘制关键点连线
                    landmark_drawing_spec=mp_drawing.DrawingSpec(
                        color=ALARM_COLOR if posture_status else NORMAL_COLOR,
                        thickness=2  # 关键点连线粗细
                    )
                )

                # ========== 警报处理逻辑 ==========
                if posture_status:
                    # 绘制红色警示边框
                    cv2.rectangle(image, (0, 0),
                                (image.shape[1] - 1, image.shape[0] - 1),
                                ALARM_COLOR, 10)
                    # 添加警示文字
                    cv2.putText(image, "POSTURE WARNING!", (50, 50),
                                cv2.FONT_HERSHEY_SIMPLEX, 1, ALARM_COLOR, 3)

                    # 播放警报音效(2秒间隔)
                    try:
                        current_time = time.time()
                        if current_time - last_play_time > 2:
                            playsound(ALARM_SOUND)
                            last_play_time = current_time
                    except Exception as e:
                        print(f"声音警报错误: {str(e)}")

            except (KeyError, AttributeError) as e:
                print(f"关键点处理错误: {str(e)}")
                continue  # 跳过当前帧处理

        # ========== 数据记录模块 ==========
        try:
            timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]  # 精确到毫秒
            with open(LOG_FILE, 'a', newline='') as f:
                csv.writer(f).writerow([
                    str(timestamp),
                    f"{ear_shoulder_diff:.4f}",   # 保留4位小数
                    f"{shoulder_hip_diff:.4f}",
                    str(posture_status)
                ])
        except Exception as e:
            print(f"数据记录错误: {str(e)}")

        # ========== 界面显示模块 ==========
        try:
            # 显示实时参数
            cv2.putText(image,
                        f"Ear-Shoulder: {ear_shoulder_diff:.3f}",
                        (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 0), 2)
            cv2.putText(image,
                        f"Shoulder-Hip: {shoulder_hip_diff:.3f}",
                        (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 0), 2)
            # 显示状态指示
            cv2.putText(image,
                        f"Status: {'WARNING' if posture_status else 'NORMAL'}",
                        (10, 90), cv2.FONT_HERSHEY_SIMPLEX, 0.6,
                        ALARM_COLOR if posture_status else NORMAL_COLOR, 2)
        except Exception as e:
            print(f"界面渲染错误: {str(e)}")

        # 显示处理后的图像
        cv2.imshow('Posture Correction', image)
        
        # 按Q键退出
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

# ================== 资源释放 ==================
cap.release()  # 释放摄像头
cv2.destroyAllWindows()  # 关闭所有OpenCV窗口

效果展示

驼背检测

总结,多学多看多练。

相关推荐
龚大龙11 分钟前
机器学习(李宏毅)——Domain Adaptation
人工智能·机器学习
vortex517 分钟前
在Kali中使用虚拟环境安装python工具的最佳实践:以 pwncat 为例
linux·python·网络安全·渗透测试·pip·kali
源码姑娘18 分钟前
基于DeepSeek的智慧医药系统(源码+部署教程)
java·人工智能·程序人生·毕业设计·springboot·健康医疗·课程设计
AIGC_ZY18 分钟前
扩散模型中三种加入条件的方式:Vanilla Guidance,Classifier Guidance 以及 Classifier-Free Guidance
深度学习·机器学习·计算机视觉
原来是猿38 分钟前
蓝桥备赛(13)- 链表和 list(上)
开发语言·数据结构·c++·算法·链表·list
项目申报小狂人1 小时前
高性能算法NGO!北方苍鹰优化算法(Northern Goshawk Optimization,NGO)
算法·数学建模
☞黑心萝卜三条杠☜1 小时前
后门攻击仓库 backdoor attack
论文阅读·人工智能
且听风吟ayan1 小时前
leetcode day26 重复的子字符串
算法·leetcode·c#
AntBlack1 小时前
Python 打包笔记 : 你别说 ,PyStand 确实简单易上手
后端·python·创业
三三木木七1 小时前
BERT、T5、GPTs,Llama
人工智能·深度学习·bert