OpenCV—Node.js教程系列:用Tensorflow和Caffe“做游戏”

AiTechYun

编辑:Yining

今天我们来看看OpenCV的深度神经网络模块。如果你想要释放神经网络的awesomeness来识别和分类图像中的物体,但完全不知道深度学习如何工作,也不知道如何建立和训练神经网络了,那么我有好消息告诉你!

第一步要做什么呢?

在本教程中,我们将学习如何在OpenCV的DNN模块中加载来自Tensorflow和Caffe的预先训练的模型,我们将利用Node.js和OpenCV深入研究两个对象识别的例子。

首先,我们将使用Tensorflow的Inception模型来识别图像中显示的对象,然后使用COCO SSD模型在单个图像中检测和识别多个不同的对象。

让我们看看它是如何工作的!在我的github repo上可以找到示例的源代码。

github repo地址:https://github.com/justadudewhohacks/opencv4nodejs

Tensorflow Inception

在训练过程中,我们训练了Tensorflow Inception模型来识别1000类的对象。如果将图像输入到神经网络,它将输出图像中显示对象的每个类的可能性。

Tensorflow Inception地址:https://www.tensorflow.org/tutorials/image_recognition

要使用OpenCV的Inception模型,我们必须加载二进制的tensorflow_inception_graph.pb和来自imagenet_comp_graph_label_strings.txt的类名列表。你可以通过下载和解压缩“inception5h.zip”来获取这些文件。

示例代码链接地址:

https://github.com/justadudewhohacks/opencv4nodejs/blob/master/examples/dnnTensorflowInception.js

// replace with path where you unzipped inception modelconst inceptionModelPath = '../data/dnn/tf-inception'const modelFile = path.resolve(inceptionModelPath, 'tensorflow_inception_graph.pb

');const classNamesFile = path.resolve(inceptionModelPath, 'imagenet_comp_graph_

label_strings.txt');if (!fs.existsSync(modelFile) || !fs.existsSync(classNamesFile)) { console.log('exiting: could not find inception model'); console.log('download the model from: https://storage.googleapis.com/download.

tensorflow.org/models/inception5h.zip'); return;}// read classNames and store them in an arrayconst classNames = fs.readFileSync(classNamesFile).toString().split("\n");// initialize tensorflow inception model from modelFileconst net = cv.readNetFromTensorflow(modelFile);

分类图像中的对象

为了对图像中的对象进行分类,我们将编写以下辅助函数:

const classifyImg = (img) => { // inception model works with 224 x 224 images, so we resize // our input images and pad the image with white pixels to // make the images have the same width and height const maxImgDim = 224; const white = new cv.Vec(255, 255, 255); const imgResized = img.resizeToMax(maxImgDim).padToSquare(white); // network accepts blobs as input const inputBlob = cv.blobFromImage(imgResized); net.setInput(inputBlob); // forward pass input through entire network, will return // classification result as 1xN Mat with confidences of each class const outputBlob = net.forward(); // find all labels with a minimum confidence const minConfidence = 0.05; const locations = outputBlob .threshold(minConfidence, 1, cv.THRESH_BINARY) .convertTo(cv.CV_8U) .findNonZero(); const result = locations.map(pt => ({ confidence: parseInt(outputBlob.at(0, pt.x) * 100) / 100, className: classNames[pt.x] })) // sort result by confidence .sort((r0, r1) => r1.confidence - r0.confidence) .map(res => `$ ($)`); return result;}

这个函数的作用如下:

准备输入图像

首先我们要知道,Tensorflow Inception网络接受224×224大小的输入图像。这就是我们调整图像大小的原因,确保它最大的尺寸是224,我们用白色像素填充图像的剩余维度,比如宽度=高度(padToSquare)。

通过网络传递图像

我们可以简单地从图像创建一个blob并调用net . forward()正向传递输入并检索输出blob。

从输出blob中提取结果

为了泛化,输出blob将简单地表示为一个矩阵(cv.Mat),它的维数依赖于模型。Inception很简单。blob仅仅是一个1xN矩阵(其中N等于类的数量),它描述了所有类的概率分布。每个条目持有一个浮点数,代表对应类的置信度。这些条目总计增加到1.0(100%)。

我们想要更仔细地研究一下我们的图像最可能的类,因此我们正在寻找具有比minConfidence更大置信度的类(本例中为5%)。

这很容易实现,我们简单地将矩阵中的所有值设置为0.05,并查找所有未设置为零的条目(findNonZero)。最后,我们将根据置信度对结果进行排序,并利用置信度返回类名

测试

现在我们将读取一些我们希望网络识别的样本数据:

const testData = [ { image: '../data/banana.jpg', label: 'banana' }, { image: '../data/husky.jpg', label: 'husky' }, { image: '../data/car.jpeg', label: 'car' }, { image: '../data/lenna.png', label: 'lenna' }];testData.forEach((data) => { const img = cv.imread(data.image); console.log('%s: ', data.label); const predictions = classifyImg(img); predictions.forEach(p => console.log(p)); console.log(); cv.imshowWait('img', img);});

如果我们对每个图像进行预测,我们将得到以下输出(或查看标题图像):

banana:banana (0.95)husky:Siberian husky (0.78)Eskimo dog (0.21)car:sports car (0.57)racer (0.12)lenna:sombrero (0.34)cowboy hat (0.3)

相当有趣。我们对哈士奇和香蕉图像的内容有一个很精确的描述。对于汽车来说,我们可能会得到不同种类的汽车,但我们可以肯定地说,这是辆汽车一定在图像中出现。当然,网络不能在无限的类上被训练,这就是为什么它没有返回一些像“女人”这样的描述。然而,它识别出了这顶帽子。

COCO SSD

这很有效,但是我们如何处理显示多个对象的图像呢。为了在单个图像中识别多个对象,我们将使用所谓的单镜头多盒探测器(SSD)。在我们的第二个示例中,我们将研究一个SSD模型,它与COCO(环境中的通用对象)数据集进行了训练。我们使用的模型已经训练了84个不同的类。

COCO数据集地址:http://cocodataset.org/

由于这是一个Caffe模型,我们必须加载一个二进制的VGG_coco_SSD_300x300_iter_400000.caffemodel和一个 protoxt文件deploy.prototxt:

// replace with path where you unzipped inception modelconst ssdcocoModelPath = '../data/dnn/coco-SSD_300x300'const prototxt = path.resolve(ssdcocoModelPath, 'deploy.prototxt');const modelFile = path.resolve(ssdcocoModelPath, 'VGG_coco_SSD_300x300_iter_40000

0.caffemodel');if (!fs.existsSync(prototxt) || !fs.existsSync(modelFile)) { console.log('exiting: could not find ssdcoco model'); console.log('download the model from: https://drive.google.com/file/d/0BzKzrI_

SkD1_dUY1Ml9GRTFpUWc/view'); return;}// initialize ssdcoco model from prototxt and modelFileconst net = cv.readNetFromCaffe(prototxt, modelFile);

利用COCO进行分类

我们的分类函数看起来与初始阶段大致相同,但这次输入将是300×300图像,输出将是1x1xNx7矩阵。

const classifyImg = (img) => { const white = new cv.Vec(255, 255, 255); // ssdcoco model works with 300 x 300 images const imgResized = img.resize(300, 300); // network accepts blobs as input const inputBlob = cv.blobFromImage(imgResized); net.setInput(inputBlob); // forward pass input through entire network, will return // classification result as 1x1xNxM Mat let outputBlob = net.forward(); // extract NxM Mat outputBlob = outputBlob.flattenFloat(outputBlob.sizes[2], outputBlob.sizes[3]); const results = Array(outputBlob.rows).fill(0) .map((res, i) => { const className = classNames[outputBlob.at(i, 1)]; const confidence = outputBlob.at(i, 2); const topLeft = new cv.Point( outputBlob.at(i, 3) * img.cols, outputBlob.at(i, 6) * img.rows ); const bottomRight = new cv.Point( outputBlob.at(i, 5) * img.cols, outputBlob.at(i, 4) * img.rows ); return ({ className, confidence, topLeft, bottomRight }) }); return results;};

我不太清楚为什么输出是1x1xNx7矩阵,但实际上我们只对Nx7部分感兴趣。为了将第3和第4维度映射到一个2D矩阵中,我们可以使用flattenFloat utility。将这个与Inception 初始输出矩阵进行比较,这个次数N并不对应于每个类,而是对应于检测到的每个对象。此外,我们最终得到了每个对象的7个条目。

为什么是7项?

记住,这里的问题有点不同。我们想要检测每个图像的多个对象,因此我们不仅可以给每个类一个置信度。我们实际想要的是一个表示图像中每个对象位置的矩形。下面你可以找到每个条目对应的内容:

.我真的不知道。

1.工作对象的类标签

2.置信度

3.矩形的最左x

4.矩形底部的y

5.矩形最右边的x

6.矩形顶部的y

输出矩阵给出了一些关于结果的非常简洁的信息。我们可以再次通过置信度来过滤结果,并将矩形绘制成每个识别对象的图像。

行动过程

为了简单起见,我将跳过绘制矩形和其他所有用于可视化的内容的代码。如果你想知道怎么做,你可以看看样本代码。

让我们把汽车的图像输入网络,然后用分类名称 car 来过滤结果:

好了!现在做一些有难度的。让我们尝试…早餐桌上的物品?

结语

这就是使用OpenCV和Node.js来神经网络识别图像中物体的过程。如果你用它来进行娱乐,我建议你去看看 Caffe Model Zoo,它为不同的使用案例提供了一些训练过的模型,你可以下载。

Caffe Model Zoo地址:https://github.com/BVLC/caffe/wiki/Model-Zoo

本文来自企鹅号 - ATYUN订阅号媒体

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大数据挖掘DT机器学习

分类-回归树模型(CART)在R语言中的实现

CART模型 ,即Classification And Regression Trees。它和一般回归分析类似,是用来对变量进行解释和预测的工具,也是数据挖掘中...

83840
来自专栏机器学习和数学

[机智的机器在学习] TensorFlow实现Kmeans聚类

对于机器学习算法来说,主要分为有监督学习和无监督学习,前面有篇文章介绍过机器学习算法的分类,不知道的童鞋可以去看看。然后今天要讲的Kmeans算法属于无监督算法...

1.4K130
来自专栏人工智能头条

基于Python的卷积神经网络和特征提取

46740
来自专栏数据派THU

独家 | 手把手教TensorFlow(附代码)

上一期我们发布了“一文读懂TensorFlow(附代码、学习资料)”,带领大家对TensorFlow进行了全面了解,并分享了入门所需的网站、图书、视频等资料,本...

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

详解循环神经网络RNN(理论篇)

让我们从一个问题开始,你能理解下面这句英文的意思吗?“working love learning we on deep”,答案显然是无法理解。那么下面这个句子呢...

12330
来自专栏Coding迪斯尼

启动网络的自我训练流程,展示网络数字图片识别效果

16340
来自专栏崔庆才的专栏

深度学习效果不好?试试 Batch Normalization 吧!

Batch Normalization(简称BN)自从提出之后,因为效果特别好,很快被作为深度学习的标准工具应用在了各种场合。BN大法虽然好,但是也存在一些局...

1.5K30
来自专栏个人分享

C4.5决策树算法概念学习

•分类(Classification)就是按照某种标准给对象贴标签,再根据标签来区分归类,类别数不变。

18720
来自专栏PaddlePaddle

转载|使用PaddleFluid和TensorFlow训练序列标注模型

上一篇通过转载|使用PaddleFluid和TensorFlow训练RNN语言模型大家了解了:

13430
来自专栏数据派THU

独家 | 一文读懂TensorFlow基础

本文长度为7196字,建议阅读10分钟 本文为你讲解如何使用Tensorflow进行机器学习和深度学习。 1. 前言 深度学习算法的成功使人工智能的研究和应用取...

26570

扫码关注云+社区

领取腾讯云代金券