月度归档:2022年04月

小程序使用最新版OpenCV教程

本文一步一步教你如何在小程序中使用最新版的OpenCV

安装基础软件

安装基础工具

pacman -S base-devel cmake git

安装以及配置emsdk

git clone https://github.com/juj/emsdk.git
cd emsdk
./emsdk install 2.0.10
./emsdk activate 2.0.10
source ./emsdk_env.sh

配置以及编译OpenCV

进入 https://opencv.org/releases/ 页面下载opencv最新版源码,并解压缩,并进入解压缩后文件夹

取消不需要的OpenCV模块,减少wasm体积

修改platforms/js/opencv_js.config.py文件根据情况,去掉不用的模块

# white_list = makeWhiteList([core, imgproc, objdetect, video, dnn, features2d, photo, aruco, calib3d])
white_list = makeWhiteList([core, imgproc])

配置OpenCV4输出独立的wasm文件

默认OpenCV4会将wasm以base64存到js文件,输出单独wasm文件便于用于微信小程序

打开modules/js/CMakeLists.txt,去掉 SINGLE_FILE参数

# set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s MODULARIZE=1 -s SINGLE_FILE=1")
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s MODULARIZE=1")

配置OpenCV禁用动态执行函数

微信小程序不支持eval()new Function()等动态执行函数,在modules/js/CMakeLists.txt中,增加DYNAMIC_EXECUTION的编译参数屏蔽这些函数的输出

# set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s MODULARIZE=1 -s SINGLE_FILE=1")
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s MODULARIZE=1")
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s DYNAMIC_EXECUTION=0")

查看编译参数

emcmake python ./platforms/js/build_js.py -h

编译OpenCV

emcmake python ./platforms/js/build_js.py build_wasm --build_wasm --build_test

build_wasm\bin目录生成了opencv.js,opencv_js.wasm,tests.html文件

压缩wasm

brotli -o build_wasm/bin/opencv_js.wasm.br build_wasm/bin/opencv_js.wasm

运行以及查看Web测试

npm i -g http-server
http-server build_wasm/bin/

在浏览器打开 http://127.0.0.1:8080/tests.html 可以查看测试结果

修改opencv.js适配微信小程序

修改前先将opencv.js格式化一下,微信小程序不支持通过url获取wasm,修改下instantiateAsync方法的else分支里面的代码,让读小程序项目下的opencv_js.wasm文件


        function instantiateAsync() {
          if (
            !wasmBinary &&
            typeof WebAssembly.instantiateStreaming === "function" &&
            !isDataURI(wasmBinaryFile) &&
            !isFileURI(wasmBinaryFile) &&
            typeof fetch === "function"
          ) {
            return fetch(wasmBinaryFile, { credentials: "same-origin" }).then(
              function (response) {
                var result = WebAssembly.instantiateStreaming(response, info);
                return result.then(
                  receiveInstantiatedSource,
                  function (reason) {
                    err("wasm streaming compile failed: " + reason);
                    err("falling back to ArrayBuffer instantiation");
                    return instantiateArrayBuffer(receiveInstantiatedSource);
                  }
                );
              }
            );
          } else {
            // return instantiateArrayBuffer(receiveInstantiatedSource);
            var result = WebAssembly.instantiate("/opencv/opencv_js.wasm.br", info);
            return result.then(
              receiveInstantiatedSource,
              function (reason) {
                err("wasm streaming compile failed: " + reason);
                err("falling back to ArrayBuffer instantiation");
                return instantiateArrayBuffer(receiveInstantiatedSource);
              }
            );
          }
        }

修改OpenCV.js的imread,imshow,VideoCapture方法支持小程序

这些方法定义在modules\js\src\helpers.js文件中,修改后重新编译和生成wasm文件即可

在小程序使用OpenCV.js

const app = getApp()
WebAssembly = WXWebAssembly;
let cv = require('../../opencv/opencv.js');

Page({
  onLoad: function (options) {
    if (cv instanceof Promise) {
      cv.then((target) => {
        console.log(target);
      })
    } else {
      console.log(cv);
    }
  }
})

参考