# 手机浏览器本地数字 OCR 方案调研

调研日期：2026-10-19。任务是从红色「百亿补贴」页面图片中找出**连续 7–9 位 ASCII 数字**，例如 `159965822`；数字本身不限颜色，不允许把带空格的数字拼接成码、不允许从 10 位以上串中截取 7–9 位。识别在手机浏览器内进行，图片不上传。本文把「项目已实现」「可以工程化」「实验／不符合纯网页约束」分开，模型大小不等于引擎总下载量。

已收到用户 r2 手机失败日志，但原照片未保存。合成截图测试只能验证流程与已覆盖的字体、颜色、布局，不能代表百亿补贴真实截图准确率，也不能据此宣称覆盖大多数国产手机。真机与真实样本校准是明确的剩余验证项。

## 12 条路线对比

| 路线 | 普通网页真实可用性 | 体积依据与设备约束 | 本项目选择 |
| --- | --- | --- | --- |
| 1. 浏览器 `TextDetector` | **实验能力，不能作通用 OCR**。Chrome 官方仍说明文本检测在实验 flag 后，接口存在也不保证底层支持；有些平台只返回框。 | 网页无需自带模型，但底层系统实现不可控。不能把 `BarcodeDetector` 的支持率套到文本检测；中国 Android 无 GMS／厂商内核差异更不能假设可用。 | 只作为将来的实测增强；不计入三个独立可用方案。[Chrome 官方说明](https://developer.chrome.com/docs/capabilities/shape-detection)。 |
| 2. Apple Live Text／Vision | **原生可用，普通网页不能直接调用 VisionKit Swift API**。Safari 的系统长按识字是用户操作，不是网页可读取的 OCR 回调。 | 不需网页下载模型，但依赖系统与设备。Apple `ImageAnalyzer.isSupported` 文档要求 A12 Bionic 或更新芯片；这并非所有 Vision API 的统一门槛。 | 可指导用户手动复制后粘贴；不能伪装成自动网页引擎。[ImageAnalyzer 能力探测](https://developer.apple.com/documentation/visionkit/imageanalyzer/issupported)、[Vision 文本识别](https://developer.apple.com/documentation/vision/recognizing-text-in-images)。 |
| 3. Android ML Kit Text Recognition v2 | **原生 Android/iOS SDK，可通过自有 App 桥接；普通网页无标准直调接口**。 | 官方 Android 文档列出每文字系统、每架构 bundled 约 4 MB，unbundled 约 260 KB 但模型由 Google Play Services 下载。正文前置要求 API 23+；页面自动摘要仍写 21，采用正文较严要求。不应将 unbundled 方案推荐给无 GMS 的国产机。 | 不安装 App 的本需求不采用。[ML Kit Android 安装与体积](https://developers.google.com/ml-kit/vision/text-recognition/v2/android)。 |
| 4. Tesseract.js + WASM LSTM | **真实浏览器本地 OCR，项目已接入**。它是 Tesseract 的 WebAssembly 封装，不是系统 OCR。 | 本地选用 6.0.1 JS / 6.0.0 core：单个 LSTM WASM 约 2.87 MB，英文量化语言包 gzip 2.95 MB；主 JS + worker + loader 约 299 KB。单次所需资产约 6.12 MB 未计 HTTP 压缩，仓库同时保存 SIMD 与非 SIMD 两套约 9.14 MB。需 WASM、Worker，非 SIMD 作为兼容路径。 | r3 默认路径与困难图兜底；按需加载、复用单 worker、裁剪目标区。数字白名单不能保证不会误认，也不能恢复已丢失的间隔。[上游项目](https://github.com/naptha/tesseract.js)、[本地资源清单](../vendor/tesseract-manifest.json)。 |
| 5. Canvas 阈值／连通域／投影 + 字形模板 | **纯 JS 可实现，项目已接入**。模板匹配是实际像素相似度计算，不是正则识图。 | 无通用推理运行时；数字模板可在设备 Canvas 根据字体生成。算法 JS 另计；r2 已删除标题模板，不进行标题识别。依赖 Canvas 与现代 JS，覆盖面较宽但系统字体不同会影响模板。 | 优先验证小包方案；灰度、颜色通道与明暗两极处理，不能只筛红字。优势是小、快，风险是粘连、轮廓、阴影、未知字体和同形字符。[模板匹配原理](https://docs.opencv.org/4.x/d4/dc6/tutorial_py_template_matching.html)；实现没有引入整套 OpenCV。 |
| 6. 专用数字 MLP／小 CNN 分类 | **可用，项目已有真实量化 MLP 权重与 JS 矩阵推理**，不是替代成另一个 Tesseract 参数。 | 当前 MLP 输入 16×24、48 隐层、11 类（含拒识），INT8 权重 JSON 为 26,993 bytes；分割与前处理代码另计，无 TFJS/ONNX 依赖。按参数计算模型可以很小，但量化 JSON 和浮点偏置仍占额外空间。 | 第二种小包方案。需先分割单字；同一分割错误会同时影响模板和 MLP。合成训练覆盖不等于真实截图泛化。[项目模型](../models/tiny-mlp-v1.json)、[推理实现](../engines/tiny-mlp.js)。 |
| 7. 数字专用 CNN/CRNN + CTC + ONNX Runtime Web | **可工程化，尚未在本项目训练或接入**。序列识别可直接输入整行，减少单字分割依赖。 | 模型需单独训练、量化、验证；不能将设想中的几十／几百 KB 当作已下载模型。可复现比较版本 ORT 1.20.1：`ort.wasm.min.js` 49,026 B，但 WASM 11,246,032 B；JSEP WASM 21,663,894 B。自定义算子精简构建可减体积。 | 若真实截图粘连多，优先后续研发；目前其运行时体积明显大于专用 JS MLP。[CRNN 原论文](https://arxiv.org/abs/1507.05717)、[ORT Web](https://onnxruntime.ai/docs/get-started/with-javascript/web.html)、[精简构建说明](https://onnxruntime.ai/docs/build/web.html)。 |
| 8. TensorFlow.js + 自训数字 CNN/CTC | **浏览器可用，需另配合适模型**。TFJS 不是开箱即用的 OCR 模型。 | 4.22.0 全量 `tf.min.js` 1,469,843 B；WASM backend JS 149,861 B、非 SIMD WASM 311,123 B，SIMD 424,594 B。仍需模型；只导入 core／指定算子可以缩小。WebGL 存在移动 GPU 精度／驱动差异；WASM/CPU 兼容路径需验证。 | 可研发，因本次小网络无需大框架未选用。[TFJS 官方后端说明](https://www.tensorflow.org/js/guide/platform_environment)、[WASM backend](https://github.com/tensorflow/tfjs/tree/master/tfjs-backend-wasm)。 |
| 9. Paddle.js OCR（PP-OCRv2 转换模型） | **有官方浏览器实现与示例**。它不同于直接在浏览器 `pip install paddleocr`。 | `@paddlejs-models/ocr@1.2.4/lib/index.js` 1,619,228 B；默认检测结构 JSON 288,358 B、识别结构 JSON 1,028,975 B，权重 chunk 分别为 2,289,764 / 4,194,304 / 4,115,204 B（HEAD 实测），这些文件合计约 13.54 MB。默认检测输入为 960×960，识别为 32×320，GPU 内存与模型处理负担比单行数字分类大。 | 可真实移植。需将默认远程模型同源自托管、适配 Worker／后端、在国产浏览器验证 WebGL；不将官方提及 UC/QQ 测试名单视为所有版本保证。[Paddle.js 官方库](https://github.com/PaddlePaddle/Paddle.js)、[OCR 源文档](https://raw.githubusercontent.com/PaddlePaddle/Paddle.js/master/packages/paddlejs-models/ocr/README.md)。 |
| 10. PaddleOCR／RapidOCR 导出 ONNX 后在 Web 运行 | **模型可复用，Python/C++ 包不能直接成为网页引擎**；需重写检测后处理、裁剪、归一化、字典与 CTC 解码。 | Paddle 官方 PP-OCRv4_mobile_rec `inference.pdiparams` 约 10.8 MB（仅识别模型，不含检测、字典、ORT）；版本、语言、量化会显著改变体积。RapidOCR 的 ONNX 文件也不能省略推理运行时。 | 更适合广泛文本识别的升级版；本次固定 7–9 位场景成本偏高。[Paddle 官方模型](https://huggingface.co/PaddlePaddle/PP-OCRv4_mobile_rec/tree/main)、[RapidOCR 上游](https://github.com/RapidAI/RapidOCR)。 |
| 11. Ocrs + RTen WASM | **有浏览器 WASM 构建，但上游明确 alpha／early preview**。 | 官方模型列表检测 `.rten` 2,523,564 B，识别 `.rten` 9,716,444 B，合计 12.24 MB，**另加 RTen/Ocrs WASM 与 JS**。当前 Latin 字符为主，数字可覆盖，但设备速度与准确率需评估。 | 可试验对照，不优先作为小包兼容方案。[Ocrs 项目状态](https://github.com/robertknight/ocrs)、[WASM 构建说明](https://github.com/robertknight/ocrs/blob/main/js/README.md)、[作者发布模型](https://huggingface.co/robertknight/ocrs/tree/main)。 |
| 12. OCRad.js（Emscripten 移植传统 OCR） | **确有纯客户端实现**，但老式规则引擎，不宜据此保证复杂截图准确率。 | 官方仓库 `ocrad.js` 原文件实测 3,208,537 B，无需另下载神经模型；现代框架和设备兼容、维护状态仍需单独验证。 | 作为轻依赖历史路线评估，不纳入此次三方案；源码／许可证义务应在正式采用前确认。[作者上游](https://github.com/antimatter15/ocrad.js)。 |

表中的「可工程化」不是已完成的测试结果。各路线都可做到推理时不上传图片，但默认 CDN 下载模型不等于离线可用；必须确认所有运行时和模型都来自本站或已缓存。

## 中国 Android 与 iPhone 的实现取舍

r3 默认使用 WASM OCR，Canvas + JS 小引擎已修复白卡片、边框和局部区域分割，可关闭自动切换分别测试；不以 Google Play Services、厂商浏览器私有桥接、WebGPU 或 `TextDetector` 为必要条件。`navigator.gpu` 存在也不代表能请求到适配器或模型算子受支持；不能用 Android 系统版本代替实际 WebView/浏览器版本。

当前源码使用 ES modules 与可选链 `?.`。可选链的已知语法起点是 Chromium 80、Safari 13.1；老内核可能在能力检测前就解析失败，需要更新系统浏览器或另做转译构建。此下限不是「这些版本已完成真机验收」的承诺。[V8 官方支持列表](https://v8.dev/features/optional-chaining)。

WASM 多线程依赖浏览器功能和 `crossOriginIsolated`，并不是「支持 WASM」就自动支持；ORT 官方可设置 `numThreads=1` 关闭多线程。基础路径不应为了线程强制整个站点启用可能影响嵌入环境的隔离策略。模型、worker、WASM 路径应相互匹配并同源部署。[ORT 官方配置](https://onnxruntime.ai/docs/tutorials/web/env-flags-and-session-options.html)。

相机使用 HTTPS + 用户明确授权。选图／相册是相机被内置浏览器限制时的基础入口。实时识别只能用最新帧、限制频率和并发，不应每帧新建 OCR worker。相机是在拍摄另一屏幕／纸面，不是读取同一手机其他 App 的画面；网页无法持续截取拼多多 App 屏幕。

r3 先识别数字，再用附近红色作为「可能为目标页面」的辅助，不限定数字颜色。不识别标题、不匹配标题字体、不要求标题相对位置；普通红背景仍不能证明来自百亿补贴。对误选页面、未知字体、强压缩、低对比或多个候选应提供裁剪／手动核对。裁剪只能改善输入，不能承诺准确率。

## 体积与速度证据如何复核

- 版本固定的 npm 包目录元数据保存在 `research/reference/*metadata.json`。来源分别是 [ORT 1.20.1](https://unpkg.com/onnxruntime-web@1.20.1/dist/?meta)、[TFJS 4.22.0](https://unpkg.com/@tensorflow/tfjs@4.22.0/dist/?meta)、[TFJS WASM 4.22.0](https://unpkg.com/@tensorflow/tfjs-backend-wasm@4.22.0/dist/?meta)、[Paddle.js OCR 1.2.4](https://unpkg.com/@paddlejs-models/ocr@1.2.4/?meta)。这些是可重现比较版本，不声称均为最新版本。
- Tesseract 的本地清单包含下载来源、固定版本、文件 bytes 和 SHA-256。包管理器的 `.tgz` 含多种构建，不能当作浏览器第一次实际需要的下载总量。
- 所有上述数值使用十进制 KB/MB（1 MB = 1,000,000 bytes），属于静态资产大小，不是峰值 RAM。图片解码、Canvas RGBA、WASM heap、模型中间激活会额外占用内存。
- 测速应区分模型首次加载、缓存后初始化、实际识别、预处理和总耗时。桌面无头 Chromium、桌面 WebKit、移动 UA／视口模拟不是真实 Android 或 iPhone 性能。

## 当前验证边界

本次三个落地引擎是模板匹配、量化 MLP 与 Tesseract WASM；前两者共享候选定位／分割部分，因此不能将两者一致当作独立证据而过度提高置信度。至少需要「目标页准确定位、整串完全匹配、误报率、拒识率」四类指标，并按字体、码长、数字颜色、压缩、缩放、阴影、粘连、空白分隔、非目标页面拆分样本。

r1 的共同前处理会拒绝白卡片数字，甚至仅面板边缘移动 2 像素就让三个入口都失败。r2 已从默认通用 OCR 路径删除该前置门槛，并对这些已复现失败做直接 OCR 回归。r3 修复 A/B 自身的白卡片、边框及轻倾斜分割，并在禁用 WASM / Worker 后独立验证。页面可关闭自动切换；开启时按实际引擎记录失败及回退。入口成功仍不能当作所选轻量模型自身识别成功。用户 r2 日志还证明通用 OCR 没有执行局部放大和单行重试；r3 补充这些路径，并用实际 Worker 参数与图片尺寸验证执行，详见 [验收记录](acceptance.md)。

真实验收还需：用户样图（可只在本机选入）、不同厂商 Android 浏览器／微信内置浏览器、iPhone Safari 的本地跑分，以及实际安装拼多多时的手动唤起测试。没有这些证据时，不把合成测试通过写成「真实页面百分之百正确」或「多数中国手机已测试」。
