机器学习实战:用nodejs实现人脸识别

 

在本文中,我将向你展示如何使用face-recognition.js执行可靠的人脸检测和识别 。 我曾经试图找一个能够精确识别人脸的Node.js库,但是没有找到,因此,我决定自己搞一个! 

这个npm包基于dlib实现,因为我发现dlib的识别精度很高。 dlib库使用深度学习方法,并附带一些预训练的模型,这些预置的模型,在LFW人脸识别基准测试上可以达到惊人的准确度:99.38% 。

为什么要搞这个东西?

最近我一直在尝试使用Node.js来构建一个人脸识别应用程序,以便从《生活大爆炸》剧中来提取和识别人物的面部。最初,我想用OpenCV的人脸识别器来实现,思路类似于我在教程Node.js + OpenCV for Face Recognition中的类似。

但是,虽然这些人脸识别器能够提供快速的预测结果,但是我发现它们不够健壮。 更确切地说,虽然他们适用于正面的人脸图像,但只要人脸姿势略有不同,就会产生相当不靠谱的预测结果。

因此,我就开始寻找替代方案,然后发现了dlib这个 C ++库,我用它的Python API试了一下,结果给我留下了深刻的印象,最后我决定: 用Node.js来实现这个功能! 因此,我创建了这个npm包,提供一个简化的Node.js 的API用于人脸识别。

face-recognition.js是什么?

我开发face-recognitiontion.js的目的,是想提供一个这样的npm包:

  • 有一个简单的API,可以让人快速上手人脸识别
  • 如果需要的话仍然允许更细粒度的识别控制
  • 易于设置(最好敲一行命令就能安装,例如npm install)

虽然这个软件包还在开发中,现在已经可以用它做点事情了:

人脸检测

你可以使用深度神经网络进行人脸检测,也可以使用简单的正面人脸识别器进行快速但但不那么可靠的检测:

人脸识别

人脸识别器是一个深度神经网络,它使用我提到的模型来计算一个独特的人脸描述符。 这个人脸识别器用标注过的人脸图像进行训练后,就可以预测输入人脸图像的标签:

人脸特征点检测

你也可以使用这个包来检测面部的特征点(5个或68个):

实战效果!

好吧,正如我所说的,我开始时尝试用OpenCV,但没能完成这个任务。 现在我有一堆150x150大小的人脸图像(分别来自Sheldon 、Raj 、 Lennard 、Howard和Stuart),我将向你展示使用这些数据来训练人脸识别器、识别新面孔是多么的简单。 这个例子的代码可以在这个仓库上找到。

准备数据

剧中每个角色不同的姿态分别采集大概20张图像:

我们将分别使用每个人的10个图像来训练识别器,其余部分来评估识别器的准确性:

const path = require('path')
const fs = require('fs')
const fr = require('face-recognition')

const dataPath = path.resolve('./data/faces')
const classNames = ['sheldon', 'lennard', 'raj', 'howard', 'stuart']

const allFiles = fs.readdirSync(dataPath)
const imagesByClass = classNames.map(c =>
  allFiles
    .filter(f => f.includes(c))
    .map(f => path.join(dataPath, f))
    .map(fp => fr.loadImage(fp))
)

const numTrainingFaces = 10
const trainDataByClass = imagesByClass.map(imgs => imgs.slice(0, numTrainingFaces))
const testDataByClass = imagesByClass.map(imgs => imgs.slice(numTrainingFaces))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

每个脸部图像的文件名中包含了人名,所以我们可以简单地实现图像和其分类的映射:

['sheldon', 'lennard', 'raj', 'howard', 'stuart']
  • 1

你可以使用fr.loadImage(fp)读取给定文件路径的图像。

检测人脸

正如我所说的,图像已经提取为150x150的大小,这是我事先用opencv4nodejs完成的。 但是你也可以用下面的代码来检测和提取人脸、保存并进行标注:

const image = fr.loadImage('image.png')
const detector = fr.FaceDetector()
const targetSize = 150
const faceImages = detector.detectFaces(image, targetSize)
faceImages.forEach((img, i) => fr.saveImage(img, `face_${i}.png`))
  • 1
  • 2
  • 3
  • 4
  • 5

训练识别器

现在我们有了数据,可以开始训练识别器:

const recognizer = fr.FaceRecognizer()

trainDataByClass.forEach((faces, label) => {
  const name = classNames[label]
  recognizer.addFaces(faces, name)
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

基本上这就是把每张人脸图像输入到神经网络中,神经网络输出面部的描述符并存储指定类别的所有描述符。 你还可以通过将numJitters指定为第三个参数来利用训练数据生成一些抖动后的图像,这个参数将应用旋转 、缩放和镜像等变换来创建每个输入人脸的不同版本图像。 增加抖动版本的数量可能有助于提高预测的准确性,但同时也会增加训练时间。

此外,我们可以存储识别器的状态,这样就不必在下次要用时重新进行训练了,只需要简单地从一个文件中加载训练好的模型:

保存:

const modelState = recognizer.serialize()
fs.writeFileSync('model.json', JSON.stringify(modelState))
  • 1
  • 2

加载:

const modelState = require('model.json')
recognizer.load(modelState)
  • 1
  • 2

识别新面孔

现在我们可以用剩余的样本数据来检查预测精度并记录结果:

const errors = classNames.map(_ => [])
testDataByClass.forEach((faces, label) => {
  const name = classNames[label]
  console.log()
  console.log('testing %s', name)
  faces.forEach((face, i) => {
    const prediction = recognizer.predictBest(face)
    console.log('%s (%s)', prediction.className, prediction.distance)

    // count number of wrong classifications
    if (prediction.className !== name) {
      errors[label] = errors[label] + 1
    }
  })
})

// print the result
const result = classNames.map((className, label) => {
  const numTestFaces = testDataByClass[label].length
  const numCorrect = numTestFaces - errors[label].length
  const accuracy = parseInt((numCorrect / numTestFaces) * 10000) / 100
  return `${className} ( ${accuracy}% ) : ${numCorrect} of ${numTestFaces} faces have been recognized correctly`
})
console.log('result:')
console.log(result)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

当前的预测是通过计算输入人脸图像的描述符向量到分类中每个描述符的欧式距离来完成的,同时也计算出所有距离的平均值 。 有人可能会说, kmeans聚类或SVM分类器将更适合这个任务,我也可能在将来实现这些算法。 但是现在使用欧几里德距离的实现,看起来执行速度很快而且效率够高。

调用predictionBest将输出具有最小距离(例如最高相似度)的结果。 输出看起来像这样:

{className:'sheldon',距离:0.5} 
  • 1

如果你想获得所有分类的脸部描述符到输入的人脸图像的距离,可以简单地使用recognitionizer.predict(image) ,它将输出一个数组,其成员包含输入图像到每个分类的距离:

  [
  {className:'sheldon',距离:0.5},
  {className:'raj',距离:0.8},
  {className:'howard',距离:0.7},
  {className:'lennard',距离:0.69},
  {className:'stuart',距离:0.75}
  ] 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

结果

运行上面的例子将给出以下结果。

使用10个面孔进行训练:

sheldon ( 90.9% ) : 10 of 11 faces have been recognized correctly
lennard ( 100% ) : 12 of 12 faces have been recognized correctly
raj ( 100% ) : 12 of 12 faces have been recognized correctly
howard ( 100% ) : 12 of 12 faces have been recognized correctly
stuart ( 100% ) : 3 of 3 faces have been recognized correctly
  • 1
  • 2
  • 3
  • 4
  • 5

每个训练只使用5个面孔 :

sheldon ( 100% ) : 16 of 16 faces have been recognized correctly
lennard ( 88.23% ) : 15 of 17 faces have been recognized correctly
raj ( 100% ) : 17 of 17 faces have been recognized correctly
howard ( 100% ) : 17 of 17 faces have been recognized correctly
stuart ( 87.5% ) : 7 of 8 faces have been recognized correctly
  • 1
  • 2
  • 3
  • 4
  • 5

结论

从结果看,即使只用一小组数据进行训练,也可以获得相当准确的结果。甚至对这些我从网上抓取的小尺寸图像(一些提取的脸部非常模糊), 结果也令人非常满意。

如果你喜欢这篇文章,记得关注我的头条号:新缸中之脑!

原文:Node.js + face-recognition.js : Simple and Robust Face Recognition using Deep Learning

机器学习实战:用nodejs实现人脸识别的更多相关文章

  1. Nodejs开发人脸识别系统-教你实现高大上的人工智能

    Nodejs开发人脸识别系统-教你实现高大上的人工智能   一.缘起缘生 前段时间有个H5很火,上传个头像就可以显示自己穿军装的样子,无意中看到了一篇帖子叫 全民刷军装背后的AI技术及简单实现 ,里面 ...

  2. [机器学习][face recognition] 一个视频人脸识别实现

    开发环境和用到的库: Ubuntu jupyter notebook(python3.6) OpenCV Dlib face_recognition 实现效果如下(视频截图): #coding=utf ...

  3. 机器学习实战kNN之手写识别

    kNN算法算是机器学习入门级绝佳的素材.书上是这样诠释的:“存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都有标签,即我们知道样本集中每一条数据与所属分类的对应关系.输入没有标签的新数据 ...

  4. [深度应用]·实战掌握Dlib人脸识别开发教程

    [深度应用]·实战掌握Dlib人脸识别开发教程 个人网站--> http://www.yansongsong.cn/ 项目GitHub地址--> https://github.com/xi ...

  5. 基于kNN的手写字体识别——《机器学习实战》笔记

    看完一节<机器学习实战>,算是踏入ML的大门了吧!这里就详细讲一下一个demo:使用kNN算法实现手写字体的简单识别 kNN 先简单介绍一下kNN,就是所谓的K-近邻算法: [作用原理]: ...

  6. 在nodejs中的集成虹软人脸识别

    ==虹软官网地址==http://www.arcsoft.com.cn 在官网注册账号,并且申请人脸识别激活码, 选择SDK版本和运行系统(windows/linux/android/ios) ,我们 ...

  7. 【从零学习openCV】IOS7人脸识别实战

    前言 接着上篇<IOS7下的人脸检測>,我们顺藤摸瓜的学习怎样在IOS7下用openCV的进行人脸识别,实际上非常easy,因为人脸检測部分已经完毕,剩下的无非调用openCV的方法对採集 ...

  8. windows下百度离线人脸识别本地部署与使用(nodejs做客户端,c++做服务端,socket做通信)

    1.离线人脸识别本地部署 详情请阅读百度人脸识别官网 2.nodejs做socket通信的客户端 为什么不直接通过调用c++编译的exe获得人脸识别结果? 原因:exe运行时会加载很多模型而消耗很多时 ...

  9. 机器学习-svd实现人脸识别

    加载sklearn中的人脸数据集 from sklearn.datasets import fetch_lfw_people faces = fetch_lfw_people() 执行上面的第二行程序 ...

随机推荐

  1. USACO 4.3 Street Race

    Street RaceIOI'95 Figure 1 gives an example of a course for a street race. You see some points, labe ...

  2. spring调用方法(接口和多个实现类的情况)

    以spring框架注入bean说明接口TestService 有2个实现类 TestServiceImp1 @Service("TestService1") ,TestServic ...

  3. linux下文件转码

    一.工具介绍 enca是一个很好用的文件转码工具,使用命令 sudo apt-get install enca 即可安装 二.基本用法 1.查看文件编码 $ enca filename 2.文件转码 ...

  4. 10 Best jQuery and HTML5 WYSIWYG Plugins

    https://www.sitepoint.com/10-best-html-wysiwyg-plugins/

  5. java 代码中设置 临时 环境变量

    System.setProperty("hadoop.home.dir", "D:\\software\\software_install\\dev_install\\h ...

  6. 牛客练习赛1 B - 树

    链接:https://www.nowcoder.com/acm/contest/2/B来源:牛客网 题目描述 shy有一颗树,树有n个结点.有k种不同颜色的染料给树染色.一个染色方案是合法的,当且仅当 ...

  7. String 的常用操作

    String 类,我可以不负责的说在 Java 中这个类应该是使用最频繁的类了.然而关于它的常用的操作,我却不甚了解.整理这个东西很反人性的,这些方法,你看到他的时候感觉很简单,但是真正用的时候还是不 ...

  8. [转]kali中eth0网卡突然消失解决方案

    前言 不知道怎么kali的eth0网卡突然消失了.这可有点难受啊.在网上查找了一番找到了解决办法,特此记录. 问题   怎么办? 解决办法 首先使用ifconfig -a命令查看所有的网卡接口  发现 ...

  9. [ 原创 ]linux centos下配置java环境教程

    一.环境 centos 7.2 二.目标 在CentOS7.2上安装jdk1.8(tar.gz安装包),并配置环境变量 jdk安装在/home/soft/jdk1.8.0-131目录下 具体步骤 1. ...

  10. CentOS下重新安装yum的方法

    不小心误删除了VPS下面的yum,大家都知道yum在linux中是很重要的一个功能,软件的下载,系统的更新都要靠他.没有yum,系统基本处于半残废状态. yum的安装操作: 在SSH里面依次输入下面的 ...