简介基于YOLOv5的车牌定位与识别源码包面向计算机视觉学习者、算法工程师及智能交通应用开发者专注解决视频流和静态图像中的车牌区域精确定位、倾斜校正与高效识别问题相比传统方法在速度和准确率上均有明显提升尤其适合车牌检测相关的课程设计、毕业设计与项目预研。资源共68个文件涵盖19个Python脚本、16张JPEG测试样例、9个YAML模型配置、5个PT权重文件并包含PTH权重、Shell脚本、Dockerfile与运行说明等压缩包整体约321.5MB目录结构完整清晰既可直接运行验证也便于按模块拆解学习。目前已有2529人学习下载。包内不仅给出基于YOLOv5的检测定位与增强OCR识别实现还涉及校正探测器、超分辨率预处理等关键环节的代码与配置附带测试图片和模型权重能够帮助使用者快速复现车牌识别全流程并进行二次开发和场景适配节省从零搭建项目的时间。 看到这个标题的时候我第一反应是熟悉。这些年帮人看过不少类似的车牌识别项目基于YOLOv5的车牌定位和识别几乎是目标检测入门后最经典的实战选题之一。但说句实话网上打包好的源码.rar质量参差不齐很多解压之后缺权重、缺依赖、缺数据集甚至代码逻辑本身就是拼凑的。这篇博文我不想只介绍怎么用这个源码而是想把这个项目背后真正需要搞懂的东西讲透从技术路线选型到数据集处理再到训练调参、识别衔接、部署落地。如果你刚拿到一份这类源码或者正准备自己做一版这份经验应该能帮你少走很多弯路。1. 先搞清楚技术路线检测与识别是两个环节1.1 为什么用YOLOv5先做定位车牌识别这个任务本质上是两个串在一起的子任务第一步是车牌在哪第二步是车牌是什么。很多人会想当然地认为直接用目标检测模型把整张车牌识别出来但实际工程里几乎没人这么做。原因很简单目标检测擅长的是定位和分类分类的对象是完整的物体而车牌是由多个字符组成的序列字符组合的合法性才是识别结果有效性的关键。所以这个项目的设计思路非常清晰用YOLOv5完成车牌的定位得到车牌区域的边界框然后对裁切出来的车牌图像做字符识别。那为什么不直接训练一个YOLOv5的字符检测模型检测出每个字符再组合成车牌理论上可行但字符尺寸小、排列密集、容易受模糊和倾斜影响直接用检测模型识别字符的稳定性远不如专门的序列识别网络。YOLOv5之所以在这个项目里被选作检测器是因为它在精度和速度之间平衡得比较好而且生态成熟。v5版本虽然是ultralytics官方近年停止积极维护的老版本但社区资料极其丰富训练、导出、部署的坑基本都被人踩过对毕设和工业原型验证来说可靠性比那些新但资料少的框架高得多。1.2 识别阶段怎么衔接有了YOLOv5输出的边界框之后接下来做的事情是把框住的区域抠出来送进识别网络。常见的衔接方式有两种第一种直接用CRNN、LPRNet这类序列识别网络对车牌区域做端到端识别输出一串字符。这种方式不需要单独做字符分割容忍一定程度的字符粘连和倾斜。第二种先做字符分割再用分类网络逐字符识别。这种方式对图像质量要求高如果车牌区域倾斜或者有反光分割就很容易出错。现在大多数开源源码里用的是第一种因为省事、鲁棒性好。你在解压后的代码里会发现检测用的是YOLOv5的推理逻辑识别部分通常是一个单独加载的权重文件和对应的识别模型类这就是两个环节的实体划分。1.3 车牌任务的特殊性和通用目标检测不同车牌识别有几个非常明显的特点直接影响方案设计字符集固定但分布不均。汉字省份简称、字母、数字都有但汉字数量少、出现频率高容易被模型带偏。车牌颜色多。蓝牌、黄牌、绿牌新能源、白牌、黑牌训练数据如果不平衡检测器会对低频颜色的车牌漏检。车牌的宽高比非常固定但透视形变严重。尤其从侧前方拍摄时车牌是梯形甚至平行四边形直接送进OCR模型效果会很差。所以后面所有关于数据、训练、识别衔接的讨论其实都是围绕这些特殊性展开的。我建议你在跑通源码之前先把这个检测识别的链路逻辑理清楚否则改代码的时候很容易把两条线搅在一起。2. 环境准备从解压RAR到把模型跑起来2.1 依赖与版本匹配源码包解压之后第一步不是急着打开代码看而是先看有没有requirements.txt。YOLOv5项目的依赖文件里通常会列出一堆库我自己复现这类项目时踩过最多次的坑就是版本冲突尤其是PyTorch和TorchVision的版本不匹配会导致opencv调用cuda加速时报错。给一个我在多个项目里实测稳定的版本组合基于YOLOv5 v5.0/v6.0分支Python 3.8 或 3.9PyTorch 1.10.x 或 1.12.x配CUDA 11.3TorchVision 0.11.x 或 0.13.xOpenCV-Python 4.5.xNumPy 1.21.x 左右新版NumPy的某些接口和旧版YOLOv5不兼容这里特别提醒一下NumPy的问题。如果你直接pip install numpy装到1.24以上跑YOLOv5推理时经常会遇到np.bool、np.int这类属性不存在的报错因为新版本把这些别名删掉了。解决方案很简单锁定1.21到1.23之间的版本或者直接在代码里用np.bool_替换。2.2 目录组织与权重文件一份完整的YOLOv5车牌识别源码目录结构大致是这个样子plate_detect_recog/ ├── detect.py # 检测入口脚本通常是YOLOv5的detect改版 ├── recognizer.py # 车牌识别模块 ├── main.py # 总流程检测识别端到端 ├── weights/ │ ├── best.pt # YOLOv5车牌检测权重 │ └── plate_rec.pth # 识别网络权重 ├── runs/detect/expN/ # 检测输出结果目录 ├── data/ │ ├── images/ # 测试图片 │ └── videos/ # 测试视频 ├── utils/ # YOLOv5的工具函数 └── models/ # YOLOv5的网络结构定义重点检查两个地方一是weights目录下有没有权重文件很多网上流传的源码包里根本没带权重或者只给了一个下载链接二是detect.py里默认读取的权重路径是否和你的目录一致。我见过太多人卡在两三百行的路径报错上其实把代码里的默认路径统一改一下就解决了。2.3 第一次运行的基本验证环境配好后先用一张相对干净的单车牌图片验证流程命令通常是这样python main.py --source data/images/blue_car.jpg --detect-weights weights/best.pt --rec-weights weights/plate_rec.pth第一遍如果直接跑通了恭喜你说明这份源码本身质量不错。如果报错优先查看是检测段报的还是识别段报的。检测段的错误常见于模型加载失败、类别数不匹配、图像读取为空识别段的错误常见于字符类别文件加载失败、中文字符编码问题。后面这些坑我会在踩坑清单里详细展开。我自己的习惯是第一遍跑通前不着急改任何参数先用默认配置确认整条链路能走通。因为很多后续改动是连锁式的如果初始状态都没验证过出了问题很难定位是原始代码的问题还是你改出来的问题。3. 数据集是车牌识别项目的地基3.1 可用的开源车牌数据集如果你拿到的源码包里自带数据集那最好。但很多情况下你需要自己准备数据。公共数据集里最常用的两个CCPDChinese City Parking Dataset中文车牌数据集里影响力最大的一个收集了超过20万张车辆图片标注了车牌位置的bounding box和整个车的bounding box。缺点是拍摄场景相对单一主要来自停车场的俯视及平视角度。CRPDChinese Road Plate Dataset更偏向道路自然场景包含复杂背景、不同光照和天气条件下的车牌数量约10万而且有省份多样性。用这些数据集训练时要注意它们的标注格式不完全是YOLOv5的txt格式。CCPD的标注直接写在文件名的字符串里需要用脚本解析出来转成txtCRPD提供的是XML或JSON标注也要转换。源码包里如果提供了转换脚本先看一下它读的是哪个数据集格式没提供的话自己写一个解析脚本也不复杂来回就是把坐标从框的宽高、角点格式换算成YOLOv5的归一化中心点格式。3.2 标注规范与难例自己标数据的话建议把目标框贴近车牌四边但不要完全贴死到字符边缘。YOLOv5的预测框是对应anchor的比例如果标注框和真实车牌的宽高比差异太大训练初期loss会下降得很慢。还有一个经常被忽略的问题车牌在图像里很小的时候很多标注人员会直接把整个车牌区域标大一些觉得反正包含了文字就行。这对检测框的精度影响很大因为识别阶段要抠出车牌区域如果标注框偏大抠出来的图会包含大量车脸背景如果偏小又会把边缘字符切掉。我的建议是标注时保留车牌边缘约2%到4%的余量这样抠图后不会破坏字符完整性也不会带入过多干扰。3.3 数据增强策略YOLOv5自带的数据增强已经比较全面包括马赛克mosaic、随机透视、颜色抖动、缩放平移等。在车牌这个任务里我要额外提醒两点第一不要过度使用旋转增强。车牌是水平排列的训练时如果加入过大角度的旋转模型会学到一个荒谬的认知竖直方向也能有车牌。这对检测是完全无效的特征。旋转角度建议控制在正负10度以内模拟的是车辆轻微颠簸的场景而不是把图倒过来。第二颜色抖动对绿牌和蓝牌的区分有潜在风险。颜色是车牌分类的重要线索如果你把蓝色车牌的色调抖动到偏绿模型在推理时可能对蓝绿车牌产生混淆。所以在颜色增强的参数上要保守饱和度调整幅度尽量控制在0.5倍到1.5倍之间。4. 训练与调参的实际操作记录4.1 输入尺寸与Anchor调整YOLOv5默认的训练输入尺寸是640x640这个参数对车牌检测很关键但又容易被忽略。如果你打算检测的车牌在原始图像里本身很小比如远距离抓拍的场景那640分辨率下车牌可能只占几十个像素特征非常模糊检测精度自然不会好。我的经验是分两种情况如果检测的是停车场的道闸相机画面车牌一般比较大640就够如果是路测场景、需要看远距离目标输入尺寸可以提升到960甚至1280。代价是训练和推理速度明显下降显存占用增大。跑不起来的话只能通过缩小batch size来妥协。Anchor方面YOLOv5在训练时会基于你的数据集自动计算anchor尺寸前提是你没有关闭搜索逻辑或者没有固定anchor。这里我踩过一次坑直接从COCO预训练权重上迁移没有重新计算anchor导致车牌这种宽高比非常极端约3.5:1的目标在几个feature map层上的匹配率很差。解决方法是用项目自带的utils/autoanchor.py跑一遍或者训练前在超参数里设置anchors: auto让模型自己适应。4.2 关键超参数训练YOLOv5使用的是data yaml和hyp yaml文件我通常会在项目原有的基础上改这几个参数lr0初始学习率默认是0.01如果你的数据集比较小几千张建议降到0.005甚至0.003防止前期震荡。batch_size显存不够的情况下很多人会无脑调小batch但要注意batch小到4甚至2时BN层统计不稳定更容易过拟合。实在显存不够优先调低输入尺寸其次再用小batch。epochs车牌检测不是特别复杂的分类任务训练150到200轮就基本收敛了。更重要的判断依据是看验证集上的mAP曲线如果曲线在最后20轮还在缓慢上升可以延长训练如果已经明显平了再训下去只会过拟合。训练命令一般是这样python train.py --data data/plate.yaml --cfg models/yolov5s.yaml --weights yolov5s.pt --epochs 150 --batch-size 16 --img 640 --hyp data/hyps/hyp.scratch-low.yaml4.3 训练监控与常见异常训练过程中我习惯每50个epoch保存一次验证集的可视化结果这样可以直接看到模型对难例的反应。最常见的异常情况是某个省份简称的汉字分类准确率特别低而数字字母都很高。这说明训练数据里那个省份的车牌数量太少需要针对性补充数据而不是盲目加训练的epoch数。另一个高发问题是过拟合严重表现是训练集loss不断下降但验证集mAP不再上升。这时候优先检查是不是输入图像分辨率设置得太小导致模型只能记住训练集的纹理细节也可以加大mosaic增强的概率让模型看到更多样的合成场景。5. 识别阶段选对方案让识别率上一个台阶5.1 三种方案对比拿到YOLOv5抠出的车牌图后识别方案的选择直接决定了最终效果。我梳理一下目前常见的三种做法方案原理优点缺点字符分割分类网络用投影或连通域定位每个字符位置送入分类器实现直观对字符间距均匀的图效果好对倾斜、反光、字符粘连敏感CRNN序列识别卷积提特征RNN建模序列CTC解码容忍字符粘连不用显式分割推理稍重训练需要序列标注LPRNet/轻量序列网络专为车牌设计的端到端识别网络轻量、支持变长输出、中文车牌效果好需要注意字符集配置、调试起来不如前两种透明源码里如果用的是第三种那一般是LPRNet或者基于它的改进版本。这类网络的优点是对车牌这种结构化的短序列特别友好模型体积小推理速度快。它内部的CTC解码器可以处理字符之间的重叠和偏移不需要精确定位每个字符所以对YOLOv5抠图时带来的微小偏差不那么敏感。5.2 识别网络的关键细节LPRNet这类模型看起来简单但真正用起来有几个细节决定成败。字符集文件是第一个要检查的东西。中文车牌的字符集包括31个省份简称汉字京、津、冀、晋、蒙、辽、吉、黑、沪、苏、浙、皖、闽、赣、鲁、豫、鄂、湘、粤、桂、琼、渝、川、贵、云、藏、陕、甘、青、宁、新加上24个字母I和O通常不用因为容易和数字1、0混淆加上10个数字总数约65个。有些实现还会加上挂学警使等特殊牌照字符。如果源码里的字符集列表和你预期不一致会造成推理时出现乱码或者概率全部集中在错误类别上。图像预处理也很关键。LPRNet通常要求输入尺寸固定比如94x24或者168x48。从YOLOv5抠出来的车牌图是各种各样的宽高比送进网络前要resize到指定尺寸。直接resize会导致字符被拉伸变形虽然网络对这种形变有一定容忍度但如果你发现识别结果经常把0和O混淆不妨先检查一下这里是否做了合理的等比缩放和填充处理。5.3 透视纠正为什么重要一个非常常见的情况检测器把车牌框出来了但框出来的区域是倾斜的。这时候如果直接把斜着的图送进LPRNet识别率会显著下降。我见过不少人在这步上摔跟头以为是识别模型不行其实是输入图像没有矫正。高效的做法不是引入一个复杂的矫正网络而是在YOLOv5输出四个角点而不是中心点宽高时用OpenCV的getPerspectiveTransform做透视矫正把车牌区域变换成一个标准的水平矩形。很多版本的YOLOv5 detect输出是旋转框或者四个角点格式这样才能还原倾斜车牌的几何信息。如果源码只输出了水平边界框那么倾斜角度过大时只能尽量裁剪到车牌主体损失部分精度。这里分享一个小技巧即便只有水平框也可以先做一个经验性的矫正。针对从画面左侧或右侧拍摄的车牌水平框内实际包含的字符区域往往偏向一侧我们可以结合车牌字符的垂直投影分布大致估算出倾斜方向和角度再做一个轻量矫正。这个方法不保证100%准确但能在纯水平框方案里明显提升识别率。6. 源码结构解读与二次开发6.1 核心目录与入口文件拿到源码后不要急着改模型结构先把代码的调用关系理出来。大多数这类项目的入口主程序在main.py或app.py内部大概流程是读图 - 调用detect函数 - 从检测结果里筛掉置信度低的框 - 遍历每个车牌框 - 抠图 - 识别 - 把结果显示在图上。从架构上看负责检测的模块往往直接复用了YOLOv5原版的代码区别在于后处理部分。原版YOLOv5在detect阶段会做NMS非极大值抑制和类别过滤车牌项目里类别只有一类所以NMS之后通常还要做一次最大框保留。为什么因为同一个车牌可能被多个不同尺度的anchor重复检测出来NMS虽然会合并大部分重叠框但偶尔会留下两三个高度重叠的框如果不去重后面识别阶段会对同一块区域识别好几遍浪费算力。某些屏幕上的重复卡车牌可能就是因为少了这步。6.2 推理流程梳理我建议用Python的断点调试把识别结果从检测到识别完整跑一遍。具体可以在detect返回后打印每一帧的目标框坐标、置信度以及抠出来的图片尺寸。你会发现这里藏着大量小问题比如坐标是整数还是浮点数、坐标系是左上角宽高还是中心点宽高、裁剪时数组索引是否越界等。这些问题在单张图上看不出来但处理视频流时高频出现。我也建议检查一下NMS的iou_thres参数。YOLOv5默认的NMS阈值是0.45如果检测框本身比较紧且多个尺度的输出重叠度较高可以提高到0.5到0.55减少重复框的同时避免把相邻的真框合并掉。6.3 如何换成自己的模型二次开发最常遇到的场景是你已经用新数据集训练了一个自定义的YOLOv5模型想替换源码里默认的best.pt。这里要注意几个匹配问题模型的类别数量必须和训练时data yaml中的类别数一致。如果训练时定义了2类比如区分汽车和车牌那推理代码里的类别列表也要相应改掉。模型的输入尺寸和anchors需要和训练时一致。直接拿一个960输入训练的权重跑640输入推理时YOLOv5会自动做letterbox缩放虽然能跑但精度可能下降。识别网络的替换更容易些只要你保证送入识别器的图像尺寸符合新模型的要求。很多LPRNet的衍生版本输入尺寸不同如果不改预处理直接换权重效果会非常差。7. 从离线跑通到实时部署优化要点7.1 ONNX导出与推理跑通离线识别只是第一步很多项目的最终目标是接入摄像头做实时识别。在PC上直接用PyTorch推理时虽然方便调试但速度往往不够尤其当检测输入分辨率设置了960或1280时。一个最基础的优化是导出ONNX然后用ONNX Runtime做推理。python export.py --weights weights/best.pt --include onnx --opset 12 --img 640导出后用onnxruntime替代PyTorch推理通常能把单帧推理时间缩短30%到50%对CPU推理尤其明显。不过要注意如果原源码里用了自定义的NMS模块比如某些版本把NMS也导进ONNX在ONNX Runtime上可能不受支持需要改用CPU端NMS或把NMS步骤放到后处理里。7.2 边缘设备部署的取舍树莓派、Jetson Nano这类设备上也经常有人跑车牌识别。以Jetson的部署为例PyTorch权重直接跑是很吃力的正确做法是用TensorRT做推理YOLOv5提供了export.py的TensorRT导出选项但有几个需要注意的点Jetson上的TensorRT版本和PyTorch导出的ONNX opset兼容性要测试opset过高会导致解析失败。TensorRT的固定batch和动态shape在车牌场景下问题不大因为输入尺寸是固定的。识别网络LPRNet本身很小CPU上跑也足够快不需要特别加速。从实际效果看在Jetson Nano上YOLOv5s加LPRNet的组合把检测输入降到416、开启半精度FP16推理后能达到15到20FPS左右对道闸类场景完全够用。7.3 性能评估部署前一定要做量化评估不要只凭一两次直观感受判断效果。我建议统计两个指标检测mAP或者至少是各类别AP和车牌级识别准确率。后者是指整张车牌的所有字符全部正确的比例。统计时把结果按车牌颜色和拍摄角度分组能快速暴露出模型在哪类数据上弱。最常见的结论是蓝牌白天表现很好但绿牌或夜间数据拉低整体指标。这时候就需要针对性补数据而不是在全局数据上再加大训练量。8. 真实场景踩坑清单8.1 绿牌黄牌样本不均衡训练数据里蓝牌占绝大多数时绿牌经常被漏检或检测置信度很低。同一个网站上下载的车牌数据集蓝牌比例可能高达70%以上绿牌不到10%。你可以用脚本统计一下训练集里各类车牌的图片数量如果绿牌、黄牌占比低于15%强烈建议补充数据。如果实在找不到额外数据可以对绿牌和黄牌图片做重复采样配合颜色抖动增强让模型至少见过这些样本。还有一个偏门但有效的经验把部分蓝牌图像的色相向绿色偏移人工构造伪绿牌样本。这个方法能提高一点泛化性但不能完全替代真数据。8.2 夜间和强光车牌识别最经典的问题就是过曝和反光。夜间场景下车灯直射或车牌本身贴了反光膜YOLOv5检测到的区域亮度几乎全白字符完全看不清。这种问题靠识别网络是解决不了的必须在检测端或者图像预处理端做文章。最常见的处理是加入自适应直方图均衡化CLAHE在把车牌图送进识别网络之前先对图像做一次光照归一化。但要注意这不是对整张原图做而是对裁剪后的车牌区域做因为车牌区域内的光照分布和全图差异很大。另一个思路是在训练识别网络时对车牌图做灰度化、亮度抖动和模糊增强模拟夜间低照度环境。实测下来这种增强能显著提升夜间识别率但对本来就清晰的白天图片会有轻微的反效果所以增强概率要控制在20%左右。8.3 多个车牌同时出现当画面里同时出现多辆车时也就是多个车牌目标检测器一般能输出多个框问题往往出在后处理和识别阶段的资源消耗上。很多源码的实现是循环处理每个框依次送识别网络如果同时出现五六辆车一帧的处理时间会被线性拉长。优化方案有两个方向一是把多个车牌的裁剪图放到一个batch里送进LPRNet利用batch推理并行处理二是过滤掉置信度特别低的框比如低于0.3的目标基本可以认为是误检没必要送识别网络。还有一个常见需求是按车牌置信度排序优先识别置信度最高的车牌因为实际道闸场景里最重要的就是离摄像头最近的那辆车。另一个小坑是相邻两辆车的车牌框离得很近时NMS可能把两个真实车牌框误合并成一个导致识别结果变成一个乱七八糟的混合字符串。解决办法是在NMS前稍微降低conf_thres并把NMS的iou_thres调低到0.4左右宁可保留更多候选框然后根据置信度排序再做一次框间去重。最后再分享一点个人体会。车牌识别这种项目真正考验人的地方不是模型选型而是对数据分布和工程细节的把控。同样的YOLOv5版本、同样的识别网络不同人训练出来的模型可能差好几个百分点差别就在于谁把困难样本处理得更细致。如果你正在做类似的毕设或者项目落地我建议把时间多花在数据清洗、难例分析和场景适配这三件事上。尤其是拿到一份别人打包的源码后先别急着训练先跑通、再理解、后修改的顺序能帮你避开80%的无意义踩坑。本文还有配套的精品资源点击获取
