在这篇 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
如果你使用的是其它的操作系统,这里有 Linux 和 Windows 版本的教程。在成功安装之后,我们就可以在 Node.js 项目中安装 node-opencv 了。
npm install --save opencv
有时安装会失败(它是开源项目,还没有到达最终完成的阶段),不过你应该可以在该项目的 GitHub 页面上找到对应的解决办法。
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 年,并且一个非常流行,被称作「最佳探测器」。算法规定了边缘侦测中三个重要的标准,列举如下:
在使用「坎尼边缘探测算法」前,我们可以先将图像转为灰度格式,通常这样做可以让我们获得更好的结果。接下来,我们可以通过高斯模糊滤镜消除图像上的噪点,它需要一个向量作为高斯核大小的参数( which receives a parameter as a field - Gaussian kernel size )。再调用这两个方法处理过后,我们可以在坎尼边缘侦测时获得更好更准确的结果。