OpenCV 入门:用 Node.js 进行图片处理 (译文)

2017-03-20 19:36:33 +08:00
 darluc

在这篇 OpenCV 入门文章中,我将会向大家展示如何使用 Node.js 进行计算机视觉处理。并且结合实例讲解使用 OpenCV 这个开源库进行图像处理的基础方法。

目前,我正在完成我的硕士论文,其中使用到了 React Native ,神经网络,和 OpenCV 计算机视觉库。请允许我向你们展示一些我在使用 OpenCV 过程中学习到的一些东西。

计算机视觉是计算机科学中的一个领域,主要专注于使用不同的算法从图像和视频中获取数据。

计算机视觉在许多领域得到了广泛地应用,例如安全摄像头的运动跟踪,控制车辆进行自动驾驶,从图片或视频中识别或搜索对象。

要实现计算机视觉算法是一件非常繁复的工作,不过幸好有 OpenCV 这个非常好的开源库,此库起源于 1999 年,并一直发展到现在。

OpenCV 官方支持 C , C ++, Python 和 Java 。幸运的是,由 Peter Braden 领导的一群 Javascript 程序员开发了一个 Javascript 的 OpenCV 接口库,名为 node-opencv

利用该接口库,我们可以实现用于图像分析的 Node.js 应用。此库目前还没有实现所有的 OpenCV 特性 - 特别是 OpenCV 3 的一些特性 - 不过已经基本够用了。

安装

要在 Node.js 中使用 OpenCV 库,你得先进行全局安装。在 MacOS 上,你可以通过 Homebrew 来安装。在这篇文章中我安装并使用的是 OpenCV 的 2.4 版本。

译者注:由于译者实际使用的是 OpenCV 3.2.0 版本,故在边缘侦测部分的代码相对于原文有所修改。

brew tap homebrew/science
brew install opencv

如果你使用的是其它的操作系统,这里有 LinuxWindows 版本的教程。在成功安装之后,我们就可以在 Node.js 项目中安装 node-opencv 了。

npm install --save opencv

有时安装会失败(它是开源项目,还没有到达最终完成的阶段),不过你应该可以在该项目的 GitHub 页面上找到对应的解决办法。

OpenCV 基础

加载及保存图片 + 矩阵

OpenCV 的最基本功能是加载和保存图像。你可以通过下面的方法调用这些功能:cv#readImage() 和 **Maritx#save()**;

const cv = require('opencv');

cv.readImage('./img/myImage.jpg', function(err, img) {
  if (err) {
    throw err;
  }
  
  const width = im.width();
  const height = im.height();
  
  if (width < 1 || height < 1) {
    throw new Error('Image has no size');
  }
  
  // do some cool stuff with img
  
  // save img
  img.save('./img/myNewImage.jpg');
});

承载加载图片数据的对象,是 OpenCV 使用的一个基本数据结构 - 矩阵。所有载入和生成的图像都是用矩阵来描述的,矩阵中的每一个元素都对应图像的一个像素。矩阵的大小由载入图像的大小决定。在 Node.js 中你可以使用特定参数调用 new Matrix() 构造方法来生成一个矩阵。

new cv.Matrix(rows, cols);
new cv.Matrix(rows, cols, type, fillValue);

修改图像

变换图像颜色是一个基础方法。例如,我们可以调用 Matrix#convertGrayscale() 得到一个灰度图片。

img.convertGrayScale();
img.save('./img/myGrayscaleImg.jpg');

在进行边缘探测时经常会用到这个方法。

我们可以使用 Matrix#convertHSVscale() 方法将图像转换为 HSV 圆柱坐标表示( HSV cylindrical-coordinate representation )。

img.convertHSVscale();
img.save('./img/myHSVscaleImg.jpg');

我们可以使用 Matrix#crop(x, y, width, height) 方法来裁剪图片,并指定其中的参数。

这个方法并不会改变当前的图像,而是返回一个全新的图像。

let croppedImg = img.crop(1000, 1000, 1000, 1000);
croppedImg.save('./img/croppedImg');

如果我们想要将图像对象赋值给另一个变量,可以使用 Matrix#copy() 方法返回一个新的图片对象。

let newImg = img.copy();

这样,我们可以用一些基础的 Matrix 方法进行工作了。我们还能找到各种模糊和滤镜方法来进行图片编辑。你可以在 GitHub 项目里的 Matrix.cc 文件中找到 Matrix 对象实现的所有方法。

腐蚀和膨胀

腐蚀和膨胀是数学形态学( mathematical morphology )的基本方法。我将结合下面的图像修改操作来解释它们是如何工作的。(译者注:具体数学定义可参考此文

二进制图像 A 通过结构元素 B 的膨胀定义如下

OpenCV 有一个 Matrix#dilate(iterations, structEl) 方法,其中的 iterations 参数指定膨胀的量,structEl 参数是用于膨胀的结构元素(默认为 3X3 )。

我们可以用此参数调用膨胀方法。

img.dilate(3);

OpenCV 调用膨胀方法时如下。

cv::dilate(self->mat, self->mat, sturctEl, cv::Point(-1, -1), 3);

调用过此方法后,我们可以得到如下修改过的图像。

二进制图像 A 通过结构元素 B 的腐蚀定义如下

在 OpenCV 中,我们可以调用 Martix#erode(iterations, structEl) 方法,和前面的膨胀方法相似。

我们可以这样调用它:

img.erode(3);

同样我们可以得到一个腐蚀过的图像。

边缘侦测

关于边缘侦测,我们可以使用「坎尼边缘探测算法」。该算法起源于 1986 年,并且一个非常流行,被称作「最佳探测器」。算法规定了边缘侦测中三个重要的标准,列举如下:

  1. 边缘侦测要保证低错误率;
  2. 良好的边缘定位 - 探测到的边缘和实际边缘像素差必须最小;
  3. 图像的边缘只能被标记一次;

在使用「坎尼边缘探测算法」前,我们可以先将图像转为灰度格式,通常这样做可以让我们获得更好的结果。接下来,我们可以通过高斯模糊滤镜消除图像上的噪点,它需要一个向量作为高斯核大小的参数( which receives a parameter as a field - Gaussian kernel size )。再调用这两个方法处理过后,我们可以在坎尼边缘侦测时获得更好更准确的结果。

点击阅读全文

翻译自:OpenCV tutorial: Computer vision with Node.js

11066 次点击
所在节点    Node.js
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/348922

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX