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

文章目录

  • 开发环境
  • 工程目录
    • CMakeLists.txt
    • main.cpp
  • web端
    • index.html
    • 效果图
  • 遇到的问题
    • JS与C++传值
    • Uncaught TypeError: Module._malloc is not a function
    • canvas像素RGBA四通道
  • 经验&&教训
  • 参考

    最近因为项目原因,研究了一下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~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/744929.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言——详解字符函数和字符串函数(一)

Hi,铁子们好呀&#xff01;今天博主来给大家更一篇C语言的字符函数和字符串函数~ 具体讲的内容如下&#xff1a; 文章目录 &#x1f386;1.字符分类函数&#x1f4af;&#x1f4af;⏩1.1 什么是字符分类函数的&#xff1f;&#x1f4af;&#x1f4af;⏩1.2 字符函数的类型有哪…

基于Python的中医药知识问答系统设计与实现

[简介] 这篇文章主要介绍了基于Python的中医药知识问答系统的设计与实现。该系统利用Python编程语言&#xff0c;结合中医药领域的知识和技术&#xff0c;实现了一个功能强大的问答系统。文章首先介绍了中医药知识的特点和传统问答系统的局限性&#xff0c;然后提出了设计思路…

【Java探索之旅】运算符解析 算术运算符,关系运算符

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; Java编程秘籍 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一、什么是运算符二、算术运算符2.1 基本四则运算&#xff08;-*/%&#xff09;2.2 增…

ThreadLocal基本原理

ThreadLocal基本原理 一、定义 ThreadLocal是java中所提供的线程本地存储机制&#xff0c;可以利用改机制将数据缓存在线程内部&#xff0c;该线程可以在任意时刻、任意方法中获取数据 二、底层原理 ThreadLocal底层是通过ThreadLocalMap来实现的&#xff0c;每个Thread对象中…

Java代码基础算法练习---2024.3.14

其实这就是从我学校的资源&#xff0c;都比较基础的算法题&#xff0c;先尽量每天都做1-2题&#xff0c;练手感。毕竟离我真正去尝试入职好的公司&#xff08;我指的就是中大厂&#xff0c;但是任重道远啊&#xff09;&#xff0c;仍有一定的时间&#xff0c;至少要等我升本之后…

安装nginx

Nginx ("engine x") 是一个高性能的HTTP和反向代理服务器&#xff0c;特点是占有内存少&#xff0c;并发能力强&#xff0c;事实上nginx的并发能力确实在同类型的网页服务器中表现较好&#xff0c;中国大陆使用nginx网站用户有&#xff1a;百度、京东、新浪、网易、腾…

Sui技术帮助Studio Mirai成功实现创意愿景

Brian和Ben Li兄弟对艺术充满热情&#xff0c;通过共同创立的研发工作室Studio Mirai&#xff0c;他们正在探索Web3技术与创意产业的交集。 Studio Mirai的第一个头像类项目&#xff08;profile picture&#xff0c;PFP&#xff09;Tamashi存在于Nozomi World中&#xff0c;这…

备战蓝桥杯Day25 - 二叉搜索树

一、基本概念 二叉搜索树&#xff08;Binary Search Tree&#xff09;&#xff0c;又称为二叉查找树或二叉排序树&#xff0c;是一种具有特定性质的二叉树。 定义&#xff1a;二叉搜索树可以是一棵空树&#xff0c;也可以是具有以下特性的非空二叉树&#xff1a; 若其左子树不…

【Memcached】

memcached 有一个很大的缺陷不能持久化&#xff0c;不能存储在硬盘里 1.NoSQL介绍 NoSQL是对 Not Only SQL、非传统关系型数据库的统称。 NoSQL一词诞生于1998年&#xff0c;2009年这个词汇被再次提出指非关系型、分布式、不提供ACID的数据库设计模式。 随着互联网时代的到…

个人信息方便后续使用

个人基本信息 姓名 性别 男 出生年月 1999/02 联系方式 所在院系 中国科学院大学计算机科学与技术学院 培养单位 沈阳自动化研究所 入学年份 2021 培养层次 硕士 邮箱 作品信息 作品名称 《顾方舟&#xff1a;为一大事来&#xff0c;成一大事去》 作品…

基于springboot+vue实现电子商务平台管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现电子商务平台管理系统演示 研究的目的和意义 据我国IT行业发布的报告表明&#xff0c;近年来&#xff0c;我国互联网发展呈快速增长趋势&#xff0c;网民的数量已达8700万&#xff0c;逼近世界第一&#xff0c;并且随着宽带的实施及降价&#xff0c;每天约有…

Python:自动化处理PDF文档集合,提取文献标题、合并文献PDF并生成目录和页码

Python&#xff1a;自动化处理PDF文档集合&#xff0c;提取文献标题、合并文献PDF并生成目录和页码 引言&#xff1a;功能概述步骤一&#xff1a;提取PDF标题步骤二&#xff1a;生成目录和页码&#xff0c;合并PDF技术亮点 代码步骤一&#xff1a;提取PDF标题&#xff08;Step_…

ROS 实时语音交互(一)ASR (流式识别)中文

目录 一、模型选择 二、流程 三、核心代码展示 背景&#xff1a;最近要做一个基于linux的语音交互&#xff0c;windows也可以跑通 一、模型选择 sherpa-ncnn 测试了四五个模型&#xff0c;只有这个模型比较好用&#xff0c;中文识别效果较好 这个模型好用./build/bin/sh…

Day63:WEB攻防-JS应用算法逆向三重断点调试调用堆栈BP插件发包安全结合

目录 前置知识 JS调试分析 JS分析调试结合Burp JS分析调试知识点&#xff1a; 1、JavaScript-作用域&调用堆栈 2、JavaScript-断点调试&全局搜索 3、JavaScript-Burp算法模块使用 前置知识 JS加密数据走向 浏览器调试 1、作用域&#xff1a;&#xff08;本地&全…

代码随想录算法训练营第四十七天|动态规划|198.打家劫舍、213.打家劫舍II、337.打家劫舍III

198.打家劫舍 文章 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报警。 给定一个代…

进程间通信的方式及原理

进程间通信&#xff08;Inter-Process Communication, IPC&#xff09;是指在多进程环境下&#xff0c;操作系统提供的一种机制&#xff0c;使得不同进程之间能够交换信息或同步它们的执行。由于每个进程都有自己的独立地址空间&#xff0c;并且操作系统为了保证进程的隔离性&a…

决策树 | 分裂算法:ID3,C4.5,CART

这里写目录标题 一. ID3算法1. 信息增益2. ID3算法特点 二. C4.5算法1. 信息增益率2. C4.5算法特点 三. CART算法1. Gini系数公式2. CART算法特点3. CART回归树的分裂评价指标 小节 在决策树算法逻辑篇中&#xff0c;我们讲解了决策树的构建方式&#xff0c;下面我们来聊一聊决…

不依赖第三方平台,用Dart语言实现 ios 消息推送

仅仅给大家提供代码,还搞不定的欢迎咨询。 void _sendIosPushNotification(BleMessage message, String deviceToken, {bool debugMode = false}) async {final Map<String, dynamic> header = {"alg": "ES256", "kid": GloabelConfigu…

Broken Keyboard (a.k.a. Beiju Text)(UVA 11988)

网址如下&#xff1a; Broken Keyboard (a.k.a. Beiju Text) - UVA 11988 - Virtual Judge (vjudge.net) &#xff08;第三方网站&#xff09; 刚刚开始我是用C的list来做的&#xff0c;不过里面的元素是char&#xff0c;直接TLE 说实话我有点震惊&#xff0c;这不是双端链表…

Day16 面向对象进阶——接Day15

Day16 面向对象进阶——接Day15 文章目录 Day16 面向对象进阶——接Day15一、抽象类及抽象方法二、接口三、多态四、对象转型五、内部类 一、抽象类及抽象方法 //抽象类 public abstract class 类名{//抽象方法public abstract void method(); }1、抽象方法交给非抽象的子类去…