MediaPipe与YOLO已训练模型实现可视化人脸和手势关键点检测

项目首页 - ZiTai_YOLOV11:基于前沿的 MediaPipe 技术与先进的 YOLOv11 预测试模型,精心打造一款强大的实时检测应用。该应用无缝连接摄像头,精准捕捉画面,能即时实现人脸检测、手势识别以及骨骼关键点检测,将检测结果实时、直观地呈现在屏幕上,为用户带来高效且便捷的视觉分析体验 。 - GitCode

一、技术原理

  1. MediaPipe 原理:MediaPipe 是一款由谷歌开发的跨平台机器学习框架,在人脸和手势关键点检测方面表现出色。它通过一系列的机器学习模型和算法,对输入的图像或视频流进行处理。对于人脸检测,MediaPipe 利用其预训练的人脸检测模型,能够快速准确地定位人脸在图像中的位置。接着,通过人脸关键点检测模型,基于深度学习算法学习人脸图像的特征,从而精确地预测出人脸的各个关键点,如眼睛、鼻子、嘴巴、脸颊等部位的关键点坐标,这些关键点能够完整地描述人脸的形状和姿态。对于手势检测,MediaPipe 同样依赖其预训练模型,分析手部的图像特征,识别出手部的各个关节点,并确定手势的姿态和关键点位置,进而实现对手势的理解和分析。
  2. YOLO 原理:YOLO(You Only Look Once)系列算法是当下流行的实时目标检测算法。其核心在于将输入图像划分为多个网格,每个网格负责预测目标的类别、位置和大小。在人脸和手势检测场景中,YOLO 模型通过在大量包含人脸和手势的图像数据集上进行训练,学习到人脸和手势的特征模式。当输入新的图像时,模型能够快速判断图像中是否存在人脸或手势,并预测出它们的边界框位置。为了进一步实现关键点检测,可结合其他基于深度学习的关键点检测算法,在检测到的人脸和手势区域内,精准预测出关键点的坐标。

二、 实现步骤

1.环境搭建

        1.使用Anaconda创建一个虚拟环境(建议使用Python3.6以上的环境)

conda create -n ZiTai python=3.8

        2.激活刚创建的虚拟环境

conda activate ZiTai

        3.安装PyTorch

pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

        4.安装必要的库(open-cv,ultralytics,mediapipe)

pip install opencv - python mediapipe ultralytics

        5.在PyCharm中导入虚拟环境

 

        6.到此环境搭建已经结束了 

2.代码实现

        1.导入必要的库

import cv2
import mediapipe as mp
from ultralytics import YOLO
  • cv2:OpenCV 库,用于计算机视觉任务,如读取摄像头帧、绘制图形和显示图像。
  • mediapipe:Google 开发的跨平台框架,用于构建多模式机器学习应用程序,这里用于手部和面部关键点检测。
  • YOLO:来自ultralytics库,用于加载和运行 YOLO(You Only Look Once)目标检测模型。

        2. 定义常量

YOLO_MODEL_PATH = "GesTure.pt"
GESTURE_BASE_DISTANCE = 0.3
HAND_MAX_NUM = 2
HAND_MIN_DETECTION_CONFIDENCE = 0.5
HAND_MIN_TRACKING_CONFIDENCE = 0.5
FACE_MAX_NUM = 1
FACE_MIN_DETECTION_CONFIDENCE = 0.5
FACE_MIN_TRACKING_CONFIDENCE = 0.5
TEXT_FONT = cv2.FONT_HERSHEY_SIMPLEX
TEXT_SCALE = 1
TEXT_COLOR = (0, 0, 255)
TEXT_THICKNESS = 2
TEXT_POSITION = (50, 50)
EXIT_KEY = ord('q')
HAND_DRAWING_SPEC_1 = mp.solutions.drawing_utils.DrawingSpec(color=(255, 0, 0), thickness=2, circle_radius=2)
HAND_DRAWING_SPEC_2 = mp.solutions.drawing_utils.DrawingSpec(color=(0, 255, 0), thickness=2)
FACE_DRAWING_SPEC_1 = mp.solutions.drawing_utils.DrawingSpec(color=(0, 255, 0), thickness=1, circle_radius=1)
FACE_DRAWING_SPEC_2 = mp.solutions.drawing_utils.DrawingSpec(color=(0, 255, 255), thickness=1)
  • 这些常量定义了模型路径、检测参数、文本显示样式、退出键以及绘制手部和面部关键点的样式。

        3. 加载 YOLO 模型

def load_yolo_model(model_path):try:return YOLO(model_path)except Exception as e:print(f"Failed to load YOLO model: {e}")raise
  • 该函数尝试加载指定路径的 YOLO 模型,如果加载失败,会打印错误信息并抛出异常。

        4. 摄像头捕获类

class CameraCapture:def __init__(self):self.cap = cv2.VideoCapture(0)if not self.cap.isOpened():print("Failed to open camera")raise Exception("Camera could not be opened.")def __enter__(self):return self.capdef __exit__(self, exc_type, exc_val, exc_tb):if self.cap.isOpened():self.cap.release()
  • __init__:初始化摄像头捕获对象,如果无法打开摄像头,会打印错误信息并抛出异常。
  • __enter__:实现上下文管理器的进入方法,返回摄像头捕获对象。
  • __exit__:实现上下文管理器的退出方法,释放摄像头资源。

        5. 计算两点之间的距离

def distance(m, n):return ((n.x - m.x) ** 2 + (n.y - m.y) ** 2) ** 0.5
  • 该函数接受两个点mn,返回它们之间的欧几里得距离。

        6.  手势检测函数

def detect_gesture(handLms):distance_0_8 = distance(handLms.landmark[0], handLms.landmark[8])distance_0_12 = distance(handLms.landmark[0], handLms.landmark[12])distance_0_16 = distance(handLms.landmark[0], handLms.landmark[16])distance_0_20 = distance(handLms.landmark[0], handLms.landmark[20])gesture = "One"if distance_0_8 >= GESTURE_BASE_DISTANCE and distance_0_12 >= GESTURE_BASE_DISTANCE and \distance_0_16 < GESTURE_BASE_DISTANCE and distance_0_20 < GESTURE_BASE_DISTANCE:gesture = "Scissor"elif distance_0_8 >= GESTURE_BASE_DISTANCE and distance_0_12 >= GESTURE_BASE_DISTANCE and \distance_0_16 >= GESTURE_BASE_DISTANCE and distance_0_20 >= GESTURE_BASE_DISTANCE:gesture = "Paper"elif distance_0_8 < GESTURE_BASE_DISTANCE and distance_0_12 < GESTURE_BASE_DISTANCE and \distance_0_16 < GESTURE_BASE_DISTANCE and distance_0_20 < GESTURE_BASE_DISTANCE:gesture = "Rock"return gesture
  • 该函数根据手部关键点之间的距离判断手势,返回相应的手势名称。

        7. 面部网格检测函数

def face_mesh_detection(image, face_mesh, mp_drawing, mp_face_mesh):results = face_mesh.process(image)if results.multi_face_landmarks:for face_landmarks in results.multi_face_landmarks:mp_drawing.draw_landmarks(image, face_landmarks, mp_face_mesh.FACEMESH_CONTOURS,FACE_DRAWING_SPEC_1,FACE_DRAWING_SPEC_2)return image

        8.主函数

def main():try:model = load_yolo_model(YOLO_MODEL_PATH)myDraw = mp.solutions.drawing_utilsmpHands = mp.solutions.handshands = mpHands.Hands(static_image_mode=False,max_num_hands=HAND_MAX_NUM,min_detection_confidence=HAND_MIN_DETECTION_CONFIDENCE,min_tracking_confidence=HAND_MIN_TRACKING_CONFIDENCE)mp_face_mesh = mp.solutions.face_meshface_mesh = mp_face_mesh.FaceMesh(static_image_mode=False,max_num_faces=FACE_MAX_NUM,min_detection_confidence=FACE_MIN_DETECTION_CONFIDENCE,min_tracking_confidence=FACE_MIN_TRACKING_CONFIDENCE)mp_drawing = mp.solutions.drawing_utilswith CameraCapture() as cap:while True:success, frame = cap.read()if not success:print("Failed to read frame from camera.")breakresults = model.predict(source=frame, device=0)annotated_frame = results[0].plot(line_width=2)for result in results:boxes = result.boxesfor box in boxes:cls = int(box.cls[0])conf = float(box.conf[0])x1, y1, x2, y2 = map(int, box.xyxy[0])label = f"{result.names[cls]} {conf:.2f}"cv2.putText(annotated_frame, label, (x1, y1 - 10), TEXT_FONT, 0.5, TEXT_COLOR, 1)results_hands = hands.process(frame)if results_hands.multi_hand_landmarks:for handLms in results_hands.multi_hand_landmarks:gesture = detect_gesture(handLms)cv2.putText(annotated_frame, gesture, TEXT_POSITION, TEXT_FONT, TEXT_SCALE, TEXT_COLOR, TEXT_THICKNESS)myDraw.draw_landmarks(annotated_frame, handLms, mpHands.HAND_CONNECTIONS,HAND_DRAWING_SPEC_1,HAND_DRAWING_SPEC_2)annotated_frame = face_mesh_detection(annotated_frame, face_mesh, mp_drawing, mp_face_mesh)cv2.imshow('Combined Detection', annotated_frame)# 通过按下指定键退出循环if cv2.waitKey(1) & 0xFF == EXIT_KEY:breakexcept Exception as e:import tracebackprint(f"An error occurred: {e}")traceback.print_exc()finally:cv2.destroyAllWindows()if 'hands' in locals():hands.close()if 'face_mesh' in locals():face_mesh.close()
  • 加载 YOLO 模型、初始化手部和面部检测对象。
  • 使用CameraCapture上下文管理器打开摄像头。
  • 循环读取摄像头帧,进行目标检测、手势检测和面部网格检测。
  • 在帧上绘制检测结果,并显示处理后的帧。
  • 按下指定键(q)退出循环。
  • 捕获并处理异常,最后释放资源,关闭窗口。

        9.  程序入口

if __name__ == "__main__":main()
  • 确保代码作为脚本运行时,调用main函数

3.完整代码

import cv2
import mediapipe as mp
from ultralytics import YOLOYOLO_MODEL_PATH = "GesTure.pt"
GESTURE_BASE_DISTANCE = 0.3
HAND_MAX_NUM = 2
HAND_MIN_DETECTION_CONFIDENCE = 0.5
HAND_MIN_TRACKING_CONFIDENCE = 0.5
FACE_MAX_NUM = 1
FACE_MIN_DETECTION_CONFIDENCE = 0.5
FACE_MIN_TRACKING_CONFIDENCE = 0.5
TEXT_FONT = cv2.FONT_HERSHEY_SIMPLEX
TEXT_SCALE = 1
TEXT_COLOR = (0, 0, 255)
TEXT_THICKNESS = 2
TEXT_POSITION = (50, 50)
EXIT_KEY = ord('q')
HAND_DRAWING_SPEC_1 = mp.solutions.drawing_utils.DrawingSpec(color=(255, 0, 0), thickness=2, circle_radius=2)
HAND_DRAWING_SPEC_2 = mp.solutions.drawing_utils.DrawingSpec(color=(0, 255, 0), thickness=2)
FACE_DRAWING_SPEC_1 = mp.solutions.drawing_utils.DrawingSpec(color=(0, 255, 0), thickness=1, circle_radius=1)
FACE_DRAWING_SPEC_2 = mp.solutions.drawing_utils.DrawingSpec(color=(0, 255, 255), thickness=1)def load_yolo_model(model_path):try:return YOLO(model_path)except Exception as e:print(f"Failed to load YOLO model: {e}")raiseclass CameraCapture:def __init__(self):self.cap = cv2.VideoCapture(0)if not self.cap.isOpened():print("Failed to open camera")raise Exception("Camera could not be opened.")def __enter__(self):return self.capdef __exit__(self, exc_type, exc_val, exc_tb):if self.cap.isOpened():self.cap.release()def distance(m, n):return ((n.x - m.x) ** 2 + (n.y - m.y) ** 2) ** 0.5def detect_gesture(handLms):distance_0_8 = distance(handLms.landmark[0], handLms.landmark[8])distance_0_12 = distance(handLms.landmark[0], handLms.landmark[12])distance_0_16 = distance(handLms.landmark[0], handLms.landmark[16])distance_0_20 = distance(handLms.landmark[0], handLms.landmark[20])gesture = "One"if distance_0_8 >= GESTURE_BASE_DISTANCE and distance_0_12 >= GESTURE_BASE_DISTANCE and \distance_0_16 < GESTURE_BASE_DISTANCE and distance_0_20 < GESTURE_BASE_DISTANCE:gesture = "Scissor"elif distance_0_8 >= GESTURE_BASE_DISTANCE and distance_0_12 >= GESTURE_BASE_DISTANCE and \distance_0_16 >= GESTURE_BASE_DISTANCE and distance_0_20 >= GESTURE_BASE_DISTANCE:gesture = "Paper"elif distance_0_8 < GESTURE_BASE_DISTANCE and distance_0_12 < GESTURE_BASE_DISTANCE and \distance_0_16 < GESTURE_BASE_DISTANCE and distance_0_20 < GESTURE_BASE_DISTANCE:gesture = "Rock"return gesturedef face_mesh_detection(image, face_mesh, mp_drawing, mp_face_mesh):results = face_mesh.process(image)if results.multi_face_landmarks:for face_landmarks in results.multi_face_landmarks:mp_drawing.draw_landmarks(image, face_landmarks, mp_face_mesh.FACEMESH_CONTOURS,FACE_DRAWING_SPEC_1,FACE_DRAWING_SPEC_2)return imagedef main():try:model = load_yolo_model(YOLO_MODEL_PATH)myDraw = mp.solutions.drawing_utilsmpHands = mp.solutions.handshands = mpHands.Hands(static_image_mode=False,max_num_hands=HAND_MAX_NUM,min_detection_confidence=HAND_MIN_DETECTION_CONFIDENCE,min_tracking_confidence=HAND_MIN_TRACKING_CONFIDENCE)mp_face_mesh = mp.solutions.face_meshface_mesh = mp_face_mesh.FaceMesh(static_image_mode=False,max_num_faces=FACE_MAX_NUM,min_detection_confidence=FACE_MIN_DETECTION_CONFIDENCE,min_tracking_confidence=FACE_MIN_TRACKING_CONFIDENCE)mp_drawing = mp.solutions.drawing_utilswith CameraCapture() as cap:while True:success, frame = cap.read()if not success:print("Failed to read frame from camera.")breakresults = model.predict(source=frame, device=0)annotated_frame = results[0].plot(line_width=2)for result in results:boxes = result.boxesfor box in boxes:cls = int(box.cls[0])conf = float(box.conf[0])x1, y1, x2, y2 = map(int, box.xyxy[0])label = f"{result.names[cls]} {conf:.2f}"cv2.putText(annotated_frame, label, (x1, y1 - 10), TEXT_FONT, 0.5, TEXT_COLOR, 1)results_hands = hands.process(frame)if results_hands.multi_hand_landmarks:for handLms in results_hands.multi_hand_landmarks:gesture = detect_gesture(handLms)cv2.putText(annotated_frame, gesture, TEXT_POSITION, TEXT_FONT, TEXT_SCALE, TEXT_COLOR, TEXT_THICKNESS)myDraw.draw_landmarks(annotated_frame, handLms, mpHands.HAND_CONNECTIONS,HAND_DRAWING_SPEC_1,HAND_DRAWING_SPEC_2)annotated_frame = face_mesh_detection(annotated_frame, face_mesh, mp_drawing, mp_face_mesh)cv2.imshow('Combined Detection', annotated_frame)# 通过按下指定键退出循环if cv2.waitKey(1) & 0xFF == EXIT_KEY:breakexcept Exception as e:import tracebackprint(f"An error occurred: {e}")traceback.print_exc()finally:cv2.destroyAllWindows()if 'hands' in locals():hands.close()if 'face_mesh' in locals():face_mesh.close()if __name__ == "__main__":main()

三、总结

        作者已将源码和预测试模型文件上传至GitCode仓库,链接在文章顶端,有何问题可以发在评论区,感谢各读者阅读。

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

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

相关文章

JAVA篇12 —— 泛型的使用

​ 欢迎来到我的主页&#xff1a;【Echo-Nie】 本篇文章收录于专栏【JAVA学习】 如果这篇文章对你有帮助&#xff0c;希望点赞收藏加关注啦~ 1 泛型介绍 先对集合进行说明&#xff0c;不能对加入到集合中的元素类型进行约束&#xff08;不安全&#xff09;。遍历的时候需要…

JavaScript 数据类型

基本概念 什么是数据类型 JavaScript是一种 灵活的动态类型语言 &#xff0c;其数据类型构成了程序的基础构建块。它主要包括两类数据类型&#xff1a; 原始数据类型 &#xff1a;包括String、Number、Boolean、Undefined、Null和Symbol。 复杂数据类型 &#xff1a;以Object…

被裁与人生的意义--春节随想

还有两个月就要被迫离开工作了十多年的公司了&#xff0c;不过有幸安安稳稳的过了一个春节&#xff0c;很知足! 我是最后一批要离开的&#xff0c;一百多号同事都没“活到”蛇年。看着一批批仁人志士被“秋后斩首”&#xff0c;马上轮到我们十来个&#xff0c;个中滋味很难言清…

Redis代金卷(优惠卷)秒杀案例-多应用版

Redis代金卷(优惠卷)秒杀案例-单应用版-CSDN博客 上面这种方案,在多应用时候会出现问题,原因是你通过用户ID加锁 但是在多应用情况下,会出现两个应用的用户都有机会进去 让多个JVM使用同一把锁 这样就需要使用分布式锁 每个JVM都会有一个锁监视器,多个JVM就会有多个锁监视器…

绘制决策树尝试3

目录 代码解读AI 随机状态 种子 定义决策树回归模型 tree的decision regressor fit 还可用来预测 export 效果图 我的X只有一个特征 为何这么多分支 &#xff1f;&#xff1f;&#xff1f; 这是CART回归 CART回归 为什么说代码是CART回归&#xff1f; 不是所有的决…

为大模型提供webui界面的利器:Open WebUI 完全本地离线部署deepseek r1

为大模型提供webui界面的利器&#xff1a;Open WebUI Open WebUI的官网&#xff1a;&#x1f3e1; Home | Open WebUI 开源代码&#xff1a;WeTab 新标签页 Open WebUI是一个可扩展、功能丰富、用户友好的自托管AI平台&#xff0c;旨在完全离线运行。它支持各种LLM运行程序&am…

langchain 实现多智能体多轮对话

这里写目录标题 工具定义模型选择graph节点函数定义graph 运行 工具定义 import random from typing import Annotated, Literalfrom langchain_core.tools import tool from langchain_core.tools.base import InjectedToolCallId from langgraph.prebuilt import InjectedSt…

【Block总结】CPCA,通道优先卷积注意力|即插即用

论文信息 标题: Channel Prior Convolutional Attention for Medical Image Segmentation 论文链接: arxiv.org 代码链接: GitHub 创新点 本文提出了一种新的通道优先卷积注意力&#xff08;CPCA&#xff09;机制&#xff0c;旨在解决医学图像分割中存在的低对比度和显著…

Python从零构建macOS状态栏应用(仿ollama)并集成AI同款流式聊天 API 服务(含打包为独立应用)

在本教程中,我们将一步步构建一个 macOS 状态栏应用程序,并集成一个 Flask 服务器,提供流式响应的 API 服务。 如果你手中正好持有一台 MacBook Pro,又怀揣着搭建 AI 聊天服务的想法,却不知从何处迈出第一步,那么这篇文章绝对是你的及时雨。 最终,我们将实现以下功能: …

强化学习、深度学习、深度强化学习的区别是什么?

前言 深度强化学习就是 深度学习 和 强化学习 的结合体。它让计算机程序&#xff08;也就是智能体&#xff09;在特定环境中不断尝试&#xff0c;从错误中学习&#xff0c;最终找到最优的行动策略。 深度学习是AlphaGo从棋谱里学习&#xff0c;强化学些Alphazero 学习规则&am…

string类(详解)

为什么学习string类&#xff1f; 1.1 C语言中的字符串 C语言中&#xff0c;字符串是以\0结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些str系列的库函数&#xff0c;但是这些库函数与字符串是分离开的&#xff0c;不太符合OOP的思想&#xf…

【Redis】set 和 zset 类型的介绍和常用命令

1. set 1.1 介绍 set 类型和 list 不同的是&#xff0c;存储的元素是无序的&#xff0c;并且元素不允许重复&#xff0c;Redis 除了支持集合内的增删查改操作&#xff0c;还支持多个集合取交集&#xff0c;并集&#xff0c;差集 1.2 常用命令 命令 介绍 时间复杂度 sadd …

一些计算机零碎知识随写(25年2月)

今天复习 MySQL 的时候&#xff0c;我突然冒出一个想法&#xff1a;能不能远程连接 MySQL 呢&#xff1f;虽说心里清楚理论上可行&#xff0c;但一直没实际操作过。 于是&#xff0c;起床后我立马打开服务器&#xff0c;准备启动 MySQL。结果&#xff0c;这一启动就发现问题了&…

ESP32-c3实现获取土壤湿度(ADC模拟量)

1硬件实物图 2引脚定义 3使用说明 4实例代码 // 定义土壤湿度传感器连接的模拟输入引脚 const int soilMoisturePin 2; // 假设连接到GPIO2void setup() {// 初始化串口通信Serial.begin(115200); }void loop() {// 读取土壤湿度传感器的模拟值int sensorValue analogRead…

Java 大视界 -- Java 大数据在量子通信安全中的应用探索(69)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

86.(2)攻防世界 WEB PHP2

之前做过&#xff0c;回顾一遍&#xff0c;详解见下面这篇博客 29.攻防世界PHP2-CSDN博客 既然是代码审计题目&#xff0c;打开后又不显示代码&#xff0c;肯定在文件里 <?php // 首先检查通过 GET 请求传递的名为 "id" 的参数值是否严格等于字符串 "admi…

从理论到实践:Linux 进程替换与 exec 系列函数

个人主页&#xff1a;chian-ocean 文章专栏-Linux 前言&#xff1a; 在Linux中&#xff0c;进程替换&#xff08;Process Substitution&#xff09;是一个非常强大的特性&#xff0c;它允许将一个进程的输出直接当作一个文件来处理。这种技术通常用于Shell脚本和命令行操作中…

【数据结构】初识链表

顺序表的优缺点 缺点&#xff1a; 中间/头部的插入删除&#xff0c;时间复杂度效率较低&#xff0c;为O(N) 空间不够的时候需要扩容。 如果是异地扩容&#xff0c;增容需要申请新空间&#xff0c;拷贝数据&#xff0c;释放旧空间&#xff0c;会有不小的消耗。 扩容可能会存在…

增删改查(CRUD)操作

文章目录 MySQL系列&#xff1a;1.CRUD简介2.Create(创建)2.1单行数据全列插入2.2 单行数据指定插入2.3 多⾏数据指定列插⼊ 3.Retrieve(读取)3.1 Select查询3.1.1 全列查询3.1.2 指定列查询3.1.3 查询字段为表达式&#xff08;都是临时表不会对原有表数据产生影响&#xff09;…

使用Pygame制作“贪吃蛇”游戏

贪吃蛇 是一款经典的休闲小游戏&#xff1a;玩家通过操控一条会不断变长的“蛇”在屏幕中移动&#xff0c;去吃随机出现的食物&#xff0c;同时要避免撞到墙壁或自己身体的其他部分。由于其逻辑相对简单&#xff0c;但可玩性和扩展性都不错&#xff0c;非常适合作为新手练习游戏…