OpenVINO™ 基于人脸landmark检测实现眼睛疲劳/睡意检测

OpenCV学堂 2021-06-22 17:00

点击上方↑↑↑OpenCV学堂”关注我

来源:公众号 因特尔网联网 授权

人脸landmark介绍


人脸landmark在人脸对齐、人脸重建、身份鉴别、人脸编辑与人脸AR等方面都有重要作用,但是什么是人脸landmark,首先看一张图:


图1(来自OpenVINO 安装包的模型库组件)


上图在检测人脸白色矩形框的基础上,通过OpenVINO自带的人脸landmark模型实现了对人脸区域关键部位35个点位的标记,它就是典型的人脸landmark提取。在深度学习没有那么流行之前,传统的人脸landmark提取有两个让人吐槽的痛点:


1. 人脸的landmark中128个点位与68个点位提取是高耗时操作;

2. 人脸landmark提取算法的抗干扰能力与普适性很差。


自从深度学习方式在计算机视觉领域大显身手之后,人脸landmark算法通过卷积神经网络实现了稳定性与精准度双提升,现在已经是很多应用标配中间步骤。根据提取的人脸landmark点数的不同,最常见分为:


5点提取最简单人脸对齐

35点提取常见人脸对齐、人脸比对、人脸AR

68点提取场景适用人脸对齐、人脸比对、人脸AR等

128点提取场景适用人脸对齐、人脸比对、人脸AR等

192及更多点提取,场景适用人脸对齐、人脸比对、人脸AR、人脸3D重建


更多点位的人脸landmark提取这里就不再列出了。


300W是人脸landmark提取最常用的一个基准数据集,支持68个点位与51个点位的人脸landmark数据标注与训练。其中68个点位的landmark人脸标注位置信息如下:


图-2来自300W数据集论文引用


人脸landmark实现疲劳检测基本原理


我们首先使用人脸检测模型,检测得到人脸ROI区域,然后使用一个人脸landmark预测模型得到人脸区域的68个点位,其中对我们最有用的是分别来自图-2中的左右眼睛周围的38、39、41、42与44、45、47、48八个点位。人的疲劳最明显的特征之一就是会闭上眼睛,要打瞌睡,我们通过上述八个点来求解,它们的横纵比就可以度量眼睛的闭合程度,辅助一个阈值就可以很好过滤,达到根据眼睛的闭合程度实现睡意/疲劳检测的目的。手绘了一个示意图如下:


图-3(手绘)


网络模型


OpenVINO中有两个自带的landmark预测模型,分别支持5点与35点定位,不符合我们期望的68个点定位的landmark模型预测。所以这里使用Github上一个开源的基于Pytorch版本实现的68个点位预测模型,它支持OpenVINO 加速,工程地址如下:

https://github.com/github-luffy/PFLD_68points_Pytorch


我git clone了上述的工程地址,然后通过下面的脚本把其中mobilenetv2的PFLD的预训练模型转换为OpenVINO可以正确读取与解析的ONNX格式,转换脚本如下:

model = torch.load("D:/projects/PFLD_68points_Pytorch-master/pretrained_model/mobileNetV2_1.0.pth")

model.cpu()

model.eval()


dummy_input1 = torch.randn(1, 3, 112, 112, dtype=torch.float)

torch.onnx.export(model, (dummy_input1), "mobilenetv2_pfld.onnx", verbose=True)


可视化的模型输入与输出结构如下:


图-4


代码实现与运行演示


在代码实现与运行演示环节,参考之前的对象检测部分,我们可以实现人脸检测,然后从人脸检测输出中得到人脸的ROI区域,这部分的代码实现在前面的文章中已经详细分享过,这里就不再赘述,我们把代码实现主要放在如何提取landmark的68个点位预测与眼睛疲劳检测部分,这部分的代码实现主要分为以下几个部分:


Step1:加载人脸landmark网络,设置输入与输出:

std::string onnx = "D:/mobilenetv2_pfld.onnx";InferenceEngine::CNNNetwork network = ie.ReadNetwork(onnx);InferenceEngine::InputsDataMap inputs = network.getInputsInfo();InferenceEngine::OutputsDataMap outputs = network.getOutputsInfo();

for (auto item : inputs) { land_input_name = item.first; auto input_data = item.second; input_data->setPrecision(Precision::FP32); input_data->setLayout(Layout::NCHW);}

for (auto item : outputs) { land_output_name = item.first; auto output_data = item.second; output_data->setPrecision(Precision::FP32);}

auto executable_network = ie.LoadNetwork(network, "CPU");landmark_request = executable_network.CreateInferRequest();

Step2:提取人脸ROI区域,并实现输入预处理!

这里有个很trick的地方就是图像的预处理,因为引用的模型来自公开训练的生成,模型在训练时候预处理方式是在推理必须要保持一致处理的,从模型示例代码中我发现它的预处理方式主要包括转换为0~1之间的浮点数数值,这部分的代码实现如下:

cv::Rect box;int w = static_cast(x2 - x1);int h = static_cast(y2 - y1);

int size = static_cast(std::max(w, h)*1.1f);int cx = x1 + w / 2;int cy = y1 + h / 2;x1 = cx - size / 2;x2 = x1 + size;y1 = cy - size / 2;y2 = y1 + size;

x1 = std::max(0.0f, x1);y1 = std::max(0.0f, y1);

x2 = std::min(static_cast(im_w), x2);y2 = std::min(static_cast(im_h), y2);

box.x = static_cast(x1);box.y = static_cast(y1);box.width = static_cast(x2 - x1);box.height = static_cast(y2 - y1);cv::Mat face_roi = curr_frame(box);cv::Mat rgb_roi;cv::cvtColor(face_roi, rgb_roi, cv::COLOR_BGR2RGB);face_roi.convertTo(face_roi, CV_32F);face_roi = face_roi / 256.0;



设置图像数据并推理

auto face_input_blob = landmark_request.GetBlob(land_input_name);matU8ToBlob2(face_roi, face_input_blob);landmark_request.Infer();



这里有个需要注意的地方,输入的输入本身是浮点数据,OpenVINO 自带Sample

代码中的函数只支持字节图像数据输入,所以需要修改一下该方法来支持浮点数图像数据输入,修改以后我重命名位matU8ToBlob2。


Step3:解析预测68个定位点并计算眼睛四个点的横纵比

这里我只计算一只眼睛每帧的数据,根据数据统计发现,当比率小于0.35左右时,有眼睛闭合的趋势,可以认为是眼睛疲劳的生物特征表现。这部分的代码实现如下:

auto land_output = landmark_request.GetBlob(land_output_name);const float* blob_out = static_cast<PrecisionTrait<Precision::FP32>::value_type*>(land_output->buffer());const SizeVectorland_dims = land_output->getTensorDesc().getDims();const int b = land_dims[0];const int cc = land_dims[1];int index = 0;std::vector<cv::Point2f>eye_pts;for (int i = 0; i< cc; i += 2) {       float x = blob_out[i] * box.width + box.x;       float y = blob_out[i + 1] * box.height + box.y;       cv::circle(curr_frame, cv::Point(x, y), 1, cv::Scalar(255, 0, 0), 1, 8, 0);       if (index == 37 || index == 38 || index == 40 || index == 41) {              eye_pts.push_back(cv::Point2f(x, y));              cv::circle(curr_frame, cv::Point(x, y), 1, cv::Scalar(0, 0, 255), 1, 8, 0);       }       if (index == 43 || index == 44 || index == 46 || index == 47) {              eye_pts.push_back(cv::Point2f(x, y));              cv::circle(curr_frame, cv::Point(x, y), 1, cv::Scalar(0, 0, 255), 1, 8, 0);       }       index++;}float e1_x = (eye_pts[0].x + eye_pts[1].x) / 2;float e1_y = (eye_pts[0].y + eye_pts[1].y) / 2;float e2_x = (eye_pts[2].x + eye_pts[3].x) / 2;float e2_y = (eye_pts[2].y + eye_pts[3].y) / 2;floatdist_w = std::sqrt(std::pow(e1_x - e2_x, 2) + std::pow(e1_y - e2_y, 2));e1_x = (eye_pts[0].x + eye_pts[3].x) / 2;e1_y = (eye_pts[0].y + eye_pts[3].y) / 2;e2_x = (eye_pts[2].x + eye_pts[1].x) / 2;e2_y = (eye_pts[2].y + eye_pts[1].y) / 2;float dist_h = std::sqrt(std::pow(e1_x - e2_x, 2) + std::pow(e1_y - e2_y, 2));float rate = dist_w / dist_h;std::cout<< rate << std::endl;if (rate < 0.35) {  cv::putText(curr_frame, "sleepy", cv::Point(box.x, box.y), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(0, 0, 255), 2, 8);  // cv::imwrite("D:/sleepy.png", curr_frame);}else {  cv::putText(curr_frame, "Norm", cv::Point(box.x, box.y), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(0, 0, 255), 2, 8);}

针对一段视频流的运行检测结果如下:


图-5(左侧位正常情况,右侧为疲劳表现)



本文参考的网络素材链接:

https://ibug.doc.ic.ac.uk/media/uploads/documents/sagonas_iccv_2013_300_w.pdf

https://github.com/github-luffy/PFLD_68points_Pytorch

扫码查看OpenCV/Pytorch/OpenVINO视频教程


 推荐阅读 

OpenCV4 C++学习 必备基础语法知识二

Tensorflow + OpenCV4 安全帽检测模型训练与推理

极简教程 | OpenCV4 C++学习 必备基础语法知识

OpenCV Python + Tesseract-OCR轻松实现中文识别

YOLOv5在最新OpenVINO 2021R02版本的部署与代码演示详解

LesionNet 医疗图像分割网络模型实现皮肤病灶分割

YOLOv5实现自定义对象训练与OpenVINO部署全解析

推理演示 | 八步助你搞定tensorRT C++ SDK调用!

基于OpenCV+ZXing手工打造,FPS300+的二维码识别库

深度解读 OpenCV中的VideoCapture视频读取

极简教程 | OpenCV4 C++学习 必备基础语法知识

OpenCV学堂 | 2020年 原创技术文章汇总

经验 | OpenCV图像旋转的原理与技巧

汇总 | OpenCV DNN模块中支持的分类网络

汇总 | OpenCV DNN支持的对象检测模型

汇总 | OpenCV4中的非典型深度学习模型


OpenCV学堂 专注计算机视觉开发技术分享,技术框架使用,包括OpenCV,Tensorflow,Pytorch教程与案例,相关算法详解,最新CV方向论文,硬核代码干货与代码案例详解!作者在CV工程化方面深度耕耘15年,感谢您的关注!
评论
  • 故障现象一辆2017款东风风神AX7车,搭载DFMA14T发动机,累计行驶里程约为13.7万km。该车冷起动后怠速运转正常,热机后怠速运转不稳,组合仪表上的发动机转速表指针上下轻微抖动。 故障诊断 用故障检测仪检测,发动机控制单元中无故障代码存储;读取发动机数据流,发现进气歧管绝对压力波动明显,有时能达到69 kPa,明显偏高,推断可能的原因有:进气系统漏气;进气歧管绝对压力传感器信号失真;发动机机械故障。首先从节气门处打烟雾,没有发现进气管周围有漏气的地方;接着拔下进气管上的两个真空
    虹科Pico汽车示波器 2025-01-08 16:51 92浏览
  • 在智能网联汽车中,各种通信技术如2G/3G/4G/5G、GNSS(全球导航卫星系统)、V2X(车联网通信)等在行业内被广泛使用。这些技术让汽车能够实现紧急呼叫、在线娱乐、导航等多种功能。EMC测试就是为了确保在复杂电磁环境下,汽车的通信系统仍然可以正常工作,保护驾乘者的安全。参考《QCT-基于LTE-V2X直连通信的车载信息交互系统技术要求及试验方法-1》标准10.5电磁兼容试验方法,下面将会从整车功能层面为大家解读V2X整车电磁兼容试验的过程。测试过程揭秘1. 设备准备为了进行电磁兼容试验,技
    北汇信息 2025-01-09 11:24 22浏览
  • 在过去十年中,自动驾驶和高级驾驶辅助系统(AD/ADAS)软件与硬件的快速发展对多传感器数据采集的设计需求提出了更高的要求。然而,目前仍缺乏能够高质量集成多传感器数据采集的解决方案。康谋ADTF正是应运而生,它提供了一个广受认可和广泛引用的软件框架,包含模块化的标准化应用程序和工具,旨在为ADAS功能的开发提供一站式体验。一、ADTF的关键之处!无论是奥迪、大众、宝马还是梅赛德斯-奔驰:他们都依赖我们不断发展的ADTF来开发智能驾驶辅助解决方案,直至实现自动驾驶的目标。从新功能的最初构思到批量生
    康谋 2025-01-09 10:04 23浏览
  • 1月7日-10日,2025年国际消费电子产品展览会(CES 2025)盛大举行,广和通发布Fibocom AI Stack,赋智千行百业端侧应用。Fibocom AI Stack提供集高性能模组、AI工具链、高性能推理引擎、海量模型、支持与服务一体化的端侧AI解决方案,帮助智能设备快速实现AI能力商用。为适应不同端侧场景的应用,AI Stack具备海量端侧AI模型及行业端侧模型,基于不同等级算力的芯片平台或模组,Fibocom AI Stack可将TensorFlow、PyTorch、ONNX、
    物吾悟小通 2025-01-08 18:17 26浏览
  • 一个真正的质量工程师(QE)必须将一件产品设计的“意图”与系统的可制造性、可服务性以及资源在现实中实现设计和产品的能力结合起来。所以,可以说,这确实是一种工程学科。我们常开玩笑说,质量工程师是工程领域里的「侦探」、「警察」或「律师」,守护神是"墨菲”,信奉的哲学就是「墨菲定律」。(注:墨菲定律是一种启发性原则,常被表述为:任何可能出错的事情最终都会出错。)做质量工程师的,有时会不受欢迎,也会被忽视,甚至可能遭遇主动或被动的阻碍,而一旦出了问题,责任往往就落在质量工程师的头上。虽然质量工程师并不负
    优思学院 2025-01-09 11:48 27浏览
  • 根据环洋市场咨询(Global Info Research)项目团队最新调研,预计2030年全球中空长航时无人机产值达到9009百万美元,2024-2030年期间年复合增长率CAGR为8.0%。 环洋市场咨询机构出版了的【全球中空长航时无人机行业总体规模、主要厂商及IPO上市调研报告,2025-2031】研究全球中空长航时无人机总体规模,包括产量、产值、消费量、主要生产地区、主要生产商及市场份额,同时分析中空长航时无人机市场主要驱动因素、阻碍因素、市场机遇、挑战、新产品发布等。报告从中空长航时
    GIRtina 2025-01-09 10:35 21浏览
  • 本文介绍编译Android13 ROOT权限固件的方法,触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。关闭selinux修改此文件("+"号为修改内容)device/rockchip/common/BoardConfig.mkBOARD_BOOT_HEADER_VERSION ?= 2BOARD_MKBOOTIMG_ARGS :=BOARD_PREBUILT_DTB
    Industio_触觉智能 2025-01-08 00:06 100浏览
  • 村田是目前全球量产硅电容的领先企业,其在2016年收购了法国IPDiA头部硅电容器公司,并于2023年6月宣布投资约100亿日元将硅电容产能提升两倍。以下内容主要来自村田官网信息整理,村田高密度硅电容器采用半导体MOS工艺开发,并使用3D结构来大幅增加电极表面,因此在给定的占位面积内增加了静电容量。村田的硅技术以嵌入非结晶基板的单片结构为基础(单层MIM和多层MIM—MIM是指金属 / 绝缘体/ 金属) 村田硅电容采用先进3D拓扑结构在100um内,使开发的有效静电容量面积相当于80个
    知白 2025-01-07 15:02 150浏览
  • 光伏逆变器是一种高效的能量转换设备,它能够将光伏太阳能板(PV)产生的不稳定的直流电压转换成与市电频率同步的交流电。这种转换后的电能不仅可以回馈至商用输电网络,还能供独立电网系统使用。光伏逆变器在商业光伏储能电站和家庭独立储能系统等应用领域中得到了广泛的应用。光耦合器,以其高速信号传输、出色的共模抑制比以及单向信号传输和光电隔离的特性,在光伏逆变器中扮演着至关重要的角色。它确保了系统的安全隔离、干扰的有效隔离以及通信信号的精准传输。光耦合器的使用不仅提高了系统的稳定性和安全性,而且由于其低功耗的
    晶台光耦 2025-01-09 09:58 21浏览
  • 「他明明跟我同梯进来,为什么就是升得比我快?」许多人都有这样的疑问:明明就战绩也不比隔壁同事差,升迁之路却比别人苦。其实,之间的差异就在于「领导力」。並非必须当管理者才需要「领导力」,而是散发领导力特质的人,才更容易被晓明。许多领导力和特质,都可以通过努力和学习获得,因此就算不是天生的领导者,也能成为一个具备领导魅力的人,进而被老板看见,向你伸出升迁的橘子枝。领导力是什么?领导力是一种能力或特质,甚至可以说是一种「影响力」。好的领导者通常具备影响和鼓励他人的能力,并导引他们朝着共同的目标和愿景前
    优思学院 2025-01-08 14:54 82浏览
  •  在全球能源结构加速向清洁、可再生方向转型的今天,风力发电作为一种绿色能源,已成为各国新能源发展的重要组成部分。然而,风力发电系统在复杂的环境中长时间运行,对系统的安全性、稳定性和抗干扰能力提出了极高要求。光耦(光电耦合器)作为一种电气隔离与信号传输器件,凭借其优秀的隔离保护性能和信号传输能力,已成为风力发电系统中不可或缺的关键组件。 风力发电系统对隔离与控制的需求风力发电系统中,包括发电机、变流器、变压器和控制系统等多个部分,通常工作在高压、大功率的环境中。光耦在这里扮演了
    晶台光耦 2025-01-08 16:03 80浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦