简介:这份资源面向深度学习初学者、目标检测方向的学生及毕业设计开发者,提供基于YOLOv5实现车牌识别的完整工程实践。压缩包内共77个文件,以29个Python脚本、17个YAML配置、21张示例图片及2个预训练权重文件为主,涵盖模型定义、训练推理、数据转换与权重下载等模块,整体约25.4MB。资源围绕数据预处理、模型训练、参数调优、验证测试与实时部署五个环节展开,读者可借助其中的网络结构配置、训练脚本与已训练权重,快速复现车牌检测流程,并在此基础上调整超参数、替换数据集或迁移到安防监控与智能交通场景。目前已有2591人学习下载,适合作为课程实践、课题研究或毕业设计的起步模板,帮助理解卷积神经网络如何自动提取车牌特征并完成端到端定位识别。
1. 车牌识别为什么选 YOLOv5:从一张违章抓拍说起
前阵子帮朋友看一个停车场出入口的抓拍项目,相机像素不低,但车牌识别率死活上不去,白天还行,一到傍晚逆光就大面积漏检。翻了他的代码才发现,检测环节用的是传统边缘加颜色分割,阈值全靠手调,光照一变就崩。这类场景其实特别适合把检测环节换成 YOLOv5——它把车牌当成一个普通目标来框,鲁棒性比手工特征强太多,而且工程化程度高,从训练到部署一条龙都有现成脚本。
这份资源就是围绕「YOLOv5 实现车牌识别」这条主线展开的,包含数据集组织、模型训练、推理后处理到部署落地的完整链路。它解决的核心问题是:让你不用从零搭检测框架,直接在一个验证过的工程结构上,把车牌检测加字符识别跑通。适合两类人:一是刚接触深度学习目标检测、想拿一个真实场景练手的工程师;二是手里有车牌识别需求、想快速验证方案可行性的开发者。下面我按自己拆包复现的顺序,把关键环节和踩过的坑讲清楚。
2. YOLOv5 车牌检测的工程结构与环境配置
2.1 为什么是 YOLOv5 而不是 v8 或 Faster R-CNN
先说说选型。车牌检测这个任务有几个特点:目标尺寸相对固定、长宽比偏扁、单张图里目标数量少(通常一到两个)、对实时性要求高。YOLOv5 在这个场景下的优势很明显。它的 anchor 机制对扁长目标友好,只要聚类出来的先验框贴合车牌比例,召回率就稳;推理速度快,n/s 版本在普通显卡上轻松跑到几十帧;生态成熟,导出 ONNX、TensorRT 的脚本都是现成的。
Faster R-CNN 精度不差,但两阶段推理慢,部署到边缘设备上很吃力。YOLOv8 更新,但如果你手里的部署工具链、后处理代码都是围绕 v5 写的,贸然换版本反而增加迁移成本。常见做法是:验证阶段用 YOLOv5s 快速迭代,确认方案可行后再考虑换更轻或更新的骨干。这个资源选 v5,我认为是务实的选择,不是追新。
2.2 目录结构与关键文件
拿到包之后别急着跑,先把结构理清楚。典型的 YOLOv5 车牌项目会包含这几块:
| 目录/文件 | 作用 | 复现时要动的地方 |
|---|---|---|
| data/ | 数据集配置与图片标签 | 改 yaml 里的路径和类别数 |
| models/ | 网络结构定义 | 一般不动,除非改 anchor |
| weights/ | 预训练权重 | 放 yolov5s.pt 做迁移学习 |
| utils/ | 数据加载、后处理、指标 | 车牌后处理常在这里加 |
| train.py | 训练入口 | 调超参 |
| detect.py | 推理入口 | 调置信度和 NMS |
车牌识别和通用检测最大的不同在于:检测框出来之后还要做字符识别。所以工程里通常会有两个模型,或者一个检测加一个 CRNN 识别。这份资源的主线是检测部分,识别部分一般接一个轻量 OCR。你得先明确自己要的是「只检测车牌位置」还是「检测加识别字符」,这决定了后面要不要再接一个识别模型。
2.3 环境配置:conda 建环境与依赖安装
环境这块翻车最多,我一般强制用 conda 隔离,避免和系统里的 torch 打架。步骤和命令如下:
# 创建独立环境,python 版本按项目要求,一般 3.8 比较稳 conda create -n plate_yolo python=3.8 -y conda activate plate_yolo # 安装 pytorch,注意 cuda 版本要和驱动匹配,这里以 cu118 为例 pip install torch==2.0.1 torchvision==0.15.2 --index-url https://download.pytorch.org/whl/cu118 # 安装项目其余依赖 pip install -r requirements.txt # 验证 torch 是否能识别到显卡 python -c "import torch; print(torch.cuda.is_available())"逻辑说明:先建环境再装 torch,是因为 requirements.txt 里往往也写了 torch,如果顺序反了,pip 可能装成 CPU 版本,训练时慢到怀疑人生。参数上,python 版本别盲目上 3.11,很多老项目的 numpy、opencv 轮子对高版本支持不好。最后那句验证一定要跑,输出 True 才算环境通了。如果输出 False,先查驱动和 cuda 版本对应关系,别急着改代码。
提示:requirements.txt 里的版本号如果和你的 cuda 冲突,优先保证 torch 和 cuda 匹配,其余依赖可以适当放宽版本。
3. 数据集准备与 YOLOv5 训练调参实战
3.1 车牌数据集标注格式与目录组织
YOLOv5 用的是 YOLO 格式标签,每张图对应一个 txt,每行是类别 中心x 中心y 宽 高,全部归一化到 0 到 1。车牌场景一般就一个类别,所以类别 id 恒为 0。目录组织常见两种,我推荐按下面这种:
dataset/ images/ train/ val/ labels/ train/ val/图片和标签文件名必须一一对应,只是后缀不同。这里有个血泪经验:标注时框要贴紧车牌边缘,别把车牌外的螺丝孔、边框留太多,否则模型学到的框会偏大,后处理裁剪字符时容易带进干扰。另外,车牌如果是倾斜的,标注框用水平矩形就行,YOLOv5 默认不做旋转框,倾斜靠数据增强和后续透视校正解决。
数据配置文件一般叫plate.yaml,内容长这样:
# 数据集根路径,建议写绝对路径,避免相对路径找不到 path: /home/user/dataset train: images/train val: images/val # 类别数,车牌只有一类 nc: 1 names: ['plate']参数说明:path写绝对路径能省掉很多「找不到文件」的玄学问题;nc一定要和标签里的最大类别 id 加一一致,写错了训练不报错但结果全乱。改完 yaml,先用官方脚本检查一遍标签有没有越界、有没有空文件,比训练到一半才发现问题划算得多。
3.2 迁移学习与超参数设置
车牌数据量通常不大,几千张就算多了,所以必须用预训练权重做迁移学习。命令如下:
# 用 yolov5s 预训练权重,训练 100 轮,批次大小按显存调 python train.py \ --weights yolov5s.pt \ --data data/plate.yaml \ --epochs 100 \ --batch-size 16 \ --img-size 640 \ --cfg models/yolov5s.yaml \ --hyp data/hyps/hyp.scratch-low.yaml \ --name plate_exp逻辑说明:--weights指定预训练权重,这是小数据集能训出来的关键;--img-size设 640 是 v5 的默认,车牌目标不大,如果显存够可以上 1280,小目标召回会更好;--hyp选低增强配置,车牌颜色和纹理比较固定,过强的色彩抖动反而有害。批次大小 16 是 8G 显存的经验值,爆显存就往下调,别硬撑。
训练过程中重点看三个指标:mAP@0.5、precision、recall。车牌场景我更看重 recall,漏检比误检麻烦,因为漏了就没法补救。如果 recall 上不去,先查标注质量,再考虑调低置信度阈值或增加正样本。
3.3 anchor 聚类:让先验框贴合车牌比例
YOLOv5 默认 anchor 是给通用目标用的,车牌又扁又宽,直接训也能收敛,但用聚类重新生成 anchor 会明显提升。项目里一般带一个聚类脚本,跑法如下:
# 对训练集标签做 k-means,生成 9 个 anchor python utils/autoanchor.py --data data/plate.yaml逻辑说明:这个脚本会读取所有训练标签的宽高,聚类出最贴合数据分布的 9 个框,然后你可以把它们替换到模型 cfg 里。参数上,聚类数保持 9 和 v5 的三个检测头对应。替换后重新训练,通常 mAP 能涨一两个点。注意别在验证集上聚类,那是数据泄露,要用训练集。
4. 推理、后处理与车牌识别串联
4.1 detect.py 推理与置信度阈值
训练完拿到best.pt,先用推理脚本看看效果:
python detect.py \ --weights runs/train/plate_exp/weights/best.pt \ --source test_images/ \ --conf-thres 0.25 \ --iou-thres 0.45 \ --save-txt逻辑说明:--conf-thres是置信度阈值,低于它的框直接丢;--iou-thres控制 NMS 的重叠阈值。车牌场景目标少,NMS 压力不大,iou 设 0.45 够用。--save-txt会把检测框坐标存下来,方便你接后续的字符识别。如果发现漏检,先把 conf 降到 0.15 看看是不是阈值卡太死;如果误检多,再往上提。
4.2 从检测框到字符识别:裁剪与透视校正
检测框出来只是第一步,要识别字符还得把车牌区域抠出来。这里有两个坑:一是框可能带背景,二是车牌有倾斜。常见做法是先按框裁剪,再做一次透视校正。核心代码逻辑如下:
import cv2 import numpy as np def crop_plate(img, box): # box 格式为 xyxy,转成整数 x1, y1, x2, y2 = map(int, box) # 适当外扩几个像素,避免切掉字符边缘 pad = 2 x1, y1 = max(0, x1 - pad), max(0, y1 - pad) x2, y2 = min(img.shape[1], x2 + pad), min(img.shape[0], y2 + pad) plate = img[y1:y2, x1:x2] # 转灰度再做自适应阈值,逆光场景更稳 gray = cv2.cvtColor(plate, cv2.COLOR_BGR2GRAY) binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2) return binary逻辑说明:外扩 pad 是为了防止框太紧切掉字符;自适应阈值比固定阈值抗光照变化,参数 11 是邻域块大小,2 是常数项,逆光时可以适当调大常数。裁剪出来的图再送进 CRNN 或轻量 OCR 做字符识别。如果车牌倾斜明显,还得先做角点检测加透视变换,把车牌摆正再识别,否则字符分割会乱。
4.3 端到端串联与结果输出
把检测和识别串起来,流程是:读图 → YOLOv5 推理 → 遍历每个框 → 裁剪校正 → 识别字符 → 输出结构化结果。输出格式建议统一成 JSON,方便下游系统对接:
results = [] for box, conf in zip(boxes, confs): plate_img = crop_plate(img, box) text = ocr_model(plate_img) # 识别模型返回字符串 results.append({ "bbox": box, "confidence": float(conf), "plate_text": text })逻辑说明:把置信度和识别文本一起返回,下游可以根据置信度做二次校验。车牌识别里常见的「0 和 O」「1 和 I」混淆,可以在识别后加一层规则校正,比如按车牌格式校验位数和字符集,不合规的标记为可疑。这一步能显著降低误识率,属于工程上很实用的后处理。
5. 避坑与常见问题排查
5.1 训练 loss 不降反升
现象:训练几轮后 box loss 或 obj loss 突然飙升。原因通常是学习率太大,或者数据里有脏标注(框越界、宽高为 0)。解决:先把学习率降一个数量级试,再用脚本扫一遍标签,把宽高小于 0.001 的框删掉。我遇到过一张图标签坐标全是 0,就是标注工具导出时出的错。
5.2 验证集 mAP 很高但实际推理漏检
现象:训练日志里 mAP@0.5 到 0.9 了,实际跑图却漏。原因多半是验证集和实际场景分布不一致,比如验证集都是白天图,实际有夜间。解决:重新划分验证集,保证覆盖各种光照和角度;推理时适当降低 conf 阈值,并检查预处理是否和训练一致(归一化方式、通道顺序)。
5.3 显存溢出 CUDA out of memory
现象:训练到一半报显存不足。原因:批次太大、img-size 太高,或者没释放中间变量。解决:先降 batch-size,再降 img-size,两者按平方关系影响显存。如果还不够,开启梯度累积模拟大批次。别一味加显存,先把参数调合理。
5.4 导出 ONNX 后推理结果对不上
现象:PyTorch 里结果正常,导出 ONNX 后框全乱。原因:导出时没指定动态轴,或者后处理里的坐标变换依赖了框架特有算子。解决:导出时加--dynamic,并核对预处理和后处理是否和原脚本一致。ONNX 的 NMS 有时要单独实现,别指望它自动带上。
5.5 车牌字符识别串位
现象:检测框没问题,但识别出来的字符顺序乱或丢字。原因:裁剪时没做透视校正,字符倾斜导致分割错位。解决:在裁剪后加一步透视变换,用车牌四个角点做映射,把车牌摆正再送识别。这一步对倾斜抓拍场景提升明显。
6. 进阶技巧:用 TensorRT 加速与精度回归验证
方案跑通之后,下一步就是提速。车牌识别在出入口场景对延迟敏感,YOLOv5 导出 TensorRT 是常见做法。流程是先把 best.pt 导出 ONNX,再用 trtexec 转 engine:
# 导出 onnx,指定动态批次 python export.py --weights best.pt --include onnx --dynamic # 转 TensorRT engine,fp16 精度,速度更快 trtexec --onnx=best.onnx --saveEngine=best.engine --fp16逻辑说明:--dynamic让批次维度可变,部署时更灵活;--fp16用半精度推理,速度通常能翻倍,精度损失很小。转完之后一定要做精度回归,别只看速度。我的习惯是拿同一批测试图,分别跑 PyTorch 和 TensorRT,逐张比对检测框的 IoU 和识别文本,IoU 低于 0.9 的挑出来看,确认不是精度塌方。
验证方法上,我一般会建一个小型回归集,覆盖白天、夜间、逆光、倾斜、污损车牌这几类,每类几十张,每次改模型或换部署方式都跑一遍,记录 mAP 和识别准确率。这个习惯帮我挡掉过好几次「训练指标好看、上线就崩」的情况。参数上,TensorRT 的 workspace 大小按显存给,一般 1G 到 2G 够用,给太大反而占资源。
还有个实用技巧:把检测和识别拆成两个 engine,检测用 fp16,识别用 fp32,因为字符识别对精度更敏感,混着用能在速度和准确率之间找平衡。部署到边缘设备时,先测功耗和散热,别只看帧率,长时间跑降频是常事。
从那以后我每次换部署后端,都强制走一遍回归集比对,不省这一步。希望帮到你。
本文还有配套的精品资源,点击获取