【教程】OpenCV—Node.js教程系列:Node.js+OpenCV面部脸识别

最近我将OpenCV普通发布版本设计的面部识别算法添加到了opencv4nodejs,它是一个npm包,允许你在Node.js应用程序中使用OpenCV。今天,我们将看一下在OpenCVs的面部模块中实现的Fisher -、Eigen -和LBPH facerecognizer,并构建一个简单的Node.js面部识别的例子。在我的github repo上可以找到示例的源代码。我们不要再浪费时间了,开始吧!

  • OpenCV普通发布版本地址:https://docs.opencv.org/3.1.0/d3/d81/tutorial_contrib_root.html
  • opencv4nodejs地址:https://github.com/justadudewhohacks/opencv4nodejs
  • OpenCVs面部模块中的实现地址:https://docs.opencv.org/2.4/modules/contrib/doc/facerec/facerec_tutorial.html
  • github repo地址:https://github.com/justadudewhohacks/opencv4nodejs/tree/master/examples

1 .工作准备图像数据

在我们对识别器进行训练之前,必须收集一些面部图像数据。如果你像我一样对行尸走肉(美国电视剧)感到兴奋,那么你很可能对我们的测试对象很熟悉。我收集了Daryl,Rick和邪恶少年Negan的图像,每人4张,总共12张。

简单地从网络中选取一些图像,我们必须提取以每个图像中显示的字符为中心的子图像。因此,我们将使用OpenCV的CascadeClassifier类来检测人物的面部:

const classifier = new cv.CascadeClassifier(cv.HAAR_FRONTALFACE_ALT2);
const getFaceImage = (grayImg) => {
  const faceRects = classifier.detectMultiScale(grayImg).objects;
  if (!faceRects.length) {
    throw new Error('failed to detect faces');
  }
  return grayImg.getRegion(faceRects[0]);
};

CascadeClassifier可以用于目标检测,它是从一个包含训练模型表示的xml文件中创建的。OpenCV为不同的使用案例提供了一些预先训练的模型,如面部检测、人眼检测、全身检测等。为了检测到面部,我们将使用HAAR_FRONTALFACE_ALT2模型。给定一个灰度图像,detectMultiScale将返回图像中潜在面部的边界矩形。我们可以简单地获取第一个最佳检测结果,并返回矩形覆盖的子图像。

图像上标上daryl <n >,rick <n >,negan <n >,n从1 – 4。我们将阅读这些图片并将它们分成一组训练和测试样本如下:

const basePath = '../data/face-recognition';
const imgsPath = path.resolve(basePath, 'imgs');
const nameMappings = ['daryl', 'rick', 'negan'];

const imgFiles = fs.readdirSync(imgsPath);

const images = imgFiles
  // get absolute file path
  .map(file => path.resolve(imgsPath, file))
  // read image
  .map(filePath => cv.imread(filePath))
  // face recognizer works with gray scale images
  .map(img => img.bgrToGray())
  // detect and extract face
  .map(getFaceImage)
  // face images must be equally sized
  .map(faceImg => faceImg.resize(80, 80));

const isImageFour = (_, i) => imgFiles[i].includes('4');
const isNotImageFour = (_, i) => !isImageFour(_, i);
// use images 1 - 3 for training
const trainImages = images.filter(isNotImageFour);
// use images 4 for testing
const testImages = images.filter(isImageFour);
// make labels
const labels = imgFiles
  .filter(isNotImageFour)
  .map(file => nameMappings.findIndex(name => file.includes(name)));

将给出以下图像:

调整图像的大小是必要的,因为识别器希望图像的大小相等。我们将使用每个角色的前3张图像进行训练,第4张用来测试识别器(第19 – 24行)。最后,我们必须标记数据(第26 – 28行)。为了训练识别器,我们需要给它提供一个图像数组(训练图像)和一个将相应标签保存为数字(标签)的数组。数据应该是这样的:

训练图像:

[Rick1, Rick2, Rick3, Daryl1, Daryl2, Daryl3, Negan1, Negan2, Negan3]

标签:

[0, 0, 0, 1, 1, 1, 2, 2, 2]

2.训练识别器

现在我们已经准备好了数据,我们将初始化识别器并对它们进行训练:

const eigen = new cv.EigenFaceRecognizer();
const fisher = new cv.FisherFaceRecognizer();
const lbph = new cv.LBPHFaceRecognizer();
eigen.train(trainImages, labels);
fisher.train(trainImages, labels);
lbph.train(trainImages, labels);

还可以将一些参数传递给识别器的构造函数来对它们进行微调,但为了简单起见,我们将使用默认设置。从逻辑上讲,训练方法期望训练图像标签数组的长度相同,标签数组必须包含至少2个不同的标签。

3.识别面部

就是这样!我们现在可以运行我们测试图像的预测:

const runPrediction = (recognizer) => {
  testImages.forEach((img) => {
    const result = recognizer.predict(img);
    console.log('predicted: %s, confidence: %s', nameMappings[result.label], result.confidence);
    cv.imshowWait('face', img);
    cv.destroyAllWindows();
  });
};

console.log('eigen:');
runPrediction(eigen);

console.log('fisher:');
runPrediction(fisher);

console.log('lbph:');
runPrediction(lbph);

运行这个示例应该给出如下输出:

eigen:
predicted daryl to be: daryl, confidence: 1245.68
predicted negan to be: negan, confidence: 2247.25
predicted rick to be: negan, confidence: 2502.47
fisher:
predicted daryl to be: daryl, confidence: 452.15
predicted negan to be: negan, confidence: 464.76
predicted rick to be: rick, confidence: 831.38
lbph:
predicted daryl to be: daryl, confidence: 108.37
predicted negan to be: negan, confidence: 119.33
predicted rick to be: rick, confidence: 105.65

每个类(角色)仅使用3个图像,我们就可以得到很好的结果。Opencv4nodejs是一个npm包,将 Node.js绑定到OpenCV,并且OpenCV普通发布版通过异步API设计。该包将本机OpenCV库的所有性能优势都带到 Node.js应用程序,允许通过Promise轻松实现多线程的CV任务。

原文发布于微信公众号 - ATYUN订阅号(atyun_com)

原文发表时间:2017-12-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏AI科技评论

开发 | 低配硬件就不能运行深度神经网络了?手把手教你克服“杀牛用鸡刀”难题

如果对深度学习有所了解的小伙伴们想必都知道,深度学习需要使用强大的服务器、加速嵌入式平台(如NVIDIA的Jetson)来运行深度学习算法,然而这也同样意味着不...

3625
来自专栏Vamei实验室

概率论02 概率公理

概率论早期用于研究赌博中的概率事件。赌徒对于结果的判断基于直觉,但高明的赌徒尝试从理性的角度来理解。然而,赌博中的一些结果似乎有矛盾。比如掷一个骰子,每个数字出...

1849
来自专栏PPV课数据科学社区

如何用spss做一般(含虚拟变量)多元线性回归

回归一直是个很重要的主题。因为在数据分析的领域里边,模型重要的也是主要的作用包括两个方面,一是发现,一是预测。而很多时候我们就要通过回归来进行预测。关...

5977
来自专栏数据派THU

手把手教你用seq2seq模型创建数据产品(附代码)

原文标题:How To Create Data Products That Are Magical Using Sequence-to-Sequence Mod...

3666
来自专栏企鹅号快讯

外国网友如何使用机器学习将邮件分类?其实很简单

AiTechYun 编辑:Yining 背景:一名叫做Anthony Dm.的外国网友试图利用机器学习将一堆未标记的电子邮件进行分类,以下是他对这次操作发表的文...

1908
来自专栏机器之心

想了解概率图模型?你要先理解图论的基本定义与形式

选自Dev To 作者:vaidehijoshi等 机器之心编译 参与:蒋思源、李泽南 图论一直是数学里十分重要的学科,其以图为研究对象,通常用来描述某些事物之...

2567
来自专栏计算机视觉life

自识别标记(self-identifying marker) -(5) 用于相机标定的CALTag图案设计

前面介绍了CALTag的工作原理、应用领域。如果我们想在实际项目中应用自识别标记,通常需要根据项目的特点来设计不同尺寸,不同数目,不同排列的图案,那么如何设计属...

1917
来自专栏hrscy

GPU 图形绘制管线

图形绘制管线描述 GPU 渲染流程,即"给定视点、三维物体、光源、照明模式和纹理等元素,如何绘制一幅二维图像"。

843
来自专栏AI科技评论

开发 | 谷歌推出开源 Python 库“Tangent”,支持前向模式自动微分

AI科技评论消息:日前,Google Research Blog 推出开源 Python库“Tangent”。据介绍,这个库与现有的机器学习库相比,存在诸多优势...

2675
来自专栏CSDN技术头条

利用GPU和Caffe训练神经网络

本文为利用GPU和Caffe训练神经网络的实战教程,介绍了根据Kaggle的“奥托集团产品分类挑战赛”的数据进行训练一种多层前馈网络模型的方法,如何将模型应用于...

19410

扫码关注云+社区