人脸landmark介绍

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

图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<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自带的函数只支持字节图像数据输入,所以需要修改一下该方法来支持浮点数图像数据输入,修改以后我重命名位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 SizeVector land_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;

float dist_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

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

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

    人脸landmark介绍 人脸landmark在人脸对齐.人脸重建.身份鉴别.人脸编辑与人脸AR等方面都有重要作用,但是什么是人脸landmark,首先看一张图: 上图在检测人脸白色矩形框的基础上,通 ...

  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. Pytorch install
  2. eclipse php 环境及调试配置
  3. [Java] 蓝桥杯BASIC-28 基础练习 Huffuman树
  4. Win10安装Nek5000
  5. win10多合一原版系统_如何制作Win10多合一系统安装盘
  6. Navicat Premium 12.0.29 / 12.1.5.0注册机激活
  7. 游戏后台架构发展历史及展望
  8. Java文字转图片超出内容自动换行
  9. 生成国庆头像网站的源码及搭建教程
  10. 计算机电源可调电阻,电脑ATX电源改0V-30V可调电源,电流7A
  11. 计算机电脑上可以做作业吗,一起作业电脑版
  12. 【图像重建】基于Split Bregman实现稀疏图像重建附matlab代码
  13. 【云计算OpenStack-OpenStack Queens版本-遇错】基于OpenStack的云计算环境搭建
  14. GZIP压缩和解压缩不删除原始文件
  15. Airbnb短租数据分析报告
  16. php电子杂志,Phpwind推电子杂志《站长天下》 网罗站长故事
  17. Python的整数与浮点数计算
  18. LaTeX命令速查手册 - 方法总比问题多
  19. 爬虫--西安二手房房价
  20. 《安富莱嵌入式周报》第308期:开源带软硬件安全认证的PLC设计,开源功率计,可靠PID实现,PR2机器人设计文件全开源,智能手表设计WASP-OS

热门文章

  1. Xcode 图片裁剪
  2. re学习笔记(93)攻防世界 - mobile进阶区 - Illusion
  3. 非正交多址接入(NOMA)背景、优势、技术方案、未来研究方向
  4. WDK学习笔记第一周
  5. linux查找缺少的命令
  6. 7+ Taskbar Tweaker的使用
  7. 晶闸管器件的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  8. POJ1001 求高精度幂 (分治高精度大数相乘)
  9. 谷安天下2013年6月CISA考前辅导 第一季
  10. apache ii评分和死亡率_APACHEⅡ评分与血乳酸清除率对危重症患者预后评估的比较...