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

相关文章

来自专栏智能算法

Learning to Rank 小结

一、学习排序(Learning to Rank) LTR(Learning torank)学习排序是一种监督学习(SupervisedLearnin...

3845
来自专栏ATYUN订阅号

自动机器学习:利用遗传算法优化递归神经网络

最近,在自动机器学习方面有很多工作,从选择合适的算法到特征选择和超参数调优。有几种可用的工具(例如:AutoML和TPOT),可以帮助用户高效地执行数百个实验。...

3385
来自专栏月色的自留地

从锅炉工到AI专家(9)

1636
来自专栏机器之心

教程 | TensorFlow从基础到实战:一步步教你创建交通标志分类神经网络

选自DataCamp 作者:Karlijn Willems 机器之心编译 参与:Panda TensorFlow 已经成为了现在最流行的深度学习框架,相信很多对...

3816
来自专栏1039778的专栏

Python 数据分析学习笔记

一、基本语法 [1507772432114_7239_1507772402948.jpg] 资料地址:http://www.icoolxue.com/album...

4629
来自专栏人工智能头条

代码解析深度学习系统编程模型:TensorFlow vs. CNTK

1437
来自专栏AI研习社

文本分类又来了,用 Scikit-Learn 解决多类文本分类问题

在商业领域有很多文本分类的应用,比如新闻故事通常由主题来分类;内容或产品常常被打上标签;基于如何在线谈论产品或品牌,用户被分成支持者等等。

821
来自专栏华章科技

大数据等最核心的关键技术:32个算法

奥地利符号计算研究所(Research Institute for Symbolic Computation,简称RISC)的Christoph Koutsch...

602
来自专栏AIUAI

Caffe2 - (三十二) Detectron 之 roi_data - 模型 minibatch blobs

3649
来自专栏钱塘大数据

32类计算机与数学领域最为重要的算法

导读: 奥地利符号计算研究所的Christoph Koutschan博士在自己的页面上发布了一篇文章,提到他做了一个调查,参与者大多数是计算机科学家,他请这些科...

2688

扫描关注云+社区