Files
nanocode/web-opencv/miniappA/README.md
T
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

197 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Paper Recognizer WASM
尿检试纸图像识别模块,OpenCV C++ 编译为 WebAssembly,适用于浏览器和微信小程序。
## 目录结构
```
├── src/
│ ├── PaperRecognizer.cpp/h # 核心识别算法
│ ├── ColorReader.cpp/h # 色块颜色读取
│ ├── PaperConfig.cpp/h # 试纸规格配置
│ ├── emsc_bridge.cpp # Emscripten 桥接(对外 API)
│ ├── Types.h # 类型定义
│ └── GlobalParams.h # 全局常量
├── web/
│ ├── paper_recognizer.js # JS 胶水代码(编译产物)
│ └── paper_recognizer.wasm # WASM 模块(编译产物)
├── build.sh # 编译脚本
├── test.js # Node.js 测试
└── README.md # 本文件
```
## 环境要求
- **Emscripten SDK**(`emsdk`),安装于 `/home/ubuntu/emsdk`
- **OpenCV** 已编译为 WASM 静态库,位于 `/home/ubuntu/opencv/build_mini_os/`
如果环境路径不同,请修改 `build.sh` 中的 `EMSDK_DIR` 和 `OPENCV_DIR`。
## 编译方法
修改 `src/` 下的代码后,执行:
```bash
cd /home/ubuntu/nanocode/web-opencv/miniappA
./build.sh
```
产物输出到 `web/` 目录:
- `web/paper_recognizer.js` — JS 胶水代码
- `web/paper_recognizer.wasm` — WASM 二进制
### 编译说明
编译使用 `-Os` 优化级别,静态链接 OpenCV core + imgproc + imgcodecs,输出单文件 WASM。
关键编译选项:
- `ALLOW_MEMORY_GROWTH=1` — 允许 WASM 内存动态增长
- `MODULARIZE=1` — 模块化导出(异步加载)
- `FILESYSTEM=0` — 不包含文件系统(减小体积)
- `DISABLE_EXCEPTION_CATCHING=1` — 禁用 C++ 异常捕获
WASM 体积:1014KB(gzip 后约 348KB)。
## 使用方法
### 加载模块
```javascript
const Module = require('./web/paper_recognizer.js');
const m = await Module();
```
浏览器中使用:
```html
<script src="paper_recognizer.js"></script>
<script>
PaperRecognizerModule().then(m => {
// m 就是模块实例
});
</script>
```
### API 说明
所有 API 通过 Module 上的函数调用,函数名带前导下划线。
#### `_recognize(data, width, height)`
执行试纸识别。
| 参数 | 类型 | 说明 |
|------|------|------|
| `data` | `number` (指针) | RGBA 像素数据在 WASM 堆中的指针 |
| `width` | `number` | 图像宽度 |
| `height` | `number` | 图像高度 |
返回 `0` 成功,`-1` 失败。
**调用前需要先将图像数据拷贝到 WASM 堆:**
```javascript
const pixels = new Uint8Array(imageData); // RGBA 格式
const ptr = m._malloc(pixels.length);
m.HEAPU8.set(pixels, ptr);
const ret = m._recognize(ptr, width, height);
```
#### `_getResultJson()`
返回识别结果的 JSON 字符串指针,使用 `m.UTF8ToString(ptr)` 读取。
返回的 JSON 结构:
```json
{
"success": true,
"errorCode": 0,
"errorMessage": "",
"paperType": "14_S",
"locatorColor": 0,
"itemCount": 14,
"smallLocatorOnLeft": true,
"blurLevel": 0,
"blurScore": 0.0,
"colorBlockCenters": [{ "x": 100.0, "y": 200.0 }, ...],
"colors": [
{
"id": 0,
"r": 200.0, "g": 150.0, "b_val": 100.0,
"h": 30.0, "s": 0.5, "v": 0.8,
"l": 60.0, "a": 10.0, "b": 20.0
}
]
}
```
#### `_getAnnotatedWidth()` / `_getAnnotatedHeight()`
获取标注图像的宽度和高度(像素)。
#### `_getAnnotatedPixels()`
返回标注图像 BGRA 像素数据的指针。每像素 4 字节(B, G, R, A),总大小 = `width * height * 4`。
```javascript
const w = m._getAnnotatedWidth();
const h = m._getAnnotatedHeight();
const ptr = m._getAnnotatedPixels();
const size = w * h * 4;
const pixels = new Uint8Array(m.HEAPU8.buffer, ptr, size);
```
#### `_freeResult()`
释放内部缓存(结果 JSON、标注图像)。每次 `_recognize()` 调用后需调用一次。
### 完整调用示例
```javascript
async function processImage(imageData, width, height) {
const m = await PaperRecognizerModule();
// 拷贝图像到 WASM 堆
const dataSize = width * height * 4;
const ptr = m._malloc(dataSize);
m.HEAPU8.set(new Uint8Array(imageData), ptr);
// 识别
const ret = m._recognize(ptr, width, height);
// 读取结果
const jsonPtr = m._getResultJson();
const result = JSON.parse(m.UTF8ToString(jsonPtr));
// 读取标注图
const aw = m._getAnnotatedWidth();
const ah = m._getAnnotatedHeight();
const ap = m._getAnnotatedPixels();
const annotatedData = new Uint8Array(m.HEAPU8.buffer, ap, aw * ah * 4);
// 清理
m._freeResult();
m._free(ptr);
return { result, annotatedData, width: aw, height: ah };
}
```
### 重要说明
1. **内存管理**:`_malloc` 分配的内存必须用 `_free` 释放;`_freeResult` 必须每次 `_recognize` 后调用。
2. **输入格式**:接收 RGBA 字节数组(每像素 4 字节),R/G/B/A 各 8 位。
3. **标注图格式**:返回 BGRA 字节数组(B/G/R/A 顺序),在 JavaScript 侧绘制到 Canvas 前可能需要转换。
4. **错误处理**:`_recognize` 返回 -1 时可通过 `_getResultJson()` 查看 `errorCode` 和 `errorMessage`。
5. **模块是单例**:多次调用 `PaperRecognizerModule()` 返回同一个实例。
## 测试
```bash
node test.js
```
测试会加载模块、用纯灰色图像调用识别,并验证所有导出函数正常。