WebAssembly封装C/C++代码含结构体 opencv Emscripten

业务需要,将C/C++算法代码集成到h5/小程序进行展示,需要进行WebAssembly封装成 .js和 .wasm

首先是C/C++代码和CMakeList.txt,都要进行修改,C/C++的那一套在Emscripten可是行不通的。

工程代码结构:CMakeList.txt, src/xxx.cpp, src/xxx.hpp。

1. ubuntu下安装Emscripten

git clone https://github.com/juj/emsdk.git
cd emsdk
./emsdk update
./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh
echo ${EMSCRIPTEN}

检查是否安装好查看emcc em++版本

emcc --version
em++ --version

2. opencv.js编译

source版的opencv里,需要进行opencv的js编译,来生成opencv.js opencv_js.js。

git clone https://github.com/opencv/opencv.git
cd opencv
python ./platforms/js/build_js.py build_js
python ./platforms/js/build_js.py build_wasm --build_wasm
python ./platforms/js/build_js.py --emscripten_dir ../emsdk/up/emscripten build_wasm --build_wasm

第一次build_wasm后可能会报错,index重定义导致冲突。

strings.h和bind.h不可修改,modules/js/bindings.cpp是生成的,可以修改:

emscripten::value_array<cv::Scalar_<double>> ("Scalar")
        .element(index<0>())
        .element(index<1>())
        .element(index<2>())
        .element(index<3>());

改成
emscripten::value_array<cv::Scalar_<double>> ("Scalar")
        .element(emscripten::index<0>())
        .element(emscripten::index<1>())
        .element(emscripten::index<2>())
        .element(emscripten::index<3>());

进去build_wasm文件下, 终端下 make,会显示编译成功。

在bin目录下有编译成功的opencv.js文件哈,大小7.4M左右。

3. Dockerfile

有简单的方法,Dockerfile搞定第1-2步,配置好环境。Dockerfile如下:

FROM trzeci/emscripten

ARG OPENCV_VERSION=4.1.0

RUN mkdir -p /third-party \
  && wget \
    -c https://github.com/opencv/opencv/archive/$OPENCV_VERSION.tar.gz \
    -O /third-party/opencv-$OPENCV_VERSION.tar.gz \
  && tar \
    -C /third-party/ \
    -xvf /third-party/opencv-$OPENCV_VERSION.tar.gz \
  && mv /third-party/opencv-$OPENCV_VERSION /third-party/opencv \
  && rm /third-party/opencv-$OPENCV_VERSION.tar.gz

WORKDIR /third-party/opencv
RUN python ./platforms/js/build_js.py build_wasm --build_wasm

还是docker配置更方便!

docker build -t images_test:0.1 .  
docker run -it --name=xxxx images_test:0.1

4. 编写CMakeList.txt

和C/C++的不太一样哦,主要是emscripten的配置。

cmake_minimum_required(VERSION 2.8)
project(ImageTest)

set( CMAKE_CXX_STANDARD 11 )

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release)
endif(NOT CMAKE_BUILD_TYPE)

include_directories( /third-party/opencv/include )
include_directories( /third-party/opencv/build_wasm )

file( GLOB opencv_include_modules "/third-party/opencv/modules/*/include" )
include_directories( ${opencv_include_modules} )

add_executable( ImageTest src/*.cpp src/*.hpp )
file( GLOB opencv_js "/third-party/opencv/build_wasm/lib/*.a" )
target_link_libraries( ImageTest ${opencv_js} )
set(COMPILE_FLAGS "-Wno-missing-prototypes")
set_target_properties( ImageTest PROPERTIES COMPILE_FLAGS ${COMPILE_FLAGS})

set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s WASM=1")
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -std=c++1z -O3 --llvm-lto 1")
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s ASSERTIONS=2")
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} --memory-init-file 0 -s TOTAL_MEMORY=134217728 -s ALLOW_MEMORY_GROWTH=1")
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} --bind")
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s ENVIRONMENT=web")
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s MODULARIZE")
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s EXPORT_ES6")

set_target_properties( ImageCheck PROPERTIES LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} --bind" )

5. cpp和hpp的编写配置

#include "ImageCheck.hpp"
#include <emscripten.h>
#include <emscripten/bind.h>


EMSCRIPTEN_BINDINGS(my_module)
{
    emscripten::value_object<imgTest>("imgTest")
        .field("xx1", &imgTest::xx1)
        .field("xx2", &imgTest::xx2)
        .field("xx3", &imgTest::xx3);
            
    emscripten::function("ImageTest", &ImageTest);
    //emscripten::function("ImageTest", select_overload<imgTest(const cv::Mat&)>(&ImageTest));
}

主要是增加EMSCRIPTEN_BINDINGS的声明。到js的声明是对象,不管类型。这里声明了 结构体 和 函数 。

cpp中输入接口的图像输入:

#include "ImageCheck.hpp"
#include <emscripten.h>
#include <emscripten/bind.h>


imgTest ImageTest(size_t img_data, int width, int height){ 
    auto data_array = reinterpret_cast<void *>(img_data);
    cv::Mat rgbaImage(height, width, CV_8UC4, data_array); // RGBA
    cv::Mat bgrImage;
    cv::cvtColor(rgbaImage, bgrImage, cv::COLOR_RGBA2BGR);

C++的结构体是:

struct imgTest {
    int xx1;  
    int xx2;        
    int xx3;   
};

6. 编译生成js 和wasm

进入工程目录:

mkdir build
cd build
emcmake cmake ..
emmake make

build里会生成js 和 wasm,之后可以用来前端集成了。

7. js如何传递图像数据给C++

在index.ts里编辑:

const buffer = my_module._malloc(cvMat.width * cvMat.height * 4);
my_module.HEAPU8.set(cvMat.data, buffer);
const result = my_module.ImageTest(buffer, cvMat.width, cvMat.height);
my_module._free(buffer);

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值