0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

node.js在训练好的神经网络模型识别图像中物体的方法

zhKF_jqr_AI 2018-04-06 13:11 次阅读

编者按:opencv4nodejs及face-recognition.js维护者Vincent Mühler介绍了如何在Node.js环境下使用训练好的神经网络模型识别图像中的物体。

今天我们将看看Node.js的OpenCV深度神经网络模块。

如果你希望释放神经网络的魔力,来辨识和分类图像中的物体,却对深度学习是如何工作的毫无头绪(像我一样),更不知道如何创建和训练神经网络,那么本文正适合你!

所以我们今天将创建什么?

在这一篇教程中,我们将了解如何通过OpenCV的DNN模块,从Tensorflow和Caffe加载预训练的模型,然后我们将深入两个基于Node.js和OpenCV进行物体识别的例子。

首先我们将使用Tensorflow的Inception模型来辨识图像中的物体,之后我们将使用COCO SSD模型检测和辨识同一图像中的多个不同物体。

你可以在我的github仓库上找到样例代码:justadudewhohacks/opencv4nodejs

Tensorflow Inception

训练过的Tensorflow Inception模型可以辨别约1000个分类的物体。如果你将图像传入网络,它将给出图像中的物体的每个分类的似然。

要在OpenCV下使用Inception模型,我们需要加载二进制文件tensorflow_inception_graph.pb以及分类名称列表imagenet_comp_graph_label_strings.txt。你可以下载inception5h.zip并解压以获得这些文件(下面的代码内有下载链接):

// 替换路径为你解压缩inception模型的路径

const 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('退出: 找不到inception模型');

console.log('从以下网址下载模型: https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip');

return;

}

// 读取classNames(分类名称),然后在数组中储存它们

const classNames = fs.readFileSync(classNamesFile).toString().split(" ");

// 从modelFile初始化tensorflow inception模块

const net = cv.readNetFromTensorflow(modelFile);

分类图像中的物品

为了分类图像中的物品,我们将编写以下帮助函数:

const classifyImg = (img) => {

// inception模型使用224 x 224 图像,

// 因此我们调整输入图像的大小,

// 并使用白像素补齐图像

const maxImgDim = 224;

const white = new cv.Vec(255, 255, 255);

const imgResized = img.resizeToMax(maxImgDim).padToSquare(white);

// 网络接受blob作为输入

const inputBlob = cv.blobFromImage(imgResized);

net.setInput(inputBlob);

// 前向传播输入至整个网络,

// 将返回包含每个分类的置信度的1xN矩阵分类结果

const outputBlob = net.forward();

// 找到大于最小置信度的所有标签

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((r0, r1) => r1.confidence - r0.confidence)

.map(res => `${res.className} (${res.confidence})`);

return result;

}

这一函数做了这些事:

准备输入图像

Tensorflow Inception网络接受224x224大小的输入图像。因此我们调整图像大小,使其最大边的大小为224,然后用白像素补齐。

让图像穿过网络

我们可以直接从图像创建blob,然后调用net.forward()前向传播输入,然后获取输出blob.

从输出blob提取结果

为了通用性,输出blob的表达形式直接是矩阵(cv.Mat),而它的维度取决于模型。在Inception下这很简单。blob不过是一个1xN矩阵(其中N等于分类数),描述了所有分类的概率分布。每个条目为一个浮点数,表示相应分类的置信度。所有条目相加,总和为1.0(100%)。

我们想仔细看看图像可能性最大的分类,因此我们查看所有置信度大于minConfidence(这个例子中是5%)。最后,我们根据置信度排序结果,并返回className、confidence对。

测试

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

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

好,模型表现不错。但是我们如何处理包含多个物体的图像呢?为了辨识单一图像中的多个物体,我们将利用单图多盒检测器(Single Shot Multibox Detector, SSD)。在我们的第二个例子中,我们将查看一个在COCO(Common Object in Context)数据集上训练的SSD模型。我们使用的这一模型在84个不同分类上训练过。

这一模型来自Caffe,因此我们将加载二进制文件VGG_coco_SSD_300x300_iter_400000.caffemodel,以及protoxt文件deploy.prototxt:

// 替换路径为你解压缩coco-SSD模型的路径

const ssdcocoModelPath = '../data/dnn/coco-SSD_300x300'

const prototxt = path.resolve(ssdcocoModelPath, 'deploy.prototxt');

const modelFile = path.resolve(ssdcocoModelPath, 'VGG_coco_SSD_300x300_iter_400000.caffemodel');

if (!fs.existsSync(prototxt) || !fs.existsSync(modelFile)) {

console.log('退出: 找不到ssdcoco模型');

console.log('从以下网址下载模型 https://drive.google.com/file/d/0BzKzrI_SkD1_dUY1Ml9GRTFpUWc/view');

return;

}

// 从prototxt和modelFile初始化ssdcoco模型

const net = cv.readNetFromCaffe(prototxt, modelFile);

基于COCO分类

我们的分类函数和基于Inception的分类函数几乎一样,不过这次输入将是300x300的图像,而输出将是1x1xNx7矩阵。

const classifyImg = (img) => {

const white = new cv.Vec(255, 255, 255);

// ssdcoco模型接受300 x 300图像

const imgResized = img.resize(300, 300);

// 网络接受blob作为输入

const inputBlob = cv.blobFromImage(imgResized);

net.setInput(inputBlob);

// 前向传播输入至整个网络,

// 将返回1x1xNxM矩阵作为分类结果

let outputBlob = net.forward();

// 提取NxM矩阵

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部分。我们可以使用flattenFloat工具函数映射第三、第四维至2D矩阵。与Inception输出矩阵相比,这次N不对应每个分类,而是检测到的每个物体。另外,每个物体对应7个条目。

为什么是7个条目?

记住,这里我们遇到的问题和之前有点不一样。我们想要检测单张图像中的多个物体,因此我们不可能仅仅给出每个分类的置信度。我们实际上想要得到的是一个指示每个物体在图中的位置的矩形。7个条目分别为:

我其实毫无头绪

物体的分类标签

分类的置信度

矩形左端的x

矩形底部的y

矩形右端的x

矩形顶部的y

输出矩阵给了我们不少关于结果的信息,这看起来相当整洁。我们同样可以根据置信度再次过滤结果,并为每个辨识出的物体在图像中绘制边框。

看看它的效果!

出于行文的简洁,我将跳过绘制矩形的代码,以及其他可视化的代码。如果你想知道具体是怎么做的,可以访问前面提到的github仓库。

让我们传入一张汽车图像到网络,然后过滤结果,看看是否检测到了car分类:

很棒!下面提高一下难度。让我们试下……一张早餐桌?

很不错!

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 神经网络
    +关注

    关注

    42

    文章

    4765

    浏览量

    100608

原文标题:当Node.js遇上OpenCV深度神经网络

文章出处:【微信号:jqr_AI,微信公众号:论智】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    训练好神经网络用于应用的时候,权值是不是不能变了?

    训练好神经网络用于应用的时候,权值是不是不能变了????就是已经训练好神经网络是不是相当于得到一个公式了,权值不能变了
    发表于 10-24 21:55

    请问Labveiw如何调用matlab训练好神经网络模型呢?

    matlab训练好了一个神经网络模型,想在labview调用,请问应该怎么做呢?或者la
    发表于 07-05 17:32

    MATLAB训练好神经网络移植到STM32F407上

    MATLAB中进行了神经网络模型训练,然后将训练好模型的阈值和权值导出来,移植到STM32
    发表于 06-16 11:14

    基于深度神经网络的激光雷达物体识别系统

    的激光雷达物体识别技术一直难以嵌入式平台上实时运行。经纬恒润经过潜心研发,攻克了深度神经网络嵌入式平台部署所面临的算子定制与加速、量化策
    发表于 12-21 07:59

    图像预处理和改进神经网络推理的简要介绍

    为提升识别准确率,采用改进神经网络,通过Mnist数据集进行训练。整体处理过程分为两步:图像预处理和改进神经网络推理。
    发表于 12-23 08:07

    卷积神经网络模型发展及应用

    network,DBN)[24], 从此拉开了深度学习大幕。随着深度学习理论的研究和发展,研究人员提 出了一系列卷积神经网络模型。为了比较不同模型 的质量,收集并整理了文献
    发表于 08-02 10:39

    卷积神经网络简介:什么是机器学习?

    ,用于描述网络的方程也有 32 个偏差和 32 个权重。CIFAR神经网络是一种广泛用于图像识别任务的CNN。它由两种主要类型的层组成:卷积层和池化层,它们
    发表于 02-23 20:11

    node.jsjs要点总结

    (Non-blocking)或异步I/O 由于Node.js一个服务器端框架,所以它主要工作之一是处理浏览器请求。传统的I/O系统,每个请求的发出都是在上一请求到达之后才发出的。所以这被称为阻塞
    发表于 10-13 10:39 0次下载

    介绍Node.js应用全链路信息获取的方法

    这种技术,就是Node.js应用全链路追踪。它是 Node.js 涉及到复杂服务端业务场景,必不可少的技术保障。
    的头像 发表于 02-10 11:21 613次阅读

    node.js实战源码

    node.js实战源码
    发表于 05-16 18:06 1次下载

    卷积神经网络模型训练步骤

    卷积神经网络模型训练步骤  卷积神经网络(Convolutional Neural Network, CNN)是一种常用的深度学习算法,广泛应用于
    的头像 发表于 08-21 16:42 1642次阅读

    卷积神经网络如何识别图像

    多层卷积层、池化层和全连接层。CNN模型通过训练识别并学习高度复杂的图像模式,对于识别物体和进行
    的头像 发表于 08-21 16:49 1899次阅读

    神经网络图像识别的应用

    随着人工智能技术的飞速发展,神经网络图像识别领域的应用日益广泛。神经网络以其强大的特征提取和分类能力,为图像识别带来了革命性的进步。本文将
    的头像 发表于 07-01 14:19 629次阅读

    MATLAB如何使用训练好网络

    引言 本文中,我们将探讨如何在MATLAB中使用训练好神经网络神经网络是一种强大的机器学习技术,广泛应用于图像识别、自然语言处理、预测
    的头像 发表于 07-03 10:06 1060次阅读

    怎么对神经网络重新训练

    重新训练神经网络是一个复杂的过程,涉及到多个步骤和考虑因素。 引言 神经网络是一种强大的机器学习模型,广泛应用于图像识别、自然语言处理、语音
    的头像 发表于 07-11 10:25 430次阅读