人脸landmark介绍

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

上图在检测人脸白色矩形框的基础上,通过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人脸标注位置信息如下:

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

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

网络模型

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)

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

代码实现与运行演示

在代码实现与运行演示环节,参考之前的对象检测部分,我们可以实现人脸检测,然后从人脸检测输出中得到人脸的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<int>(x2 - x1);
int h = static_cast<int>(y2 - y1);int size = static_cast<int>(std::max<float>(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<float>(im_w), x2);
y2 = std::min(static_cast<float>(im_h), y2);box.x = static_cast<int>(x1);
box.y = static_cast<int>(y1);
box.width = static_cast<int>(x2 - x1);
box.height = static_cast<int>(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<float>(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);
}

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

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

https://ibug.doc.ic.ac.uk/media/uploads/documents/sagonas_iccv_2013_300_w.pdf
https://github.com/github-luffy/PFLD_68points_Pytorch

如欲了解更多OpenVINO™ 开发资料,请扫描下方二维码,我们会把最新资料及时推送给您。

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

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

    人脸landmark介绍 人脸landmark在人脸对齐.人脸重建.身份鉴别.人脸编辑与人脸AR等方面都有重要作用,但是什么是,首先看一张图: 图1(来自OpenVINO安装包的模型库组件) 上图在检 ...

  2. 基于MATLAB人脸检测的汽车疲劳驾驶检测

    课题介绍 疲劳驾驶导致汽车交通事故逐年增加,为了提升驾车的安全性,需对驾驶员疲劳状态实时监测并及时提醒. 为了提高疲劳驾驶判断效率及准确率,本文运用Viola-Jones 框架特征矩阵进行人脸预判断: ...

  3. 一种基于人脸追踪和特征分析的疲劳驾驶预警平台

    目录 整体描述 1. 嵌入式端: 2.程序端: 3. 辅助功能: 4. 项目整体工作流程 5. 不足之处 效果演示 程序源码 算法篇 基于AdaBoost级联分类器的人脸/眼睛位置检测算法 基于特征脸 ...

  4. perclos嘴巴_基于人脸追踪和特征分析的疲劳驾驶预警系统设计

    齐伟 张来刚 刘朝阳 摘 要:本文通过对人脸追踪和疲劳特征分析的研究设计了一个疲劳驾驶预警系统,通过特征人脸识别器来进行驾驶人身份的验证;通过坐标解算来获取驾驶人的头部姿态.电脑端将驾驶人的眨眼频率. ...

  5. 基于MATLAB人眼开度的疲劳识别

    摘 要 目前,随着人们生活水平的提高,各国人民汽车保有量也越来越多,伴随而来的是交通事故也在不断增多.研究表明,疲劳驾驶是造成交通事故日益严重的重要原因.开展驾驶员疲劳检测和预警的研究工作,有着十分重 ...

  6. 疲劳驾驶监测方案_疲劳驾驶检测方法

    司机疲劳驾驶容易引起严重的交通事故,根据以往的交通事故案例分析,由于疲劳驾驶造成的交通事故占据37.91%,由此可见疲劳驾驶的危害之大.但是目前还是有很多人不知道自己是否属于疲劳驾驶,下面小编给大家说 ...

  7. OpenCV3实现人脸识别(一)——基于OpenCV3级联分类器实现人脸检测与眼睛检测

    前言 1.OpenCV官方训练好的人脸和眼睛的级联分类器,3.30的版本都放在opencv\sources\data这个文件夹下,在OpenCV这个文件夹中,主要有 Haar特征 和 LBP特征进行人 ...

  8. 基于人脸关键点检测的驾驶员睡意检测系统

    摘要 驾驶员注意力不集中或者分心是道路交通事故的主要原因. 为了减少道路交通事故,设计开发驾驶员疲劳检测系统至关重要. 本研究利用人脸关键点检测方法提出了驾驶员睡意检测系统,目的是使驾驶更安全. 一. ...

  9. [计算机视觉]人脸应用:人脸检测、人脸对比、五官检测、眨眼检测、活体检测、疲劳检测

    人脸应用在计算机视觉体系中占很大一块,在深度学习火起来之前,基于传统机器学习的人脸应用就已经很成熟了,有很多商用应用场景.本文用一个可以实际运行的Demo来说明人脸应用中常见的技术概念,包含'人脸检测 ...

最新文章

  1. mybatis mapper.xml --注释 带参数的坑
  2. Eclipse中集成Tomcat
  3. java锁方法和锁代码块_java的同步方法和同步代码块,对象锁,类锁区别
  4. 设计模式中的那些工厂
  5. Ansible 之 用户管理
  6. 【机器学习】机器学习从零到掌握之六 -- 教你使用验证分类器测试算法
  7. mysql 定时统计_PHP+MySQL定时数据统计优化
  8. 《赢在中国》第二赛季108将进京
  9. Kali学习 | 密码攻击:6.10 创建密码字典
  10. flash cs6汉化成中文,附汉化包
  11. Linux搭建Nacos及Nacos集群
  12. php 如何移动文件,php怎样移动文件
  13. 求余函数mod和fmod
  14. matlab图无线型,如何使用MATLAB进行移动无线信道模型的建模资料概述
  15. ESP32-CAM MicroPython配新板出现的PSRAM问题
  16. Improving Twitter Sentiment Classification Using Topic-Enriched Multi-Prototype Word Embeddings
  17. 小米是最能赚外国人钱的国产手机品牌,其他手机品牌只能窝里横
  18. C语言编程>第二十六周 ⑥ 请补充fun函数,该函数的功能是:按 “0”到 “9”统计一个字符串中的奇数数字字符各自出现的次数,结果保存在数组num中。注意:不能使用字符串库函数。
  19. 以色列技术!Amimon无线WHDI技术解析
  20. 日语输入法时的部分实用快捷键

热门文章

  1. 【QNX Hypervisor 2.2 用户手册】1.5 内存
  2. 工程学导论的学习感悟
  3. 苹果自带相册打马赛克_剪映app怎么给视频局部打马赛克
  4. BI神器Power Query(22)-- 同一列内多重替换(2)
  5. 彻底卸载secureCRT
  6. 数据结构之链表(Studing Play with DataStruct)
  7. UnicodeEncodeError: 'gbk' codec can't encode character '\xa9' in position 314810: illegal multibyte
  8. php 变量 问号,php – Laravel查询返回问号而不是变量值
  9. Codeforces 1215 A. Yellow Cards
  10. 人工智能情感分析源码,垃圾短信邮箱分析