face-api.js中加入MTCNN:进一步支持使用JS实时进行人脸跟踪和识别

2023-11-16

如果你现在正在阅读这篇文章,那么你可能已经阅读了我的介绍文章(JS使用者福音:在浏览器中运行人脸识别)或者之前使用过face-api.js。如果你还没有听说过face-api.js,我建议你先阅读介绍文章再回来阅读本文。

和往常一样,本文中为你准备了一个代码示例。我们将解析一个小的应用程序,这个程序将在浏览器中访问摄像头图像执行实时人脸检测和人脸识别,让我们开始吧!

使用face-api.js进行人脸检测

到目前为止,face-api.js单独实现了基于SSD Mobilenet v1的CNN进行人脸检测。虽然这个是一个非常精确的人脸检测器,但SSD并不像其他架构那么快(在推理时间方面),并且可能无法通过这个人脸检测器实现实时检测,除非你或者你的用户在他们的机器中内置了一个不错的GPU。

事实证明,你并不总是需要那么高的准确度,有时候你会宁愿用高精度换取更快的人脸检测器。

所以我们要用到MTCNN,它现在可以在face-ap .js中使用了!MTCNN是一种更轻量级的面部检测器。与SSD Mobilenet v1相比:

优点:

  • 更短的推理时间(更快的检测速度)
  • 同时检测5个面部标志点(我们“免费”获得人脸对齐)
  • 模型更小:相比对于6MB(量化的SSD Mobilenet v1权重)来说,它仅约2MB
  • 可配置性:你可以调整一些参数以提高性能以满足你的特定要求

缺点:

  • 不如SSD Mobilenet v1准确

MTCNN – 同时进行人脸检测和面部地标

MTCNN(Multi-task Cascaded Convolutional Neural Networks)是一种由3个阶段组成的算法,它可以检测图像中人脸的边界框以及它们的5个点的面部地标。每个阶段通过将其输入通过CNN逐步改善检测结果,CNN返回具有其分数的候选边界框,然后是非最大抑制。

论文:https://kpzhang93.github.io/MTCNN_face_detection_alignment/paper/spl.pdf

在阶段1中,输入图像被缩放多次以构建影像金字塔并且图像的每个缩放版本都通过其CNN传递。在第2阶段和第3阶段,我们为每个边界框提取图像块并调整它们的大小(第2阶段为24×24,第3 阶段为48×48),然后通过该阶段的CNN传递它们。除了边界框和分数之外,阶段3还为每个边界框计算5个面部地标点。

在修改了一些MTCNN实现之后,结果表明,与SSD Mobilenet v1相比,即使在CPU上运行推断,也可以在更低的推断时间获得相当可靠的检测结果。并且,从5个面部地标点中,我们可以免费获得面部对齐!这样,在计算面部描述符之前,我们不必执行68点面部地标检测作为中间步骤。

尽管在我看来这很有前景,我还是继续在tfjs-core中实现了这一点经过几天的努力,我终于能够找到一个有效的解决方案。

摄像头人脸跟踪和人脸识别

如前所述,我们现在将看看如何使用摄像头实现人脸跟踪和人脸识别。在这个例子中,我会使用我的摄像头再次跟踪和识别一些《生活大爆炸》主角的脸,但当然你可以使用这些代码来跟踪和识别自己。

要显示网络摄像头中的帧,只需使用如下视频元素即可。此外,我将一个绝对定位的画布放在视频元素的顶部,具有相同的高度和宽度。我们将使用画布作为透明的叠加层,稍后我们可以在上面绘制检测结果:

<div style="position: relative" class="margin">
  <video onplay="onPlay(this)" id="inputVideo" autoplay muted></video>
  <canvas id="overlay" />
</div>

 

加载页面后,我们将加载MTCNN模型和人脸识别模型,以计算面部描述符。此外,我们使用navigator.getUserMedia将我们的摄像头流附加到视频元素:

$(document).ready(function() {
  run()
})
    
async function run() {
  // load the models
  await faceapi.loadMtcnnModel('/')
  await faceapi.loadFaceRecognitionModel('/')
  
  // try to access users webcam and stream the images
  // to the video element
  const videoEl = document.getElementById('inputVideo')
  navigator.getUserMedia(
    { video: {} },
    stream => videoEl.srcObject = stream,
    err => console.error(err)
  )
}


要跟踪摄像头中的人脸,我们会将minFaceSize增加到至少200px仅检测较大尺寸的人脸使我们获得更短的推理时间,因为网络将图像缩小的系数更大:现在程序应该会请求授予浏览器访问摄像头的权限。在我们为视频元素指定的onPlay回调中,我们将处理每个帧的实际加工。注意,一旦视频开始播放,就会触发onplay事件。

人脸检测

正如我所说,我们可以在这里配置一些检测参数。默认参数:

const mtcnnForwardParams = {
  // number of scaled versions of the input image passed through the CNN
  // of the first stage, lower numbers will result in lower inference time,
  // but will also be less accurate
  maxNumScales: 10,
  // scale factor used to calculate the scale steps of the image
  // pyramid used in stage 1
  scaleFactor: 0.709,
  // the score threshold values used to filter the bounding
  // boxes of stage 1, 2 and 3
  scoreThresholds: [0.6, 0.7, 0.7],
  // mininum face size to expect, the higher the faster processing will be,
  // but smaller faces won't be detected
  minFaceSize: 20
}

要跟踪摄像头中的人脸,我们会将minFaceSize增加到至少200px仅检测较大尺寸的人脸使我们获得更短的推理时间,因为网络将图像缩小的系数更大:

const mtcnnForwardParams = {
  // limiting the search space to larger faces for webcam detection
  minFaceSize: 200
}

const mtcnnResults = await faceapi.mtcnn(document.getElementById('inputVideo'), mtcnnForwardParams)

 

如你所见,我们可以简单地将视频元素提供给它,就像图像或画布元素那样。

通过MTCNN前向传递给我们一个FaceDetection数组(边界框+得分)以及每个检测到的人脸的FaceLandmark5。现在我们可以将结果绘制到叠加层上:

faceapi.drawDetection('overlay', mtcnnResults.map(res => res.faceDetection), { withScore: false })
faceapi.drawLandmarks('overlay', mtcnnResults.map(res => res.faceLandmarks), { lineWidth: 4, color: 'red' })


计算人脸描述符例子如下,到目前为止,我们将得到下面的结论:

face-api.js中加入MTCNN:进一步支持使用JS实时进行人脸跟踪和识别

从我之前的教程中你应该已经知道,在计算任何面部描述符之前,我们需要将人脸地标的位置与人脸边界框的位置对其。从对齐的框中,我们提取对齐的通过人脸识别网络传递的面部张量:

const alignedFaceBoxes = results.map(
  ({ faceLandmarks }) => faceLandmarks.align()
)

const alignedFaceTensors = await extractFaceTensors(input, alignedFaceBoxes)

const descriptors = await Promise.all(alignedFaceTensors.map(
  faceTensor => faceapi.computeFaceDescriptor(faceTensor)
))

// free memory
alignedFaceTensors.forEach(t => t.dispose())

 

 

如果你觉得这样做很麻烦,代码太多,还有一个方便快捷的函数—faceapi.allFacesMtcnn。它可以检测图像中所有人脸并计算它们的描述符(类似于faceapi.allFaces):

const fullFaceDescriptions = await faceapi.allFacesMtcnn(document.getElementById('inputVideo'), mtcnnParams)
// fullFaceDescriptions[0].detection
// fullFaceDescriptions[0].landmarks
// fullFaceDescriptions[0].descriptor

人脸识别

从现在开始,我们只需按照上一个教程中的方式进行操作。回想一下,为了识别人脸,在运行主循环之前,我们必须为每个我们想要识别(参考数据)的人的示例图像预先计算一个(至少一个)面部描述符。为了做出决策,是哪一个人坐在摄像头前面,我们将在参考数据中的面部描述符中查询人脸描述符并返回最相似的匹配:

const sortAsc = (a, b) => a - b

const results = fullFaceDescriptions.map((fd) => {
  const bestMatch = refDescriptors.map(
    ({ descriptor, label }) => ({
      label,
      distance: faceapi.euclideanDistance(fd.descriptor, descriptor)
    })
  ).sort(sortAsc)[0]
       
  return {
    detection: fd.detection,
    label: bestMatch.label,
    distance: bestMatch.distance
  }
})

如果你只想跟踪自己,只需自拍一张然后运行faceapi.allFaces就可以检索自己脸部的面部描述符(参考描述符)。然后,可以使用faceapi.euclideanDistance直接计算查询面部描述符的距离(从你的摄像头图像到参考描述符)

最后,我们将带有预测标签的文本和相对于边界框位置的距离再次绘制到覆盖层画布上:

// 0.6 is a good distance threshold value to judge
// whether the descriptors match or not
const maxDistance = 0.6

results.forEach(result => {
  faceapi.drawDetection(canvas, result.detection, { withScore: false })
  
  const text = `${result.distance < maxDistance ? result.className : 'unknown'} (${result.distance})`
  const { x, y, height: boxHeight } = detection.getBox()
  faceapi.drawText(
    canvas.getContext('2d'),
    x,
    y + boxHeight,
    text
  )
})


face-api.js中加入MTCNN:进一步支持使用JS实时进行人脸跟踪和识别

然后,不要忘记调用onPlay继续迭代处理最近的帧。就是这些!

结语

最后要注意的是,为每一帧重新计算查询面部描述符是一种非常幼稚的方法。显然,有更有效的方法,例如每隔x帧跟踪和更新检测结果的面部描述符。通常,被跟踪的人脸的姿势不会在几帧中有剧烈地改变。但为了简单起见,这样就可以了。如果你想要从中挤出更多的fps,可以利用这一点。

示例的完整源代码:https://github.com/justadudewhohacks/face-api.js/blob/master/examples/views/mtcnnFaceRecognitionWebcam.htm
l

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

face-api.js中加入MTCNN:进一步支持使用JS实时进行人脸跟踪和识别 的相关文章

随机推荐

  • 2023数学建模思路 - 案例

    更多数学建模案例 https mianbaoduo com o bread YpyXmZhs 一 背景 二 高斯分布的指数族形式 三 对数配分函数与充分统计量的关系 三 极大似然估计与充分统计量 lt
  • ppt转换成pdf免费软件

    为什么80 的码农都做不了架构师 gt gt gt ppt转换成pdf免费软件 导读 使用 ppt转换成pdf转换器当然是转换ppt文件的一个方法 但毕竟好的转换工具并不多 对于从事大量文案处理的工作人员来讲 没有一款专业好用的ppt转换成
  • Linux下使用鼠标滚轮

    Linux下使用鼠标滚轮 让acrobat pdfreader支持滚轮鼠标 这些天用acroread看pdf文件 发现不支持鼠标滚轮 很不爽 最终在水母上搜到了解决方法 将如下内容加到 Xresources文件中 AcroRead XmSc
  • 方差、标准差、协方差、协方差矩阵、散度矩阵

    方差 统计中的方差 样本方差 是每个样本值与全体样本值的平均数之差的平方值的平均数 概率论中方差用来度量随机变量和其数学期望 即均值 之间的偏离程度 1 统计 方差用来计算每一个变量 观察值 与总体均数之间的差异 为避免出现离均差总和为零
  • 小程序实现滚动加载(懒加载)

    前言 小程序是一项很受欢迎的技术 随着其能力的不断增强 越来越多的人开始使用小程序来完成各种任务 当我面面临一个页面有非常多的数据时 该如何处理呢 显然一次性全部加载完 会非常消耗性能的 为了解决这些问题从而出现了一种叫滚动加载的数据处理方
  • 数字时钟仿真电路设计

    课题设计要求 时间以24小时为一个周期 显示时 分 秒 具有校时功能 可以分别对时分秒进行单独校时 使其校正到标准时间 计时过程具有报时功能 当时间到达整点前十秒进行蜂鸣报时 为了保证计时的稳定及准确 须由晶体振荡器提供表针时间基准信号 准
  • 微信公众号开发config:fail,Error: invalid url domain总结自己遇到的几种原因

    1 JS接口安全域名配置错误 不要http 2 设置安全域名时 txt文件未在域名根目录下 3 appid错误 用了其他公众号的 4 ios手机 获取的当前url与实际不一致 详情见下一篇文章
  • Gradle版本7+ AAR包的引入应用

    ARR包的使用 作为一个安卓的初学者 因为某些个客户需要我们提供安卓SDK 我们压根没有移动端业务 为了赚钱 硬着头皮从0开始写一个SDK 终于我这个 百度战士 也靠百度打出了aar包 问题来了 当你搜索安卓如何引用aar 包的时候 是不是
  • Unity物体拖拽系统(一)

    在游戏制作的过程中 我们经常会遇到拖拽物体到某个位置并做其他操作的需求 比如我们会把装备拖动到装备栏来使用这个装备 为了方便的解决这个问题 我制作了一套耦合性比较低的拖拽系统 这套拖拽会适配我们之前制作的按键系统 很简单的就可以添加上手柄的
  • 哈希表查找失败的平均查找长度_哈希算法高大上?也不过如此

    01 知识框架 02 知识点详解 1 散列表的相关概念 什么是散列表和散列函数 是根据关键码值 Key value 而直接进行访问的数据结构 也就是说 它通过把关键码值映射到表中一个位置来访问记录 以加快查找的速度 这个映射函数叫做 散列函
  • VTK(0)---CMake工程

    VTK 0 CMake工程 目录 前言 一 指定cmake版本 二 设置工程 三 针对Qt 自动使用moc uic rcc程序预处理 h文件 ui文件等 四 平台移植问题 五 设置编译模式 六 找到包 七 包含头文件等 八 链接库文件 九
  • 自定义进度条,支持显示浮点数

    思路 QT原生的进度条默认只支持显示整型值 这里重新封装了进度条 支持显示浮点数 内部同时设置了进度条样式 支持显示提示信息 GitHub下载链接 https github com caochuanlin progressbar 头文件 c
  • 01.项目目录搭建以及styled-Components和Reser.css的结合使用

    首先 我们使用脚手架创建了一个新的项目 这里我们对项目的一些基本文件进行整理 首先将一些不需要的文件删除 删除之后留下一些需要的文件 如下 这里我们将原来的style css已经重命名为style js文件 下面安装styled Compo
  • NPM Magic

    NPM Magic package json package json 最起码要包含 name 和 version 快速初始化 package json npm init yes dependencies 生产环境依赖的包 devDepen
  • 安规电容,X电容,Y电容

    什么是安规电容 首先要说一下 安规 是安全规范的简称 安全规范对产品的装置与电子组件有明确的陈述及指导 以避免由于设计不良或使用不当而导致电击 能量 打火 拉弧 爆炸 火灾 辐射 机械与热 高温危险 化学危险等事故和灾害 要求生产厂商尽可能
  • Vue3训练营笔记

    vue3脚手架的详细使用说明 文档下载 https download csdn net download qq 42740465 87939368 spm 1001 2014 3001 5503
  • ROS学习(1)—Ubuntu20.04系统安装noetic学习日志

    1 前言 ROS知识自学 现有博文比较多 而且参差不齐 为了梳理自己的学习思路 形成自身的知识体系 撰写自己的学习日志文档 参考文章及链接均在文章末尾显示 2 主要安装步骤 2 1 更换源文件 添加软件源文件则是将国外服务器的下载地址更改为
  • 标识符和关键字的规则

    大家好 我是耀曜 这段事件没有怎么更新文章 主要是最近换工作 有一年的工作经验 说白了就是一个初级Java后端开发的新手 这段时间面了很多家 我也很纳闷问的都是基础差不多都忘掉了的 以后这段事间耀曜会发布一些关于面试的问题的总结 希望对看到
  • Android 数据的保存,检索,删除之Cursor

    今天遇到的一个问题是如何将数据删除后 将原来的id也相应的做改变呢 如果说对其id值进行逐个修改这也是可以的 但是当数据增多的时候 我们这么做就会很大程度上的降低程序的性能 所以我们想到的就是不要根据id的检索来获取数据库中的值 因为这样做
  • face-api.js中加入MTCNN:进一步支持使用JS实时进行人脸跟踪和识别

    如果你现在正在阅读这篇文章 那么你可能已经阅读了我的介绍文章 JS使用者福音 在浏览器中运行人脸识别 或者之前使用过face api js 如果你还没有听说过face api js 我建议你先阅读介绍文章再回来阅读本文 和往常一样 本文中为