mirror of
https://github.com/sanyuered/WeChat-MiniProgram-AR-WASM.git
synced 2025-09-27 03:15:54 +08:00
added OpenCV
This commit is contained in:
27
README.md
27
README.md
@@ -2,20 +2,29 @@
|
||||
|
||||
| 日期 | 内容 |
|
||||
| -- | -- |
|
||||
| 2021-12-03 | 新增:微信小程序运行Go语言WebAssembly的示例。也包含网页运行Go语言的示例。 |
|
||||
| 2021-12-05 | 新增:微信小程序运行OpenCV的示例。也包含网页运行OpenCV的示例。 |
|
||||
| 2021-12-03 | 新增:微信小程序运行Go语言的示例。也包含网页运行Go语言的示例。 |
|
||||
|
||||
## 介绍
|
||||
|
||||
将Go语言编译为WebAssembly,使用微信小程序的WXWebAssembly功能运行WebAssembly。
|
||||
1、将Go语言编译为WebAssembly,使用微信小程序的WXWebAssembly功能运行WebAssembly。
|
||||
|
||||
因为Go语言能快速开发WebAssembly,所以使用Go语言能为小程序快速开发WebAssembly。
|
||||
|
||||
2、在微信小程序中使用WebAssembly版的OpenCV,让我们开发图像视觉。
|
||||
|
||||
[WXWebAssembly官方文档](https://developers.weixin.qq.com/miniprogram/dev/framework/performance/wasm.html)
|
||||
|
||||
## 网页版
|
||||
|
||||
在线预览,和小程序版使用的是相同的wasm文件。
|
||||
|
||||
运行Go
|
||||
|
||||
[https://sanyuered.github.io/WeChat-MiniProgram-AR-WASM/go_dev/lesson1.html](https://sanyuered.github.io/WeChat-MiniProgram-AR-WASM/go_dev/lesson1.html)
|
||||
|
||||
运行OpenCV
|
||||
|
||||
[https://sanyuered.github.io/WeChat-MiniProgram-AR-WASM/go_dev/lesson1.html](https://sanyuered.github.io/WeChat-MiniProgram-AR-WASM/go_dev/lesson1.html)
|
||||
|
||||
## 小程序版
|
||||
@@ -50,6 +59,20 @@ Go运行时,会调用小程序的console.log()输出信息。
|
||||
|
||||

|
||||
|
||||
## 小程序调用OpenCV的函数。
|
||||
|
||||
灰度化
|
||||
|
||||

|
||||
|
||||
边缘检测
|
||||
|
||||

|
||||
|
||||
特征点检测
|
||||
|
||||

|
||||
|
||||
## 目录结构
|
||||
|
||||
/:小程序一侧的源代码
|
||||
|
BIN
package_lesson2/assets/opencv3.4.16.wasm.br
Normal file
BIN
package_lesson2/assets/opencv3.4.16.wasm.br
Normal file
Binary file not shown.
9653
package_lesson2/assets/opencv_exec.js
Normal file
9653
package_lesson2/assets/opencv_exec.js
Normal file
File diff suppressed because it is too large
Load Diff
BIN
package_lesson2/assets/sampleImage1.jpg
Normal file
BIN
package_lesson2/assets/sampleImage1.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
151
package_lesson2/index.js
Normal file
151
package_lesson2/index.js
Normal file
@@ -0,0 +1,151 @@
|
||||
// 画布
|
||||
const canvas1 = 'canvas1'
|
||||
// 示例图片
|
||||
const sampleImage1 = './assets/sampleImage1.jpg'
|
||||
// 画布最大宽度
|
||||
const maxCanvasWidth = 375
|
||||
// wasm路径
|
||||
global.wasm_url = '/package_lesson2/assets/opencv3.4.16.wasm.br'
|
||||
// opencv_exec.js会从global.wasm_url获取wasm路径
|
||||
let cv = require('./assets/opencv_exec.js');
|
||||
|
||||
Page({
|
||||
// 画布的dom对象
|
||||
canvasDom: null,
|
||||
data: {
|
||||
canvas1Width: 375,
|
||||
canvas1Height: 150,
|
||||
// 示例图片
|
||||
sampleImage1Url: sampleImage1,
|
||||
},
|
||||
onReady() {
|
||||
// 可见的画布
|
||||
this.initCanvas(canvas1)
|
||||
},
|
||||
// 获取画布
|
||||
initCanvas(canvasId) {
|
||||
var _that = this;
|
||||
wx.createSelectorQuery()
|
||||
.select('#' + canvasId)
|
||||
.fields({ node: true, size: true })
|
||||
.exec((res) => {
|
||||
const canvas2d = res[0].node;
|
||||
// 设置画布的宽度和高度
|
||||
canvas2d.width = res[0].width;
|
||||
canvas2d.height = res[0].height;
|
||||
_that.canvasDom = canvas2d
|
||||
});
|
||||
},
|
||||
// 获取图像数据和调整图像大小
|
||||
getImageData(image,offscreenCanvas) {
|
||||
var _that = this
|
||||
// const ctx = wx.createCanvasContext(canvasId);
|
||||
var canvasWidth = image.width;
|
||||
if (canvasWidth > maxCanvasWidth) {
|
||||
canvasWidth = maxCanvasWidth;
|
||||
}
|
||||
// canvas Height
|
||||
var canvasHeight = Math.floor(canvasWidth * (image.height / image.width));
|
||||
// 离屏画布的宽度和高度不能小于图像的
|
||||
offscreenCanvas.width = canvasWidth;
|
||||
offscreenCanvas.height = canvasHeight;
|
||||
// draw image on canvas
|
||||
var ctx = offscreenCanvas.getContext('2d')
|
||||
ctx.drawImage(image, 0, 0, canvasWidth, canvasHeight);
|
||||
// get image data from canvas
|
||||
var imgData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
|
||||
|
||||
return imgData
|
||||
},
|
||||
// 创建图像对象
|
||||
async createImageElement(imgUrl) {
|
||||
var _that = this
|
||||
// 创建2d类型的离屏画布(需要微信基础库2.16.1以上)
|
||||
var offscreenCanvas = wx.createOffscreenCanvas({type: '2d'});
|
||||
const image = offscreenCanvas.createImage();
|
||||
await new Promise(function (resolve, reject) {
|
||||
image.onload = resolve
|
||||
image.onerror = reject
|
||||
image.src = imgUrl
|
||||
})
|
||||
const imageData = _that.getImageData(image,offscreenCanvas)
|
||||
return imageData
|
||||
},
|
||||
imgProcess1(imageData, canvasDom) {
|
||||
// 读取图像
|
||||
let src = cv.imread(imageData);
|
||||
let dst = new cv.Mat();
|
||||
// 灰度化
|
||||
cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY, 0);
|
||||
// 显示图像
|
||||
cv.imshow(canvasDom, dst);
|
||||
// 回收对象
|
||||
src.delete();
|
||||
dst.delete()
|
||||
},
|
||||
imgProcess2(imageData, canvasDom) {
|
||||
let src = cv.imread(imageData);
|
||||
let dst = new cv.Mat();
|
||||
|
||||
// 灰度化
|
||||
cv.cvtColor(src, src, cv.COLOR_RGBA2GRAY, 0);
|
||||
// 边缘检测
|
||||
cv.Canny(src, dst, 50, 100, 3, false);
|
||||
|
||||
cv.imshow(canvasDom, dst);
|
||||
src.delete();
|
||||
dst.delete()
|
||||
},
|
||||
imgProcess3(imageData, canvasDom) {
|
||||
let src = cv.imread(imageData);
|
||||
let dst = new cv.Mat();
|
||||
|
||||
// 灰度化
|
||||
cv.cvtColor(src, src, cv.COLOR_RGBA2GRAY, 0);
|
||||
|
||||
var orb = new cv.ORB();
|
||||
var keypoints = new cv.KeyPointVector();
|
||||
var descriptors = new cv.Mat();
|
||||
// 特征点
|
||||
orb.detect(src, keypoints)
|
||||
// 特征点的描述因子
|
||||
orb.compute(src, keypoints, descriptors)
|
||||
// 绘制特征点
|
||||
cv.drawKeypoints(src, keypoints, dst)
|
||||
|
||||
cv.imshow(canvasDom, dst);
|
||||
src.delete();
|
||||
dst.delete()
|
||||
},
|
||||
async btnRun1() {
|
||||
var _that = this;
|
||||
// 将图像转换为ImageData
|
||||
const image1Data = await _that.createImageElement(sampleImage1)
|
||||
// 设置画布的显示大小
|
||||
_that.setData({
|
||||
canvas1Width: image1Data.width,
|
||||
canvas1Height: image1Data.height,
|
||||
})
|
||||
_that.imgProcess1(image1Data, _that.canvasDom)
|
||||
},
|
||||
async btnRun2() {
|
||||
// 同上
|
||||
var _that = this;
|
||||
const image1Data = await _that.createImageElement(sampleImage1)
|
||||
_that.setData({
|
||||
canvas1Width: image1Data.width,
|
||||
canvas1Height: image1Data.height,
|
||||
})
|
||||
_that.imgProcess2(image1Data, _that.canvasDom)
|
||||
},
|
||||
async btnRun3() {
|
||||
// 同上
|
||||
var _that = this;
|
||||
const image1Data = await _that.createImageElement(sampleImage1)
|
||||
_that.setData({
|
||||
canvas1Width: image1Data.width,
|
||||
canvas1Height: image1Data.height,
|
||||
})
|
||||
_that.imgProcess3(image1Data, _that.canvasDom)
|
||||
},
|
||||
})
|
4
package_lesson2/index.json
Normal file
4
package_lesson2/index.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"navigationBarTitleText": "Lesson 2"
|
||||
}
|
19
package_lesson2/index.wxml
Normal file
19
package_lesson2/index.wxml
Normal file
@@ -0,0 +1,19 @@
|
||||
<view class="page">
|
||||
<view class="page__bd">
|
||||
<view class="weui-panel">
|
||||
<view class="weui-panel__hd">图像处理</view>
|
||||
<view class="weui-panel__bd">
|
||||
<image src="{{sampleImage1Url}}" mode="aspectFit" class="inputImage"></image>
|
||||
<!-- canvas v2-->
|
||||
<canvas id="canvas1" type="2d" class="visibleCanvas"
|
||||
style="width:{{canvas1Width}}px;height:{{canvas1Height}}px;"></canvas>
|
||||
|
||||
<view class="weui-media-box">
|
||||
<button bindtap="btnRun1" class="marginTop10" type="primary">灰度化</button>
|
||||
<button bindtap="btnRun2" class="marginTop10" type="primary">边缘检测</button>
|
||||
<button bindtap="btnRun3" class="marginTop10" type="primary">特征点检测</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
21
package_lesson2/index.wxss
Normal file
21
package_lesson2/index.wxss
Normal file
@@ -0,0 +1,21 @@
|
||||
/**index.wxss**/
|
||||
.button-sp-area{
|
||||
margin: 0 auto;
|
||||
padding-top: 15px;
|
||||
width: 60%;
|
||||
}
|
||||
.mini-btn{
|
||||
margin-right: 5px;
|
||||
}
|
||||
.weui-panel__hd{
|
||||
font-weight:bold;
|
||||
color:#333;
|
||||
}
|
||||
|
||||
.visibleCanvas{
|
||||
margin:auto;
|
||||
}
|
||||
|
||||
.inputImage{
|
||||
width:375px;
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
<view class="page">
|
||||
<view class="page__bd">
|
||||
<!-- Video Mask -->
|
||||
|
||||
<view class="weui-panel">
|
||||
<view class="weui-panel__hd">Go和小程序互操作</view>
|
||||
<view class="weui-panel__bd">
|
||||
@@ -16,5 +16,21 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="weui-panel">
|
||||
<view class="weui-panel__hd">小程序使用OpenCV</view>
|
||||
<view class="weui-panel__bd">
|
||||
<view class="weui-media-box weui-media-box_text">
|
||||
<view class="weui-media-box__desc">
|
||||
使用WXWebAssembly.instantiate初始化OpenCV运行环境。
|
||||
</view>
|
||||
<view class="weui-media-box__info">
|
||||
<navigator url="/package_lesson2/index" class="marginTop10">
|
||||
<button class="weui-btn" type="primary">Lesson 2</button>
|
||||
</navigator>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
@@ -13,6 +13,10 @@
|
||||
{
|
||||
"type": "folder",
|
||||
"value": "go_dev"
|
||||
},
|
||||
{
|
||||
"type": "folder",
|
||||
"value": "opencv_dev"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -55,7 +59,7 @@
|
||||
"useCompilerPlugins": false
|
||||
},
|
||||
"compileType": "miniprogram",
|
||||
"libVersion": "2.15.0",
|
||||
"libVersion": "2.16.1",
|
||||
"appid": "wxb4cdacc73d2d71c7",
|
||||
"projectname": "WeChat-WebAR",
|
||||
"debugOptions": {
|
||||
|
BIN
screenshot/1.jpg
BIN
screenshot/1.jpg
Binary file not shown.
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 26 KiB |
BIN
screenshot/4-1.jpg
Normal file
BIN
screenshot/4-1.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
BIN
screenshot/4-2.jpg
Normal file
BIN
screenshot/4-2.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
BIN
screenshot/4-3.jpg
Normal file
BIN
screenshot/4-3.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 39 KiB |
Reference in New Issue
Block a user