WebAssembly探索篇(四)emcc和cmake编译opencv复杂案例


    最近因为项目原因,研究了一下WebAssembly。2015年上线与JS、HTML、CSS并称web界四语言,额,虽然已经上线快10年,但是研究的人好少,注定这个探索之路是崎岖的。(事实也是这样,已经耗进去快2周了,人都麻了-_-||)
    这篇文章主要介绍在引用图像增强算法时遇到的一些问题,因涉及算法内容,以下代码将做一些处理。。。javaer表示知识的海洋真广阔呀~

开发环境

为啥要把开发环境放在第一位呢,这里面也是采了无数的坑。

开发工具版本
Ubuntu18.04
emscripten3.1.55
cmake3.28.3
opencv3.2.0

工程目录

┌─imageAlgorithm  项目名称 
│─build             编译文件(emcmake和emmake后的产物)
│  └─CMakeFile       
│  │  └─...      
│  └─cmake_install.cmake
│  └─CMakeCache.txt
│  └─Makefile
│  └─imageAlgorithm.js
│  └─imageAlgorithm.wasm
├─main.cpp          主入口
├─algorithm1.cpp          算法1
├─...           
├─algorithmN.cpp         算法N  
├─head1.h     算法1头文件 
├─headN.h 
├─CMakeLists.txt        

CMakeLists.txt


cmake_minimum_required( VERSION 3.8 )
set( CMAKE_CXX_STANDARD 17 )
project( imageAlgorithm )

# Needed for opencv2/opencv.hpp
include_directories( /root/wasm/opencv-demo/opencv/include )

# Needed by opencv.hpp for opencv2/opencv_modules.hpp
include_directories( /root/wasm/opencv-demo/opencv/platforms/js/build_wasm )

# Needed by opencv_modules.hpp for every module
file( GLOB opencv_include_modules "/root/wasm/opencv-demo/opencv/modules/*/include" )
include_directories( ${opencv_include_modules} )

# 此处将所有.cpp文件加入,此处省略下,可以把参与编译的cpp文件全部放在一个文件夹下面 
add_executable( imageAlgorithm main.cpp algorithm1.cpp algorithm2.cpp ... algorithmN.cpp)

# Link to opencv.js precompiled libraries
file( GLOB opencv_js "/root/wasm/opencv-demo/opencv/platforms/js/build_wasm/lib/*.a" )
target_link_libraries( imageAlgorithm ${opencv_js} )

set_target_properties(imageAlgorithm PROPERTIES LINK_FLAGS "-s EXIT_RUNTIME=1 -O3 -sNO_DISABLE_EXCEPTION_CATCHING -sALLOW_MEMORY_GROWTH -s EXPORTED_FUNCTIONS=\"['_postProcess', '_malloc', '_free', '_postProcess1']\"")

main.cpp

在编写过程中发现emscripten对C++支持度不够,不能直接暴露类的方法,所以不得不在最外面在包裹一层main.cpp

#include "algorithm.h"
#include <emscripten.h>

extern "C"  void postProcess1(unsigned char* image, int width, int height) {  
    
    // 创建一个 Mat 对象来存储传入的图像数据
    cv::Mat mat(height, width, CV_8UC4, image);
    // 将红色和绿色通道全部置零
    cv::MatIterator_<cv::Vec4b> it, end;
    for (it = mat.begin<cv::Vec4b>(), end = mat.end<cv::Vec4b>(); it != end; ++it) {
         (*it)[2] = 0; // 红色通道置零
         (*it)[1] = 0; // 绿色通道置零
    }
}

web端

使用emcc+cmake执行编译,将生成后的js和wasm文件拷贝至web项目中,web项目结构如下:

┌─web  项目名称 
│─imageAlgorithm.js          
│  imageAlgorithm.wasm    
│  index.html

index.html

主要变量的说明:

  • canvas1为原图,图片数据imageData
  • canvas2为经过算法处理后的图,图片数据postImageData
// 从canvas1中获取图像数据                  
const imageData = ctx.getImageData(0, 0, width, height);
// 获取图像的像素数组 
const pixelData = imageData.data;
var pixels = new Uint8Array(pixelData);
// 分配内存 
var dataptr = Module._malloc(pixelData.length);
Module.HEAPU8.set(pixels, dataptr);
// 调用C/C++算法处理
Module._postProcess1(dataptr, width, height);
 
// 设置canvas2的image对象
var postImageData = ctxNew.createImageData(width, height);
// 将像素数组数据从内存复制到 ImageData 对象
var imageDataArray = Module.HEAPU8.subarray(dataptr, dataptr + width * height * 4); // 假设每个像素有 RGBA 四个通道
postImageData.data.set(imageDataArray);
// 将 ImageData 对象绘制到 Canvas 上
ctxNew.putImageData(postImageData, 0, 0);

// 释放内存
Module._free(dataptr)

效果图

在这里插入图片描述

遇到的问题

JS与C++传值

2.4 JavaScript与C交换数据

真的没想到啊,两者之间只能传递Number!!!

需要在JavaScript与C/C++之间交换大块的数据时,直接使用参数传递数据显然不可行,此时可以通过内存来交换数据

Uncaught TypeError: Module._malloc is not a function

在JS中调用Module._malloc报错,理论上,Emscripten应该会把C/C++所有的默认方法都exported出来,为啥会报这个错误呢?

BUG: Uncaught TypeError: Module._malloc is not a function

在emscripten-core项目issue中找到相同问题,有个大佬回复了:版本升级到3.1.31后为了减小emscripten导出体积,把这些默认的导出配置cut掉了,需要开发者自行配置,看官方的changelog
于是乎改一下CMakeLists中的导出命令行,在EXPORTED_FUNCTIONS中加入_malloc_free

canvas像素RGBA四通道

在将前面所有坑都淌过一遍后,觉得自己离最终胜利只有0.1m的距离了,然而现实很残酷,调用算法后的效果图明显不是那么回事!于是乎,不得不从数据对比上下手,将web端和C++算法里的数据取间隔打印,然后终于发现问题点了!

从canvas获取的像素数据是RGBA,而算法中接收时使用CV_8UC3创建cv::Mat对象(这不是RGB么)
最终方案:在算法中进行处理,保证算法处理完图像指针的内容是4通道!

经验&&教训

  1. 官网上都是解决方案,耐心看
  2. 刚学习某方面的知识,可以去github上找demo
  3. 跟踪问题时,先从大的方面定位,然后逐步缩小范围
  4. 尝试在源码github的issue中寻找解决方案
  5. stackoverflow多看跟帖,必然有很多大佬回复

参考

一些有用的学习文档
WebAssembly
Emscripten-FAQ
emscripten-core github issues
C/C++面向WebAssembly编程

最后在吐槽一句,emscripten的知识真少啊~~~~ WebAssembly高级用法待后续探索,TBC~

  • 30
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这个问题看起来是在尝试使用EmscriptenOpenCV库时遇到的错误,具体来说是在尝试加载opencv2/opencv.hpp文件时找不到该文件。 Emscripten是一个将C++编译WebAssembly的工具,它允许你使用C++库在浏览器中运行。然而,由于Emscripten的限制,某些库可能无法直接在浏览器中运行。OpenCV库就是一个例子,它包含了许多C++的头文件和库文件,这些文件在浏览器环境中可能无法正确加载。 解决这个问题的方法通常有以下几种: 1. **使用Emscripten的替代库**:Emscripten提供了一些替代库,如Emscripten的图像处理库,可以用来替代OpenCV。你可以尝试使用这些替代库来代替OpenCV。 2. **将OpenCV库转换为WebAssembly**:有一些工具可以将OpenCV库转换为WebAssembly格式,这样就可以在浏览器中运行了。但是,这个过程可能会比较复杂,并且可能需要进行一些调整以适应浏览器环境。 3. **在服务器端使用OpenCV**:如果你的应用主要在服务器端运行,那么可以考虑将OpenCV库安装到服务器上,然后在服务器上使用它。 4. **重新考虑你的需求**:如果你的应用不需要用到OpenCV的某些功能,那么可能需要重新考虑你的需求,看看是否有其他库或方法可以满足你的需求。 对于这个具体的问题,我建议你检查你的环境是否正确安装了EmscriptenOpenCV库,以及是否正确设置了它们的路径。你可以尝试在命令行中运行一些简单的EmscriptenOpenCV代码来检查是否能够成功运行。 希望这些信息能够帮助你解决问题!如果你还有其他问题,欢迎随时向我提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值