使用Node.js在深度学习中做图片预处理的方法

背景

最近在做一个和对象识别相关的项目,由于团队内技术栈偏向 JavaScript,在已经用 PythonTensorflow 搭建好了对象识别服务器后,为了不再增加团队成员维护成本,所以尽可能将训练和识别之外的任务交给 Node.js 来做,今天要讲到的图片预处理就是其中之一。

这里对还不了解深度学习的人就几个概念做个简单的解释

  1. 对象识别:对象识别可理解为计算机在一张图片中发现某个或某些指定的物体,比如找到里面所有的狗。
  2. 训练:计算机学会对象识别这个本领就像人类学会说话一样,需要不断地练习,深度学习中管这个过程叫做 “训练”。
  3. 训练集:人类学会说话需要看别人怎么说,听别人的声音等等,这些能够让自己学会说话的信息在深度学习中称为训练集,只不过对象识别中需要的训练集只有图片。

做图片预处理的目的是为了解决对象识别中训练集不足的问题。当对象识别应用于某个专用领域的时候,就会遇到这个问题。如果你是识别一只狗,这样的图片一大把,而且有人已经训练好了,并且可以提供服务给大家使用了。如果你是识别团队内的文化衫,这样的图片就太少了,费了老半天劲拍 100 张,这样的数据量依然少得可怜。要知道网上那些成熟的 AI 服务,训练集随随便便就成千上万,甚至以亿为单位。当然,专用领域一般需求也比较简单,需要识别出来的东西种类不多,特征也比较明显,但是仍然会希望训练集越大越好,这时候就可以对所拥有的图片做一些处理,来生成新的图片,从而扩充当前的训练集,这个过程就叫图片预处理了。

常见的图片预处理方式有以下几种:

  • 旋转。由于旋转的角度可以是任意值,所以需要随机生成一些角度来旋转,这又称为随机旋转。
  • 翻转。相当于在图片旁边放面镜子,新图片就是镜子内的图片,一般有水平翻转和竖直翻转两种。
  • 调节亮度。调节过手机的亮度就能体会这个意思。
  • 调节饱和度。调节过传统电视就能体会到这个意思,饱和度越高,色彩显示越鲜艳,反之给人一种冷色的感觉。
  • 调节色相。这个相当于给整个图片变颜色一样,想象一下以前调出来的绿色电视。
  • 调节对比度。这个会让图片亮的地方更亮,暗的地方更暗。也可以想象一下电视上的对比度调节,不得不说电视机启蒙了这些专业名词。

上述每项操作都需要视场景而选择,目前适用于我们团队的处理方式主要也就是上面这些。还有一些白化、Gamma 处理等操作,由于不是那么直观,有兴趣的人可以自己去了解。

安装 gm

gm是一个图片处理的 npm 库,性能在 Node.js 库中应该算佼佼者了,它底层默认使用的是 GraphicsMagick,所以你需要先安装 GraphicsMagick,在 Mac 系统中直接用 Homebrew 安装:

brew install graphicsmagick

其他系统的安装方式可以直接前往官网查看。

如果你需要在图片上添加文字,还需要安装 ghostscript,在 Mac 上可以用 brew install ghostscript 安装。由于本文没涉及到这一个功能,所以可以不用安装。

同时,需要将 gm 安装在你的项目下:

npm i gm -S

预处理

为了直观,我选了一张图片作为预处理对象:

另外,在本文的示例代码中,每种预处理方法的函数名都是参照 TensorflowImage 模块的同名方法而定,更多处理图片的方法可以前往 Tensorflow 文档官网自行查看,同时去 gm 官方文档 中寻找相同作用的方法。

翻转

沿 Y 轴翻转用到了 gm.flip 方法:

import gm from 'gm';

/**
 * 沿 Y 轴翻转,即上下颠倒
 * @param inputPath 输入的图像文件路径
 * @param outputPath 输出的图像文件路径
 * @param callback 处理后的回调函数
 */
function flip(inputPath, outputPath, callback) {
  gm(inputPath)
    .flip()
    .write(outputPath, callback);
}

翻转后的效果如下图所示:

沿 X 轴翻转用到了 gm.flop 方法:

import gm from 'gm';

/**
 * 沿 X 轴翻转,即上下颠倒
 * @param inputPath 输入的图像文件路径
 * @param outputPath 输出的图像文件路径
 * @param callback 处理后的回调函数
 */
function flop(inputPath, outputPath, callback) {
  gm(inputPath)
    .flop()
    .write(outputPath, callback);
}

翻转后的效果如下图所示:

你还可以把 .flip.flop 组合起来使用,形成对角线翻转的效果:

如果把原图看成一个前端组件,即一个购物按钮组,里面每个按钮的背景可以自定义,按钮里面由文字、分隔线、文字三种元素组成,那么上面翻转后的图片是可以看成同一个组件的,即可以拿来作为训练集。

有时候,翻转带来的效果并不是自己想要的,可能翻转后,和原来的图片就不应该视作同一个东西了,这时候这种方法就有局限性了。

调整亮度

相比之后,调整亮度就显得更加普适了,无论是什么图片,调整亮度后,里面的东西依然还是原来的那个东西。

调整亮度用到了 gm.modulate 方法:

/**
 * 调整亮度
 * @param inputPath 输入的图像文件路径
 * @param outputPath 输出的图像文件路径
 * @param brightness 图像亮度的值,基准值是 100,比 100 高则是增加亮度,比 100 低则是减少亮度
 * @param callback 处理后的回调函数
 */
function adjustBrightness(inputPath, outputPath, brightness, callback) {
  gm(inputPath)
    .modulate(brightness, 100, 100)
    .write(outputPath, callback);
}

.modulate 方法是一个多功能的方法,可以同时调整图片的亮度、饱和度和色相三种特性,这三种特性分别对应着该方法的三个参数,这里只调整亮度,所以只改变第一个参数(比 100 高则是增加亮度,比 100 低则是减少亮度),其他保持 100 基准值不变。

我把亮度从 0 - 200 的图片都生成了出来,并进行了对比,选出了一个亮度处理较为合适的区间。可以看看 0 - 200 之间相邻亮度相差为 10 的图片之间的差别(提示:每张图片的左上角标识出了该图片的亮度):

可以看到亮度为 60 以下的图片,都太暗了,细节不够明显,亮度为 150 以上的图片,都太亮了,也是细节不够明显。而经过多张图片综合对比之后,我认为 [60, 140] 这个区间的图片质量比较好,与原图相比不会丢失太多细节。

再来看看亮度为 50 和 60 的两张图片,其实看起来像是一张图片一样,不符合训练集多样性的原则,更何况是相邻亮度相差为 1 的两张图片。所以最终决定作为训练集的相邻两张图片亮度差为 20,这样差异就比较明显,比如亮度为 80 和亮度为 100 的两张图片。

最终,调节亮度产生的新图片将会是 4 张。从亮度为 60 的图片开始,每增加 20 亮度就选出来加入训练集,直到亮度为 140 的图片,其中亮度为 100 的图片不算。

调节饱和度

调节饱和度也是用 .modulate 方法,只不过是调节第二个参数:

/**
 * 调整饱和度
 * @param inputPath 输入的图像文件路径
 * @param outputPath 输出的图像文件路径
 * @param saturation 图像饱和度的值,基准值是 100,比 100 高则是增加饱和度,比 100 低则是减少饱和度
 * @param callback 处理后的回调函数
 */
function adjustSaturation(inputPath, outputPath, saturation, callback) {
  gm(inputPath)
    .modulate(100, saturation, 100)
    .write(outputPath, callback);
}

同样按调节亮度的方法来确定饱和度的范围以及训练集中相邻两张图片的饱和度相差多少。可以看看相邻饱和度相差为 10 的图片之间的差别(提示:每张图片的左上角标识出了该图片的饱和度):

调节饱和度的产生的图片细节没有丢,大多都能够用作训练集中的图片,与亮度一样,饱和度相差 20 的两张图片差异性明显。另外,饱和度大于 140 的时候,图片改变就不明显了。所以调节饱和度产生的新图片将会是 6 张。从饱和度为 0 的图片开始,每增加 20 饱和度就选出来加入训练集,直到饱和度为 140 的图片,其中饱和度为 100 的图片不算。

调节色相

调节色相的方法在此场景下是最有用的方法,产生的训练集最多,率先来看下色相相邻为 10 的图片之间的差距吧(提示:每张图片的左上角标识出了该图片的色相):

几乎每个图片都能作为新的训练集,由于色相调节范围只能在 0 - 200 之间,所以从色相为 0 的图片开始,每增加 10 色相就选出来加入训练集,直到色相为 190 的图片,其中色相为 100 的图片不算。 这样就能够产生 20 张图片作为训练集。

至于调节色相的代码则和亮度、饱和度一样,只是改变了第三个参数:

/**
 * 调整色相
 * @param inputPath 输入的图像文件路径
 * @param outputPath 输出的图像文件路径
 * @param hue 图像色相的值,基准值是 100,比 100 高则是增加色相,比 100 低则是减少色相
 * @param callback 处理后的回调函数
 */
function adjustHue(inputPath, outputPath, hue, callback) {
  gm(inputPath)
    .modulate(100, 100, hue)
    .write(outputPath, callback);
}

调节色相并不是万能的,只是适用于这个场景,当然,我们团队的需求都是类似这个场景的。但是,如果你要训练识别梨的人工智能,告诉它有个蓝色的梨显然是不合适的。

调节对比度

调整对比度用到了 gm.contrast 方法:

/**
 * 调整对比度
 * @param inputPath 输入的图像文件路径
 * @param outputPath 输出的图像文件路径
 * @param multiplier 调节对比度的因子,默认是 0,可以为负值,n 表示增加 n 次对比度,-n 表示降低 n 次对比度
 * @param callback 处理后的回调函数
 */
function adjustContrast(inputPath, outputPath, multiplier, callback) {
  gm(inputPath)
    .contrast(multiplier)
    .write(outputPath, callback);
}

下面是对比度因子从 -10 到 10 之间的图像,可以看到图片质量较好的区间是 [-5, 2],其他都会丢失一些细节。另外相邻对比度因子的图片之间的差异也比较明显,所以每张图片都可作为训练集,这样又多出 7 张图片。

总结

通过上述 5 种方法,可以在一张图片的基础上额外获得 40 张图片,即训练集是原来的 40 倍。这还是在没有多种方法混合使用的情况下,如果混合使用,恐怕几百倍都不止。

gm 还支持对图片进行其他处理方式,你可以自己去发掘,每种方式在特定场景下都有自己的局限性,需要你去甄选。希望大家都有一个自己满意的训练集。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • nodejs修复ipa处理过的png图片

    最近做项目遇到一个需求:解析apk和ipa包,然后把里面的icon上传到服务器. 问题 解析上传过程比较简单,我使用JSZip对apk和ipa进行解压,然后把找到里面的icon上传到服务器.但是,当我在网页中使用图片时,问题出现了.对于apk中的icon,没有任何问题,但是对于ipa中解析出来的图片,在safari中可以正常显示,在其他任何浏览器去无法显示. 原因 Google后发现,是苹果对png图片进行了优化处理,具体看这篇文章(查看),在文章中我们可以了解到一些有用信息: Apple us

  • nodejs处理图片的中间件node-images详解

    Cross-platform image decoder(png/jpeg/gif) and encoder(png/jpeg) for Node.js node.js轻量级跨平台图像编解码库 var images = require("images"); images("input.jpg") //Load image from file //加载图像文件 .size(400) //Geometric scaling the image to 400 pixels

  • angular.js+node.js实现下载图片处理详解

    前言 本文主要介绍的是angular.js+node.js实现下载图片处理,下载有两种方式,下面话不多说,来看看详细的介绍吧. 第一种: 不指定完整路径,然后发送get给server让server自己去拼接路径,然后用express的res.download来做下载: Express: var filePath = path.join(savePath, file[0].name); console.log('Download file: ' + filePath); res.download(

  • nodejs图片处理工具gm用法小结

    在做H5应用中,有时候会涉及到一些图片加工处理的操作,nodejs有一个很好的后台图片处理module,就是这里说的gm.gm有官方文档,但感觉写得太抽象,反而看不懂了.这里把一些常见的用法写下,供大家参考. 安装 首先要安装 GraphicsMagick或者ImageMagick,然后 npm install --save gm GraphicsMagick和ImageMagick的区别 GraphicsMagick是从ImageMagick中分离出来的,推荐下载ImageMagick 加载G

  • 轻松创建nodejs服务器(10):处理上传图片

    本节我们将实现,用户上传图片,并将该图片在浏览器中显示出来. 这里我们要用到的外部模块是Felix Geisendörfer开发的node-formidable模块.它对解析上传的文件数据做了很好的抽象. 要安装这个外部模块,需在cmd下执行命令: 复制代码 代码如下: npm install formidable 如果输出类似的信息就代表安装成功了: 复制代码 代码如下: npm info build Success: formidable@1.0.14 安装成功后我们用request将其引入

  • nodejs和php实现图片访问实时处理

    我在访问时光网.网易云音乐等网站时,发现将它们页面中的一些图片URL修改一下就可以得到不同尺寸的图片,于是思考了其实现方案,我的思路是:URL Rewrite + 实时处理 + 缓存,对用户请求的URL进行重写,然后利用图片处理类库对图片进行处理,接着缓存该尺寸图片并输出到浏览器.使用PHP和Node.js实现了一遍,基本达到了需要的效果. 1.Nginx+Node.js(express)实现 URL重写 这里Nginx主要是做一个URL重写和反向代理的功能,配置如下所示: location ~

  • 使用Node.js在深度学习中做图片预处理的方法

    背景 最近在做一个和对象识别相关的项目,由于团队内技术栈偏向 JavaScript,在已经用 Python 和 Tensorflow 搭建好了对象识别服务器后,为了不再增加团队成员维护成本,所以尽可能将训练和识别之外的任务交给 Node.js 来做,今天要讲到的图片预处理就是其中之一. 这里对还不了解深度学习的人就几个概念做个简单的解释 对象识别:对象识别可理解为计算机在一张图片中发现某个或某些指定的物体,比如找到里面所有的狗. 训练:计算机学会对象识别这个本领就像人类学会说话一样,需要不断地练

  • Node.js读写文件之批量替换图片的实现方法

    问题:文件夹A中有大量图片文件,需要用另外一个图片替换掉A中图片,但是命名保持不变. 手工的做法如下: 1)浏览器打开图片->2)另存为->3)目标文件夹->4)找到一个图片->5)替换->6)确定 然后,重复步骤2)和之后的步骤.不小心会漏掉或重复. 这么麻烦,使用node.js来处理改如何呢?代码如下: var fs=require('fs'), cp=require('child_process'); var url='Moriarty.jpg' var rs=fs.r

  • node.js读取Excel数据(下载图片)的方法示例

    前言 因为组织观影活动需要统计报名和收集影评,选择微信小程序"报名工具",管理员下载数据发现影评只是一个图片的URL链接,需要自己手动下载,哪里能难倒程序员? 1. 下载的Excel数据表: 2. 代码: const xlsx = require('xlsx'); const mkdirp = require('mkdirp'); const request = require('request'); const fs = require('fs'); const workbook =

  • node.js(express)中使用Jcrop进行图片剪切上传功能

    需求说明 简单来说就是要实现用户上传头像,并且要保存用户裁切后的部分作为用户头像. 第一步,选择图片: 第二步,在弹窗页面中展现并进行裁切: 第三步,点击"保存",上传服务器. 实现过程 说来有点坎坷,相当于做了2遍,走了弯路. 第1遍是用户一选择图片,就进行了上传,然后返回一个地址,所以在弹层上展现的图片已经是服务器上的图片了,然后进行裁切,再保存. 第2遍找到的一个方法,是在第1遍做到裁切处理时候想到的,即弹层展现的是用户机器上选择的图片,不用先上传,但是用image/base64

  • python 深度学习中的4种激活函数

    这篇文章用来整理一下入门深度学习过程中接触到的四种激活函数,下面会从公式.代码以及图像三个方面介绍这几种激活函数,首先来明确一下是哪四种: Sigmoid函数 Tahn函数 ReLu函数 SoftMax函数 激活函数的作用 下面图像A是一个线性可分问题,也就是说对于两类点(蓝点和绿点),你通过一条直线就可以实现完全分类. 当然图像A是最理想.也是最简单的一种二分类问题,但是现实中往往存在一些非常复杂的线性不可分问题,比如图像B,你是找不到任何一条直线可以将图像B中蓝点和绿点完全分开的,你必须圈出

  • Node.JS在命令行中检查Chrome浏览器是否安装并打开指定网址

    使用Windows命令行cmd可以指定浏览器打开网址.在node.js中使用start即可: 比如分别用Chrome和IE打开网址 start chrome http://www.google.cn start iexplore http://www.google.cn 但是当用户没有安装Chrome时使用start则会报错,并会弹出错误对话框: [Window Title] chrome [Content] Windows 找不到文件 'chrome'.请确定文件名是否正确后,再试一次. 如果

  • Node.js如何在项目中操作MySQL

    目录 1.在项目中操作 MySQL的步骤 2.安装与配置 mysql 模块 1.安装 mysql 模块 2.配置 mysql 模块 3.测试 mysql 模块能否正常工作 3.使用 mysql 模块操作 MySQL 数据库 1.查询数据 2.插入数据 3.插入数据的便捷方式 4.更新数据 5.更新数据的便捷方式 6.删除数据 7.标记删除 1.在项目中操作 MySQL的步骤 (1)安装操作 MySQL 数据库的第三方模块(mysql) (2)通过 mysql 模块连接到 MySQL 数据库 (3

  • 深度学习中shape[0]、shape[1]、shape[2]的区别详解

    深度学习中shape[0].shape[1].shape[2]的区别详解对于图像来说: img.shape[0]:图像的垂直尺寸(高度) img.shape[1]:图像的水平尺寸(宽度) img.shape[2]:图像的通道数 举例来说,下面是一张300X534X3的图像,我们用代码,进行验证. 代码如下: import matplotlib.image as mpimg # mpimg 用于读取图片 if __name__ == '__main__': img = mpimg.imread('

  • Java与Node.js利用AES加密解密出相同结果的方法示例

    前言 工作中遇到nodejs端通过aes加密,安卓客户端Java解密,同样nodejs也需要解密安卓客户端加密过来的内容,发现两个加密结果不一样,查询资料发现java端需要对密钥再MD5加密一遍,以下是Java与Node.js利用AES加密解密出相同结果的方法,需要的朋友们下面来一起学习学习吧. JAVA代码如下: package g.g; import java.security.MessageDigest; import javax.crypto.Cipher; import javax.c

  • js基础之DOM中元素对象的属性方法详解

    在 HTML DOM (文档对象模型)中,每个部分都是节点. 节点是DOM结构中最基本的组成单元,每一个HTML标签都是DOM结构的节点. 文档是一个    文档节点 . 所有的HTML元素都是    元素节点 所有 HTML 属性都是    属性节点 文本插入到 HTML 元素是    文本节点 注释是    注释节点. 最基本的节点类型是Node类型,其他所有类型都继承自Node,DOM操作往往是js中开销最大的部分,因而NodeList导致的问题最多.要注意:NodeList是'动态的',

随机推荐