使用tensorflow.js在浏览器中实现人脸识别

  |   0 评论   |   0 浏览   |   给我丶鼓励

如何通过深度学习解决人脸识别

如果您是那种希望尽快入门的男孩(或女孩),则可以跳过本节,直接进入代码。但是为了更好地了解 face-api.js 中用于实现人脸识别的方法,我强烈建议您继续学习,因为我经常被问到这一点。
为简单起见,我们实际上要实现的目标是,识别出具有其面部图像的人,例如 输入图像。我们这样做的方法是为我们要识别的每个人提供一张(或多张)图像,并标上人名,例如参考数据。现在我们将输入图像与参考数据进行比较,找到最相似参考图片。如果两个图像足够相似,我们将输出人名,否则我们输出 '未知'。
听起来像是个计划!但是,仍然存在两个问题。首先,如果我们有一个显示多个人的图像并且我们想要识别所有这些人怎么办?其次,我们需要能够为两个面部图像获得这种相似性度量,以便对其进行比较...

人脸检测

第一个问题的答案是面部检测。简而言之,我们将首先在输入图像中定位所有面部。Face-api.js 为不同用例实现了多个面部检测器。
最准确的人脸检测器是 SSD(单发多盒检测器),它基本上是基于 MobileNet V1 的 CNN,在网络顶部堆叠了一些附加的盒预测层。
更进一步,face-api.js 实现了优化的 Tiny Face Detector,基本上是 Tiny Yolo v2 的甚至更小版本,它利用深度可分离卷积代替常规卷积,与 SSD MobileNet V1 相比,它速度更快,但精度略低。
最后,还有一个 MTCNN(多任务级联卷积神经网络)实现,但是,出于实验目的,这种实现通常在如今已经存在。
网络返回每个面部的边界框及其对应的分数,例如,每个边界框显示一张面部的概率。分数用于过滤边界框,因为图像可能根本不包含任何面孔。请注意,即使只有一个人,也应该执行面部检测以检索边界框。

人脸关键点检测和人脸对齐

第一个问题解决了!但是,我想指出的是,我们要对齐边界框,以便在将每个框以面部为中心的图像提取出来之前,将它们传递到面部识别网络,因为这将使面部识别更加准确!
为此,face-api.js 实现了一个简单的 CNN,该 CNN 返回给定面部图像的 68 个点面部界标:

从界标位置开始,边界框可以在面部居中。在下面,您可以看到人脸检测的结果(左)与对齐的人脸图像(右)的比较:

人脸识别

现在我们可以将提取并对齐的面部图像输入到面部识别网络中,该网络基于类似 ResNet-34 的架构,并且基本上与 dlib 中实现的架构相对应。该网络已经过训练,可以学习将人脸的特征映射到人脸描述符(具有 128 个值的特征向量),这通常也被称为人脸嵌入。
现在回到比较两个人脸的原始问题:我们将使用每个提取的人脸图像的人脸描述符,并将它们与参考数据的人脸描述符进行比较。更准确地说,我们可以计算两个面部描述符之间的欧式距离,并基于阈值判断两个面部是否相似(对于 150 x 150 尺寸的面部图像 0.6 是一个好的阈值)。使用欧几里得距离效果很好,但是您当然可以使用任何分类器。

使用模型

导入包

<script src="face-api.js"></script>`

或者使用

npm i face-api.js

加载模型数据

根据应用程序的需求,您可以专门加载所需的模型,但是要运行一个完整的端到端示例,我们将需要加载人脸检测,人脸界标和人脸识别模型。模型文件可以在仓库中找到,可以在这里找到。
模型权重已经量化,与原始模型相比,模型文件的大小减少了 75%,从而使您的客户端仅加载所需的最少数据。此外,模型权重被划分为最大 4 MB 的块,以允许浏览器缓存这些文件,从而使它们仅需加载一次。
模型文件可以简单地以静态资产的形式在您的 Web 应用程序中提供,也可以将它们托管在其他位置,并且可以通过指定文件的路由或 URL 来加载。假设您是将它们以及您的资产在 public / models 下提供在 models 目录中:

const MODEL_URL = '/models'

await faceapi.loadSsdMobilenetv1Model(MODEL_URL)
await faceapi.loadFaceLandmarkModel(MODEL_URL)
await faceapi.loadFaceRecognitionModel(MODEL_URL)

从输入图像接收所有面孔的完整描述

神经网络接受 HTML 图像,画布或视频元素或张量作为输入。要检测输入图像的所有面部边界框,我们只需说:

const input = document.getElementById('myImage')let fullFaceDescriptions = await faceapi.detectAllFaces(input).withFaceLandmarks().withFaceDescriptors()

完整的面部描述包含检测结果(边界框 + 分数),面部标志以及计算出的描述符。通过省略 faceapi.detectAllFaces(input,options)的第二个 options 参数,默认情况下,SSD MobileNet V1 将用于人脸检测。要改用 Tiny Face Detector 或 MTCNN,只需指定相应的选项即可。
有关面部检测选项的详细文档,请查看 GitHub 存储库的自述文件中的相应部分。请注意,您要像使用 SSD MobileNet V1 模型一样,要预先加载要使用的面部检测器的相应模型。
返回的边界框和界标位置相对于原始图像/媒体尺寸。如果显示的图像尺寸与原始图像尺寸不符,您可以简单地调整它们的尺寸:

fullFaceDescriptions = faceapi.resizeResults(fullFaceDescriptions)

我们可以通过将边界框绘制到画布中来可视化检测结果:

faceapi.draw.drawDetections(canvas, fullFaceDescriptions)

人脸关键点可以显示如下:

faceapi.draw.drawLandmarks(canvas, fullFaceDescriptions)

人脸识别

现在我们知道了如何在给定输入图像的情况下检索所有面部的位置和描述符,我们将获得一些分别显示一个人的图像并计算其面部描述符。这些描述符将作为我们的参考数据。
假设我们有一些适用于主题的示例图像,我们首先从 URL 获取图像,然后使用 faceapi.fetchImage 从其数据缓冲区中创建 HTML 图像元素。对于每个获取的图像,我们将定位被摄对象的脸部并计算脸部描述符,就像我们之前对输入图像所做的那样:

const labels = ['sheldon' 'raj', 'leonard', 'howard']

const labeledFaceDescriptors = await Promise.all(
  labels.map(async label => {
    // fetch image data from urls and convert blob to HTMLImage element
    const imgUrl = `${label}.png`
    const img = await faceapi.fetchImage(imgUrl)
  
    // detect the face with the highest score in the image and compute it's landmarks and face descriptor
    const fullFaceDescription = await faceapi.detectSingleFace(img).withFaceLandmarks().withFaceDescriptor()
  
    if (!fullFaceDescription) {
      throw new Error(`no faces detected for ${label}`)
    }
  
    const faceDescriptors = [fullFaceDescription.descriptor]
    return new faceapi.LabeledFaceDescriptors(label, faceDescriptors)
  })
)

请注意,这次我们使用的是 faceapi.detectSingleFace,它将仅返回检测到的得分最高的人脸,因为我们假设,该图像中仅显示给定标签的字符。
现在,剩下要做的就是将来自我们输入图像的检测到的面部的面部描述符与我们的参考数据进行匹配,例如标记的面部描述符。为此,我们可以如下使用 faceapi.FaceMatcher:


const maxDescriptorDistance = 0.6
const faceMatcher = new faceapi.FaceMatcher(labeledFaceDescriptors, maxDescriptorDistance)

const results = fullFaceDescriptions.map(fd => faceMatcher.findBestMatch(fd.descriptor))

人脸匹配器使用欧几里德距离作为相似性度量,事实证明效果很好。我们最终为输入图像中检测到的每个脸部提供了最佳匹配,其中包含标签 + 匹配的欧式距离。
最后,我们可以将边界框及其标签绘制到画布中以显示结果:

results.forEach((bestMatch, i) => {
  const box = fullFaceDescriptions[i].detection.box
  const text = bestMatch.toString()
  const drawBox = new faceapi.draw.DrawBox(box, { label: text })
  drawBox.draw(canvas)
})

该库的开源地址: https://github.com/justadudewhohacks/face-api.js


标题:使用tensorflow.js在浏览器中实现人脸识别
作者:给我丶鼓励
地址:https://blog.doiduoyi.com/articles/1591154317185.html

评论

发表评论