ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

从零搭建车牌识别系统:YOLOv5与CRNN的实战应用与优化

2026/9/4 22:13:44 拓冰建站 浏览量
从零搭建车牌识别系统:YOLOv5与CRNN的实战应用与优化 简介本资源是一个面向人工智能课程设计与毕业设计实践的深度学习车牌识别系统完整实现聚焦智能交通、停车场管理及治安监控等实际场景适合具备Python与PyTorch基础的本科生、研究生开展项目开发与边缘部署学习。压缩包共104个文件7.55MB涵盖37个核心Python脚本含YOLO车牌检测、LPRNetSTNet字符识别主干代码、41个配置类YAML文件模型参数、训练超参、树莓派部署环境定义、7份结构化Markdown文档含Deeplearning.md理论解析与RaspberrySetting.md全流程部署指南、5个Shell自动化脚本及2个Dockerfile支撑从训练、测试到树莓派端轻量化部署的全链路实践。已有49人下载学习资源提供清晰的模块化目录结构、.gitignore规范管理、README快速上手指引及.ipynb交互式教程特别包含空间变换矫正、车牌图像预处理与端侧推理优化等关键细节可直接复用于课程报告、毕设答辩与工程原型验证。1. 从零到一一个车牌识别项目的诞生与核心价值最近在整理硬盘翻出来一个老项目——“基于深度学习的车牌识别系统.zip”。解压开来看着里面熟悉的代码、模型文件和一堆测试图片很多回忆涌上心头。这大概是我几年前为了验证一个想法从零开始搭建的一个车牌识别原型系统。虽然现在市面上成熟的车牌识别SDK和API已经非常多但自己动手走一遍从数据准备、模型训练到部署推理的全流程那种收获感是完全不同的。今天我就把这个项目的核心思路、关键实现细节以及踩过的那些坑系统地梳理一遍希望能给对计算机视觉、深度学习应用感兴趣特别是想自己动手做一个完整项目的朋友一些参考。车牌识别或者说车辆牌照自动识别是一个典型的计算机视觉任务属于目标检测和光学字符识别的结合体。它的应用场景非常广泛从我们每天进出小区的道闸、高速公路的ETC收费、停车场的无人值守到交通违章抓拍、车辆轨迹追踪等安防领域背后都有它的身影。这个项目的核心目标就是利用深度学习技术让计算机能够像人眼一样从一张包含车辆的图片中准确地定位出车牌的位置并识别出上面的字符。整个过程可以拆解为两个核心子任务车牌检测和车牌字符识别。听起来简单但要让模型在各种光照、角度、污损、模糊的情况下都表现稳定里面有不少门道。2. 技术选型与整体架构设计为什么是YOLOCRNN在动手写代码之前最关键的一步是确定技术路线。这直接决定了后续数据怎么处理、模型怎么训练、系统怎么搭建。当时我主要对比了几种主流方案。2.1 车牌检测模块的抉择从传统方法到深度学习早期的车牌检测多基于颜色、纹理、边缘等手工特征比如利用车牌蓝底白字国内常见的HSV颜色空间特征或者利用车牌区域具有密集垂直边缘的特点进行定位。这些方法在光照均匀、背景简单的场景下效果尚可但一旦遇到光线变化、车身颜色干扰、或者车牌倾斜就很容易失效鲁棒性很差。因此我毫不犹豫地选择了基于深度学习的目标检测模型。当时主流的候选者有Faster R-CNN、SSD和YOLO系列。Faster R-CNN是两阶段检测器的代表精度高但速度相对慢SSD和YOLO是单阶段检测器速度优势明显。考虑到车牌识别往往有实时性要求比如视频流分析我最终选择了YOLOv5。理由很充分首先YOLOv5在速度和精度上取得了很好的平衡其PyTorch实现生态完善训练和部署都非常方便其次它的模型结构清晰从轻量级的YOLOv5s到大型的YOLOv5x有多种尺寸可选可以根据实际硬件条件灵活选择最后社区活跃遇到问题容易找到解决方案。对于车牌这种尺寸相对固定、长宽比特征明显国内车牌多为440mm*140mm比例约3.14:1的目标YOLO这类检测器经过针对性训练后定位精度完全足够。2.2 字符识别模块的考量分割识别与端到端识别检测到车牌区域后下一步就是识别上面的字符。这里主要有两种思路先分割后识别先将车牌图像进行二值化、字符分割得到单个字符的切图然后利用一个分类网络如CNN对每个字符进行分类。这种方法思路直观但严重依赖分割的准确性。车牌字符间隔不均、粘连、污损都会导致分割失败进而导致整个识别流程崩溃。端到端识别不进行显式的字符分割直接将整个车牌区域图像输入一个序列识别模型直接输出字符序列。这种方法避免了分割的难题但需要模型能够自动学习字符间的上下文关系。我选择了第二种方案采用了CRNN卷积循环神经网络模型。CRNN结合了CNN和RNN的优势CNN部分如ResNet、VGG的变体负责从图像中提取丰富的视觉特征序列RNN部分常用BiLSTM即双向长短时记忆网络负责对特征序列进行建模捕捉字符之间的上下文依赖关系最后接一个CTC连接主义时序分类损失层它允许模型在训练时不需要对每一个输入帧都进行精确的字符对齐非常适合这种不定长序列的识别任务。对于中文车牌包含汉字、字母、数字CRNN是当时非常成熟和高效的方案。2.3 系统整体工作流基于以上选择整个系统的Pipeline就清晰了输入一张车辆图像或视频帧。车牌检测图像输入训练好的YOLOv5模型输出一个或多个车牌的边界框坐标(x1, y1, x2, y2)和置信度。车牌矫正与裁剪根据边界框从原图中裁剪出车牌区域。由于拍摄角度问题裁剪出的车牌可能是倾斜的这里通常需要进行透视变换或仿射变换进行矫正将其“拉正”得到一个规整的矩形车牌图像。这一步对后续字符识别的准确性提升巨大。字符识别将矫正后的车牌图像输入训练好的CRNN模型模型直接输出识别出的字符串如“京A·12345”。输出结构化信息通常包括车牌号、置信度、位置等。这个流程看似线性但每个环节都有大量细节需要处理任何一个环节的疏忽都会导致最终结果不佳。3. 数据模型效果的基石与预处理的艺术“数据决定模型的上限算法只是逼近这个上限”。这句话在深度学习领域是至理名言。对于车牌识别项目数据的准备和处理占据了至少一半的工作量。3.1 数据收集与标注当时的数据来源主要有几个公开数据集如CCPD一个大型的中国车牌数据集、网络爬取需注意版权和隐私、以及自己拍摄。我混合使用了CCPD数据集的一部分和自己收集的一些图片总共大约有2万张包含车牌的车辆图像。标注工作是体力活也是技术活。对于检测任务需要使用标注工具如LabelImg、CVAT为每张图中的车牌画上矩形框并打上统一的标签如license_plate。对于识别任务则需要在检测框的基础上标注出正确的车牌号码字符串。这里有一个关键点检测和识别的标注最好能关联起来。也就是说一张图里每个车牌的边界框和对应的车牌号是一一对应的。这样在制作训练集时可以很方便地生成检测标签.txt文件包含类别和归一化坐标和识别用的图像-标签对。3.2 数据预处理与增强策略原始数据不可能完美覆盖所有场景因此数据增强是提升模型泛化能力的利器。对于车牌识别我主要采用了以下几种增强方式并解释了为什么用它们几何变换包括随机旋转小角度如±15度模拟车牌轻微倾斜、缩放、平移、裁剪。这能让模型适应不同距离、角度拍摄的车牌。颜色空间变换调整亮度、对比度、饱和度模拟不同天气阴天、黄昏、夜晚车灯照射和光照条件。车牌识别最怕的就是反光和阴影。模拟噪声与模糊添加高斯噪声、椒盐噪声以及运动模糊、高斯模糊。这能模拟车辆移动、摄像头抖动或低质量摄像头带来的图像退化。模拟真实干扰在车牌区域随机添加一些水滴、泥点污渍的模拟图案。这一点增强对提升模型在恶劣天气下的鲁棒性非常有效。注意数据增强需要合理设置参数幅度。过度的旋转可能导致车牌形状扭曲到不现实的程度过度的模糊可能让字符根本无法辨认。增强的目的是“扩充”数据分布而不是“扭曲”它。3.3 制作CRNN训练数据对于CRNN其训练数据是单张车牌图片和对应的文本标签。我们需要从已标注的检测数据中根据边界框裁剪出车牌区域并进行高度归一化。例如将所有车牌图像的高度resize到32像素宽度按比例缩放。这是因为CRNN的CNN部分通常要求输入图像高度固定而宽度可以变化以适应不同长度的车牌。标签文件则是一个简单的文本文件每行记录图片路径和对应的车牌字符串例如./plate_images/001.jpg 京A12345 ./plate_images/002.jpg 粤B·AB888字符集需要预先定义好包含所有可能出现的字符31个省简称汉字京、津、冀…、24个英文字母I和O通常禁用、10个数字。总共约65个类别。4. 模型训练实战参数、技巧与坑位实录有了数据就可以开始训练模型了。这里分开讲检测模型和识别模型的训练。4.1 YOLOv5车牌检测模型训练我使用的是YOLOv5的官方代码库。训练前的主要配置工作数据配置文件 (data.yaml)指定训练集、验证集的图片路径、类别数量nc: 1只有‘车牌’一类和类别名称。模型配置文件选择yolov5s.yaml这是一个比较小的模型在速度和精度上比较平衡适合快速实验和部署在普通算力设备上。超参数调整img-size: 设置为640。YOLOv5训练时会自动进行多尺度训练这是其优势之一。batch-size: 根据GPU显存调整我用的卡是GTX 1080Tibatch-size设为16。epochs: 总共训练300个epoch。通常会观察训练损失和验证集指标如mAP0.5的变化在指标平稳后可以提前停止。optimizer: 使用默认的SGD优化器学习率lr0设为0.01并配合余弦退火学习率调度让学习率在训练后期逐渐减小有助于模型收敛到更优的局部最优点。训练过程中要密切关注损失曲线和评价指标。YOLOv5的训练脚本会实时输出这些信息并保存最好的模型权重best.pt。一个常见的问题是模型在训练集上损失下降但在验证集上指标不升反降这可能是过拟合的迹象。对策包括增加数据增强的多样性、使用更轻量的模型、或者加入正则化如Dropout但YOLO结构本身已有设计。实操心得在训练早期建议先在小规模数据如1000张图上跑几个epoch快速验证整个数据管道和训练流程是否正确。比如检查数据加载是否正确、增强后的图像是否合理、损失是否在下降。这能避免在大规模数据上训练几天后才发现基础错误。4.2 CRNN车牌字符识别模型训练CRNN的训练相对独立。我参考了经典的CRNN-Pytorch实现。关键点如下网络结构CNN部分我使用了轻量化的MobileNetV2的卷积层来提取特征替代了原论文中较重的VGG。RNN部分使用了两层双向LSTM隐藏层单元数为256。这样在保证精度的同时大大提升了推理速度。输入与输出输入是归一化高度如32的车牌图像宽度不定。经过CNN后特征图在宽度方向上被压缩通常通过池化或步幅卷积形成一个特征序列。这个序列输入BiLSTM最终每个时间步的输出通过一个全连接层映射到字符类别概率再交给CTC损失计算。CTC损失的理解这是CRNN训练的核心。它最大的好处是不需要在训练数据中标注每个字符在图像中的具体位置。只需要提供整个图像和对应的序列标签。CTC会自动处理对齐问题允许模型输出比标签更长的序列通过引入“空白”标签然后通过动态规划算法找到最优的对齐方式。这极大地简化了标注工作。训练技巧学习率策略同样使用余弦退火或步进下降。数据增强对单张车牌图片同样可以进行轻微的仿射变换、颜色抖动但幅度要比检测阶段小得多因为字符的几何结构需要保持。处理长尾分布车牌字符中数字和某些字母如AB出现的频率远高于某些汉字如“藏”、“琼”。可以在损失函数中引入类别权重或者对稀有字符样本进行过采样以平衡各类别的学习。训练CRNN时一个直观的评估方法是看模型在验证集上的字符准确率和序列准确率。字符准确率是指所有预测字符中正确的比例序列准确率是指整个车牌字符串完全预测正确的比例。后者显然要求更高也是我们更关注的指标。5. 集成与优化让系统真正跑起来训练好两个模型只是第一步如何将它们集成到一个稳定、高效、可用的系统中是另一个挑战。5.1 推理流程的代码实现推理脚本需要串联整个流程。以下是一个简化的核心代码逻辑import cv2 import torch from models.experimental import attempt_load # YOLOv5 from crnn_model import CRNN # 自定义CRNN模型 from plate_processing import warp_plate # 车牌矫正函数 # 1. 加载模型 device torch.device(cuda if torch.cuda.is_available() else cpu) detect_model attempt_load(./weights/yolov5s_plate.pt, device).eval() crnn_model CRNN(...).to(device).eval() crnn_model.load_state_dict(torch.load(./weights/crnn_plate.pth)) # 2. 读取图像 img cv2.imread(car.jpg) img_rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 3. YOLOv5检测 with torch.no_grad(): detections detect_model(img_rgb)[0] # 获取检测结果 # detections 包含 [x1, y1, x2, y2, conf, cls] # 4. 遍历每个检测框 for det in detections: x1, y1, x2, y2, conf, cls det if conf 0.5: # 置信度阈值过滤 continue # 裁剪车牌区域 plate_patch img[int(y1):int(y2), int(x1):int(x2)] # 5. 车牌矫正 plate_corrected warp_plate(plate_patch) # 6. CRNN识别 plate_text recognize_plate(crnn_model, plate_corrected, device) print(f检测到车牌: {plate_text}, 置信度: {conf:.2f}) # 7. 可视化可选 cv2.rectangle(img, (int(x1), int(y1)), (int(x2), int(y2)), (0,255,0), 2) cv2.putText(img, plate_text, (int(x1), int(y1)-10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0,255,0), 2) cv2.imshow(Result, img) cv2.waitKey(0)5.2 性能优化技巧在实际部署尤其是处理视频流时性能至关重要。模型轻量化如果对速度要求极高可以考虑将YOLOv5替换为更轻量的版本如YOLOv5n或者使用专门的模型压缩技术如剪枝、量化。PyTorch提供了动态量化和静态量化工具可以将FP32模型转换为INT8模型在几乎不损失精度的情况下显著提升推理速度并减少内存占用。推理引擎优化使用torch.jit.trace或torch.jit.script将模型转换为TorchScript可以获得更优的运行时性能。更进一步可以尝试使用ONNX将模型导出然后利用TensorRT或OpenVINO等针对特定硬件NVIDIA GPU, Intel CPU优化的推理引擎进行部署速度提升可能达到数倍。Pipeline并行对于视频流检测和识别可以尝试并行处理。例如当一帧在进行车牌识别时下一帧可以同时进行车牌检测。但这需要更复杂的多线程或异步编程。5.3 处理疑难案例提升系统鲁棒性一个健壮的系统必须能处理各种边缘情况。我在测试中遇到了不少问题并总结了应对方法问题现象可能原因解决方案车牌检测不到光照过暗/过曝、车牌尺寸过小、严重遮挡1. 在检测前对图像进行自适应直方图均衡化CLAHE或伽马校正改善光照。2. 训练数据中加入更多极端光照和小目标样本。3. 适当降低检测置信度阈值但需警惕误检。车牌定位框不准车身有类似车牌纹理的干扰物、车牌倾斜角度大1. 使用更准确的数据集训练确保标注框紧贴车牌边缘。2. 在数据增强中加入更多大角度倾斜和复杂背景的样本。3. 后处理中使用NMS非极大值抑制的变体如Soft-NMS处理重叠框。字符识别错误车牌污损、模糊、字体特殊、字符粘连1. 强化CRNN训练数据加入模拟污损、模糊的增强。2. 在识别前对矫正后的车牌图像进行超分辨率重建使用ESPCN等轻量模型或去模糊处理提升图像质量。3. 引入语言模型进行后处理纠错。例如利用车牌编码规则如省份简称发牌机关代号序号构建一个简单的概率模型对CRNN的原始输出进行校验和修正可以显著降低“0”和“D”、“8”和“B”这类形似字符的误识别率。其中引入语言模型进行后处理是一个性价比极高的优化。它不需要重新训练深度学习模型只是基于规则和统计信息对结果进行微调往往能将序列识别准确率提升好几个百分点。6. 项目总结与可扩展方向回顾这个项目从数据爬取、清洗、标注到模型选型、训练、调试再到最后的集成、优化和测试是一个完整的深度学习应用闭环。它不仅仅是对YOLO和CRNN两个模型的应用更涉及到计算机视觉项目全流程的实践。最大的收获不是调出了一个高精度的模型而是对整个流程中可能遇到的问题有了预判和解决思路。这个原型系统还有很多可以深化和扩展的方向。例如可以尝试更先进的检测模型如YOLOv8或DETR识别模型可以尝试基于Transformer的Vision Transformer (ViT) 结合序列建模。对于更复杂的场景如双层车牌香港、摩托车牌、新能源车牌的特殊结构需要专门的数据和模型调整。此外将整个系统封装成RESTful API或GRPC服务方便其他系统调用或者部署到嵌入式设备如Jetson Nano实现边缘计算都是非常有价值的工程化工作。最后分享一个我踩过的“坑”在训练CRNN时初期准确率一直上不去排查了很久才发现是字符集定义出了问题。我最初漏掉了车牌号码中可能出现的字母“I”但实际上有些地区的车牌如某些特殊号段或早期车牌是包含的。虽然出现频率极低但一旦测试集里出现模型必定认错。这提醒我们在定义分类问题时务必穷举所有可能的类别哪怕某些类别样本极少也可以通过数据合成或增强的方式补充进去否则就会留下系统性的缺陷。深度学习模型很强大但它的能力边界最终是由我们喂给它的数据决定的。本文还有配套的精品资源点击获取