更新记录
1.2.6(2026-11-14)
修改插件描述
1.2.5(2026-11-14)
真正的离线OCR,纯端侧推理,无需联网,识别速度快,识别率高,在高频使用场景下,节省大量费用。基于目前流行的YOLO11+PP-OCR做了大量训练,支持自动旋转和裁剪,提高识别率,结果以json形式方式返回
平台兼容性
uni-app x(5.31)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| - | - | √ | √ | × | × |
其他
| 多语言 | 暗黑模式 | 宽屏模式 | 蒸汽模式 |
|---|---|---|---|
| × | × | √ | √ |
vf-idcard-ocr · VisionForge 身份证离线OCR
身份证端侧 OCR 插件。把一张身份证照片的路径丢进来,插件在本机完成自动旋转纠正 → 卡面裁剪 → 中文识别 → 字段结构化,返回结构化字段、裁剪后的卡面图,以及每个文字行在「识别图 / 纠正图 / 原图」三套坐标系里的位置。
纯端侧推理,不联网、不上传、不申请任何权限。
| 项 | 值 |
|---|---|
| 插件 id | vf-idcard-ocr |
| 版本 | 1.2.5 |
| 类型 | UTS API 插件 + 原生混编(Kotlin / Swift) |
| 支持平台 | Android、iOS |
| 未支持 | 鸿蒙(未实现)、Web / 小程序(调用返回 9010005) |
| HBuilderX | 4.61+(uni-app-x 5.31+) |
| 运行方式 | 必须自定义基座 / 云打包(含三方 ONNX Runtime 与 27 MB 模型资源,标准基座不含) |
| 网络与权限 | 不联网、不采集、不申请权限 |
1. 能力
| 能力 | 说明 |
|---|---|
| 自动旋转纠正 | EXIF 归一化 + 0/90/180/270 四方向枚举打分,自动选正 |
| 方向二次判定 | 背景干扰误选 180° 时,按「号码行应在最下方」的强几何特征再翻 180° |
| 卡面裁剪 | 按文字框外接矩形 + 身份证物理宽高比 85.6 / 54 反推卡面边界,裁掉桌面背景;裁剪后重新检测再识别 |
| 逐行中文 OCR | PP-OCRv3 行级识别,每行先过 0/180 方向分类器再识别 |
| 字段结构化 | 姓名、性别、民族、出生、住址、身份证号、签发机关、有效期限;含 GB 11643 校验位与交叉一致性检查 |
| 三套坐标 | 每个文字框同时给出识别图 / 纠正图 / 原图坐标,画框不用自己换算 |
| 英文 key JSON | json 字段可直接落库或传后端;有效期限拆成 startDate / endDate / permanent |
| 拒识 | 非身份证(驾驶证、发票等)返回 docType=other 并拒识,不返回垃圾字段 |
识别一张约 1~3 秒(中端机,含方向纠正的 4 次检测);首次调用额外包含模型加载与预热,之后会话复用。
2. 目录结构
uni_modules/vf-idcard-ocr/
├── package.json # 插件清单(id / 版本 / 平台 / 价格声明)
├── readme.md # 本文件
├── changelog.md # 更新日志
├── components/
│ └── vf-idcard-ocr/
│ └── vf-idcard-ocr.uvue # ★ 完整示例页:选图 → 识别 → 裁剪图显示 → 填表 → 耗时
├── tools/ # 自检与算法参考(不参与运行)
│ ├── check_contract.py # 资源 SHA256 / 导出 / JSON 契约 / 字段逻辑 / 转译红线
│ ├── reference_pipeline.py # Python 算法参考链路(可实跑对照)
│ └── *.json # 参考结果与回归用例
└── utssdk/
├── interface.uts # 对外类型、错误码、函数签名
├── common.uts # 跨平台:JSON 解析 + 字段抽取 + GB11643 校验
├── app-android/
│ ├── index.uts # 入口(IO 线程推理,主线程回调)
│ ├── IdCardNative.kt # Kotlin 推理引擎
│ ├── config.json # onnxruntime-android / exifinterface
│ ├── AndroidManifest.xml
│ └── assets/ # 5 个模型(27 MB)
├── app-ios/
│ ├── index.uts # 入口
│ ├── IdCardNative.swift # Swift 推理引擎
│ ├── config.json # onnxruntime-objc 1.20.0
│ ├── info.plist
│ └── Resources/ # 同 5 个模型(27 MB)
└── web/
└── index.uts # 明确不支持,返回 9010005
模型资源
Android assets/ 与 iOS Resources/ 各一份,SHA256 一致:
| 文件 | 大小 | 作用 |
|---|---|---|
vf_idcard_cls_v2.onnx |
5.9 MB | 自训版式分类 [1,3,160,160] RGB → front / back / other |
vf_idcard_det_v2.onnx |
10 MB | 自训文字行检测 [1,3,256,256] RGB |
vf_ppocr_rec_v3.onnx |
11 MB | PP-OCRv3 中文识别 [1,3,48,W] BGR → 6625 类 |
vf_ppocr_angle_cls.onnx |
572 KB | 行级 0/180 方向分类 |
vf_ppocr_keys.txt |
26 KB | CTC 字典 6623 行(运行期类表 = blank + 6623 + 空格 = 6625) |
三方依赖
| 平台 | 依赖 |
|---|---|
| Android | com.microsoft.onnxruntime:onnxruntime-android:1.20.0、androidx.exifinterface:exifinterface:1.3.7 |
| iOS | onnxruntime-objc 1.20.0(CocoaPods,deploymentTarget 12.0) |
宿主若已内置同版本 ORT,可从 config.json 移除重复依赖避免冲突。
3. 接入步骤
-
把整个
uni_modules/vf-idcard-ocr/拷进项目的uni_modules/目录。 -
HBuilderX 4.61+ 打开项目,制作自定义基座(或直接云打包)。标准基座不会打入 ORT 与模型资源。
-
页面里 import 插件根目录(不要 import
utssdk/下的文件):import { recognize, configure, getVersion, VfRecognizeResult } from '@/uni_modules/vf-idcard-ocr' -
用
uni.chooseImage取图片路径,传给recognize({ imagePath })。 -
打包后若报
9010003,说明模型资源没进包:Android 用context.assets.open("vf_idcard_cls_v2.onnx")验证,iOS 用Bundle.main.path(forResource:"vf_idcard_cls_v2", ofType:"onnx")验证。
类型导入必须是值与类型混写的普通 import,写
import type会把运行时绑定擦掉。
4. 示例代码
4.1 完整示例页(推荐先跑这个)
插件自带一份可直接运行的完整表单页:
uni_modules/vf-idcard-ocr/components/vf-idcard-ocr/vf-idcard-ocr.uvue
两种跑法:
- 当独立页面:把该文件复制到
pages/idcard-ocr/index.uvue,在pages.json注册路由即可。 - 当组件嵌入:uni-app x 的 easycom 会自动把
uni_modules/<插件>/components/<名>/<名>.uvue注册为<vf-idcard-ocr />,直接写标签使用(该页是整页scroll-view布局,适合整页嵌入)。
它覆盖了这些内容,可作为接入模板直接删改:
| 区域 | 演示的能力 |
|---|---|
| 顶部 | 插件版本、auto / cpu 后端切换(A/B 对比精度与速度) |
| 耗时总览 | 端到端耗时、costMs / costRotateMs / costOcrMs 分段、累计与完成面数、实际生效后端 |
| 两个图片区 | 人像面 / 国徽面各自「拍照」「相册」;选图即识别,按 docType 自动分流到正确区域 |
| 图片显示 | 成功后图片区直接换成裁剪图(croppedImageUri),角标显示纠正角度,点击预览 |
| 表单 | 8 个字段自动填入且可手改(:value + @input,不用 v-model) |
| 校验区 | 版式置信度、GB 11643 校验位、四方向打分、裁剪框与三套坐标系 |
| 文字行 | 逐行文本 + box / boxCorrected / boxOriginal 三套坐标(可折叠) |
| 底部 | 重新识别(两面串行跑,避免 ORT 会话并发)、复制结果 JSON、清空 |
4.2 最小接入代码
一个页面里最少的可用代码(完整版见 4.1 的 uvue):
<template>
<view style="padding: 24rpx;">
<button @click="pick">选身份证照片</button>
<image v-if="preview.length > 0" :src="preview" mode="widthFix" style="margin-top: 24rpx;" />
<text style="margin-top: 24rpx;">{{ summary }}</text>
</view>
</template>
<script setup lang="uts">
import { recognize, VfRecognizeResult } from '@/uni_modules/vf-idcard-ocr'
const preview = ref<string>('')
const summary = ref<string>('')
function pick() : void {
uni.chooseImage({
count: 1,
sourceType: ['camera', 'album'],
success: (r) => {
const path = r.tempFilePaths[0]
recognize({
imagePath: path,
success: (res : VfRecognizeResult) : void => {
// 页面要显示的是「裁剪后只保留卡面」的图;没有则退回纠正图、原图
preview.value = res.croppedImageUri.length > 0 ? res.croppedImageUri
: (res.correctedImageUri.length > 0 ? res.correctedImageUri : path)
summary.value = `${res.fields.name} ${res.fields.idNumber} ${res.fields.address}`
},
fail: (e) => {
summary.value = `识别失败 ${e.errCode}:${e.errMsg}`
}
})
}
})
}
</script>
4.3 接入时的四个要点
- 显示用
Uri字段,不要用Path字段。原生绝对路径直接给<image>会空白,必须用带file://的croppedImageUri/correctedImageUri。 - 「重新识别」要用原图路径,不要拿裁剪图再识别一次(会二次裁剪、越裁越小)。示例页把原图单独存在
frontRaw/backRaw。 - 正反面要串行识别。两个 ORT 会话并发推理容易抢内存,示例页用回调串联跑第二面。
- 页面状态用基础类型(
string/number/boolean/string[]),不要长期持有插件返回的大对象,规避 UTS 泛型与可空联合类型的平台差异。
5. API
| 函数 | 说明 |
|---|---|
recognize(options) |
异步识别。imagePath 必填;success / fail / complete 各触发一次 |
configure(config) |
可选,设置全局默认值;不调用即 auto / on / on / on |
getVersion() |
同步返回版本字符串 |
配置项全部是 string 枚举,不是 boolean(规避 UTS 结构入参 boolean 的平台差异):
| 参数 | 取值 | 默认 | 说明 |
|---|---|---|---|
backend |
'auto' / 'cpu' |
auto |
auto = 加速器优先(NNAPI / Core ML)+ 预热探测 + 自动降级 CPU |
angleCorrection |
'on' / 'off' |
on |
每行 OCR 前做 0/180 判定并翻转 |
saveCorrected |
'on' / 'off' |
on |
是否把纠正图 / 裁剪图落盘并回传路径 |
cropCard |
'on' / 'off' |
on |
关闭后退回「不裁剪」的旧行为,便于 A/B 对比 |
// 全局配置一次,之后所有调用只传图片
configure({ backend: 'auto', angleCorrection: 'on', saveCorrected: 'on', cropCard: 'on' })
// 单次覆盖
recognize({ imagePath: path, backend: 'cpu', success: (res) => {} })
错误码
| 码 | 含义 |
|---|---|
9010001 |
路径为空 / 解析不出可读文件 |
9010002 |
图片解码失败(常见:HEIC 等不支持的编码) |
9010003 |
模型资源或推理会话失败(多为资源没进包) |
9010004 |
推理异常 |
9010005 |
平台不支持 |
9010006 |
参数非法 |
6. 返回结果
| 字段 | 类型 | 说明 |
|---|---|---|
docType / docTypeScore / rejected / reason |
string / number / boolean / string | front 人像面、back 国徽面、other 拒识 |
imageWidth / imageHeight |
number | EXIF 归一化后原图尺寸 |
correctedWidth / correctedHeight |
number | 旋转纠正后、裁剪前尺寸 |
croppedWidth / croppedHeight |
number | 识别图(裁剪后)尺寸 |
rotation / rotationAdjusted / exifOrientation |
number / boolean / number | 纠正角度、是否触发方向二次判定、原始 EXIF |
rotationScores |
VfRotationScore[] |
四方向打分明细(调试旋转判定用) |
correctedImagePath / correctedImageUri |
string | 纠正图原生路径 / file:// URI |
cropped / cropReason |
boolean / string | 是否真的裁掉背景;card-crop / off / not-needed / guard-reject / rejected |
croppedImagePath / croppedImageUri |
string | 裁剪图原生路径 / file:// URI(页面显示用 Uri) |
cropBox / cropBoxOriginal |
VfRect |
裁剪框在纠正图 / 原图的坐标 |
contentBox / contentBoxCorrected / contentBoxOriginal |
VfRect |
文字区域外接矩形,三套坐标 |
lines |
VfTextLine[] |
全部文字行(按阅读顺序),含 box / boxCorrected / boxOriginal、text、textScore、angleFlipped |
fields |
VfFields |
8 个业务字段 + startDate / endDate / permanent + checks |
fields.checks |
VfFieldChecks |
GB 11643 校验位、号码派生出生/性别、交叉一致性、是否回填 |
json |
string | 业务结果 JSON(全英文 key、2 空格缩进),可直接落库 |
backend / costMs / costRotateMs / costOcrMs |
string / number | 实际后端与分段耗时 |
rawJson |
string | 原生层原始 JSON,扩展调试用 |
画框换算:显示裁剪图时用 lines[i].box,按 显示宽度 / croppedWidth 等比放大;要在用户原图上画框用 lines[i].boxOriginal,按 显示宽度 / imageWidth 换算。
有效期限:validPeriod 是展示串(如 2021-09-27 ~ 2041-09-27);startDate / endDate 是 YYYY-MM-DD;长期证件 endDate 为空串且 permanent = 1,否则 permanent = 0。
7. 识别流程
图片路径
→ 路径归一(uni 虚拟路径 / content:// / file:// → 原生绝对路径)
→ EXIF 归一化 + 长边降采样到 ≤1600
→ 四方向枚举打分(自训 cls + det,0.45×版式 + 0.35×框数 + 0.20×框置信 - 0.15×竖版)
→ 方向二次判定(号码行跑到最上方 → 再翻 180°)
→ 卡面裁剪(文字框外接矩形 + 85.6/54 宽高比,安全带 guard 不达标就放弃裁剪)
→ 裁剪图上重新做文字检测
→ 逐行 0/180 纠正 → 逐行 OCR
→ 字段抽取(阅读方向自愈、标签剥离、地址去重、GB 11643 校验)
→ 三套坐标逆映射输出
score < 0.25 或判 other 直接拒识。不含任意小角度倾斜与透视矫正 —— 拍摄明显变形时请在上层做边缘检测与透视变换。
8. 后端策略
auto(默认):Android cls/det 优先 NNAPI,iOS 优先 Core ML;建会话后用全 0 张量预热探测,驱动不完整自动降级 CPU;CPU 永远兜底。- rec / angle 是动态 shape 模型,固定走 CPU,规避各家加速器对动态维度的支持差异。
cpu:全部强制 CPU,结果最可复现,适合排查精度问题。- 返回的
backend字段告诉你实际生效的后端,便于埋点与灰度。
9. 已知限制
| # | 限制 | 建议 |
|---|---|---|
| 1 | 只支持身份证正/反面 | 其他证照会判 other 拒识,需另训版式与字段规则 |
| 2 | 不含透视矫正、模糊/反光检测 | 拍摄时让证件占满画面、避免强反光 |
| 3 | 端侧是逐行轻量 OCR | 对准确率要求极高时,可把 correctedImagePath 送服务端复核 |
| 4 | 合照/多证同框未切分 | 另一张证件的地址行可能串入;拍摄时单张占满画面 |
| 5 | 模型资源 27 MB/平台 | 包体积敏感可换 fp16/int8 变体并同步预处理 |
| 6 | 原图、纠正图含 PII | 插件不上传不加密,业务侧需自行加密存储并清理缓存文件 |
10. 依赖与许可
PP-OCRv3 识别/方向模型与字典来自 rapidocr_onnxruntime(Apache-2.0 / PaddleOCR 相关许可);版式分类与文字行检测为本项目自训(YOLO11n)。商用分发前请核对模型许可证与分发条款,并在 App 隐私政策中说明「证件信息仅在本机处理、不上传」。
更新记录见 changelog.md。

收藏人数:
购买普通授权版(
试用
赞赏(0)
下载 5
赞赏 0
下载 12765317
赞赏 1959
赞赏
京公网安备:11010802035340号