【深度学习实战—9】:基于MediaPipe的坐姿检测

news2024/11/16 17:30:41

✨博客主页:王乐予🎈
✨年轻人要:Living for the moment(活在当下)!💪
🏆推荐专栏:【图像处理】【千锤百炼Python】【深度学习】【排序算法】

目录

  • 😺一、MediaPipe概述
  • 😺二、MediaPipe姿态特征点检测
    • 🐶2.1 概述
    • 🐶2.2 度量函数
  • 😺三、代码实现
    • 🐶3.1 utils.py
    • 🐶3.2 main.py
  • 😺四、参考

😺一、MediaPipe概述

MediaPipe 是一款由 Google Research 开发并开源的多媒体机器学习模型应用框架。

MediaPipe目前支持的解决方案(Solution)及支持的平台如下图所示:
在这里插入图片描述

😺二、MediaPipe姿态特征点检测

🐶2.1 概述

通过 MediaPipe Pose Marker,可以检测图片或视频中人体的特征点。使用此任务识别关键的身体位置,分析姿势并对动作进行分类。该任务会在图片坐标和三维世界坐标中输出身体姿势地标。

姿势特征点使用一系列模型来预测姿势特征点。第一个模型检测图片帧中是否存在人体,第二个模型则在身体上定位地标。

姿势特征点模型会跟踪 33 个身体特征点位置,表示以下身体部位的大致位置:
请添加图片描述
点位信息如下:

0 - nose
1 - left eye (inner)
2 - left eye
3 - left eye (outer)
4 - right eye (inner)
5 - right eye
6 - right eye (outer)
7 - left ear
8 - right ear
9 - mouth (left)
10 - mouth (right)
11 - left shoulder
12 - right shoulder
13 - left elbow
14 - right elbow
15 - left wrist
16 - right wrist
17 - left pinky
18 - right pinky
19 - left index
20 - right index
21 - left thumb
22 - right thumb
23 - left hip
24 - right hip
25 - left knee
26 - right knee
27 - left ankle
28 - right ankle
29 - left heel
30 - right heel
31 - left foot index
32 - right foot index

🐶2.2 度量函数

坐姿检测将使用不同关键点的向量夹角做判定,向量内角图如下:
在这里插入图片描述
内角计算与向量的起止顺序有关,在上图中,假定选择kpt1和kpt2为人体的两个关键点,kpt3为向量起始点即kpt1的垂直方向任意位置的点,则夹角为:
θ = arccos ⁡ ( P 12 → × P 13 → ∣ P 12 → ∣ ∣ P 13 → ∣ ) \theta =\arccos (\frac{\overrightarrow{P_{12} } \times \overrightarrow{P_{13} } }{\left | \overrightarrow{P_{12} } \right | \left | \overrightarrow{P_{13} } \right | } ) θ=arccos( P12 P13 P12 ×P13 )

不妨设kpt3的y3坐标为0,则带入坐标值有:
θ = arccos ⁡ ( y 1 2 − y 1 × y 2 y 1 ( x 2 − x 1 ) 2 + ( y 2 − y 1 ) 2 ) \theta =\arccos (\frac{y_{1}^{2} - y_{1}\times y_{2} }{y_{1}\sqrt{(x_{2}-x_{1})^{2}+(y_{2}-y_{1})^{2} } } ) θ=arccos(y1(x2x1)2+(y2y1)2 y12y1×y2)

根据上图可知 θ \theta θ为锐角,如果向量方向为由kpt2指向kpt1,则需要在kpt2的垂直方向标记点kpt3,此时 θ \theta θ为钝角。

😺三、代码实现

  • utils.py:包含度量函数的定义与姿态检测函数
  • main.py:主函数,获取需要的关键点数据,绘图

🐶3.1 utils.py

import math as m


# 度量函数
def findAngle(x1, y1, x2, y2):
    theta = m.acos((y2 - y1) * (-y1) / (m.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) * y1))
    degree = int(180/m.pi)*theta
    return degree

"""
歪头监控:计算 左耳(7点)和 右耳(8点)的夹角
低头监控:计算 左嘴角(9点)和 左肩膀(11点)的夹角
侧脸监控:计算 右眼内(4点)和 左耳(7点)的距离,计算 左眼内(1点)和 右耳(8点)的距离
高低肩监控:计算 左肩膀(11点)和 右肩膀(12点)的夹角            *****有的人左肩和右肩一个高一个低*****
撑桌监控:如果 左嘴角(9点)或者 右嘴角(10点)的 y 坐标 大于 左肩膀(11点)或 右肩膀(12点)的 y 坐标,视为撑桌
仰头监控:计算 鼻子(0点)和 左耳(7点)的夹角
趴桌监控:如果 左肩膀(11点)和 右肩膀(12点)的 归一化y坐标 之和大于0.75,判定为趴桌
"""
def all_detection(nose_x, nose_y,                               # 鼻子(0点)的 x 坐标 和 y 坐标
                  left_eye_inner_x, left_eye_inner_y,           # 左眼内(1点)的 x 坐标 和 y 坐标
                  right_eye_inner_x, right_eye_inner_y,         # 右眼内(4点)的 x 坐标 和 y 坐标
                  left_ear_x, left_ear_y,                       # 左耳(7点)的 x 坐标 和 y 坐标
                  right_ear_x, right_ear_y,                     # 右耳(8点)的 x 坐标 和 y 坐标
                  left_mouth_x, left_mouth_y,                   # 左嘴角(9点)的 x 坐标 和 y 坐标
                  right_mouth_x, right_mouth_y,                 # 右嘴角(10点)的 x 坐标 和 y 坐标
                  left_shoulder_x, left_shoulder_y,             # 左肩膀(11点)的 x 坐标 和 y 坐标
                  right_shoulder_x, right_shoulder_y,           # 右肩膀(12点)的 x 坐标 和 y 坐标
                  left_shoulder_x_norm, left_shoulder_y_norm,   # 归一化后的左肩膀(11点)的 x 坐标 和 y 坐标
                  right_shoulder_x_norm, right_shoulder_y_norm  # 归一化后的右肩膀(12点)的 x 坐标 和 y 坐标
                  ):
    waitou_inclination = findAngle(left_ear_x, left_ear_y, right_ear_x, right_ear_y)
    ditou_inclination = findAngle(left_mouth_x, left_mouth_y, left_shoulder_x, left_shoulder_y)
    gaodijian_inclination = findAngle(left_shoulder_x, left_shoulder_y, right_shoulder_x, right_shoulder_y)
    yangtou_inclination = findAngle(nose_x, nose_y, left_ear_x, left_ear_y)
    if waitou_inclination < 80:
        tmp = '左歪头'
    elif waitou_inclination > 100:
        tmp = '右歪头'
    elif (left_shoulder_y_norm + right_shoulder_y_norm) > 1.5:
        tmp = '趴桌'
    elif ditou_inclination < 115:
        tmp = '低头'
    elif left_ear_x < right_eye_inner_x:
        tmp = '左侧脸'
    elif right_ear_x > left_eye_inner_x:
        tmp = '右侧脸'
    elif gaodijian_inclination > 100:
        tmp = '高低肩'
    elif gaodijian_inclination < 80:
        tmp = '高低肩'
    elif (left_mouth_y or right_mouth_y) > (left_shoulder_y or right_shoulder_y):
        tmp = '撑桌'
    elif yangtou_inclination > 90:
        tmp = '仰头'
    else:
        tmp = '正脸'
    return tmp

🐶3.2 main.py

import cv2
import mediapipe as mp
from utils import *


mp_pose = mp.solutions.pose
pose = mp_pose.Pose(model_complexity=1, min_detection_confidence=0.5, min_tracking_confidence=0.5)
mp_drawing = mp.solutions.drawing_utils

cap = cv2.VideoCapture(0)

while True:
    ret, frame = cap.read()
    h, w = frame.shape[:2]
    image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    keypoints = pose.process(image)

    image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
    lm = keypoints.pose_landmarks
    lmPose = mp_pose.PoseLandmark

    # 歪头监控
    left_ear_x = int(lm.landmark[lmPose.LEFT_EAR].x * w)    # 左耳(7点)x 坐标
    left_ear_y = int(lm.landmark[lmPose.LEFT_EAR].y * h)    # 左耳(7点)y 坐标
    right_ear_x = int(lm.landmark[lmPose.RIGHT_EAR].x * w)  # 右耳(8点)x 坐标
    right_ear_y = int(lm.landmark[lmPose.RIGHT_EAR].y * h)  # 右耳(8点)y 坐标

    # 低头监控
    left_mouth_x = int(lm.landmark[lmPose.MOUTH_LEFT].x * w)    # 左嘴角(9点)x 坐标
    left_mouth_y = int(lm.landmark[lmPose.MOUTH_LEFT].y * h)    # 左嘴角(9点)y 坐标
    left_shoulder_x = int(lm.landmark[lmPose.LEFT_SHOULDER].x * w)    # 左肩膀(11点)x 坐标
    left_shoulder_y = int(lm.landmark[lmPose.LEFT_SHOULDER].y * h)    # 左肩膀(11点)y 坐标

    # 侧脸监控
    left_eye_inner_x = int(lm.landmark[lmPose.LEFT_EYE_INNER].x * w)    # 左眼内(1点)x 坐标
    left_eye_inner_y = int(lm.landmark[lmPose.LEFT_EYE_INNER].y * h)    # 左眼内(1点)y 坐标
    right_eye_inner_x = int(lm.landmark[lmPose.RIGHT_EYE_INNER].x * w)  # 右眼内(4点)x 坐标
    right_eye_inner_y = int(lm.landmark[lmPose.RIGHT_EYE_INNER].y * h)  # 右眼内(4点)y 坐标

    # 高低肩监控
    right_shoulder_x = int(lm.landmark[lmPose.RIGHT_SHOULDER].x * w)  # 右肩膀(12点)x 坐标
    right_shoulder_y = int(lm.landmark[lmPose.RIGHT_SHOULDER].y * h)  # 右肩膀(12点)y 坐标

    # 撑桌监控
    right_mouth_x = int(lm.landmark[lmPose.MOUTH_RIGHT].x * w)  # 左嘴角(10点)x 坐标
    right_mouth_y = int(lm.landmark[lmPose.MOUTH_RIGHT].y * h)  # 左嘴角(10点)y 坐标

    # 仰头监控
    nose_x = int(lm.landmark[lmPose.NOSE].x * w)    # 鼻子(0点)x 坐标
    nose_y = int(lm.landmark[lmPose.NOSE].y * h)    # 鼻子(0点)y 坐标

    # 趴桌监控
    left_shoulder_x_norm = lm.landmark[lmPose.LEFT_SHOULDER].x  # 左肩膀(11点)x 坐标-归一化
    left_shoulder_y_norm = lm.landmark[lmPose.LEFT_SHOULDER].y  # 左肩膀(11点)y 坐标-归一化
    right_shoulder_x_norm = lm.landmark[lmPose.RIGHT_SHOULDER].x  # 右肩膀(12点)x 坐标-归一化
    right_shoulder_y_norm = lm.landmark[lmPose.RIGHT_SHOULDER].y  # 右肩膀(12点)y 坐标-归一化

    results = all_detection(nose_x, nose_y,
                  left_eye_inner_x, left_eye_inner_y,
                  right_eye_inner_x, right_eye_inner_y,
                  left_ear_x, left_ear_y,
                  right_ear_x, right_ear_y,
                  left_mouth_x, left_mouth_y,
                  right_mouth_x, right_mouth_y,
                  left_shoulder_x, left_shoulder_y,
                  right_shoulder_x, right_shoulder_y,
                  left_shoulder_x_norm, left_shoulder_y_norm,
                  right_shoulder_x_norm, right_shoulder_y_norm)
    print(results)


    mp_drawing.draw_landmarks(image, keypoints.pose_landmarks, mp_pose.POSE_CONNECTIONS)
    cv2.imshow("Image", image)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

需要注意的是utils.py中的判定指标不是固定的,根据摄像头的位置动态调整才能达到满意的效果。

😺四、参考

Google:pose_landmarker
LearnOpencv:building-a-body-posture-analysis-system-using-mediapipe

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1713886.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

链动3+1模式:深度解析与优势探讨

在数字化营销领域&#xff0c;链动模式因其强大的裂变能力和高效的引流机制而备受瞩目。其中&#xff0c;链动21模式一度是商家们的首选&#xff0c;但随着时间的推移&#xff0c;其存在的问题也逐渐显现&#xff1a;预留小号和较低的复购率成为制约其进一步发展的瓶颈。为了解…

速看!!24上软考【电子商务设计师】真题回顾,含答案解析

2024上半年软考考试已经结束了&#xff0c;为大家整理了网友回忆版的电子商务设计师真题及答案&#xff0c;25-26日两批考试总共60道题。 上半年考试的宝子们可以对答案预估分数&#xff01;准备下半年考的宝子可以提前把握考试知识点和出题方向&#xff0c;说不定会遇到相同考…

基于匹配追踪和最大重叠离散小波变换的ECG心电信号R波检测(MATLAB 2018a)

准确识别心电信号的R波是进行HRV分析的前提。因此&#xff0c;开发出准确的心电信号R波检测方法十分重要。近几十年来&#xff0c;提出的R峰检测方法主要分为两个阶段。第1阶段是预处理阶段&#xff0c;目的是对受不同噪声影响的原始心电信号进行降噪处理&#xff0c;从而实现增…

定点化和模型量化(三)

量化解决的是训练使用的浮点和运行使用的硬件只支持定点的矛盾。这里介绍一些实际量化中使用到的工具。 SNPE简介 The Snapdragon Neural Processing Engine (SNPE)是高通骁龙为了加速网络模型设计的框架。但它不只支持高通&#xff0c;SNPE还支持多种硬件平台&#xff0c;AR…

神经网络不确定性综述(Part III)——Uncertainty estimation_Bayesian neural networks

相关链接&#xff1a; 神经网络不确定性综述(Part I)——A survey of uncertainty in deep neural networks-CSDN博客 神经网络不确定性综述(Part II)——Uncertainty estimation_Single deterministic methods-CSDN博客 神经网络不确定性综述(Part III)——Uncertainty est…

11. Django 常用的Web应用程序

11. 常用的Web应用程序 Django为开发者提供了常见的Web应用程序, 如会话控制, 缓存机制, CSRF防护, 消息框架, 分页功能, 国际化和本地化, 单元测试和自定义中间件. 内置的Web应用程序大大优化了网站性能, 并且完善了安全防护机制, 同时也提高了开发者的开发效率.11.1 会话控制…

纷享销客当选江西省数字经济学会首席信息官专业委员会副主任委员

5月11日&#xff0c;江西省数字经济学会首席信息官(CIO)专业委员会成立大会暨“新质生产力”企业数字化转型论坛在南昌香格里拉大酒店隆重举行。 江西省工业和信息化厅作为指导单位&#xff0c;由江西省数字经济学会、南昌市中小企业服务局主办&#xff0c;金蝶软件&#xff0…

idea、datagrip注册记录下

一、DataGrip注册 DataGrip版本号&#xff1a;DataGrip 2023.2 访问地址&#xff1a;https://3.jetbra.in/ 点击“hardbin.com”&#xff0c;下载“jetbra.zip” 在vm里面添加上&#xff1a; -javaagent:D:\work\idea\jetbra\ja-netfilter.jarjetbrains重启datagrip 在刚刚…

香港苏州商会、香港青年科学家协会博士团参观李良济,加强人才交流,促进科创合作与共赢

近日&#xff0c;香港苏州商会、香港青年科学家协会联合主办的苏港青年科创交流会成功举行&#xff0c;香港青年科学家协会博士团神州行苏州站启动。 5月26日&#xff0c;香港苏州商会及香港青年科学家协会博士团走进李良济&#xff0c;先后参观了李良济中医药文化展厅&#xf…

zynq之UART

之前尝试UART0&#xff08;MIO50、51&#xff09;&#xff0c;串口调试助手收到发送的内容。 现在板子上EMIO端有多个串口&#xff0c;所以看看这个怎么弄。 串口是484的转接板&#xff08;接232的串口就会输出乱码&#xff09; https://blog.51cto.com/u_15262460/2882973 …

vue+css解决图片变形问题(flex-shrink: 0)

解决前 给图片添加 flex-shrink: 0;即可解决图片变形问题

leetcode 1270 向公司CEO汇报工作的所有人(postgresql)

需求 员工表&#xff1a;Employees ---------------------- | Column Name | Type | ---------------------- | employee_id | int | | employee_name | varchar | | manager_id | int | ---------------------- employee_id 是这个表的主键。 这个表中每一行中&#xff0c;e…

四川音盛佳云电子商务有限公司可靠吗?怎么样?

在数字经济的浪潮中&#xff0c;抖音电商以其独特的魅力逐渐崭露头角&#xff0c;成为电商领域的一股新势力。而四川音盛佳云电子商务有限公司&#xff0c;正是这股新势力中的佼佼者&#xff0c;以其专业的服务和创新的理念&#xff0c;引领着抖音电商的发展潮流。 四川音盛佳…

用docker搭建的Vulfocus镜像管理界面没有镜像可以拉取解决办法

ps&#xff1a;截止到今天2023.4.2&#xff0c;kali和vps的docker拉取的vulfocus镜像会有版本的区别&#xff0c;虽然都是拉取的最新版&#xff0c;vps上镜像为3个月以前&#xff0c;kali上为16个月以前&#xff0c;所以在修改 views.py 文件时&#xff0c;可能会发现文件内容不…

Sping源码(九)—— Bean的初始化(非懒加载)— getMergedLocalBeanDefinition

序言 前两篇文章介绍了Bean初始化之前的一些准备工作&#xff0c;包括设置BeanFacroty的ConversionService属性以及将Bean进行冻结。这篇文章将会进入到preInstantiateSingletons方法。进一步了解Bean的初始化流程。 preInstantiateSingletons public void preInstantiateSin…

JS实现彩色图片转换为黑白图片

1. 使用 Canvas 研究 canvas 时发现一个有趣的现象——将彩色图片巧妙地转换为黑白图片。以下是实现这一功能的简洁代码示例&#xff1a; <div style"display: flex"><img src"./panda.jpeg" /><button onclick"change()">转…

[C++]debug介绍+debug时如何查看指针指向内存处的值

一、简介 预备工具和知识&#xff1a;使用使用VSCode使用Debug。 本文简介&#xff1a;本文将简要介绍debug中Continue&#xff0c;Step Over&#xff0c;Step Into和Restart的功能。并介绍如何在debug时查看动态内存地址&#xff08;指针&#xff09;的值&#xff1b; 二、D…

强国机械制造有限公司开展中国制造2050系列高端论坛

为深入探讨中国制造2050战略的实施路径和未来发展方向,强国机械制造有限公司2023年10月13日举办了一系列高端论坛。这些论坛吸引了众多业内专家、学者和企业代表参加,共同交流前沿观点和经验,以推动中国制造业的创新与发展。 本次系列高端论坛涵盖了多个关键主题,以下是各论坛…

《Ai企业知识库》rasa-rasa Core核心-认知理解以及配置文件应用

阿丹&#xff1a; 其实在整个rasa中的关键元素和关键的核心在前面多多少少也涉及到了很多&#xff0c;这里就是开始涉及到了rasa的训练核心core。 Rasa Core: Rasa Core 是Rasa框架中的一个组件&#xff0c;它负责处理对话管理部分&#xff0c;即决定对话流程中机器人的下一步…

大模型预训练结果到底是什么?

近日参加一个线下 AI 交流会议&#xff0c;会上有个非本行业的老师提问&#xff1a;“大家说的训练好的大模型到底是什么&#xff1f;是像 Word 软件一样可以直接使用的程序吗&#xff1f;” 这个问题看似简单&#xff0c;却一下把我问住了。的确&#xff0c;我们这些身处 AI 领…