资讯动态

YOLOv5车牌检测与OCR识别两段式架构实战指南

发布时间:2026/10/4 4:48:32 来源:尧图企业网站定制
简介面向计算机视觉开发者和深度学习初学者这是一份以YOLOv5为检测框架的车牌检测与识别一体化实现方案适用于智能交通、停车场管理等场景下的车牌定位与字符识别。资源共84个文件压缩包约78.16MB内容涵盖Python训练与推理脚本、YOLOv5s/m/l等模型配置、预训练权重、大批量JPG车拍照、XML标注文件以及字符识别网络LPRNet权重从目标检测到车牌字符识别均有可运行代码支撑。包内目录结构清晰权重、配置、数据、脚本分层存放并附有Dockerfile和requirements.txt便于复现环境和二次开发。当前已有2057人学习下载适合希望快速跑通YOLOv5车牌识别全流程、学习模型训练与部署细节的开发者。1. 车牌识别项目里YOLOv5只解决检测这一半别让它硬扛识别停车场出入口、小区门禁、高速卡口的摄像头画面最终要的不是一个“框”而是“粤B12345”这样的字符串。YOLOv5车牌检测和识别这类需求工程上最稳妥的拆法是把任务分成两段YOLOv5先把车牌区域从画面里检测出来再交给一个OCR网络把框里的字符读成文本。适合正在做安防、智慧停车、卡口系统的开发者也适合想拿yolov5训练自己的数据集练手的人。核心结论是检测和识别解耦数据好标、问题好定位、部署好替换一段式端到端模型在车牌这种小目标场景里性价比反而更低。2. 先检测再识别两段式架构为什么是车牌落地的默认解2.1 检测与识别解耦换来的是三个实际好处第一数据集不用混着标。检测模型只需要把车牌外边框标成一个类别不管车牌是蓝牌、绿牌、黄牌也不管上面几个字符识别模型拿到的是裁切好的车牌小图只需要关心字符内容是不是清晰。两个模型的训练数据可以分开迭代哪一侧指标差就补哪一侧。第二问题定位快。车牌号码识别错先看检测框是不是准。如果YOLOv5输出框把车牌的左右边界吃掉了半个字符那就是检测模型的标签或者样本问题如果框得严丝合缝但OCR还是读错基本可以断定是识别模型的事不用在两个模型之间来回猜。这种隔离在项目交付阶段尤其省时间。第三部署替换灵活。同样是YOLOv5检测前端低算力设备换yolov5n后端服务器用yolov5m识别模型也可以单独换成更轻量的LPRNet或者更重的CRNN互不影响。很多工业项目里甚至直接沿用YOLOv5官方仓库只改数据集和超参数就能快速出效果。如果你想先看yolov5网络结构图再动手官方仓库的yolov5s.yaml里写得很清楚Backbone从6x6卷积到C3模块再到SPPFNeck用PANet把三个尺度的特征图送到Head。车牌检测一般关注中等和较深的两个尺度最浅的尺度负责大目标对车牌这种小目标帮助有限这也是后面调输入分辨率时优先动640和960的原因。2.2 一段式端到端车牌的适用边界市面上也有一体化方案输入整张图输出车牌字符串。这类端到端模型把检测和识别放进同一个网络里省掉了中间的检测框传递。实际用下来它有两个不好绕的坎一是训练数据要求极高同一种车牌要覆盖各种角度、光照、模糊等级否则字符错一个很难定位是检测错了还是识别错了二是小目标车牌在画面里只有几十个像素时端到端模型的召回率明显不如两段式——检测模型至少能把框画出来OCR再想办法而端到端模型一旦漏检整张图就废了。一段式方案在车牌领域并不是新东西LPRNet本身就能端到端识别字符序列但它的输入是已经裁好的车牌图不是整张场景图。真正从整图直接到字符串的模型在实际项目里要处理大量“没有车牌的车”这种负样本训练成本远高于两段式。所以在车牌识别这个方向上两段式是默认选择。2.3 OCR选型LPRNet、CRNN还是PaddleOCR检测框拿到以后识别车牌字符有几个常见选择。小项目里用LPRNet比较多它轻量、序列长度固定适合蓝牌和单行车牌CRNN更适合字符长度不固定的场景绿牌八位字符也能处理PaddleOCR这类通用OCR对车牌这种长宽比极端的文字区域反而不占优势它更适合版面识别。选型时可以按表来方案输入优点注意点LPRNet裁切后的车牌小图模型小、推理快对倾斜车牌敏感CRNN定宽车牌图字符序列建模好需要更多训练数据PaddleOCR整图或裁切图通用文本识别强车牌场景需微调我一般会把LPRNet当主力因为车牌字符数有限中文省份简称加字母数字固定长度的序列建模足够部署时省掉动态序列解码那一大堆依赖。OCR训练数据来自检测模型裁出的车牌小图注意字符类别设计省份简称京、粤、沪和字母数字要分开定义别把“京”和“9”混成一个类。很多识别翻车案例都是字符类别数定义错了一个类别里塞了两个长相接近的字符模型再怎么调也学不出来。2.4 最小推理流程用官方权重先跑通检测动手训练之前先把官方流程跑一遍。python detect.py --weights yolov5s.pt --source test.jpg --conf 0.5这个命令的含义是加载yolov5s预训练权重对test.jpg做推理置信度阈值取0.5。--conf是后处理阶段的关键参数低于0.5的检测框会被过滤掉--iou 0.45控制NMS阶段两个重叠框的合并程度。第一次跑通的目的不是检测车牌——官方权重里没有车牌类别——而是确认环境、权重和推理链路是通的。如果推理结果里出现大量重叠框多半是NMS的iou阈值设得太大如果该检出的车牌没框出来先把conf调低到0.25试别一上来就动模型。后处理在整个检测链路里经常被当成黑匣子其实就三个参数conf、iou、max_det。max_det限制单张图最多输出几个框停车场多车场景建议设成不低于10。3. 准备车牌训练集从数据来源到VOC转YOLO格式3.1 数据来源与挑选标准先明确一点车牌检测模型训练只需要把牌框出来类别就一个plate。数据集可以用公开的车牌数据集比如CCPD这类停车场场景采集的也可以自己拍或从项目现场抽帧。我见过不少项目直接用现场摄像头抽帧选帧时注意不要连续抽同一个车位的同一辆车要把场景多样性拉起来。挑选标准按优先级排一是车牌类型覆盖蓝牌、绿牌、黄牌至少各占一批单层蓝牌和双层黄牌最好都有二是距离和角度画面里车牌大小从40像素到200像素都要有侧倾角光照分白天、黄昏、夜间三是模糊和遮挡留一部分但比例控制在10%以内否则模型学不到清晰特征。这里有个容易翻车的点不要只挑正对着的清晰车牌那种数据集训练出来的模型一到出入口道闸斜拍角度就漏检。3.2 标注格式与VOC转YOLO的批量脚本常见标注工具导出的是VOC或COCO格式。YOLOv5训练需要的是每张图对应一个txt文件每行是“class x_center y_center width height”坐标经过归一化单位是0到1的小数。以下脚本把VOC XML批量转成YOLO txt适用于单类别车牌检测import os import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, out_dir, img_width, img_height, class_id0): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.iter(object): name obj.findtext(name) if name ! plate: # 只保留车牌类别其它标签忽略 continue bndbox obj.find(bndbox) x1 float(bndbox.findtext(xmin)) y1 float(bndbox.findtext(ymin)) x2 float(bndbox.findtext(xmax)) y2 float(bndbox.findtext(ymax)) # 转成YOLO要求的中心点加宽高并除以图像宽高做归一化 x_center (x1 x2) / 2 / img_width y_center (y1 y2) / 2 / img_height w (x2 - x1) / img_width h (y2 - y1) / img_height lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) if lines: out_path os.path.join(out_dir, os.path.basename(xml_path).replace(.xml, .txt)) with open(out_path, w, encodingutf-8) as f: f.write(\n.join(lines)) if __name__ __main__: voc_to_yolo(annotations/1.xml, labels, 1920, 1080)脚本里三个参数要说清楚。第一是img_width和img_height必须和图片实际尺寸一致用训练图片的宽高而不是XML里写死的resize尺寸第二是class_id这里写0如果后续想区分蓝牌、绿牌、黄牌三个类别就改成不同的id同时训练配置里的nc要跟着改第三是过滤逻辑名单类别里只认plate其它标注框直接跳过避免把车身或车灯也当作车牌框进去。坐标归一化要理解YOLO的框是用中心点和宽高表示的不能用角点直接写进txt。3.3 目录结构与data.yaml的写法YOLOv5训练时读的是data.yaml指定的路径目录结构我一般这样组织datasets/plate/ images/ train/ val/ labels/ train/ val/ data.yamldata.yaml内容是train: /absolute/path/to/datasets/plate/images/train val: /absolute/path/to/datasets/plate/images/val nc: 1 names: [plate]train和val路径填的是images目录YOLOv5会自动去同级labels目录找对应的txt。这里建议用绝对路径相对路径容易在切换工作目录后翻车。常见坑是路径写错后训练能开始但recall一直是0因为标签文件一个都没读进去。检查方法训练启动日志里会有dataset统计信息看instance的数量如果为0就是标签路径没对上。提示训练日志如果出现“train and val are the same dataset”这类提示不要慌回去检查data.yaml里的val路径验证集必须和训练集分开。3.4 数据增强的取舍Mosaic与旋转别乱开yolov5默认开Mosaic增强它对小目标检测很有帮助——车牌在画面里经常是小目标四张图拼一张能提高模型对多尺度车牌的学习。但车牌要求字符边缘锐利Mosaic拼图会让车牌边缘被切碎所以训练后期建议把mosaic关掉在超参数文件里把mosaic设为0.0再用前几十轮的结果继续finetune。旋转增强也要克制。车牌检测需要容忍一定角度的倾斜但过大的旋转会让检测框变成倾斜框——注意YOLOv5输出的是水平矩形框没法直接输出带角度的框。旋转增强开的度数越大模型预测的水平框和真实标注框的IoU越容易被拉低。一般hyp文件里degrees设5到10就够不要超过15。yolov5超参数这个话题热度一直高其实对车牌这种长宽比固定的目标动mosaic、degrees、hsv这三项就够了别再叠一堆花活。4. 用yolov5训练自己的车牌数据集超参数与训练命令拆解4.1 预训练权重和网络结构怎么选YOLOv5官方仓库提供了n/s/m/l/x几个尺寸的预训练权重。车牌检测场景里yolov5n适合树莓派和嵌入式设备yolov5s是通用首选yolov5m适合对召回率要求高的卡口项目。判断标准是显存和帧率6G显存以下用s10G显存想刷精度用m。网络结构上Backbone用CSP结构的C3模块Neck用SPPF和PANet做多尺度融合Head输出三个尺度的预测框。训练车牌这种小目标输入分辨率比模型尺寸更敏感640起步车牌普遍偏小的场景用960。4.2 训练命令逐段拆解img、batch、epochs、hyppython train.py --data data.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100 --hyp hyp.scratch-low.yaml --name plate_exp参数含义--data指向data.yaml--weights用COCO预训练权重做迁移学习比从零训练收敛快得多--img 640是训练时输入分辨率--batch 16是每轮迭代的样本数--epochs 100对车牌这种单类别数据集通常足够--hyp选择官方自带的超参数文件基础配置用hyp.scratch-low.yaml就行。batch大小的选择直接决定训练能不能跑起来。显存不足时优先调小batch而不是调小imgbatch低于8时BatchNorm统计会变得不稳定loss曲线会抖得厉害。如果12G显存用yolov5sbatch 16是比较稳的组合。超参数文件里的lr0初始学习率默认0.01小数据集可以降到0.005避免前期震荡。这里有个经验车牌数据集一般几千张到一两万张就够epochs不用学别人跑300轮100轮足够收敛跑太多反而记住背景。4.3 训练中看哪些指标P、R、mAP0.5与loss曲线训练日志里重点看几个值P精确率、R召回率、mAP0.5、mAP0.5:0.95。车牌检测项目里mAP0.5比mAP0.5:0.95更贴近实际因为部署时NMS的IoU阈值通常就是0.5左右。val_box_mAP这个值稳定上升说明模型在学如果P很高但R低说明检出来都准但漏检多需要补样本或调低conf阈值如果R高但P低说明误检多常见原因是把车身反光、车灯也框了进来要检查标注集里是不是漏标了大量车牌导致负样本把模型带偏。loss曲线方面box_loss代表边框回归损失obj_loss代表目标置信度损失cls_loss单类别模型里参考价值不大。训练到60轮后loss曲线进入平台期但mAP还在涨属于正常现象继续跑完即可。真正要警惕的是val loss在80轮后反弹那就是过拟合的开始这时候best.pt的保存轮数往往在70轮附近直接用best.pt就行不要用last.pt。4.4 用detect.py验证conf与后处理怎么调python detect.py --weights runs/train/plate_exp/weights/best.pt --source test.jpg --conf 0.5 --iou 0.45 --max_det 10训练刚结束的模型先别急着集成。拿现场照片跑一遍detect.py看三类错误漏检、误检、框偏移。漏检就调低--conf到0.25看能不能框出来误检多就调高到0.6框偏移严重比如框只盖住车牌的一半字符说明训练数据里标注框不紧回到标注环节修正。这里还要说一句后处理的事。yolov5后处理包含置信度过滤、NMS去重、类别过滤三个步骤很多新手只调conf不调iou。实际上车位上相邻车辆的车牌不会重叠iou对车牌场景影响不大真正关键的是conf。我在项目里会把conf从0.25到0.7做一次扫描挑出召回和误检平衡的那个点固化进部署代码。5. 车牌检测落地避坑五个常见的翻车现场与排查顺序5.1 蓝牌和绿牌混训导致漏检拆类别比调参有用现象单独训练蓝牌模型准确率很高把新能源绿牌加进去一起训之后蓝牌漏检率反而上升。原因蓝牌和绿牌的宽度、字符间距差异较大绿牌照搬到蓝牌的深层特征上模型在同一个类别里学到互相冲突的分布。如果数据量不平衡模型会偏向样本多的一类。解决先做类别区分。把plate类别拆成blue_plate和green_plate两个类nc改成2names对应改然后重新训练。检测框类别分开后OCR那边只需要按框的内容读字符不需要管类别两个类别在识别阶段共用同一个OCR模型。这个做法比硬调超参数有效属于把问题交给数据组织而不是交给训练玄学。5.2 夜间和强曝光下检测框抖动预处理优先现象同一辆车停在原地视频连续推理时检测框在车牌的上下边界来回跳OCR偶尔读错一个字符。原因车牌的边缘在夜间受车灯和地面反光影响像素对比度不稳定强光下车牌反光区域过曝YOLOv5提取到的目标特征在前景和背景之间摇摆。解决先做图像预处理再进模型夜间用CLAHE限制对比度自适应直方图均衡增强车牌区域纹理比直接换模型参数见效快。推理链路里加一步cv2.createCLAHE(clipLimit2.0, tileGridSize(8, 8))。如果现场是固定摄像头更直接的办法是调整相机曝光参数让车牌区域不要过曝这比任何后处理都省事。这一条血泪经验来自一个地下车库项目我们调了三天模型最后发现是相机自动曝光把车牌拍糊了。5.3 倾斜车牌识别率低先查检测框再查OCR现象检测框位置准但OCR读出来的字符错尤其倾斜超过30度的车牌。原因OCR训练数据里倾斜样本太少或者OCR输入图没有做透视校正。YOLOv5输出的水平框对倾斜车牌来说会包含大量背景字符被压扁。解决按顺序排查。第一步看检测框是否完整包含车牌四角第二步对框内图像做透视校正用OpenCV的getPerspectiveTransform把车牌区域拉正然后再送OCR第三步如果还不行给OCR训练集加旋转样本旋转范围正负15度起步。这里经常有人把顺序反过来先去调OCR模型结果是白调——问题在检测框传入的图就没拉正。5.4 显存不足batch、分辨率与模型尺寸的取舍顺序现象batch 16 yolov5s 640分辨率在12G显卡上报CUDA out of memory。原因显存被中间特征图占满batch一次性载入的样本太多。解决按优先级试。先把batch降到4能跑但BatchNorm统计容易不稳再把--img从640降到512车牌分辨率低一些但训练目标本身就是小目标分辨率降低对最终精度影响有限最后才考虑换yolov5n或开启梯度累积。YOLOv5的命令行里有--workers和--cache显存不足时不要开--cache ram那会把数据集预载到显存里。12G以下显存老老实实用yolov5s batch 8 img 640这是最稳的组合。5.5 远距离小目标漏检分辨率、P2层与镜头三选一现象摄像头安装高度高、视场角大15米外的车牌在画面里只有30像素宽检测召回率明显下降。原因小目标在骨干网络下采样过程中特征被稀释三个检测尺度里最小的输出层对30像素的目标依然不敏感。解决最直接的手段是把输入分辨率提高到960甚至1280代价是推理变慢第二个手段是修改模型结构开启P2输出层对小车牌很有帮助第三个手段是硬件上换长焦镜头缩小视场角让车牌在画面里占更多像素。部署阶段如果已经定死相机位置我的习惯是先用分辨率提升如果帧率不达标再退回640并用裁剪区域二次检测。6. 检测框外扩、视频回放验证与轻量部署交付前值得做的三件事6.1 检测框外扩10%再交给OCR车牌检测模型输出的框紧贴车牌边缘直接裁切会让字符顶到图像边界OCR对这类输入的鲁棒性差。推理代码里我会把框向外扩10%再把坐标裁剪回图像范围内。这一小步能明显降低字符漏读。代码上就是检测后处理里加两步x1 max(0, int(x1 - 0.1 * (x2 - x1))) y1 max(0, int(y1 - 0.1 * (y2 - y1))) x2 min(W, int(x2 0.1 * (x2 - x1))) y2 min(H, int(y2 0.1 * (y2 - y1)))框外扩的逻辑车牌字符识别需要一点边距OCR卷积核才能在字符和背景之间学到过渡特征紧贴的框等于把边距信息裁掉了。这个技巧在树莓派和RK3568这类边缘设备上尤其管用不增加算力成本。6.2 用视频回放验证端到端稳定性单张图验证容易产生幸存者偏差我一般会让现场录一段10分钟的视频跑完推理后用脚本统计每帧的检测框中心点坐标变化。车牌检测框在视频里应该稳定平滑如果框的宽度在连续帧里忽大忽小多半是样本里倾斜和远近变化不够需要回训练环节补数据。视频回放验证还能顺便测OCR的帧级错误率比人工盯屏幕靠谱。6.3 树莓派与RK3568上的轻量化导出树莓派和RK3568这类设备上导出ONNX后做INT8量化车牌检测这类单类别任务精度损失通常可接受。模型尺寸上优先yolov5n实测帧率比yolov5s高一倍以上。导出命令python export.py --weights best.pt --include onnx --simplify --opset 12之后用onnxruntime推理conf阈值沿用训练完扫描出来的值不要重新拍脑袋设。ROS无人小车和锥桶检测项目里也都是同样的套路先验证模型再谈部署优化。写到这我想起一个教训第一次做车牌识别时我把全部精力花在调YOLOv5超参数上结果现场漏检的根因是摄像头安装仰角太大车牌在画面里一直是侧倾状态。后来把预处理和检测框外扩加上识别率才真正上去。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑