编译使用OpenCV的js版本
OpenCV是图像处理开发者绕不过去的门槛,而现在web方式分发是一种主流的渠道,所以有必要编译一个javascript版本的OpenCV,就可以在Html5的应用中方便地进行图像处理了。这其中的技术自然是非常复杂,毕竟要把C++代码编译成可以在浏览器上跑的js代码。不过,这些底层的东西已经有前辈们封装好了,我们直接用就行。即使如此,在编译的过程中仍然会遇到一些问题,特此记录,以供后来参阅。建议在MacOS或者Linux下尝试,Windows平台下编译起来可能没这么简单。
1. 安装 Emscripten
这这套可行的解决方案中,需要emscripten组件的支持,这是一种可以将C/C++代码编译成javascript程序库的LLVM编译器。具体概念不清楚也无所谓,反正知道需要安装这个就行。
第一步:从github上下载emsdk
git clone https://github.com/emscripten-core/emsdk.git
第二步:进入到emsdk目录下,并执行安装指令
cd emsdk
./emsdk install latest
安装过程需要从网络下载一些东西,可能会有些慢。
第三步:安装完成后需要执行一条指令激活该软件
./emsdk activate latest
第四步:激活完成之后,还是不能正常使用,因为系统没有办法找到对应文件的路径,因此需要设置环境变量
source ./emsdk_env.sh
到此,emscripten工具就安装完成了。
2. 安装Java
这个安装工具链还会调用Java,建议安装较新一点的版本,这里查询一下本次安装使用的版本
java --version
openjdk 11.0.2 2019-01-15
OpenJDK Runtime Environment 18.9 (build 11.0.2+9)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.2+9, mixed mode)
3. 安装Python
编译OpenCV时,需要调用Python程序,所以也需要先安装Python。不过绝大部分的MacOS和Linux都已经安装了Python,因此主要检查一下就行
python --version
Python 3.7.7
4. 编译OpenCV的js版本
以上的emscripten+java+python都准备好之后,把OpenCV编译成js的工具链就搭建完成了。但是还有一个重要依赖,那就是OpenCV编译本身依赖的东西。所以,建议最好在将OpenCV编程成js之前,先把C++版本的OpenCV编译通过。这样各种需要的依赖就都齐全了。就可以正常执行下面的步骤。
第一步:从github下载最新的OpenCV代码,当然也可以用你需要的版本。
git clone https://github.com/opencv/opencv.git
第二步:进入opencv目录,执行编译操作,没想到报错了。
cd opencv
python ./platforms/js/build_js.py build_js
按照正常的逻辑应该会编译通过的,但是在添加环境变量时,使用的官方脚本“./emsdk_env.sh”不够完善,这里先看报了什么错:
报错1:
Cannot get Emscripten path, please specify it either by EMSCRIPTEN environment variable or --emscripten_dir option.
从报错信息可以知道是环境变量没设置,但是也给出了建议,这里为了避免麻烦,直接从命令行将这个路径设置传递进去。
解决方案:(不完善的)
需要指定EMSCRIPTEN的路径,这里使用命令行参数 –emscripten_dir=../emsdk来指定,结果报如下错误
正常逻辑应该是传送emsdk的安装目录,但是这样操作之后,又报了新的错误。
报错2:
CMake Error at /usr/local/Cellar/cmake/3.17.0_1/share/cmake/Modules/CMakeDetermineSystem.cmake:99 (message):
Could not find toolchain file:
/Users/jielyu/CodeStudio/web/emsdk/cmake/Modules/Platform/Emscripten.cmake
Call Stack (most recent call first):
CMakeLists.txt:106 (enable_language)
看这个报错信息说是找不到对应的cmake文件,显然是我们通过命令行传送进去的路径传错了。
解决办法:
python ./platforms/js/build_js.py --emscripten_dir ../emsdk/upstream/emscripten build_js
本次编译修改到这里就万事大吉了,坐等编译产出。
可能遇到
但是网上也有人说遇到了其他错误,可能与拉取OpenCV代码的时机有关。
如果报pthread相关的错误。
在编译脚本build_js.py的155行的位置添加flags += "-s USE_PTHREADS=0 "
除了使用 build_js 还可以使用 build_wasm。
构建WebAssembly版本
python ./platforms/js/build_js.py --emscripten_dir ../emsdk/upstream/emscripten build_wasm --build_wasm
但是我看两个编译出来的js文件大小完全一样,所以也就没有什么意义了。
5. 测试编译opencv.js
编译完成后会生成文件 build_js/bin/opencv.js,这就是我们需要的js版本的OpenCV。接下来的工作就是测试这个文件是否能够正常使用。
可以直接使用OpenCV的文档教程中提供的一个Html+js的例子
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello OpenCV.js</title>
</head>
<body>
<h2>Hello OpenCV.js</h2>
<p id="status">OpenCV.js is loading...</p>
<div>
<div class="inputoutput">
<img id="imageSrc" alt="No Image" />
<div class="caption">imageSrc <input type="file" id="fileInput" name="file" /></div>
</div>
<div class="inputoutput">
<canvas id="canvasOutput" ></canvas>
<div class="caption">canvasOutput</div>
</div>
</div>
<script type="text/javascript">
let imgElement = document.getElementById('imageSrc');
let inputElement = document.getElementById('fileInput');
inputElement.addEventListener('change', (e) => {
imgElement.src = URL.createObjectURL(e.target.files[0]);
}, false);
imgElement.onload = function() {
let mat = cv.imread(imgElement);
cv.imshow('canvasOutput', mat);
mat.delete();
};
function onOpenCvReady() {
document.getElementById('status').innerHTML = 'OpenCV.js is ready.';
}
</script>
<script async src="opencv.js" onload="onOpenCvReady();" type="text/javascript"></script>
</body>
</html>
直接将这段代码写入html 文件即可,注意该html文件要与opencv.js文件在相同目录下。直接打开这个html文件显示如下:

点击按钮,选择一张图片之后,显示的效果如下:

这个效果的实现原理是:先将选择的图片路径设置为img标签的src属性值,然后通过OpenCV从这个img标签读取图片数据,然后将OpenCV的Mat数据结构显示在canvas标签上。
6. 编译文档
这一步并不是必须的,不过还是记录一下。编译OpenCV自带的文档,需要使用到doxygen,在MacOS下安装很方便,直接执行一下指令即可:
brew install doxygen
安装完成之后,就可以返回到opencv的目录下执行编译文档的指令了。
python ./platforms/js/build_js.py --emscripten_dir ../emsdk/upstream/emscripten build_js --build_doc
编译完成后,根据终端中给出的信息,就可以找到文档的根html文件。
到此,将OpenCV编译成js库的过程就记录完成了。

COMMENT
博客评论区功能由Github Issue提供,提交Issue时请以本文标题为话题。
"BG101-编译使用OpenCV的js版本"