更新记录

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. 接入步骤

  1. 把整个 uni_modules/vf-idcard-ocr/ 拷进项目的 uni_modules/ 目录。

  2. HBuilderX 4.61+ 打开项目,制作自定义基座(或直接云打包)。标准基座不会打入 ORT 与模型资源。

  3. 页面里 import 插件根目录(不要 import utssdk/ 下的文件):

    import { recognize, configure, getVersion, VfRecognizeResult } from '@/uni_modules/vf-idcard-ocr'
  4. 用 uni.chooseImage 取图片路径,传给 recognize({ imagePath })。

  5. 打包后若报 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 接入时的四个要点

  1. 显示用 Uri 字段,不要用 Path 字段。原生绝对路径直接给 <image> 会空白,必须用带 file:// 的 croppedImageUri / correctedImageUri。
  2. 「重新识别」要用原图路径,不要拿裁剪图再识别一次(会二次裁剪、越裁越小)。示例页把原图单独存在 frontRaw / backRaw。
  3. 正反面要串行识别。两个 ORT 会话并发推理容易抢内存,示例页用回调串联跑第二面。
  4. 页面状态用基础类型(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。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

当前版本不申请任何权限(仅做本地图片读写,沙盒路径与系统选择器已授权的 URI 均无需额外权限)。拍照/相册由宿主页面调用 uni.chooseImage 触发,相机权限由宿主 App 自行声明:Android(android.permission.CAMERA)、iOS(NSCameraUsageDescription);相册走系统选择器一般无需权限。Android 4.41+ 相册选原图时系统返回的 content:// URI 仅做只读访问并复制到应用私有缓存,识别后立即删除。

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

当前版本(1.2.5)不采集任何数据、不发起任何网络请求:只在端侧读取调用方传入的本地图片,并把旋转纠正图/裁剪图写到应用自己的沙盒缓存目录。识别出的证件字段仅在设备内存中处理,不上传、不落库、不回传给插件方。

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无

暂无用户评论。