155 lines
4.1 KiB
Markdown
155 lines
4.1 KiB
Markdown
# paper-recognizer — 微信小程序尿检试纸识别
|
||
|
||
纯 JavaScript 实现,零依赖,约 40KB。复制即用。
|
||
|
||
## 文件说明
|
||
|
||
```
|
||
miniapp/
|
||
├── paper-recognizer.js # 核心识别引擎(唯一必需文件)
|
||
└── README.md
|
||
```
|
||
|
||
## 快速集成
|
||
|
||
### 1. 复制文件
|
||
|
||
将 `paper-recognizer.js` 放入小程序项目的 `utils/` 目录。
|
||
|
||
### 2. 页面引入
|
||
|
||
```javascript
|
||
// pages/recognize/recognize.js
|
||
const { PaperRecognizer } = require('../../utils/paper-recognizer.js');
|
||
const recognizer = new PaperRecognizer();
|
||
```
|
||
|
||
### 3. 拍照识别
|
||
|
||
```javascript
|
||
Page({
|
||
data: { result: null },
|
||
|
||
// 拍照
|
||
onTakePhoto() {
|
||
wx.chooseImage({
|
||
count: 1,
|
||
sourceType: ['camera'],
|
||
success: (res) => this.doRecognize(res.tempFilePaths[0])
|
||
});
|
||
},
|
||
|
||
// 识别
|
||
doRecognize(filePath) {
|
||
wx.getImageInfo({
|
||
src: filePath,
|
||
success: (info) => {
|
||
// 建议长边超过 1500px 时先缩放,保证性能
|
||
const maxLen = 1500;
|
||
let w = info.width, h = info.height;
|
||
if (Math.max(w, h) > maxLen) {
|
||
const scale = maxLen / Math.max(w, h);
|
||
w = Math.round(w * scale);
|
||
h = Math.round(h * scale);
|
||
}
|
||
|
||
// 离屏 Canvas 获取像素
|
||
const ctx = wx.createCanvasContext('offscreenCanvas', this);
|
||
ctx.drawImage(filePath, 0, 0, w, h);
|
||
ctx.draw(false, () => {
|
||
wx.canvasGetImageData({
|
||
canvasId: 'offscreenCanvas',
|
||
x: 0, y: 0, width: w, height: h,
|
||
success: (res) => {
|
||
const rgba = new Uint8Array(res.data);
|
||
const result = this.recognizer.recognize(rgba, w, h);
|
||
|
||
if (result.success) {
|
||
console.log('试纸类型:', result.paperType);
|
||
console.log('色块数量:', result.itemCount);
|
||
console.log('定位块颜色:', result.locatorColor);
|
||
console.log('颜色数据:', result.colors);
|
||
} else {
|
||
console.error('识别失败:', result.errorCode, result.errorMessage);
|
||
}
|
||
}
|
||
});
|
||
});
|
||
}
|
||
});
|
||
}
|
||
});
|
||
```
|
||
|
||
### 3. 相册选图识别
|
||
|
||
```javascript
|
||
wx.chooseImage({
|
||
count: 1,
|
||
sourceType: ['album'],
|
||
success: (res) => this.doRecognize(res.tempFilePaths[0])
|
||
});
|
||
```
|
||
|
||
## 识别结果字段
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `success` | boolean | 是否成功 |
|
||
| `errorCode` | number | 错误码(成功为 0) |
|
||
| `errorMessage` | string | 错误描述 |
|
||
| `paperType` | string | 试纸类型,如 "14_S", "11_L" |
|
||
| `itemCount` | number | 色块数量 |
|
||
| `locatorColor` | string | 定位块颜色 "Red"/"Green"/"Blue" |
|
||
| `smallLocatorOnLeft` | boolean | 小定位块是否在左侧 |
|
||
| `blurLevel` | string | 清晰度 "None"/"Slight"/"Severe" |
|
||
| `blurScore` | number | 清晰度分数(越高越清晰,>300 为 None) |
|
||
| `colors` | array | 色块颜色数组 `[{id, r, g, b}, ...]` |
|
||
|
||
## 错误码
|
||
|
||
| 码 | 含义 |
|
||
|----|------|
|
||
| 0 | 成功 |
|
||
| -1 | 未找到定位块 |
|
||
| -2 | 定位块配对失败 |
|
||
| -3 | 定位块颜色不一致 |
|
||
| -4 | 未找到匹配的试纸配置 |
|
||
| -5 | 未知试纸类型 |
|
||
|
||
## 性能参考
|
||
|
||
| 图片分辨率 | 预估耗时 | 建议 |
|
||
|-----------|---------|------|
|
||
| < 800×100 | < 20ms | 直接处理 |
|
||
| ~1100×400 | ~150ms | 直接处理 |
|
||
| ~2500×1100 | ~600ms | 建议缩放到 1500px |
|
||
| > 3000px | > 1s | 必须缩放 |
|
||
|
||
## 注意事项
|
||
|
||
1. **Canvas 必须存在于 WXML 中** — 即使隐藏也要声明:
|
||
|
||
```html
|
||
<canvas canvas-id="offscreenCanvas"
|
||
style="position:fixed;top:-9999px;left:-9999px;width:750px;height:750px;">
|
||
</canvas>
|
||
```
|
||
|
||
2. **拍照时保持试纸平整** — 严重透视变形或大角度旋转可能导致识别失败。
|
||
|
||
3. **光照均匀** — 算法使用 HSV 颜色分割,极端光照(强反光、暗光)下定位块可能漏检。
|
||
|
||
4. **仅支持 14/11/8 项试纸** — 支持短型(S)和长型(L)两种规格。
|
||
|
||
## 试纸类型清单
|
||
|
||
| paperType | itemCount | 说明 |
|
||
|-----------|-----------|------|
|
||
| 14_S | 14 | 14 项短型 |
|
||
| 14_L | 14 | 14 项长型 |
|
||
| 11_S | 11 | 11 项短型 |
|
||
| 11_L | 11 | 11 项长型 |
|
||
| 8_S | 8 | 8 项短型 |
|
||
| 8_L | 8 | 8 项长型 |
|