【教程】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 条评论
登录 后参与评论

相关文章

来自专栏Tencentcloud

交互式数字作品教程——专为艺术家的你!

这篇文章不是对循环神经网络的综合概述。它适用于没有任何机器学习背景的读者。其目的是向艺术家和设计师展示如何使用预先训练的神经网络——使用简单的Javascrip...

2206
来自专栏CVer

重磅 | TensorFlow学习资料最全集锦

TensorFlow 已然成为深度学习框架中的扛把子,各位童鞋即使没有学习过,但一定有所耳闻。本文总结了TensorFlow相关的入门指南、网上教程、视频教程、...

1513
来自专栏专知

机器翻译新时代:Facebook 开源无监督机器翻译模型和大规模训练语料

【导读】基于深度学习的机器翻译往往需要数量非常庞大的平行语料,这一前提使得当前最先进的技术无法被有效地用于那些平行语料比较匮乏的语言之间。为了解决这一问题,Fa...

45311
来自专栏章鱼的慢慢技术路

解救小哈——DFS算法举例

2278
来自专栏深度学习之tensorflow实战篇

SPSS Modeler 介绍决策树

本文将通过 SPSS Modeler 介绍决策树 (Decision tree) 演算法于银行行销领域的应用实例。通过使用网路公开电销资料建立不同决策树模型,分...

3488
来自专栏机器学习之旅

python开发:特征工程代码模版(二)

正题开始: 这篇文章是入门级的特征处理的打包解决方案的python实现汇总,如果想get一些新鲜血液的朋友可以叉了,只是方便玩数据的人进行数据特征筛选的代码集...

1063
来自专栏CVer

TensorFlow从入门到精通 | 预告篇

[TensorFlow从入门到精通]系列课程既包含TensorFlow的基础知识点(如Graph),还有卷积神经网络、模型的保存和恢复、迁移学习、Fine-Tu...

1154
来自专栏深度学习自然语言处理

调参的一些个人拙见

最近的事。。浓缩成下面的一张图。 ? 调参有哪些方法呢? 语料处理。这个是之后一切操作的基础。有人或许认为算法是最重要的,其实不然,语料处理真的真的是最重要的。...

2795
来自专栏量子位

机器学习玩转Flappy Bird全书:六大“流派”从原理到代码

被Flappy Bird虐过么?反击的号角吹响了 作为一个曾经风靡一时的游戏,《Flappy Bird》曾经虐过很多的人类玩家。 而过去一段时间以来,好多人类借...

4079
来自专栏架构之路

蓄水池抽样-Reservoir Sampling

 英文原文:hadoop-stratified-randosampling-algorithm         译者:bruce-accumulate    ...

2733

扫码关注云+社区