OpenCV在Web端应用的实践文档

561 阅读10分钟

1、前言

计算机视觉

计算机视觉是人工智能 (AI) 的一个领域,是指让计算机和系统能够从图像、视频和其他视觉输入中获取有意义的信息,并根据该信息采取行动或提供建议。 如果说人工智能赋予计算机思考的能力,那么计算机视觉就是赋予发现、观察和理解的能力。

计算机视觉应用涵盖了多个方向,包括但不限于:

  • 图像分类和识别:顾名思义,就是辨别图像是什么,或者说图像中的物体属于什么类别,例如识别数字、物体等。
  • 目标检测:目标检测通常包含两方面的工作,首先是在图像中找到目标,然后就是识别目标。。
  • 人脸识别和人脸检测:包括人脸识别、人脸检测、人脸匹配、人脸对齐等等,这应该是计算机视觉方面最热门也是发展最成熟的应用,而且已经比较广泛的应用在各种安全、身份认证等,比如人脸支付、人脸解锁。这也是目前人脸在做的东西
  • 图像分割:图像分割是基于图像检测的,它需要检测到目标物体,然后把物体分割出来。。
  • 视频跟踪:跟踪视频序列中的对象,并估计它们的位置和运动。
  • 图像生成:图像生成是根据一张图片生成修改部分区域的图片或者是全新的图片的任务。
  • 图像重构:也称为图像修复(Image Inpainting),其目的就是修复图像中缺失的地方,比如可以用于修复一些老的有损坏的黑白照片和影片。通常会采用常用的数据集,然后人为制造图片中需要修复的地方

2,前端传统处理图像相关方法

前端传统处理图像的方式主要是利用canvas api进行相关图像处理,HTML5的Canvas元素提供了2D和3D绘图功能,可以通过JavaScript对图像进行处理、绘制和操作,

除了原生canvas api,一些基于Canvas封装的库,例如fabric.js、p5.js、paper.js等,也提供了图像处理功能和算法。使用Canvas API可以实现一些简单的图像处理效果,如图像滤镜、颜色调整等。

优点:

1,兼容性好,Canvas 是 HTML5 标准的一部分,浏览器原生支持,无需额外的插件或扩展。这使得 Canvas 处理图像具有广泛的兼容性和跨平台性,可以在各种现代浏览器中运行。

2,简单易用:Canvas API 提供了简单且易于理解的方法,使得图像处理任务变得简便。可以使用 JavaScript 直接操作 Canvas 元素,并使用 Canvas 的 2D 上下文进行图像绘制、像素级操作和简单的图像处理操作。

3,实时交互和排查:在Canvas元素支持实时渲染和交互,可以实时查看操作图像的效果。

4,可嵌入性:Canvas 元素可以轻松嵌入到网页中的其他元素中,与其他 HTML 元素和页面内容进行集成。这使得在网页中实现图像处理和展示变得简单,并可以与其他 Web 技术(如 CSS 和 JavaScript)进行交互

弊端:

1,性能和处理能力限制:Canvas 是基于像素的绘图技术,对于复杂的图像处理操作或处理大尺寸图像时,性能可能受限,例如一些图像缩放和非比例变形,可能会出现失真问题。图像处理的算法和操作在 JavaScript 中运行,可能导致较慢的处理速度和响应时间。除此之外,其只提供一些基本的图像处理能力,对于复杂的处理任务能力有限。

2,无法直接操作图像数据:在 Canvas 中,图像数据以像素的形式呈现,但不能直接访问和修改像素数据。图像数据通常需要通过 getImageData 和 putImageData 等方法来进行读取和写入。这可能导致对图像数据进行高级处理变得复杂和低效。

3,阻塞主线程问题:例如在人脸识别场景,需要保持视频流的流畅度,但是上面说到使用canvas处理较大图像耗时较长,是个大型计算,会阻塞主线程,所以可能会造成视频流卡顿,尤其是在移动设备中,卡顿更为明显。需要将这种针对图像的复杂操作放到webworker中,避免造成主线程的卡顿问题,但是在worker中只能使用OffscreenCanvas,而OffscreenCanvas的兼容性也很差。

3,WebAssembly(Wasm)方案

WebAssembly(简称 Wasm)是一种开放的、可移植的二进制格式,用于在现代Web浏览器中执行高性能的代码,WebAssembly 可以在各种操作系统和设备上运行,包括桌面、移动设备和嵌入式系统。这使得开发人员可以编写一次代码,然后在多个平台上部署和运行。基于此,我们可以使用C/C++、rust等语言编写出处理图像的代码或者利用现成的C/C++图像处理库,将其转唯Wasm,然后在浏览器上运行,弥补JS图像处理的弊端。

优点:

1,高性能和多语言选择性:与传统的 JavaScript 相比,通过编写 C/C++ 代码,可以获得更高的执行速度和更低的延迟,尤其是对于计算密集型任务 和需要频繁的数值计算。其次我们选择也变多起来,因为C/C++、rust有很多高性能计算机视觉库。

2,跨平台和兼容性:由于 WebAssembly 是一种标准化的跨平台格式,因此可以在各种操作系统和设备上运行,包括桌面、移动设备和嵌入式系统。 这为开发人员提供了一种跨平台的解决方案,使得使用 C/C++ 库的功能可以在不同的平台和环境中保持一致。

3,安全性:WebAssembly 通过提供严格的内存隔离和沙盒执行环境,确保了安全性。它可以在浏览器中运行不受信任的代码,而不会对用户设备或浏览器本身造成威胁。

4,可在webWorker中执行。可以将图像处理操作放到webWorker中,减少主线程的负担。

弊端:

1,需要额外的配置和维护:将 C/C++ 库和 WebAssembly 部署到前端应用中可能需要一些额外的步骤和配置。需要构建和编译 C/C++ 代码为 WebAssembly 模块,并将其与前端应用集成。

2,浏览器兼容性问题:WebAssembly 无法支持 Chrome 57 以下的版本,但可以覆盖所有 Firefox 52 以上版本,在较低版本,可能需要一些backup方案

3,额外工作和学习成本:WebAssembly 和 C/C++ 开发需要具备一定的编程技能和经验,这可能需要额外的学习和了解,增加了开发的复杂性和学习曲线。虽然 C/C++ 通常提供了更高的执行速度和更好的底层控制,但是可能需要你手动控制一些内存的释放工作。

总结:虽然Canvas api简单易用,但是其处理图像性能却是比较低,不适用于一些对性能要求较高的场景。

wasm方案虽然可以提供较好的性能,但是需要额外的学习成本和工作,以及要考虑兼容性问题。

4,opencv介绍

OpenCV (Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库。OpenCV 作为计算机视觉领域最为成熟的开源库,在实际业务中经常被运用于进行图像和视频处理。OpenCV 使用 C/C++ 进行编写,并且提供了 Python、Java、C#、Go、Javascript 等接口。他可以编译成wasm继而在浏览器上运行。

它包含了数百个计算机视觉算法。它有一个模块化的结构,囊括了几个共享的或静态的库,其中包括:

  • Core functionality(核心功能) :一个简洁基本且模块化的数据结构,包含了多维数组(矩阵)和用于其他模块的基本功能,例如矩阵的相乘、转置等功能。
  • Image processing(图像处理) :包括线性和非线性的图像滤波、几何图像转换(缩放、仿射和透视调整)、颜色模式转换、直方图等等。
  • Video(视频) :一个视频分析模块,其包含了运动估计、背景消除和目标跟踪算法。
  • Calib3d:提供基本的多视图几何算法、平面和立体影像校正、物体定位、立体通信算法和三维重建。
  • Features2d:显著特征探测器、描述符和描述符匹配器。
  • Objectect:检测对象和预定义的类的实例(例如:脸部、眼睛、杯子、人、车等等)。
  • Highgui(图形界面) :提供一个简单易用的UI。
  • Video I/O:提供一个简单易用的视频捕获和编码解码界面。
  • GPU:来自于不同的OpenCV模块的GPU加速算法。
  • ...... 一些其他的辅助模块,例如FLANN(神经网络)和Google测试封装等等。

我们知道opencv可以编译成Wasm,继而在web端运行,我们讲一下,如何编译成wasm。

5,opencv编译成wasm

我们上面说到c/c++的opencv库可以编译成wasm在浏览器上运行,而OpenCV.js 是将 C++ 版的 OpenCV 通过 Emscripten 编译为 WebAssembly 版本的 OpenCV.js 库,库地址github.com/TechStark/o…

但是直接引用这个包有一个问题,就是OpenCV 提供的预编译的版本或者默认编译下的 OpenCV.js 文件通常都比较大,通常需要 10MB 左右,整体体积会更大。这对于前端项目来说是难以接受的,每个用户在第一次打开该页面时需要加载 10MB 以上的资源,将会耗费较长时间。尤其是在人脸场景下,这会增加客户在前置的等待时间,所以我们需要对于包体积进行优化。

OpenCV 包含了非常丰富的各种图像处理的工具,但是在我们实际中可能并不会用到其中大部分的内容,所以可以在编译时对于需要编译的内容进行裁剪,只编译实际业务中所需要用到的部分。下面介绍下,自己手动编译opencv.js的过程,具体可参考docs.opencv.org/4.x/d4/da1/…

1,安装emsdk(Emscripten SDK)和cmake

emsdk 是用于开发和部署 WebAssembly 应用程序的工具包,而 CMake 则是一个构建工具,用于生成构建 WebAssembly 模块所需的构建系统文件。它们都是在 WebAssembly 开发过程中常用的工具,用于编译、构建和管理 WebAssembly 项目。

emsdk安装cmake安装

2,build

clone需要编译的opencv c++代码,代码库 github.com/opencv/open…

clone到本地后,(1)可以将platforms/js/build_js.py 文件中不需要的模块的编译状态置为OFF,使得opencv在编译为wasm中不编译此模块,以减少wasm的体积,如下图,将-DBUILD_opencv_dnn(神经网络相关)等关闭。

(2)可以在platforms/js/opencv_js.config.py文件中,将不需要的函数去掉,以减少打包体积,例如人脸这块只用到了Core functionality和Image processing相关模块, 可以将其他模块去除掉,如下:

完成这些后,就可以执行编译命令了,然后在项目根目录下通过命令 :

python3 platforms/js/build_js.py build_js --emscripten_dir <emscripten位置>/upstream/emscripten --build_wasm --clean_build_dir

编译即可得到我们的包,最后试了下,按照我们的要求最小可以打包到1.4M左右

3,使用

打包好的js文件返回的是一个promise,如下,返回的是一个promise(这个promise是异步加载其中wasm)。

所以可以使用script引入如下:

也可以通过import引入,但是会报如下错误

可以参考github.com/TechStark/o… 中的解决方案,在webpack中加入如下解决

引入之后,就可以在web端使用opencv的api了。