人脸68关键点与K210疲劳检测
目录
人脸68关键点检测
检测闭眼睁眼
双眼关键点检测
计算眼睛的闭合程度:
原理:
设置阈值进行判断
实时监测和更新
拓展:通过判断上下眼皮重合程度去判断是否闭眼
检测嘴巴是否闭合
提取嘴唇上下轮廓的关键点
计算嘴唇上下轮廓关键点之间的距离
计算嘴角到上嘴唇中心的距离
计算嘴角到下嘴唇中心的距离
将两个距离相加作为嘴唇的闭合程度指标
判断嘴巴是否闭合
K210疲劳检测
前两天在做项目的时候,想通过偷懒的方式去试试,不用目标检测去检测疲劳,而是通过人脸检测的68关键点去通过检测睁眼闭眼和张嘴闭嘴去检测闭眼和打瞌睡。那让我们来试试吧。
人脸68关键点检测
人脸68关键点检测是一种计算机视觉技术,旨在识别和定位人脸图像中的关键点。这些关键点通常包括眼睛、鼻子、嘴巴等面部特征的位置。通过检测这些关键点,可以实现人脸识别、表情识别、姿势估计等
主要的步骤:
- 检测人脸:首先需要使用人脸检测算法确定图像中人脸的位置。
- 提取关键点:在检测到的人脸区域内,使用特定的算法来识别和标记关键点的位置。
- 分类关键点:将检测到的关键点分为不同的类别,如眼睛、鼻子、嘴巴等。
检测闭眼睁眼
双眼关键点检测
在68个关键点中,一般左眼和右眼的位置会分别由多个关键点表示。这些关键点的坐标通常以 (x, y) 形式给出,其中 x 表示水平方向的位置,y 表示垂直方向的位置。
import cv2
# 加载人脸关键点检测器
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
# 读取图像
img = cv2.imread('face_image.jpg')
# 转换为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 检测人脸
faces = detector(gray)
for face in faces:# 获取关键点landmarks = predictor(gray, face)for n in range(37, 48): # 提取左眼和右眼的关键点x = landmarks.part(n).xy = landmarks.part(n).ycv2.circle(img, (x, y), 2, (0, 255, 0), -1) # 在关键点处画圆
计算眼睛的闭合程度:
原理:
通过计算眼睛关键点的纵向位置(Y 坐标)的差值,并加权求和来反映眼睛的状态。
对于每只眼睛,首先计算关键点的纵向位置(Y 坐标)的差值。可以选择一些具有代表性的关键点来进行计算,比如眼睛的上下眼睑或者眼角等位置点。 对这些差值进行加权求和,可以根据不同的应用场景进行加权,比如可以将靠近眼睛中心的关键点的差值赋予更高的权重,因为这些部位更能反映眼睛的状态。
眼睛闭合程度计算公式:
- 首先,选择上眼睑和下眼睑的关键点,分别计算它们的平均纵向位置(Y 坐标)。
- 然后,通过上眼睑平均位置减去下眼睑平均位置,得到一个值表示眼睛的闭合程度。这个值越小,表示眼睛越闭合\
[ \text{闭合程度} = \text{上眼睑平均位置} - \text{下眼睑平均位置} ]
其中,上眼睑平均位置和下眼睑平均位置分别表示对应关键点的纵向位置的平均值。
# 计算眼睛的闭合程度
def eye_closure_ratio(eye_landmarks):# 假设我们选取了上眼睑关键点的索引为[1, 2, 3],下眼睑关键点的索引为[4, 5, 6]upper_lid_points = eye_landmarks[1:4]lower_lid_points = eye_landmarks[4:7]# 计算上下眼睑的平均纵向位置upper_lid_y_mean = sum([point[1] for point in upper_lid_points]) / len(upper_lid_points)lower_lid_y_mean = sum([point[1] for point in lower_lid_points]) / len(lower_lid_points)# 计算纵向位置的差值,这里可以根据具体情况加权求和diff = upper_lid_y_mean - lower_lid_y_meanreturn diff
设置阈值进行判断
根据实际情况,可以设置一个阈值来判断眼睛是否闭合。当加权求和的结果小于阈值时,可以认为眼睛是闭合的;反之则是睁开的。
# 判断眼睛是否闭合
def is_eye_closed(eye_landmarks, threshold):closure_ratio = eye_closure_ratio(eye_landmarks)if closure_ratio < threshold:return True # 眼睛闭合else:return False # 眼睛睁开
实时监测和更新
在实时监测过程中,不断更新眼睛关键点的位置信息,并重新计算眼睛的闭合程度,以实现对眼睛状态的准确监测。
# 循环实时监测
while True:ret, frame = cap.read() # 从摄像头读取画面gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)faces = detector(gray)for face in faces:landmarks = predictor(gray, face)left_eye_landmarks = [(landmarks.part(n).x, landmarks.part(n).y) for n in range(36, 42)] # 左眼关键点right_eye_landmarks = [(landmarks.part(n).x, landmarks.part(n).y) for n in range(42, 48)] # 右眼关键点# 计算左眼闭合程度并判断left_eye_closed = is_eye_closed(left_eye_landmarks, 5) # 假设阈值设为5# 计算右眼闭合程度并判断right_eye_closed = is_eye_closed(right_eye_landmarks, 5) # 假设阈值设为5# 综合判断眼睛状态if left_eye_closed and right_eye_closed:print("Both eyes closed")elif left_eye_closed:print("Left eye closed")elif right_eye_closed:print("Right eye closed")else:print("Eyes open")
拓展:通过判断上下眼皮重合程度去判断是否闭眼
通过判断上下眼皮的重合程度来间接判断眼睛是否闭合。当眼睛闭合时,上下眼皮会有一定程度的重合,而睁开时则不会存在明显的重合。
具体实现方法可以是计算上下眼睑之间的垂直距离,并将其与总眼睛高度的比值作为闭合程度的度量指标。当这个比值超过一定阈值时,可以判断为闭眼状态
# 计算上下眼皮重合程度
def eyelid_overlap_ratio(eye_landmarks):# 假设我们选取了上眼睑关键点的索引为[1, 2, 3],下眼睑关键点的索引为[4, 5, 6]upper_lid_points = eye_landmarks[1:4]lower_lid_points = eye_landmarks[4:7]# 计算上下眼睑之间的垂直距离vertical_distance = lower_lid_points[0][1] - upper_lid_points[-1][1]# 计算垂直距离与总眼睛高度的比值eye_height = max(eye_landmarks, key=lambda x: x[1])[1] - min(eye_landmarks, key=lambda x: x[1])[1]overlap_ratio = vertical_distance / eye_heightreturn overlap_ratio
检测嘴巴是否闭合
提取嘴唇上下轮廓的关键点
根据人脸关键点的位置信息,提取出嘴唇上下轮廓的关键点。一般而言,嘴唇上下轮廓的关键点包括嘴角、上嘴唇中心、下嘴唇中心等关键点。
计算嘴唇上下轮廓关键点之间的距离
选择合适的距离度量方法(如欧氏距离)计算嘴唇上下轮廓关键点之间的距离。具体来说,可以计算嘴角到上嘴唇中心和嘴角到下嘴唇中心的距离,并将这两个距离相加作为嘴唇的闭合程度指标。
计算嘴角到上嘴唇中心的距离
使用欧氏距离公式计算嘴角到上嘴唇中心的距离: [ distance_top = \sqrt{(x_{top} - x_{corner})^2 + (y_{top} - y_{corner})^2} ] 其中 (x_{top}) 和 (y_{top}) 分别是上嘴唇中心的 x、y 坐标,(x_{corner}) 和 (y_{corner}) 分别是嘴角的 x、y 坐标。
计算嘴角到下嘴唇中心的距离
同样使用欧氏距离公式计算嘴角到下嘴唇中心的距离: [ distance_bottom = \sqrt{(x_{bottom} - x_{corner})^2 + (y_{bottom} - y_{corner})^2} ] 其中 (x_{bottom}) 和 (y_{bottom}) 分别是下嘴唇中心的 x、y 坐标。
将两个距离相加作为嘴唇的闭合程度指标
将嘴角到上嘴唇中心的距离 (distance_top) 和嘴角到下嘴唇中心的距离 (distance_bottom) 相加,得到嘴唇的闭合程度指标: [ distance_total = distance_top + distance_bottom ]
判断嘴巴是否闭合
设定一个阈值,根据嘴唇上下轮廓关键点之间的距禀与该阈值的比较结果来判断嘴巴是否闭合。通常情况下,当嘴唇闭合时,嘴唇上下轮廓的关键点之间的距离会比较小;而当嘴巴张开时,这个距离会增大。
import math
# 计算欧氏距离
def euclidean_distance(point1, point2):return math.sqrt((point2[0] - point1[0])**2 + (point2[1] - point1[1])**2)
# 提取嘴唇上下轮廓的关键点索引(假设为索引0到11)
mouth_landmarks = face_landmarks[0:12] # 假设face_landmarks包含了所有68个关键点的坐标
# 计算嘴唇上下轮廓关键点之间的距离
lip_distances = []
for i in range(len(mouth_landmarks)//2):distance = euclidean_distance(mouth_landmarks[i], mouth_landmarks[i + len(mouth_landmarks)//2])lip_distances.append(distance)
# 计算平均距离
avg_distance = sum(lip_distances) / len(lip_distances)
# 设定阈值
threshold = 5.0
# 判断嘴巴是否闭合
if avg_distance < threshold:print("嘴巴闭合")
else:print("嘴巴张开")
K210疲劳检测
项目的来源:对K210人脸检测68关键点的一种拓展
如何通过人脸检测68关键点去检测疲劳情况
代码是根据K210的例程改的,也只是使用上下眼皮的距离和上下嘴唇的距离来检测疲劳状态
import sensor, image, time, lcd
from maix import KPU
import gclcd.init()
sensor.reset()sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_vflip(True) # 摄像头后置sensor.skip_frames(time=500)
clock = time.clock()od_img = image.Image(size=(320, 256), copy_to_fb=False)# 构建KPU对象
# 需要导入2个模型,分别是人脸检测模型和68关键点检测模型
anchor = (0.893, 1.463, 0.245, 0.389, 1.55, 2.58, 0.375, 0.594, 3.099, 5.038, 0.057, 0.090, 0.567, 0.904, 0.101, 0.160, 0.159, 0.255)
kpu_face_detect = KPU()
print("Loading face detection model")
kpu_face_detect.load_kmodel("/sd/face_detect.kmodel")
kpu_face_detect.init_yolo2(anchor, anchor_num=9, img_w=320, img_h=240, net_w=320, net_h=256, layer_w=10, layer_h=8, threshold=0.7, nms_value=0.2, classes=1)kpu_lm68 = KPU()
print("Loading landmark 68 model")
kpu_lm68.load_kmodel("/sd/landmark68.kmodel")RATIO = 0.08while True:gc.collect()clock.tick() # Update the FPS clock.img = sensor.snapshot()od_img.draw_image(img, 0, 0)od_img.pix_to_ai()kpu_face_detect.run_with_output(od_img)detections = kpu_face_detect.regionlayer_yolo2()fps = clock.fps()if len(detections) > 0:for det in detections:x1_t = max(int(det[0] - RATIO * det[2]), 0)x2_t = min(int(det[0] + det[2] + RATIO * det[2]), 319)y1_t = max(int(det[1] - RATIO * det[3]), 0)y2_t = min(int(det[1] + det[3] + RATIO * det[3]), 255)cut_img_w = x2_t - x1_t + 1cut_img_h = y2_t - y1_t + 1face_cut = img.cut(x1_t, y1_t, cut_img_w, cut_img_h)face_cut_128 = face_cut.resize(128, 128)face_cut_128.pix_to_ai()out = kpu_lm68.run_with_output(face_cut_128, getlist=True)if out is not None:left_eye_height = out[41][1] - out[37][1]right_eye_height = out[47][1] - out[43][1]eye_height_avg = (left_eye_height + right_eye_height) / 2mouth_height = out[66][1] - out[62][1]if eye_height_avg < 10 and mouth_height > 15:print("Tired: Eyes closed, Mouth open")elif eye_height_avg < 10:print("Tired: Eyes closed")elif mouth_height > 15:print("Tired: Mouth open")del face_cut_128del face_cutimg.draw_string(0, 0, "%2.1f fps" % fps, color=(0, 60, 255), scale=2.0)lcd.display(img)gc.collect()kpu_face_detect.deinit()
kpu_lm68.deinit()
相关文章:
人脸68关键点与K210疲劳检测
目录 人脸68关键点检测 检测闭眼睁眼 双眼关键点检测 计算眼睛的闭合程度: 原理: 设置阈值进行判断 实时监测和更新 拓展:通过判断上下眼皮重合程度去判断是否闭眼 检测嘴巴是否闭合 提取嘴唇上下轮廓的关键点 计算嘴唇上下轮廓关键点之间的距…...
【跟着GPT4学JAVA】异常篇
JAVA异常中的知识点 问: 介绍下JAVA中的异常有哪些知识点吧 答: Java中的异常处理是一个重要的知识点,主要包括以下内容: 异常体系:Java的异常类是Throwable类派生出来的,Throwable下有两个重要的子类:Err…...
Ubuntu上安装d4rl数据集
Ubuntu上安装d4rl数据集 D4RL的官方 github: https://github.com/Farama-Foundation/D4RL 一、安装Mujoco 1.1 官网下载mujoco210文件 如果装过可以跳过这步 链接:https://github.com/deepmind/mujoco/releases/tag/2.1.0 下载第一个文件即可。我这里是在windo…...
C++之STL整理(4)之set 用法(创建、赋值、增删查改)详解
C之STL整理(4)之set 用法(创建、赋值、增删查改)详解 注:整理一些突然学到的C知识,随时mark一下 例如:忘记的关键字用法,新关键字,新数据结构 C 的map用法整理 C之STL整理…...
IDEA MyBatisCodeHelper Pro最新版(持续更新)
目录 0. 你想要的0.1 包下载0.2 使用jh 1. 功能介绍2. 下载安装2.1 在idea中插件市场安装2.2 在jetbrains插件市场下载安装 3. 简单使用3.1 创建一个SpringBoot项目3.2 配置数据库3.3 一键生成实体类、mapper 0. 你想要的 0.1 包下载 测试系统:Windows(…...
sheng的学习笔记-AI-YOLO算法,目标检测
AI目录:sheng的学习笔记-AI目录-CSDN博客 目录 目标定位(Object localization) 定义 原理图 具体做法: 输出向量 图片中没有检测对象的样例 损失函数 编辑 特征点检测(Landmark detection) 定义&a…...
C# wpf 嵌入wpf控件
WPF Hwnd窗口互操作系列 第一章 嵌入Hwnd窗口 第二章 嵌入WinForm控件 第三章 嵌入WPF控件(本章) 第四章 底部嵌入HwndHost 文章目录 WPF Hwnd窗口互操作系列前言一、如何实现?1、继承HwndHost2、添加Content属性3、创建wpf窗口并设置Conten…...
云原生(六)、CICD - Jenkins快速入门
Jenkuns快速入门 一、CICD概述 CICD是持续集成(Continuous Integration)和持续部署(Continuous Deployment)的缩写。它是软件开发中的一种流程和方法论,旨在通过自动化的方式频繁地将代码集成到共享存储库中…...
基于java+springboot+vue实现的付费自习室管理系统(文末源码+Lw+ppt)23-400
摘 要 付费自习室管理系统采用B/S架构,数据库是MySQL。网站的搭建与开发采用了先进的java进行编写,使用了springboot框架。该系统从两个对象:由管理员和用户来对系统进行设计构建。主要功能包括:个人信息修改,对用户…...
【JavaParser笔记02】JavaParser解析Java源代码中的类字段信息(javadoc注释、字段名称)
这篇文章,主要介绍如何使用JavaParser解析Java源代码中的类字段信息(javadoc注释、字段名称)。 目录 一、JavaParser依赖库 1.1、引入依赖 1.2、获取类成员信息 (1)案例代码 <...
Spring IoCDI(3)
DI详解 接下来学习一下依赖注入DI的细节. 依赖注入是一个过程, 是指IoC容器在创建Bean时, 去提供运行时所依赖的资源, 而资源指的就是对象. 在之前的案例中, 使用了Autowired这个注解, 完成了依赖注入这个操作. 简单来说, 就是把对象取出来放到某个类的属性中. 在一些文章中…...
保研线性代数机器学习基础复习1
1.什么是代数(algebra)? 为了形式化一个概念,构建出有关这个概念的符号以及操作符号的公式。 2.什么是线性代数(linear algebra)? 一项关于向量以及操作向量的公式的研究。 3.举一些向量的例子&#x…...
js绑定事件的方法
在JavaScript中,绑定事件的方法主要有以下几种: HTML属性方式:直接在HTML元素中使用事件属性来绑定事件。 html<button onclick"alert(Hello World!)">Click Me</button> DOM属性方式:通过JavaScript代码…...
是德科技keysight N9000B 信号分析仪
181/2461/8938产品概述: 工程的内涵就是将各种创意有机地联系起来,并解决遇到的问题。 CXA 信号分析仪具有出色的实际性能,它是一款出类拔萃、经济高效的基本信号表征工具。 它的功能十分强大,为一般用途和教育行业的用户执行测试…...
软考 - 系统架构设计师 - 架构风格
软件架构风格是指描述特定软件系统组织方式的惯用模式。组织方式描述了系统的组成构件,以及这些构件的组织方式,惯用模式指众多系统所共有的结构和语义。 目录 架构风格 数据流风格 批处理架构风格 管道 - 过滤器架构风格 调用 / 返回风格 主程序…...
CleanMyMac X2024专业免费的国产Mac笔记本清理软件
非常高兴有机会向大家介绍CleanMyMac X 2024这款专业的Mac清理软件。它以其强大的清理能力、系统优化效果、出色的用户体验以及高度的安全性,在Mac清理软件市场中独树一帜。 CleanMyMac X2024全新版下载如下: https://wm.makeding.com/iclk/?zoneid49983 一、主要…...
ES6 模块化操作
ES6模块化主要有两个操作:import 和 export 如果在html文件的script中引用模块的话,要设置<script type"module"> 一种导入导出方法: a.js//分别暴露 export let num 1 export function compute(a, b){return a b }//统…...
统计XML文件内标签的种类和其数量及将xml格式转换为yolov5所需的txt格式
1、统计XML文件内标签的种类和其数量 对于自己标注的数据集,需在标注完成后需要对标注好的XML文件校验,下面是代码,只需将SrcDir换成需要统计的xml的文件夹即可。 import os from tqdm import tqdm import xml.dom.minidomdef ReadXml(File…...
《操作系统导论》第14章读书笔记:插叙:内存操作API
《操作系统导论》第14章读书笔记:插叙:内存操作API —— 杭州 2024-03-30 夜 文章目录 《操作系统导论》第14章读书笔记:插叙:内存操作API1.内存类型1.1.栈内存:它的申请和释放操作是编译器来隐式管理的,所…...
HAProxy + Vitess负载均衡
一、环境搭建 Vitess环境搭建: 具体vitess安装不再赘述,主要是需要启动3个vtgate(官方推荐vtgate和vtablet数量一致) 操作: 在vitess/examples/common/scripts目录中,修改vtgate-up.sh文件,…...
2024年京东云主机租用价格_京东云服务器优惠价格表
2024年京东云服务器优惠价格表,轻量云主机优惠价格5.8元1个月、轻量云主机2C2G3M价格50元一年、196元三年,2C4G5M轻量云主机165元一年,4核8G5M云主机880元一年,游戏联机服务器4C16G配置26元1个月、4C32G价格65元1个月、8核32G费用…...
qt-C++笔记之QSpinBox控件
qt-C笔记之QSpinBox控件 code review! 文章目录 qt-C笔记之QSpinBox控件1.运行2.main.cpp3.main.pro4.《Qt6 C开发指南》:4.4 QSpinBox 和QDoubleSpinBox 1.运行 2.main.cpp #include <QApplication> #include <QSpinBox> #include <QPushButton&g…...
Linux(CentOS)/Windows-C++ 云备份项目(服务器网络通信模块,业务处理模块设计,断点续传设计)
此模块将网络通信模块和业务处理模块进行了合并 网络通信通过httplib库搭建完成业务处理: 文件上传请求:备份客户端上传的文件,响应上传成功客户端列表请求:客户端请求备份文件的请求页面,服务器响应文件下载请求&…...
【QQ版】QQ群短剧机器人源码 全网短剧机器人插件
内容目录 一、详细介绍二、效果展示2.效果图展示 三、学习资料下载 一、详细介绍 QQ版本可以兼容两个框架(HTQQ,MYQQ这两个的vip版也可以使用) 支持私聊与群聊,命令是 搜剧影视关键词 如果无法搜索到影视资源,请使用下方命令&…...
矩阵间关系的建立
参考文献 2-D Compressive Sensing-Based Visually Secure Multilevel Image Encryption Scheme 加密整体流程如下: 我们关注左上角这一部分: 如何在两个图像之间构建关系,当然是借助第3个矩阵。 A. Establish Relationships Between Different Images 简单说明如下: …...
【C++】C到C++的入门知识
目录 1、C关键字 2、命名空间 2.1 命名空间的定义 2.2 命名空间的使用 2.2.1 加命名空间名称及作用域限定符 2.2.2 使用using将命名空间中某个成员引入 2.2.3 使用using namespace 命名空间名称引入 3、C输入&输出 4、缺省参数 4.1 缺省参数的概念 4.2 缺省参数的…...
【c++】简单的日期计算器
🔥个人主页:Quitecoder 🔥专栏:c笔记仓 朋友们大家好啊,在我们学习了默认成员函数后,我们本节内容来完成知识的实践,来实现一个简易的日期计算器 目录 头文件声明函数函数的实现1.全缺省默认构…...
基于easyx库的C/C++游戏编程实例-飞机大战
飞机大战游戏设计 首先创建飞机/子弹结构: struct Plane {int x;int y;bool live;int width;int height;int type;int hp; }player,bul[BUL_NUM],enemy[ENE_NUM];你需要加载图片: void ImageLoad() {//背景loadimage(&bg[0], "./image/飞机大…...
stitcher类实现多图自动拼接
效果展示 第一组: 第二组: 第三组: 第四组: 运行代码 import os import sys import cv2 import numpy as npdef Stitch(imgs,savePath): stitcher cv2.Stitcher.create(cv2.Stitcher_PANORAMA)(result, pano) stitcher.st…...
Ubuntu下udp通信
一、知识准备阶段 socket是什么?套接字是什么? https://blog.csdn.net/m0_37925202/article/details/80286946 Socket程序从Windows移植到Linux下的一些注意事项 sockaddr和sockaddr_in详解 bzero和memset函数 函数原型:void bzero&…...
云南定制化网站建设/网络优化工程师证书
1.删除数组中的多个元素,也就是去掉数组中不符合条件的选项 分析:用for或者forEach遍历数组的话在方法体内部 splice后数组长度发生了变化,最后得不到正确的结果。 filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。…...
wordpress facebook login/谷歌外链工具
两个节点,都可以更新数据,并且互为主从,容易产生的问题:数据不一致;因此慎用,考虑要点:自动增长id,配置一个节点使用奇数id 主主复制的配置步骤: (1) 各节点使用一个惟一…...
广州网络帮助建站/seo搜索引擎优化工程师招聘
http://www.trirand.com/jqgridwiki/doku.php?idwiki:jqgriddocs...
青浦营销型网站建设/东莞网站建设工作
PMP认证在国内的背景 随着国家经济建设从基础设施转向高端产业以及市场项目规模扩大,投资额度上升,在项目中对项目管理者的要求也越来越高,国内科技的发展,企业扩展项目管理人才时的要求也会随之提高,这时候很需要竞争…...
前端开发线上培训/网站seo在线优化
2019独角兽企业重金招聘Python工程师标准>>> 1、连接MYSQL数据库代码 <?php $connecmysql_connect("localhost","root","root") or die("不能连接数据库服务器: ".mysql_error()); mysql_select_db("l…...
中堂仿做网站/平面设计培训
1、加载父类,加载父类的静态属性和静态代码块 2、加载子类,加载子类的静态属性和静态代码块 3、初始化父类中的非静态属性并赋初值,执行父类非静态代码块,执行父类构造。 4、初始化子类中的非静态属性并赋初值,执行代码…...