说明:V1--V5 为交互式 SVG/HTML 组件,在配套单文件 HTML(
lpr-deep-dive.html)中可直接操作:四段式 pipeline 解剖、透视变换四点拖拽与 H 矩阵实算、CTC 对齐路径网格、误差复合计算器、方案选型卡片。本 Markdown 版给出等价的文字、数值与表格结论。公式为 LaTeX 源码,GitHub / VS Code / Typora 等可渲染。
口径说明 :本篇"车牌识别"(License Plate Recognition, LPR / ANPR)指"从图像中定位车牌并读出号码"的完整链路,聚焦中国民用车牌 (GA36-2018 标准)。检测(detection)与识别(recognition)两段都覆盖;"先检测车辆再检测车牌"的两级方案只在部署章节提及。字符集口径:31 个省级简称 + 10 个数字 + 24 个字母(剔除 I、O)= 65 类,与 CCPD 数据集一致。
0 · 导读
一条主线把八个问题串起来:
车牌识别把一张 H×W×3H\times W\times 3H×W×3 的图像变成一串 7--8 个字符:检测回答"牌在哪"(输出一个四边形),矫正回答"牌正不正"(输出一个单应矩阵),识别回答"牌上写的什么"(输出一条 CTC 路径)。深度学习在检测段换掉了颜色/边缘特征,在识别段换掉了字符分割------而端到端真正消灭的,是分阶段之间的误差复合。
| 主题 | 回答的问题 | 关键词 |
|---|---|---|
| 任务分解 | 从图到字符分几步 | 四段式、端到端、65 类字符集 |
| 检测 | 牌在哪 | 颜色/边缘 → YOLO、小目标、CCPD |
| 矫正 | 牌正不正 | 四点定位、单应矩阵、DLT、STN |
| 识别 | 写的什么 | CRNN、BiLSTM、CTC 前向算法 |
| 误差传播 | 为什么端到端赢 | pcharLp_{\text{char}}^{L}pcharL 复合、框偏移 |
| 数据 | 用什么训 | CCPD 十变体、增强、难例 |
| 部署 | 怎么上线 | 选型、量化、边缘、视频流 |
| 评测 | 怎么算准 | 字符级 vs 整牌级、误区 |
阅读顺序建议:Q1 定契约 → Q2/Q3/Q4 吃透三个环节的数学 → Q5 理解端到端胜出的定量理由 → Q6/Q7 落地 → Q8 纠错。附录 A/B/C 是字符集速查、公式汇总与工程实操清单。
Q1 · 任务分解:从一张图到一串字符
传统四段式 pipeline
在深度学习之前(以及今天大多数工程系统里),车牌识别被切成四个级联阶段:
| 阶段 | 输入 | 输出 | 传统方法 | 深度学习方法 |
|---|---|---|---|---|
| ① 检测 detection | 整幅图像 | 车牌矩形框(后来是四点) | 颜色分割(HSV 查表)+ 边缘密度 + 形态学 | YOLO / SSD / Faster R-CNN |
| ② 矫正 rectification | 图像 + 车牌框 | 正对的标准车牌图(如 94×24) | 四点定位 + 透视变换 / 仿射变换 | 同上,或 STN 可微分矫正 |
| ③ 字符分割 segmentation | 矫正后的车牌图 | 7--8 个单字符图 | 垂直投影 + 连通域 + 固定宽度切分 | 被消灭(见 Q4) |
| ④ 字符识别 recognition | 单字符图 ×7 | 每个字符的类别 | 模板匹配 / 小 CNN 分类器 | CRNN + CTC / LPRNet |
深度学习改变了什么:两处替换、一处消灭
- 替换检测:颜色/边缘特征 → CNN 检测器。传统方法在光照剧变、车身同色、多车牌场景下崩溃;CNN 检测器把"什么是车牌"变成学到的特征。
- 替换识别:单字符分类 → 序列识别。早期方案把矫正后车牌按固定宽度切成 7 格、每格过一个分类头(假设每个字符等宽、位置对齐)------字符间距不等、边框干扰都会让切分错位。
- 消灭分割 :CRNN + CTC 在不切分字符的条件下直接输出序列:特征图上每个时间步输出一个字符概率分布,CTC 损失允许"输出与标签不对齐"------一个字符占几个时间步、哪个时间步是空白(blank),全部交给模型学。
中国车牌:为什么这是一个"被规则约束"的识别问题
| 属性 | 口径 | 对算法的意义 |
|---|---|---|
| 字符集 | 65 类:31 省级简称(汉字)+ 10 数字 + 24 字母(26 去掉 I、O) | 闭集分类,类别数小;I/O 剔除是天然的先验约束 |
| 长度 | 燃油车 7 位(汉字 + 字母 + 5 位序号);小型新能源 8 位(序号第一位为 D/F 等能源标识字母) | 定长先验可用于后处理与校验 |
| 结构 | 省简称 + 发牌机关字母 + 序号;序号不含 I/O,最多 2 个字母 | 位置相关的字符分布(第 1 位只可能是 31 省之一) |
| 颜色 | 蓝底白字(燃油)、绿底黑字(新能源)、黄底黑字(大型车)、白底(军警) | 颜色是检测阶段的强特征,也是分类依据 |
| 尺寸 | 92 式 440×140 mm;新能源 480×140 mm;字符高约 45/43 mm | 长宽比 ≈ 3.1:1~3.4:1,可做 anchor 先验 |
核心认知 :车牌识别是闭集、定长、强结构先验的问题------这比通用 OCR(开放词表、任意长度)容易得多。GA36 编码规则本身就是校验器:识别引擎在 1/I、0/O 之间犹豫时可以直接排除候选;LPRNet 甚至显式引入"车牌模板语言模型"做后过滤(Q4)。
难在哪里:一张清单
| 难点 | 定量描述 | 主要打击环节 |
|---|---|---|
| 小目标 | CCPD 中车牌面积占比 0.2%--10%(文件名首字段),720×1160 图上典型 130×40 px | 检测 |
| 倾斜/透视 | CCPD-Rotate 水平倾斜 20--25°;Tilt 变体水平 15--45° + 垂直 15--45° | 检测 + 矫正 |
| 光照 | CCPD-DB:车牌区域过暗或过曝;夜间反光 | 检测 + 识别 |
| 运动模糊 | CCPD-Blur:相机抖动导致整体模糊 | 识别 |
| 天气 | CCPD-Weather:雨/雪/雾 | 全链路 |
| 污损遮挡 | 泥点、损坏、栏杆遮挡------CCPD-Challenge 综合难例 | 识别 |
| 相似字符 | 0/O、1/I、8/B、5/S、2/Z(I/O 已被标准剔除,降低了难度) | 识别 |
| 多车牌 | 一辆图内多车、或车尾双牌 | 检测 |
Q2 · 检测:车牌在哪
传统方法的三板斧(及其死因)
- 颜色分割 :把 RGB 转 HSV,蓝色车牌按色相区间(OpenCV 尺度 H≈100--130)二值化,绿色同理;
cv2.inRange+ 形态学闭运算 + 连通域。死因:光照色偏、车身蓝色、阴影。 - 边缘密度:车牌区域字符密集 → 灰度梯度统计值高,滑动窗口 + 阈值。死因:车牌边界与渐变背景不总有高边缘。
- MSER(最大稳定极值区域):字符笔画是稳定的亮/暗区域。死因:模糊场景下字符区域不稳定。
这三者的共同问题是手工特征 + 级联阈值:每一级都为上一级的错误买单(Q5 定量)。
深度学习检测器:一图流
现代方案清一色是通用目标检测器:YOLO 系列(v5/v7/v8/v10/v11)、SSD、Faster R-CNN、anchor-free 的 FCOS/CenterNet。车牌检测相比通用检测有三个特殊性,都可以 exploitation:
- 长宽比固定 ≈3:1:anchor 直接按 (3:1) 设计,回归余量小;
- 单类别:只有"车牌"一类(NP 场景另设负样本类),分类分支极简;
- 小目标:必须处理特征图分辨率问题------这是下面展开的像素级账。
小目标的像素级账
CCPD 图像 720×1160,车牌典型尺寸约 130×40 px(面积占比中位数约 1%)。看它在各层级特征图上占几格:
| 特征层级 | stride | 特征图尺寸(720×1160 输入) | 车牌占用格数 | 评价 |
|---|---|---|---|---|
| P2 | 4 | 180×290 | ≈32×10 | 太早,语义不足,计算贵 |
| P3 | 8 | 90×145 | ≈16×5 | 甜点:语义 + 分辨率兼顾 |
| P4 | 16 | 45×72 | ≈8×2.5 | 可用但偏粗 |
| P5 | 32 | 22×36 | ≈4×1.25 | 单格只有 1 行多,回归抖动致命 |
YOLOv5/v8 默认检测头在 P3/P4/P5(stride 8/16/32),车牌主要落在 P3------这就是"高分辨率输入 + P3 主检测"成为车牌检测标配的原因。若输入直接从 720×1160 下采样到 640×640(NPU 方形约束,见 vision-encoder 篇口径),stride-8 特征图上仍是 16×5 格,够用;但若用 320×320 输入,P5 上车牌只剩 2×0.6 格,检测率塌方。
像素级结论 :车牌检测的硬约束不是 mAP 而是特征图上的格子数:车牌短边在 P3 上要 ≥4--5 格。反推输入分辨率下限:短边 px ÷ 8 ≥ 4 → 400 px 以上。1080p Surveillance 场景直接送原图即可;NPU 前置 resize 时注意别把 4MP 主码流一刀切到 640 以下。
CCPD:车牌识别的 ImageNet 时刻
CCPD(Chinese City Parking Dataset)(Xu et al., ECCV 2018,中科大,合肥停车场实采)是第一个大规模、标注精细、按难度分层的中文车牌数据集,也是今天所有中文 LPR 论文的默认基准:
| 子集 | 张数(约) | 难度维度 |
|---|---|---|
| CCPD-Base | 200k | 常规:不同视角/距离/光照 |
| CCPD-FN | 20k | 距离过远或过近 |
| CCPD-DB | 20k | 车牌区域过暗/过曝 |
| CCPD-Rotate | 10k | 水平倾斜 20--25°,垂直 ±10° |
| CCPD-Tilt | 10k | 水平 15--45° + 垂直 15--45° |
| CCPD-Weather | 10k | 雨/雪/雾 |
| CCPD-Blur | 5k | 相机抖动模糊 |
| CCPD-Challenge | 10k | 综合最难 benchmark |
| CCPD-NP | 5k | 无车牌负样本(防误检) |
| CCPD-Green(2020 新增) | --- | 新能源 8 位绿牌 |
全部图像 720×1160×3。标注内嵌在文件名里,七字段:
025-95_113-154&383_386&473-386&473_177&454_154&383_363&402-0_0_22_27_27_33_16-37-15.jpg
│ │ │ │ │ └ 模糊度 15
│ │ │ │ └ 亮度 37
│ │ │ └ 车牌号(字典编码:0=皖、0=A、22=Y ...)
│ │ └ 边界框:左上 (154,383) → 右下 (386,473)
│ └ 倾斜角:水平 95°、垂直 113°
└ 面积占比 2.5%
注意第三组是四个角点 (不是水平框)------CCPD 从标注上就支持任意四边形定位 + 四点矫正的完整链路。官方 baseline 是 RPNet:wR2 定位网络(预测变换矩阵)+ RPnet 端到端检测识别一体网络。
Q3 · 矫正:透视变换的数学
车牌在图像中几乎总是透视变形 的四边形(侧拍、俯拍、云台抖动)。识别网络的训练输入却是正对的标准图。矫正就是把任意四边形映射回标准矩形,数学工具是单应矩阵(homography)。
四点定位 → 单应矩阵:完整 DLT 推导
设车牌四个角点在原图中的齐次坐标为 (xi,yi,1)T(x_i, y_i, 1)^\mathsf{T}(xi,yi,1)T(i=1..4i=1..4i=1..4),要映射到标准矩形的目标角点 (ui,vi,1)T(u_i, v_i, 1)^\mathsf{T}(ui,vi,1)T(如 94×24 的四个角)。单应矩阵 H∈R3×3H\in\mathbb{R}^{3\times 3}H∈R3×3 定义:
u′v′w′=h11h12h13h21h22h23h31h32h33xy1,u=u′w′,v=v′w′\begin{bmatrix} u' \\ v' \\ w' \end{bmatrix} = \begin{bmatrix} h_{11} & h_{12} & h_{13} \\ h_{21} & h_{22} & h_{23} \\ h_{31} & h_{32} & h_{33} \end{bmatrix} \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}, \qquad u = \frac{u'}{w'},\quad v = \frac{v'}{w'} u′v′w′ = h11h21h31h12h22h32h13h23h33 xy1 ,u=w′u′,v=w′v′
HHH 有 9 个元素但尺度不定,归一化 h33=1h_{33}=1h33=1 后剩 8 个自由度。展开前两类坐标:
u=h11x+h12y+h13h31x+h32y+1,v=h21x+h22y+h23h31x+h32y+1u = \frac{h_{11}x + h_{12}y + h_{13}}{h_{31}x + h_{32}y + 1}, \qquad v = \frac{h_{21}x + h_{22}y + h_{23}}{h_{31}x + h_{32}y + 1}u=h31x+h32y+1h11x+h12y+h13,v=h31x+h32y+1h21x+h22y+h23
交叉相乘消分母,每组对应点给出 2 个线性方程:
h11x+h12y+h13−h31 xu−h32 yu=uh_{11}x + h_{12}y + h_{13} - h_{31}\,xu - h_{32}\,yu = uh11x+h12y+h13−h31xu−h32yu=u
h21x+h22y+h23−h31 xv−h32 yv=vh_{21}x + h_{22}y + h_{23} - h_{31}\,xv - h_{32}\,yv = vh21x+h22y+h23−h31xv−h32yv=v
4 组点 → 8 个方程 → 8 个未知数,恰定解 。写成矩阵形式 Ah=bA\mathbf{h} = \mathbf{b}Ah=b(AAA 是 8×8),高斯消元或 SVD 求解。这就是 DLT(Direct Linear Transform)------OpenCV 的 cv2.getPerspectiveTransform(src, dst) 内部就是这 8 个方程。
几何直觉 :为什么"恰好 4 个点"?透视变换保直线、保平行线的交点关系,但 8 个自由度需要 4 组对应点(每组贡献 2 个约束)。3 个点欠定(2∘2^\circ2∘ 残余:可绕某条直线翻转),4 个点刚好锁死。这也是检测网络要回归四角点而不是水平框的原因:水平框 + 长宽比无法表达俯拍变形,四点才可以。
为什么矫正对识别率是"生死线"
设矫正后标准车牌 94×24 px,7 个字符,平均每个字符 94/7 ≈ 13.4 px 宽、约 24 px 高。识别网络的 CNN 感受野、宽卷积核(如 LPRNet 的 1×13)都是按"正对车牌"训练的。框不准 → 矫正后内容系统性偏移或残缺:
| 检测框误差 | 矫正后损失 | 后果 |
|---|---|---|
| 左边界偏 5 px | 第 1 字符(省简称,13.4 px 宽)损失 ≈37% | 省简称不可识别 |
| 右边界偏 5 px | 末位序号损失 ≈37% | 序号错识 |
| 上边界偏 3 px | 字符高度损失 12.5%(24 px 口径) | 笔画粘连 |
| 旋转 5° 未矫正 | 字符切变形 ≈ 高度方向的 8.7% 剪切 | 形变分布外,识别率跌 |
所以工程上检测框的质量标准从来不是"框住了"而是角点级精度:IoU 0.9 的水平框对应四角点误差可能已达 3--5 px,直接吃掉一个字符。CCPD 标注四角点、RPNet 直接回归变换矩阵,都是在回答这件事。
STN:把矫正做进网络里
STN(Spatial Transformer Network)(Jaderberg et al., NeurIPS 2015)的思路:矫正参数也由网络预测、且可微,于是"定位 → 矫正 → 识别"可以端到端反传。结构是一个微型定位网络 LocNet:输入图像 → 卷积 → 输出 6 个仿射参数(或 STN 原版的透视参数)→ 用可微分 grid sampling 对输入做变换。
LPRNet 的 STN 即此形态 :输入 94×24×3 → LocNet(3×3 stride 3 卷积 + 3×3 平均池化 + 卷积 + concat + dropout 0.5 + 两个全连接)→ 6 参数(Tanh 激活缩放到 -1,1 区间)→ 矫正后的图像送骨干网络。论文里有个值得记住的工程细节:LocNet 在训练前 5k iterations 保持关闭,之后才打开------因为识别分支初期太弱,LocNet 拿不到有意义的梯度,一开始就开会把变换矩阵带偏。
Q4 · 识别:CRNN 与 CTC
CRNN:把图像变成"时间序列"
CRNN(Shi et al., TPAMI 2017)是车牌/场景文字识别的标准骨架,三段式:
图像 100×32 → [CNN] → 特征图 25×1×512 → [Map-to-Sequence] → 25 步 × 512 维 → [BiLSTM] → [CTC 转录层]
CNN 的作用不是分类而是reshape :宽度方向保留序列结构(100 → 50 → 25,两次 2×2 maxpool,宽度 4 倍下采样),高度方向彻底压掉(32 → 1)。于是特征图的每一列 = 一个时间步,宽 25 步、每步 512 维------图像被解释成"横向书写的句子"。
| 量 | CRNN 口径 | 说明 |
|---|---|---|
| 输入 | 100×32(宽×高)×3 | 高度压到 1,宽度 = 序列长 |
| 时间步 TTT | 25 | 由宽度下采样倍率决定(100/4) |
| 每步维度 | 512 | CNN 输出通道数 |
| RNN | 2 层 BiLSTM,隐藏 256×2 向 | 上下文约束(前文对后文的约束) |
| 输出 | 25 步 × $ | \mathcal{V} |
LPRNet 则更激进:去掉 LSTM,用 1×13 的宽卷积替代 BiLSTM 捕捉局部字符上下文(每个字符在 94 px 宽图上约占 13 px,1×13 感受野恰好覆盖一个字符),再拼接全局上下文 embedding(对骨干输出做 global pooling 后平铺拼接)。动机是嵌入式设备跑 LSTM 太贵------这是"精度换速度"的经典一刀。
CTC:为什么需要它、数学是什么
CTC(Connectionist Temporal Classification) (Graves et al., ICML 2006)解决的是一个不对齐问题:网络输出 TTT 步(T=25T=25T=25),标签只有 LLL 个字符(L=7L=7L=7),网络自己也不知道哪个字符该占哪几步。CTC 的办法是引入空白符号 blank(记为 ∅) ,把"一条路径"定义为每步选一个符号,一条路径折叠(先去 blank、再合并相邻重复)后若等于标签,就是该标签的一条合法路径。标签概率 = 所有合法路径概率之和。
以标签 l=(l1,...,lL)l = (l_1,\dots,l_L)l=(l1,...,lL) 为例,先扩展为
l′=(∅, l1, ∅, l2, ∅, ..., lL, ∅),∣l′∣=S=2L+1l' = (\varnothing,\, l_1,\, \varnothing,\, l_2,\, \varnothing,\,\dots,\, l_L,\, \varnothing), \qquad |l'| = S = 2L+1l′=(∅,l1,∅,l2,∅,...,lL,∅),∣l′∣=S=2L+1
(首尾加 blank,相邻字符间插 blank。)定义 αt(s)\alpha_t(s)αt(s) = 前 ttt 步所有路径中、折叠后等于 l1:s′l'_{1:s}l1:s′ 的概率之和。递推(t≥2t \ge 2t≥2):
αt(s)=(αt−1(s)+αt−1(s−1))⋅yt(ls′)\alpha_t(s) = \Big(\alpha_{t-1}(s) + \alpha_{t-1}(s-1)\Big)\cdot y_t(l'_s)αt(s)=(αt−1(s)+αt−1(s−1))⋅yt(ls′)
其中 yt(ls′)y_t(l'_s)yt(ls′) 是 ttt 步输出分布中符号 ls′l'_sls′ 的概率。关键的第三条转移路径 要小心:若 ls′l'sls′ 既不是 blank、也与 ls−2′l'{s-2}ls−2′ 不同(即 sss 是一个"可以新开始"的字符位),还允许从 s−2s-2s−2 直接跳过来:
αt(s)=(αt−1(s)+αt−1(s−1)+αt−1(s−2))⋅yt(ls′)\alpha_t(s) = \Big(\alpha_{t-1}(s) + \alpha_{t-1}(s-1) + \alpha_{t-1}(s-2)\Big)\cdot y_t(l'_s)αt(s)=(αt−1(s)+αt−1(s−1)+αt−1(s−2))⋅yt(ls′)
(ls′=∅l'_s = \varnothingls′=∅ 或 ls′=ls−2′l's = l'{s-2}ls′=ls−2′ 时禁止 s−2s-2s−2 跳入------否则会把两个独立重复字符错误地折叠成一个。)初值 α1(1)=y1(∅)\alpha_1(1) = y_1(\varnothing)α1(1)=y1(∅)、α1(2)=y1(l1)\alpha_1(2) = y_1(l_1)α1(2)=y1(l1),其余为 0。损失:
LCTC=−logP(l ∣ x)=−log(αT(S)+αT(S−1))\mathcal{L}_{\text{CTC}} = -\log P(l\,|\,x) = -\log\big(\alpha_T(S) + \alpha_T(S-1)\big)LCTC=−logP(l∣x)=−log(αT(S)+αT(S−1))
(终点停在 SSS 或 S−1S-1S−1 都算收敛------末尾 blank 可虚设。)
折叠规则的两条军规,直接决定解码正确性:
- 路径 π=(∅, 京, 京, ∅, A, 1, 1, ∅)\pi = (\varnothing,\, \text{京},\, \text{京},\, \varnothing,\, \text{A},\, \text{1},\, \text{1},\, \varnothing)π=(∅,京,京,∅,A,1,1,∅) → 去 blank → 京京A11 → 合并相邻重复 → 京A1;
- 要输出"京京"(两个相同字符相邻),路径必须 是中 blank 分隔的:(京,∅,京)(\text{京}, \varnothing, \text{京})(京,∅,京),直接 (京,京)(\text{京},\text{京})(京,京) 会折叠成一个京。
交互 V3(HTML 版) :网格可视化 T=12T=12T=12 步 × 15 状态(标签 京A12345,S=15S=15S=15),可切换两条合法路径,看它们如何各自折叠到同一标签------CTC 的全部思想就在"多路径同标签"这六个字里。
解码:贪心、束搜索与后过滤
- 贪心:每步取 argmax,折叠后输出。快,但一步错步步错(错误会改变后续最优路径)。
- 束搜索(beam search) :维护 top-κ\kappaκ 前缀路径,保留总概率更高的序列。CTC 概率可分解,beam search 是标准操作。
- 后过滤(post-filtering) :LPRNet 用车牌模板语言模型------beam search 吐出 top-N 候选后,按目标国车牌规则(字符集、位置约束、长度)筛出第一个合法的。比如候选"京A12I45"直接因 I 非法被剔除。这是把 GA36 编码先验接进推理端的标准做法,零训练成本,专治"差一点就对了"。
Q5 · 端到端与误差传播:为什么分阶段会输
误差复合的定量模型
设三个级联环节各自的成功率:检测(找到且框准)pdetp_{\text{det}}pdet、矫正(四点定位准、变换成功)prectp_{\text{rect}}prect、单字符识别 pcharp_{\text{char}}pchar。则整牌(LLL 位全对)成功率:
pplate=pdet⋅prect⋅pchar Lp_{\text{plate}} = p_{\text{det}} \cdot p_{\text{rect}} \cdot p_{\text{char}}^{\,L}pplate=pdet⋅prect⋅pcharL
LLL 次幂是全文最重要的一个数学事实:任何单字符的小误差都被车牌长度指数放大。
| pdetp_{\text{det}}pdet | prectp_{\text{rect}}prect | pcharp_{\text{char}}pchar | pplatep_{\text{plate}}pplate(L=7) | pplatep_{\text{plate}}pplate(L=8,新能源) |
|---|---|---|---|---|
| 0.990 | 0.990 | 0.990 | 91.4% | 90.4% |
| 0.990 | 0.990 | 0.995 | 94.6% | 94.2% |
| 0.990 | 0.990 | 0.999 | 97.3% | 97.2% |
| 0.995 | 0.995 | 0.995 | 95.6% | 95.1% |
| 0.999 | 0.999 | 0.999 | 99.1% | 99.0% |
三个读数:
- 单字符 99% 听起来很高,整牌只有 91.4%------7 位复合吃掉 8.6 个点。停车场计费场景 91% 意味着每 10 辆车错 1 辆,不可接受。
- 反解:要整牌 99%(检测、矫正各 99.9%),需要 pchar≥0.99/0.9987≈99.89%p_{\text{char}} \ge \sqrt7{0.99/0.998} \approx 99.89\%pchar≥70.99/0.998 ≈99.89%------单字符四个 9。分阶段方案里这个数字由独立的识别网络给出,训练目标(单字符交叉熵)与最终指标(整牌全对)不一致。
- 端到端方案(CTC 在整牌上算损失)训练目标与业务指标天然对齐:CTC 损失下降 = 整牌概率上升,不存在"单字符 99.9% 但整牌 97%"的错位。
检测框偏移的像素级传导
分阶段方案里,检测框误差经过矫正系统性传导 到识别(Q3 已算过账):框偏 5 px = 边界字符损失 37%。而端到端网络共享特征,检测分支的梯度直接受整牌损失约束------框不准会通过识别分支反传,"逼着"检测头输出更准的角点。这是 RPNet 一类端到端工作的机理:不是检测变准了,是检测被识别的需求逼准了。
端到端的代价与边界
端到端不是免费午餐:
| 维度 | 分阶段(YOLO + LPRNet) | 端到端(RPNet 类) |
|---|---|---|
| 数据标注 | 检测框 + 字符序列可分开标注 | 必须同一张图同时有两类标注 |
| 模块可维护性 | 可单独升级/回滚(换识别器不动检测) | 一损俱损,调试难度高 |
| 难例定位 | 误差可归因到具体环节 | 端到端黑盒,需分环节探针 |
| 速度 | 两级前向(+YOLO 全图检测) | 单次前向,通常更快 |
| 训练 | 两个独立训练任务 | 联合训练,调参敏感(loss 权重) |
工程建议 :多数业务(停车场、卡口)用分阶段 + 强检测 + 强识别更稳------两段都可独立用最新权重热替换;端到端留给算力/时延極端受限(边缘盒子、单帧 <10 ms)或数据标注齐全的队伍。
Q6 · 数据:CCPD 与增强
增强策略按环节设计
| 增强 | 模拟的 degradation | 打击环节 | 实现要点 |
|---|---|---|---|
| 随机透视(4 角扰动) | 拍摄视角 | 检测 + 矫正 | 与 CCPD-Tilt/Rotate 同分布 |
| 方向性运动模糊 | 相机/车辆抖动 | 识别 | 沿运动方向的模糊核,长度 3--15 px |
| 亮度/对比度/伽马 | 昼夜、曝光 | 识别 | 车牌区域过曝要单独模拟(CCPD-DB) |
| 雨雪雾叠加 | 天气 | 全链路 | 半透明噪声层 + 高斯雾 |
| 高斯/椒盐噪声 | 传感器 | 识别 | 低照度升噪 |
| 随机 affine(旋转/缩放/平移) | 装调误差 | 识别 | LPRNet 训练即用此类增强 |
| 颜色抖动(蓝/绿误判) | 同色车身 | 检测 | HSV 域小扰动 |
LPRNet 的训练配方(可作起点):Adam、batch 32、lr 1e-3、每 100k 步衰减 10×、总 250k 步;增强为随机 affine;LocNet 第 5k 步后开启(Q3)。
难例挖掘(hard example mining)
- 训练中期捞出整牌错识但检测正确的样本------它们正是字符混淆对(0/O 剔除后主要剩 8/B、5/S、2/Z、D/0 等);
- 对混淆对做过采样或在损失里加权;
- 新能源车牌必须单独重视:8 位、绿底黑字、D/F 开头,与蓝牌视觉差异大------只用蓝牌训练的模型上绿牌通常掉 5--10 个点。CCPD-Green(2020)就是为这个问题加的。
Q7 · 工程部署
方案选型
| 方案 | 检测 | 识别 | 速度(1080p,GPU) | 精度(CCPD-Weather 口径) | 体积/部署 |
|---|---|---|---|---|---|
| 传统级联 | 颜色+边缘 | 分割 + 单字 CNN | 慢(CPU 级) | 低(光照一变就崩) | 已淘汰 |
| YOLO + CRNN | YOLOv8s | CRNN(BiLSTM) | ≈30--60 FPS | 高,BiLSTM 精度上限高 | 中,LSTM 边缘不友好 |
| YOLO + LPRNet | YOLOv8s | LPRNet(无 RNN) | ≈50--100 FPS | 高(略低于 CRNN) | 小,适合边缘 |
| 端到端 RPNet | 一体 | 一体 | ≈60 FPS+ | 高 | 训练/调试成本高 |
(速度为量级参考,依赖硬件与输入分辨率;精度列给相对排序,绝对数字随测试集而变。)
量化与压缩
- INT8 后量化:车牌识别对量化中等敏感------检测框回归比分类敏感,字符分类在 65 类闭集上耐性较好。经验值:整牌准确率损失 <1 个点,速度 2--3×、体积 4×。RK3588 / ORBBEC 类 NPU 的典型路线。
- 通道剪枝:LPRNet 骨干本身小(Fire/Inception 块做的是宽而非深),剪枝收益有限,优先量化。
- 输入分辨率:识别分支锁 94×24(与训练一致);检测分支 640×640 起(Q2 的格子数账),别为省算力降到 320。
视频流:跟踪 + 识别
停车场/卡口是视频流场景,逐帧全图检测是浪费。标准架构:检测 + 跟踪(SORT/ByteTrack)+ 关键帧择优识别------同一 track 内只在置信度最高或最正对的一帧上跑矫正 + 识别,车牌号做多数投票。收益:识别算力降一个量级,且投票本身消掉单帧误识(视频流场景下整牌准确率普遍比单帧高 1--3 个点)。
Q8 · 评测与误区
指标口径
| 指标 | 定义 | 用途 |
|---|---|---|
| 检测 mAP@0.5 | 框级 IoU>0.5 的平均精度 | 检测器迭代 |
| 检测 mAP@0.5:0.95 | COCO 严格口径 | 同上 |
| 整牌级准确率 | 7/8 位字符全对才算对 | 唯一有业务意义的口径 |
| 字符级准确率 | 单字符分类正确率 | 训练期诊断 |
| 端到端整牌准确率 | 从原图直接出号,全对才算对 | 最终交付指标 |
误区清单
- "把检测 mAP 当识别率汇报":mAP 0.95 的检测器 + 99% 的字符准确率 = 91.4% 整牌(Q5 的账)。汇报必须用整牌口径。
- "字符级 99% 很高了":7 次幂复合,见上。
- 只训蓝牌不训绿牌:新能源 8 位绿牌是独立分布,2026 年新车渗透率过半,漏训等于漏一半车流。
- 测试集泄漏:CCPD 按图划分不够------同一停车场相邻帧高度相似,split 要按场景/时间分。自采数据更要注意"训练集里的车牌出现在测试集里"。
- 忽视负样本(CCPD-NP):没有无车牌负样本的检测器在空地/广告牌上狂报假阳性。
- 用水平框标注训四点检测:侧拍场景水平框 IoU 天然上不去,且矫正时四角点误差大(Q3 的像素账)。要么按四点标注,要么接受矫正损失。
- decode 不过滤:beam search 输出不过车牌模板(GA36 规则)后过滤,等于把字符集和位置先验白扔。
- 直接套用开放域 OCR:通用 OCR 词表开放、长度不定,用在定长闭集车牌上是杀鸡用牛刀且更慢------先验用满才是车牌场景的正确姿势。
A · 附录:中国车牌字符集与编码规则速查
字符集 65 类(CCPD 口径):
| 段 | 类数 | 内容 |
|---|---|---|
| 省级简称 | 31 | 京沪津渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼 |
| 数字 | 10 | 0--9 |
| 字母 | 24 | A--Z 剔除 I、O(与 1、0 视觉混淆) |
编码结构(GA36-2018,普通小型车):
[省简称(1)] [发牌机关字母(1)] [序号(5)] 共 7 位
京 A 1 2 3 4 5
- 序号为数字 + 字母混排,不含 I/O,最多 2 位字母;字母位置受号段规则约束;
- 小型新能源汽车:序号 6 位且第三码必为字母(D=纯电优先,F=非纯电优先),共 8 位;
- 大型车(黄牌)序号结构不同;警车以"警"结尾、使馆"使"、领馆"领"------特殊号牌需单独建模,通用场景建议业务层过滤。
位置先验的用法:第 1 位候选只有 31 省;第 2 位只有 24 字母;第 3--8 位是 34 类(数字+24 字母)。推理时对每个位置做 mask,等价于把字符级准确率再抬一截------这是车牌任务独享的福利。
B · 附录:公式汇总
| 量 | 公式 | 备注 |
|---|---|---|
| 单应矩阵 | u=(h11x+h12y+h13)/(h31x+h32y+1)u=(h_{11}x+h_{12}y+h_{13})/(h_{31}x+h_{32}y+1)u=(h11x+h12y+h13)/(h31x+h32y+1) 等 | h33=1h_{33}=1h33=1,8 DOF,4 组点定解 |
| DLT | Ah=bA\mathbf{h}=\mathbf{b}Ah=b,8×8 线性系统 | OpenCV getPerspectiveTransform |
| CRNN 时间步 | T=Win/4T = W_{\text{in}} / 4T=Win/4(100→25) | 宽 4× 下采样,高压到 1 |
| CTC 扩展标签 | l′=(∅,l1,∅,...,lL,∅)l'=(\varnothing,l_1,\varnothing,\dots,l_L,\varnothing)l′=(∅,l1,∅,...,lL,∅),S=2L+1S=2L+1S=2L+1 | blank 插位 |
| CTC 前向 | αt(s)=(αt−1(s)+αt−1(s−1))⋅yt(ls′)\alpha_t(s)=(\alpha_{t-1}(s)+\alpha_{t-1}(s-1))\cdot y_t(l'_s)αt(s)=(αt−1(s)+αt−1(s−1))⋅yt(ls′)(+s−2s{-}2s−2 项若允许) | 重复字符间必须有 blank |
| CTC 损失 | L=−log(αT(S)+αT(S−1))\mathcal{L}=-\log(\alpha_T(S)+\alpha_T(S-1))L=−log(αT(S)+αT(S−1)) | 整牌级目标 |
| 整牌成功率 | pplate=pdet⋅prect⋅pcharLp_{\text{plate}}=p_{\text{det}}\cdot p_{\text{rect}}\cdot p_{\text{char}}^{L}pplate=pdet⋅prect⋅pcharL | LLL 次幂是核心 |
| 反解单字符要求 | pchar≥pplate/(pdetprect)Lp_{\text{char}}\ge \sqrtL{p_{\text{plate}}/(p_{\text{det}}p_{\text{rect}})}pchar≥Lpplate/(pdetprect) | 99.9%/99.9% → 99.89%@L=7 |
| 车牌特征图格子 | plate_px/stride\text{plate\_px}/\text{stride}plate_px/stride,P3 需 ≥4--5 格 | 决定输入分辨率下限 |
| 字符宽度 | Wplate/LW_{\text{plate}} / LWplate/L(94/7≈13.4 px) | 框偏移传导的基准 |
C · 附录:工程实操清单(P0)
按优先级排列,每项都是可独立验证的:
- P0-1 检测输入分辨率:确认车牌短边在 P3(stride-8)上 ≥4--5 格;720×1160 直送,resize 下限 640 短边。
- P0-2 检测标注形态:侧拍场景用四角点标注(CCPD 同规格);只有水平框时,评估矫正损失的字符缺口(Q3 表)。
- P0-3 字符集与位置 mask:训练/推理统一 65 类;推理端做位置 mask + GA36 模板后过滤,白捡的准确率。
- P0-4 新能源覆盖:训练集必须含绿牌(8 位);单独测 CCPD-Green 子集准确率,不达标前不上线计费。
- P0-5 评测口径:交付指标只有整牌级;字符级仅作训练诊断;测试集按场景划分防泄漏。
- P0-6 负样本:检测器训入 CCPD-NP 类负样本,压广告牌/空地假阳性。
- P0-7 视频流架构:检测 + ByteTrack + 关键帧识别 + 多数投票,识别算力降一个量级。
- P0-8 量化基线:INT8 后量化建立基线(整牌损失 <1 点再上线),留 FP16 回滚分支。
小结
把全篇压缩成六句话:
- 车牌识别四段式(检测 → 矫正 → 分割 → 识别)里,深度学习替换了检测特征、替换了识别范式,消灭的是字符分割------CRNN + CTC 让"不切分字符直接出序列"成立;
- 检测的硬约束是特征图格子数:车牌短边在 P3(stride-8)上要 ≥4--5 格,这反推出输入分辨率下限(短边 400 px 以上,实务 640 起步);
- 矫正是纯几何:四点 → 8 方程 → 单应矩阵(DLT);框偏 5 px = 边界字符损失 37%,所以角点级精度才是检测的质量标准;
- CTC 的全部思想是"多路径同标签":扩展标签插 blank、前向递推 αt(s)\alpha_t(s)αt(s) 求和全部合法路径、损失 −log(αT(S)+αT(S−1))-\log(\alpha_T(S)+\alpha_T(S-1))−log(αT(S)+αT(S−1)) 天然是整牌级目标;
- 整牌成功率 pdet⋅prect⋅pcharLp_{\text{det}}\cdot p_{\text{rect}}\cdot p_{\text{char}}^{L}pdet⋅prect⋅pcharL:单字符 99% 只换来 91.4% 整牌,指数复合是端到端胜出的定量理由;反解四个 9 的单字符要求,分阶段方案给不起;
- 中国车牌是闭集(65 类)、定长(7/8 位)、强结构(位置 mask + GA36 模板后过滤)的问题------先验用满,比换更大的模型更划算。