OpenCV和Mediapipe实现摸嘴或鼻检测

目录

引言

1.过程简介

2. 代码结构

2.1 导入库

2.2 初始化模型

2.3 读取视频流或摄像头

2.4 初始化FPS计算

2.5 主循环

2.6 转换BGR图像为RGB图像

2.7 运行姿势检测模型和手部检测模型

2.8 绘制姿势关键点及连接线

2.9 检测手部关键点

2.10 判断手部与鼻子、嘴的相对位置

2.11 计算并显示FPS

2.12 显示结果

2.13 退出程序

2.14 释放资源

3. 实现思路

4. 注意事项

5. 总结

行业应用

代码实现

效果展示


引言

        这份代码使用了 MediaPipe 库中的 Pose 模型和 Hands 模型,以及 OpenCV 库,用于实时监测摄像头捕捉到的视频中的姿势和手部动作。主要功能包括标记关键点、绘制姿势连接线以及通过手部与鼻子、嘴的相对位置判定实现了简单的动作监测。

1.过程简介

        这段代码实现了使用MediaPipe库进行人体姿势和手部动作检测,并在摄像头视频流上展示检测结果和实时FPS。

        首先,导入了需要的库,包括cv2和mediapipe。然后,通过mp_pose.Pose()和mp_hands.Hands()初始化了MediaPipe的Pose和Hands模型。

        接下来,通过cap = cv2.VideoCapture(0)打开了摄像头,获取视频流。然后,通过循环读取每一帧的图像,直到视频结束。

        在循环中,首先将BGR图像转换为RGB图像,然后分别使用pose.process()和hands.process()运行姿势和手部检测模型,获得检测结果。

        接着,通过mp.solutions.drawing_utils.draw_landmarks()方法绘制姿势关键点和连接线。如果检测到手部关键点,遍历每个手部关键点,将关键点绘制为圆点。

        在手部检测的过程中,同样检测了鼻尖和嘴巴的位置,判断手部和鼻尖、嘴巴的距离是否小于一定阈值,如果满足条件,则认为在摸鼻子或摸嘴巴。

        在最后,计算FPS并显示在图像上,然后通过cv2.imshow()显示图像。同时,通过cv2.waitKey(1)判断是否按下ESC键,如果是则退出循环。

        最后,释放摄像头资源并关闭所有窗口。

2. 代码结构

2.1 导入库

import cv2 import mediapipe as mp import time

导入 OpenCV 和 MediaPipe 库。

2.2 初始化模型

mp_pose = mp.solutions.pose mp_hands = mp.solutions.hands pose = mp_pose.Pose() hands = mp_hands.Hands() 

初始化姿势检测模型和手部检测模型。

2.3 读取视频流或摄像头

cap = cv2.VideoCapture(0)

打开默认摄像头,获取视频流。

2.4 初始化FPS计算

fps_start_time = time.time() fps_frame_count = 0 fps = 0

记录开始时间和帧数,计算每秒帧数(FPS)。

2.5 主循环

while cap.isOpened(): ret, frame = cap.read() if not ret: break

主循环用于读取视频流的每一帧。

2.6 转换BGR图像为RGB图像

rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

将每一帧从 BGR 转换为 RGB,以适应 MediaPipe 模型。

2.7 运行姿势检测模型和手部检测模型

pose_results = pose.process(rgb_frame) hand_results = hands.process(rgb_frame)

运行姿势检测模型和手部检测模型,获取检测结果。

2.8 绘制姿势关键点及连接线

if pose_results.pose_landmarks: mp.solutions.drawing_utils.draw_landmarks(frame, pose_results.pose_landmarks, mp_pose.POSE_CONNECTIONS)

通过 mp.solutions.drawing_utils.draw_landmarks 绘制姿势关键点及连接线。

2.9 检测手部关键点

if hand_results.multi_hand_landmarks: for landmarks in hand_results.multi_hand_landmarks: # 处理手部关键点

对检测到的手部关键点进行处理。

2.10 判断手部与鼻子、嘴的相对位置

# 判断手是否接近鼻子
distance_to_nose = cv2.norm((nose_x, nose_y), (hand_x, hand_y))
if distance_to_nose < 10:  # 调整阈值以适应你的实际情况
cv2.putText(frame, "Touching Nose", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 155, 155), 2,cv2.LINE_AA)# 判断手是否接近嘴巴
distance_to_mouth = cv2.norm((mouth_x, mouth_y), (hand_x, hand_y))
if distance_to_mouth < 20:  # 调整阈值以适应你的实际情况
cv2.putText(frame, "Touching Mouth", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 155, 155), 2,cv2.LINE_AA)
# 判断手部和鼻尖位置关系 # 判断手部和嘴巴位置关系 

通过相对位置判定手部与鼻子、嘴的关系。

2.11 计算并显示FPS

    # 计算FPSfps_frame_count += 1if fps_frame_count >= 15:fps_end_time = time.time()fps = round(fps_frame_count / (fps_end_time - fps_start_time), 2)fps_frame_count = 0fps_start_time = time.time()# 显示FPScv2.putText(frame, f"FPS: {fps}", (10, 90), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv2.LINE_AA)

# 计算并显示FPS

计算帧率,并在视频窗口上方显示。

2.12 显示结果

cv2.imshow('Pose and Hand Detection', frame)

使用 cv2.imshow 显示最终结果。

2.13 退出程序

if cv2.waitKey(1) & 0xFF == 27: # 按ESC键退出 break 

通过按下 ESC 键退出程序。

2.14 释放资源

cap.release() cv2.destroyAllWindows()

释放摄像头资源,关闭所有窗口。

3. 实现思路

        该代码首先通过 MediaPipe 库提供的 Pose 和 Hands 模型,获取姿势和手部的关键点。然后,通过 OpenCV 绘制姿势关键点和连接线,并在每一帧中检测手部的相对位置,判断是否进行了摸鼻子和摸嘴的动作。

4. 注意事项

  • 使用 MediaPipe 提供的模型进行姿势和手部检测。
  • 通过 OpenCV 绘制姿势关键点和连接线,提高可视化效果。
  • 通过相对位置判定手部与鼻子、嘴的关系,实现了动作监测。

5. 总结

        这份代码展示了如何结合 MediaPipe 和 OpenCV 库,实现实时的姿势和手部检测,并通过相对位置的判定,实现了简单的动作监测。代码结构清晰,易于理解和扩展。


行业应用

        此模块可以用作汽车内部摄像头的部署,来实时检测驾驶员的驾驶专注度以达到警示驾驶员的目的。


 

代码实现

import cv2
import mediapipe as mp
import time# 初始化MediaPipe Pose模型和Hand模型
mp_pose = mp.solutions.pose
mp_hands = mp.solutions.hands
pose = mp_pose.Pose()
hands = mp_hands.Hands()# 读取视频流或摄像头
cap = cv2.VideoCapture(0)  # 0表示默认摄像头# 初始化FPS计算
fps_start_time = time.time()
fps_frame_count = 0
fps = 0while cap.isOpened():ret, frame = cap.read()if not ret:break# 转换BGR图像为RGB图像rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)# 运行姿势估计模型pose_results = pose.process(rgb_frame)# 运行手部估计模型hand_results = hands.process(rgb_frame)# 绘制姿势关键点及连接线if pose_results.pose_landmarks:mp.solutions.drawing_utils.draw_landmarks(frame, pose_results.pose_landmarks, mp_pose.POSE_CONNECTIONS)# 检测手部关键点if hand_results.multi_hand_landmarks:for landmarks in hand_results.multi_hand_landmarks:for point in landmarks.landmark:x, y, _ = int(point.x * frame.shape[1]), int(point.y * frame.shape[0]), int(point.z * frame.shape[1] * 5)cv2.circle(frame, (x, y), 5, (155, 155, 0), -1)# 获取鼻尖位置if pose_results.pose_landmarks:nose_landmark = pose_results.pose_landmarks.landmark[mp_pose.PoseLandmark.NOSE]nose_x, nose_y = int(nose_landmark.x * frame.shape[1]), int(nose_landmark.y * frame.shape[0])# 获取嘴巴位置mouth_landmark = pose_results.pose_landmarks.landmark[int((mp_pose.PoseLandmark.MOUTH_LEFT + mp_pose.PoseLandmark.MOUTH_RIGHT) / 2)]mouth_x, mouth_y = int(mouth_landmark.x * frame.shape[1]), int(mouth_landmark.y * frame.shape[0])# 判断手部和鼻尖位置关系,如果距离小于一定阈值,则判定为摸鼻子for landmarks in hand_results.multi_hand_landmarks:for point in landmarks.landmark:hand_x, hand_y, _ = int(point.x * frame.shape[1]), int(point.y * frame.shape[0]), int(point.z * frame.shape[1] * 5)# 判断手是否接近鼻子distance_to_nose = cv2.norm((nose_x, nose_y), (hand_x, hand_y))if distance_to_nose < 10:  # 调整阈值以适应你的实际情况cv2.putText(frame, "Touching Nose", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 155, 155), 2,cv2.LINE_AA)# 判断手是否接近嘴巴distance_to_mouth = cv2.norm((mouth_x, mouth_y), (hand_x, hand_y))if distance_to_mouth < 20:  # 调整阈值以适应你的实际情况cv2.putText(frame, "Touching Mouth", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 155, 155), 2,cv2.LINE_AA)# 计算FPSfps_frame_count += 1if fps_frame_count >= 15:fps_end_time = time.time()fps = round(fps_frame_count / (fps_end_time - fps_start_time), 2)fps_frame_count = 0fps_start_time = time.time()# 显示FPScv2.putText(frame, f"FPS: {fps}", (10, 90), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv2.LINE_AA)# 显示结果cv2.imshow('Pose and Hand Detection', frame)# 退出程序if cv2.waitKey(1) & 0xFF == 27:  # 按ESC键退出break# 释放资源
cap.release()
cv2.destroyAllWindows()

        其实我还想要加入眼睛的部分,但是我写的眼睛部分检测的代码有BUG,所以我就暂时没有加上去,等我研究研究啦~~~~


效果展示

ヾ( ̄▽ ̄)Bye~Bye~

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

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

相关文章

使用Flask快速搭建轻量级Web应用【第127篇—Flask】

使用Flask快速搭建轻量级Web应用 在Web开发领域&#xff0c;选择适合项目需求的框架至关重要。Flask&#xff0c;一个轻量级的Python Web框架&#xff0c;以其简洁、灵活和易扩展的特性而备受开发者青睐。本文将介绍如何使用Flask迅速搭建一个轻量级的Web应用&#xff0c;并通过…

数学建模——蒙特卡洛法

目录 1.介绍2.可以做的题型3.实战3.1求pi的值3.2求定积分x^2 的值 参加了大大小小很多场比赛了&#xff0c;但是都是混子&#xff0c;但还是打算记录一下吧&#xff0c;系统认真过一遍。后续功力深厚&#xff0c;会拓展写的文章&#xff0c;目前是干货&#xff0c;一些背景啥的…

C#多线程(5)——异步方法async与await

在上一章节中&#xff0c;为大家介绍了C#多线程&#xff08;4&#xff09;——任务并行库TPL&#xff0c;TPL是从.NetFramwork4.0后引入的基于异步操作的一组API&#xff0c;核心关注于任务【 T a s k 和 T a s k < T > \textcolor{red}{Task 和 Task<T>} Task和Ta…

轴向磁通电机(轴向电机)属于高效节能型电机 本土企业已具备高性能产品生产实力

轴向磁通电机&#xff08;轴向电机&#xff09;属于高效节能型电机 本土企业已具备高性能产品生产实力 按照磁通路径方向不同&#xff0c;电机可分为径向磁通电机以及轴向磁通电机两种类型。轴向磁通电机又称轴向电机&#xff0c;指电机旋转轴与磁通方向平行的磁通电机。与径向…

每日shell脚本之批量重命名文件

每日shell脚本之批量重命名文件 #!/bin/bash# 设置要修改的目录路径和前缀 directory"/path/to/directory" prefix"new_"# 遍历目录下的所有文件 for file in "$directory"/*; do# 获取文件名&#xff08;不包含路径&#xff09;filename$(base…

MyBatis-Plus知识点(二)

一、条件构造器和常用接口 1、wapper介绍 Wrapper &#xff1a; 条件构造抽象类&#xff0c;最顶端父类 AbstractWrapper &#xff1a; 用于查询条件封装&#xff0c;生成 sql 的 where 条件 QueryWrapper &#xff1a; 查询条件封装 UpdateWrapper &#xff1a; Update 条…

Ai-M61-32SU+字库+LCD

Ai-M61-32SU 有4M flash&#xff0c;可以下载一个200多K的GB2312_80字库 一、将gb2312_80.bin(字库文件)烧录到Ai-M61-32SU中 1、将gb2312_80.bin放到工程的根目录 2、修改flash_prog_cfg.ini文件&#xff0c;增加了partition和media部分 [cfg] # 0: no erase, 1:programmed …

什么是R语言?什么是R包?-R语言001

R语言是一种专为统计计算和图形而设计的编程语言和环境。它最初由罗斯伊哈卡和罗伯特亨特尔在1993年创建&#xff0c;灵感来源于S语言。R语言已经发展成为统计学、数据分析、科学研究以及许多其他领域中最受欢迎和广泛使用的工具之一。R语言的核心是一个开源的解释型语言&#…

(delphi11最新学习资料) Object Pascal 学习笔记---第7章第1节( 其他面向对象语言中的类 )

7.1.2 其他面向对象语言中的类 ​ 作为比较&#xff0c;这是用 C# 和 Java 编写的 TDate 类&#xff08;在这种简化的情况下&#xff0c;它们碰巧是相同的&#xff09;&#xff0c;使用了一套更合适的命名规则&#xff0c;方法的代码省略了&#xff1a; // C# and Java langu…

js视频上传的方法

一、视频上传于图片上传类似他们的上传方法一样。路径不同标签不同&#xff1b; 二、直接上效果 三、直接上代码 // // 上传图片 let urls "https://wwz.jingyi.icu/"; let a $("form img") // console.log(a);function fl() {let read document.getE…

mysql备份和还原全部的数据库

备份数据库 mysqldump -u root -p --all-databases > all_databases_backup.sql还原数据库 删除之前的全部数据库(谨慎操作) mysql -u root -p -e "DROP DATABASE IF EXISTS database_name;" --skip-column-names还原数据库&#xff0c;需要有权限&#xff0c;…

1. git 常用命令

1.使用 git pull 命令拉取文件 git pull git pull origin master [ 这条命令会从远程仓库&#xff08;通常是 origin&#xff09;拉取 master 分支的最新更改并合并到你的本地 master 分支 ]2.使用git add命令将所有文件添加到Git仓库。 git add .3.使用git commit命令提交你…

探索制氮机在农产品保鲜中的应用方式

在现代生活中&#xff0c;农产品保鲜成为老生常谈的话题&#xff0c;水果数次厂商总是在为如何使水果蔬菜能够保存时间长一点而发愁&#xff0c;而制氮机的出现则解决了这一难题&#xff0c;为农产品保鲜技术带来了革命性的变革。本期恒业通小编和您一起了解制氮机在水果,蔬菜保…

Pytorch基础(21)-- torch.repeat_interleave()方法

分享一下自己目前在维护的Github项目&#xff0c;由于本人博士阶段接触了一个全新的研究方向-----使用机器学习、强化学习、深度学习等方法解决组合优化问题&#xff0c;维护这个项目的目的&#xff1a; &#xff08;1&#xff09;记录自己阅读过的paper&#xff0c;同时分享一…

【数学建模】熵权法 Python代码

熵权法是一种客观的赋权方法&#xff0c;它可以靠数据本身得出权重。 依据的原理&#xff1a;指标的变异程度越小&#xff0c;所反映的信息量也越少&#xff0c;其对应的权值也应该越低。 import numpy as np#自定义对数函数mylog&#xff0c;用于处理输入数组中的0元素 def m…

ROS机器人操作系统底层原理及代码剖析

本文介绍ROS机器人操作系统&#xff08;Robot Operating System&#xff09;的实现原理&#xff0c;从最底层分析ROS代码是如何实现的。 1、序列化 把通信的内容&#xff08;也就是消息message&#xff09;序列化是通信的基础&#xff0c;所以我们先研究序列化。 尽管笔者从事…

jenkins部署go应用 基于docker

丢弃旧的的构建 github 拉取代码 拉取代码排除指定配置文件 报错 环境变量失效 服务器版本为1.21.6 但是一直没有生效

字符串|替换数字

卡码网题目链接 #include<iostream> using namespace std; int main() {string s;while (cin >> s) {int count 0; // 统计数字的个数int sOldSize s.size();for (int i 0; i < s.size(); i) {if (s[i] > 0 && s[i] < 9) {count;}}// 扩充字符…

6.同步异步、正则表达式

JS执行机制 js的特点&#xff1a;单线程&#xff0c;同一时间只能做一件事 可以通过多核CPU解决这个问题&#xff0c;允许js脚本创建多个线程&#xff0c;于是js出现了同步和异步 同步 程序执行的时候按照顺序依次执行 异步 程序执行的时候&#xff0c;会跳过某个步骤继续…

什么是deterministic training(确定性训练),pytorch如何实现

deterministic training&#xff08;确定性训练&#xff09;是一种训练机器学习模型的方式&#xff0c;其主要特点是确保在相同的初始条件下&#xff0c;每次训练都会得到相同的结果。换句话说&#xff0c;确定性训练旨在消除随机性&#xff0c;使得模型的训练过程是可重复和可…