更新记录

1.0.0(2026-08-22)

YOLO车牌检测 + CRNN OCR + 颜色识别, 端侧离线推理,包含 拍照识别 与 实时视频流识别 两种模式


平台兼容性

uni-app x(4.66)

Chrome Safari Android iOS 鸿蒙 微信小程序
× × 8.0 - - -

其他

多语言 暗黑模式 宽屏模式
× ×

车牌识别 App 使用说明

基于 uni-app x 的 Android 端侧车牌识别应用,采用 YOLOv5 检测 + CRNN OCR + 颜色识别,ONNX 离线推理,无需后端服务器。


目录


一、简介

本项目是一个 纯端侧 车牌识别 Android 应用,核心算法管线为:

YOLOv5 车牌检测 → 透视矫正 → CRNN 字符识别 → 颜色分类

所有推理均在设备本地通过 ONNX Runtime 完成,不依赖任何网络后端

核心能力

能力 说明
车牌检测 YOLOv5 模型,输入 1280×1280,支持单图多车牌
字符识别 CRNN + CTC 解码,支持单层/双层车牌
颜色识别 softmax 分类,覆盖蓝/绿/黄/白/黑五种标准车牌颜色
拍照识别 选择相册图片或现场拍摄,单张识别
视频流识别 CameraX 实时预览,逐帧推理,画框 Overlay + 悬浮结果
离线运行 无需网络,模型打包在 assets 内

二、功能特性

拍照识别模式

  • 支持从相册选择图片或直接调用相机拍摄
  • 识别结果展示车牌号、颜色、类型(单层/双层)、检测置信度
  • 支持单张图片中的多车牌同时识别
  • 页面加载时自动初始化引擎(首次约 1-2 秒)

视频流识别模式

  • CameraX 实时相机预览,逐帧自动识别
  • 画面上叠加亮绿色车牌框 + 车牌号标签(Overlay)
  • 悬浮显示当前最优识别结果(车牌号/颜色/类型/置信度)
  • 实时帧率显示
  • 手电筒切换(支持设备)
  • 识别历史记录(自动去重,最多保留 50 条)
  • 一键复制最新车牌号
  • 页面退出自动释放相机资源

颜色领域校正

内置中文车牌颜色规则引擎,对模型输出进行后校正:

  • 末位"学"→黄牌(教练车);末位"挂"→黄牌(挂车);末位"警"→白牌(警车)
  • 8 位 + 黄→绿牌(新能源);8 位 + 绿→绿牌(保留)
  • 7 位 + 绿→按黑蓝概率翻色(7 位不可能是新能源绿牌)
  • 前缀"使"/末位"领"→黑牌(使领车);含"港"/"澳"→黑牌;前缀"民航"→白牌
  • 黑蓝边界抖动兜底:softmax 概率差 < 0.10 时归蓝

三、环境要求

运行环境

项目 要求
操作系统 Android 5.0 (API 21) 及以上
架构 armeabi-v7a / arm64-v8a / x86_64
相机 具备后置摄像头(视频流识别必需)
存储 ≥ 50MB 可用空间(含模型文件)

4.3 制作自定义基座

由于项目依赖 onnxruntime-androidandroidx.camera(CameraX),必须使用自定义基座才能真机运行。标准基座不含这些库。

操作路径:运行 → 运行到手机或模拟器 → 制作自定义调试基座

4.4 真机运行

  1. 手机开启 USB 调试,连接电脑
  2. 运行 → 运行到手机或模拟器 → 运行到 Android App 基座
  3. 选择刚才制作的自定义基座
  4. App 安装后自动启动,首页为功能入口选择页

五、使用指南

5.1 拍照识别

入口:App 启动 → 首页点击「拍照识别」,或从视频流页面点击「拍照识别 →」跳转。

操作步骤

  1. 选择图片:点击「选择 / 拍照」按钮,从相册选取或现场拍摄一张包含车牌的图片
  2. 等待初始化:首次使用时页面会自动初始化引擎,状态栏显示初始化结果
  3. 开始识别:点击「开始识别」按钮,等待 1-3 秒
  4. 查看结果:识别完成后,页面下方展示车牌号、颜色、类型和置信度
  5. 重新识别:可重新选图或拍摄,每次识别覆盖上次结果

如果未识别到车牌,页面会提示「未识别到车牌」。请确保图片中车牌清晰、占比不过小。

5.2 视频流识别

入口:首页点击「视频流识别」,或从拍照识别页面点击「视频流识别 →」跳转。

操作步骤

  1. 授权相机:首次点击「开始识别」时,系统弹出相机权限请求,点击「允许」
  2. 再次点击开始:授权后需再次点击「开始识别」启动相机预览
  3. 实时识别:相机启动后自动逐帧识别,画面上出现绿色车牌框 + 车牌号标签
  4. 悬浮结果:画面左上角悬浮显示当前最优车牌号(黄色大字)+ 颜色/类型/置信度
  5. 历史记录:每次新识别的车牌自动加入下方历史列表(同号不重复入栈)
  6. 手电筒:点击「手电筒」按钮切换闪光灯(暗光环境辅助)
  7. 复制车牌:点击「复制车牌」将最新车牌号复制到剪贴板
  8. 停止:点击「停止」暂停识别,退出页面自动释放相机

识别帧率显示在状态栏右侧(如 12 fps)。帧率受设备性能和图像复杂度影响。


六、API 参考

6.1 函数式 API

UTS 插件 uni-plate-recognizer 提供三个函数,适用于拍照识别场景:

import { initPlate, recognizeImage, releasePlate } from '@/uni_modules/uni-plate-recognizer'

initPlate(): InitResult

初始化识别引擎(加载 ONNX 模型)。幂等,重复调用无副作用。

返回字段 类型 说明
success boolean 是否初始化成功
message string 失败原因(成功时为空)
const r = initPlate()
if (r.success) {
  console.log('引擎就绪')
} else {
  console.log('初始化失败: ' + r.message)
}

recognizeImage(path: string): string

识别单张本地图片,返回 JSON 数组字符串。

参数 类型 说明
path string 图片文件绝对路径(支持 file:// 前缀,自动剥离)
返回 说明
string JSON 数组字符串,无结果时返回 "[]"
const json = recognizeImage('/storage/emulated/0/DCIM/photo.jpg')
// json = [{"plateNo":"京A12345","plateColor":"蓝色","rect":[120,80,300,160],"detectConf":0.92,"plateType":0}]
const list = JSON.parse<PlateResult[]>(json) ?? []

releasePlate(): void

释放引擎资源(全局单例)。通常在 App 退出时调用,普通使用无需手动释放。

releasePlate()

6.2 组件式 API

UTS 兼容模式组件 <plate-camera>,适用于实时视频流识别场景:

<plate-camera ref="cam" @recognize="onRecognize" @status="onStatus"></plate-camera>

事件

事件名 参数 触发时机
recognize string(JSON 数组字符串) 每帧识别到结果时触发
status string(JSON:{"fps":N,"msg":"..."}) 帧率更新或状态变化时触发

方法

通过 ref 获取组件实例后调用:

import { PlateCameraElement } from '@/uni_modules/uni-plate-recognizer'

const cam = ref<PlateCameraElement | null>(null)

// 启动相机预览 + 实时识别(内部检查 CAMERA 权限)
cam.value?.startCamera()

// 停止相机预览与识别
cam.value?.stopCamera()

// 切换手电筒开关
cam.value?.toggleTorch()

事件处理示例

// 识别结果回调:取置信度最高的一张
function onRecognize(json: string): void {
  const list = JSON.parse<PlateResult[]>(json) ?? []
  if (list.length == 0) return
  let best = list[0]
  for (let i = 1; i < list.length; i++) {
    if (list[i].detectConf > best.detectConf) best = list[i]
  }
  // 更新 UI...
}

// 状态回调
function onStatus(payload: string): void {
  const o = JSON.parse<StatusInfo>(payload)
  if (o != null) {
    fps.value = o.fps
    statusMsg.value = o.msg
  }
}

6.3 返回数据结构

PlateResult

字段 类型 说明
plateNo string 车牌号码,如 "京A12345"
plateColor string 车牌颜色:黑色 / 蓝色 / 绿色 / 白色 / 黄色
rect number[] 检测框坐标 [x1, y1, x2, y2](原图像素)
detectConf number 检测置信度,0~1 浮点数
plateType number 车牌类型:0 = 单层,1 = 双层

InitResult

字段 类型 说明
success boolean 是否初始化成功
message string 失败原因(成功时为空)

JSON 示例

[
  {
    "plateNo": "京A12345",
    "plateColor": "蓝色",
    "rect": [120, 80, 300, 160],
    "detectConf": 0.92,
    "plateType": 0
  }
]

七、构建与部署

依赖声明

插件依赖声明在 uni_modules/uni-plate-recognizer/utssdk/app-android/config.json

{
  "dependencies": [
    "com.microsoft.onnxruntime:onnxruntime-android:1.18.0",
    "androidx.camera:camera-core:1.3.4",
    "androidx.camera:camera-camera2:1.3.4",
    "androidx.camera:camera-lifecycle:1.3.4",
    "androidx.camera:camera-view:1.3.4"
  ],
  "minSdkVersion": 21
}
  • onnxruntime-android:端侧 ONNX 推理运行时
  • androidx.camera:*:CameraX 相机预览与帧分析(视频流识别用,1.3.4 稳定版)
  • 图像处理(letterbox 缩放、透视矫正、双层拼接)全部用 Android 原生 Bitmap/Canvas/Matrix 实现,不依赖 OpenCV

构建步骤

  1. 用 HBuilderX 打开工程
  2. 确认运行环境配置(Gradle / JDK / Android SDK 路径正确)
  3. 运行 → 运行到手机或模拟器 → 制作自定义调试基座
  4. 构建完成后运行到 Android 基座进行真机调试

重建基座的场景

以下情况需要删除旧基座并重新制作:

  • 修改了 config.json 中的依赖版本
  • 新增/替换了 assets/ 下的 ONNX 模型文件
  • 修改了 Kotlin 引擎代码(PlateRecognizer.kt 等)
  • 升级了 HBuilderX 版本

旧基座文件位置:unpackage/debug/android_debug.apk,删除后重新制作即可。

打包发布

使用 HBuilderX 云打包 功能,选择「自定义基座」方式打包正式 APK。发布前确保:

  • manifest.jsonversionName / versionCode 已更新
  • App 图标已配置(manifest.json → app.distribute.icons
  • 模型文件已打包进 assets

八、项目结构

vehicle_license_plate_recognition/
├── App.uvue                          # 应用入口(生命周期 + 双击退出)
├── main.uts                          # 主入口
├── manifest.json                     # 应用配置
├── pages.json                        # 页面路由(index / plate / plate-video)
├── pages/
│   ├── index/index.uvue              # 首页(功能入口选择)
│   ├── plate/plate.uvue              # 拍照识别页
│   └── plate-video/plate-video.uvue  # 视频流识别页
├── static/
│   └── logo.png                      # 应用图标
├── uni_modules/
│   └── uni-plate-recognizer/         # UTS 车牌识别插件
│       ├── package.json              # 插件清单
│       └── utssdk/
│           ├── interface.uts         # 对外类型声明(PlateResult / InitResult)
│           └── app-android/
│               ├── index.uts         # 插件 API 实现(initPlate / recognizeImage / releasePlate)
│               ├── index.vue         # plate-camera UTS 组件实现
│               ├── config.json       # 依赖声明(onnxruntime + CameraX)
│               ├── AndroidManifest.xml  # CAMERA 权限
│               ├── PlateRecognizer.kt      # 引擎主入口(全局单例 + 检测/识别主流程)
│               ├── PlateCameraView.kt       # 相机封装(CameraX 预览 + 逐帧分析 + Overlay)
│               ├── PlateTypes.kt            # 类型定义 + 算法常量(字符集/颜色/均值/方差)
│               ├── PlatePreprocess.kt       # 前处理(letterbox / 检测预处理 / OCR 预处理)
│               ├── PlatePostprocess.kt      # 后处理(NMS / 坐标还原 / 透视矫正 / CTC 解码)
│               └── assets/
│                   ├── plate_detect.onnx     # 车牌检测模型(1280×1280)
│                   ├── plate_rec_color.onnx   # 字符识别 + 颜色分类模型
│                   └── fonts/platech.ttf      # 中文字体
├── apk/                              # 构建产物
└── unpackage/                        # HBuilderX 打包输出

九、技术架构

算法管线

输入图片 / 相机帧
  │
  ▼
letterbox 缩放 → 1280×1280(检测模型输入)
  │
  ▼
YOLOv5 检测 → [batch, 100800, 15]
  │
  ▼
NMS 去重 → 坐标还原到原图 → 透视矫正裁切车牌区域
  │
  ▼
CRNN 识别(BGR 通道顺序)+ 颜色分类(softmax)
  │
  ▼
CTC 解码 → 双层拼接 → 颜色领域校正
  │
  ▼
输出 [{ plateNo, plateColor, rect, detectConf, plateType }]

视频流数据流

CameraX ImageAnalysis(后台线程)
  → ImageProxy (YUV_420_888)
  → NV21 + YuvImage.compressToJpeg + decodeByteArray
  → Matrix.postRotate(rotationDegrees)          // 旋正
  → Bitmap.createScaledBitmap(宽 960)           // 降采样
  → PlateRecognizer.recognizeToJson(bmp)         // 复用全局单例
  → Handler(mainLooper).post → $emit('recognize', json)

性能策略

策略 说明
跳帧 ImageAnalysis STRATEGY_KEEP_ONLY_LATEST,积压帧自动丢弃
降采样 每帧缩放到宽 960px 再送引擎
后台线程 分析跑在独立单线程执行器(plate-analyzer 守护线程),不阻塞 UI
引擎复用 PlateRecognizer 全局单例,照片页与视频页共用同一 OrtSession,零额外模型内存
主线程 emit 识别结果通过 Handler(Looper.getMainLooper()) 切回主线程


十一、常见问题

Q1:提示「找不到名称"ai"」编译错误

原因:HBuilderX 未配置运行环境,Gradle 无法解析 onnxruntime-android 三方 AAR。

解决:在 HBuilderX 设置 → 运行配置 中正确填入 Gradle、Gradle JDK(17)、Android SDK 路径。

Q2:真机运行白屏或闪退

原因:使用了标准基座而非自定义基座。

解决:删除 unpackage/debug/android_debug.apk,重新制作自定义调试基座后运行。

Q3:视频流识别首次点击「开始识别」无反应

原因:首次使用需授予相机权限。

解决:点击「开始识别」→ 系统弹出授权框 → 点击「允许」→ 再次点击「开始识别」即可启动。

Q4:识别结果车牌号不完整或颜色错误

可能原因

  • 图片中车牌过小或模糊 → 尝试近距离拍摄
  • 光线不足 → 视频流模式可开手电筒辅助
  • 车牌角度过大 → 尽量正面拍摄

Q5:视频流帧率很低

可能原因:设备性能不足或图像复杂度过高。

优化:引擎已内置跳帧(KEEP_ONLY_LATEST)和降采样(宽 960px)策略。如帧率仍低于 5fps,建议在性能更好的设备上运行。

隐私、权限声明

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

<!-- 实时视频流识别所需相机权限 --> <uses-permission android:name="android.permission.CAMERA" /> <!-- 声明相机硬件特性,非强制,避免无摄像头设备无法安装 --> <uses-feature android:name="android.hardware.camera" android:required="false" /> <uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />

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

插件不采集任何数据

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

暂无用户评论。