尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

YOLOv5+LPRNet车牌识别:从CCPD训练到部署全流程

YOLOv5+LPRNet车牌识别:从CCPD训练到部署全流程 简介基于YOLOv5与LPRNet的车牌检测识别项目包面向毕业设计、课程设计及软件工程实践场景解决车牌定位与字符识别的完整流程问题适合需要快速搭建可演示系统的学习者与开发者。压缩包共59个文件大小16.72MB以22个Python源码文件为核心涵盖数据集划分、CCPD格式转换、YOLOv5检测模型训练、LPRNet识别模型训练以及测试推理等脚本并提供训练好的pt与pth模型权重下载解压后即可直接运行验证。配套的jpg与png示例图、yaml超参配置、txt依赖说明及md教程文档进一步降低了复现门槛便于按模块学习与二次开发。教程从环境准备、数据预处理到训练调参与结果可视化均有详细说明目录结构清晰可帮助读者快速掌握车牌检测识别项目的完整技术链路。目前已有432人学习下载适合作为课程设计或毕业设计的参考实现。1. 车牌检测与识别流水线从CCPD数据集到YOLOv5LPRNet的完整落地一辆车从画面中出现到车牌号被读出来中间隔着两个问题车牌在哪车牌是什么。前者是目标检测后者是字符识别两个问题用不同的模型解决才合理。YOLOv5负责在整张图中框出车牌区域LPRNet则把裁剪出的车牌图像直接映射成字符串中间不需要字符分割。这套组合在CCPD数据集上训练能覆盖大部分真实场景下的中国车牌识别需求尤其适合毕设、工程原型和边缘设备推理场景。本文会从数据集处理、检测模型训练、识别模型训练到两条链路串联给出可以直接照着跑的参数和命令并把常见的坑标注出来。2. CCPD数据集车牌检测与识别的数据底盘2.1 CCPD数据集结构与关键字段CCPDChinese City Parking Dataset是中科大收集的大型停车场真实场景车牌数据集图像来自不同天气、光照和角度下的实拍比合成车牌数据更接近实际部署环境。整个数据集按省份简称、字母、数字和车牌类型做了信息冗余标注文件名本身就携带了车牌字符和角点坐标。CCPD2019包含约25万张图像CCPD2020补充了更多恶劣天气和模糊样本。文件名格式类似025-95_113-154383_386473-386473_177454_154383_363402-0_0_22_27_27_33_16-37-15.jpg各段含义分别是车牌宽度占比、车牌高度占比、车牌左上和右下角坐标、车牌的四个角点坐标、车牌字符编码、亮度评分、模糊评分。文件名中的154383_386473就是检测框的左上角(154, 383)和右下角(386, 473)386473_177454_154383_363402是车牌的四个角点用于透视校正。下载后建议先解压并确认目录结构是否符合YOLOv5的预期。常见做法是将数据按train/val划分每个子目录下放images和labels两个文件夹YOLOv5训练时会自动匹配相同前缀的.txt标注文件和.jpg图像文件。CCPD原始数据没有VOC格式的XML标注需要从文件名解析坐标后自行生成YOLOv5的txt标注。2.2 用脚本将CCPD转换为YOLOv5训练格式YOLOv5的标注格式是归一化后的class x_center y_center width height类别只有一类车牌。下面这个脚本会遍历CCPD图像文件名提取角点坐标中的左上与右下点再归一化写入txt。需要注意坐标原点是图像左上角CCPD文件名里的坐标已经是像素值不需要额外偏移。import os import cv2 src_img_dir CCPD2019 out_img_dir dataset/images out_lbl_dir dataset/labels os.makedirs(out_img_dir, exist_okTrue) os.makedirs(out_lbl_dir, exist_okTrue) for fname in os.listdir(src_img_dir): if not fname.endswith(.jpg): continue parts fname.split(-) # 第四段是左上角与右下角坐标格式如 154383_386473 box_part parts[2] left_top, right_bottom box_part.split(_) x1, y1 map(int, left_top.split()) x2, y2 map(int, right_bottom.split()) img cv2.imread(os.path.join(src_img_dir, fname)) h, w img.shape[:2] x_center ((x1 x2) / 2) / w y_center ((y1 y2) / 2) / h box_w (x2 - x1) / w box_h (y2 - y1) / h label_name fname.replace(.jpg, .txt) with open(os.path.join(out_lbl_dir, label_name), w) as f: f.write(f0 {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}\n) # 顺便拷贝图片到目标目录 os.system(fcp {os.path.join(src_img_dir, fname)} {os.path.join(out_img_dir, fname)})脚本的逻辑很直接按-切分文件名后取第三段再按_和拆出两个点坐标。这里没有做train/val划分建议先随机抽取10%的图像作为验证集避免同一停车场的相近角度图像全部落进训练集导致过拟合。更严谨的做法是按采集时间或地理位置划分但CCPD文件名里没有这些信息随机划分是常见妥协方案。转换完成后还需要在dataset/下创建CCPD.yamltrain: dataset/images/train val: dataset/images/val nc: 1 names: [plate]nc: 1表示只有一个类别也就是车牌。如果后续想同时检测车脸或车型需要修改这里并重新生成标注。2.3 数据增强与样本分布检查转换完格式后先别急着训练。用下面命令统计一下标注框的尺寸分布这直接决定YOLOv5的锚框参数怎么设置。python -c import os import numpy as np sizes [] for f in os.listdir(dataset/labels/train): with open(os.path.join(dataset/labels/train, f)) as fh: for line in fh: _, x, y, w, h map(float, line.split()) sizes.append((w, h)) arr np.array(sizes) print(mean w,h:, arr.mean(axis0)) print(max w,h:, arr.max(axis0)) print(min w,h:, arr.min(axis0)) 车牌在图像中通常是小目标尤其是停车场整车的画面车牌宽高往往只有图像的十分之一甚至更小。如果平均框宽小于0.15训练时建议开启YOLOv5的--multi-scale参数让模型在不同输入尺度上看到目标增强小目标检测能力。同时CCPD中相当一部分图像有透视形变检测框是倾斜的但YOLOv5输出的是水平框会引入一定的背景噪声这在识别阶段需要靠LPRNet的鲁棒性来消化。3. YOLOv5车牌检测模型选择、超参数与训练命令3.1 为什么检测端选YOLOv5而不是传统图像处理传统车牌定位靠边缘检测、颜色阈值和形态学闭运算在固定角度、固定光照的卡口场景下效果尚可但一旦遇到逆光、阴影、车身颜色与车牌底色接近的情况阈值参数就会失效。YOLOv5将车牌定位转化为回归问题直接预测边界框和置信度天然适配多角度、多尺度场景。相比于Faster R-CNNYOLOv5在推理速度和工程易用性上有明显优势相比YOLOv8等新版本YOLOv5的生态更成熟网上能找到大量训练自己的数据集的现成配置和踩坑记录这也是毕设和企业原型项目选它的主要原因。YOLOv5的网络结构延续了CSPDarknet的设计思路。骨干网络用CSPNet降低冗余梯度计算颈部用PANet做多尺度特征融合检测头在三个不同尺度的特征图上输出预测框。车牌识别场景下输入分辨率不需要太高--img 416通常就够用过高的分辨率只会增加推理延迟对小目标的提升有限。实际训练时预训练权重选择yolov5s.pt或yolov5m.pts版本参数量小、训练快m版本精度更高但推理稍慢。车牌只有一个类别s版本已经足够。3.2 训练自己的车牌检测模型的完整命令环境配置是第一个坑。YOLOv5官方代码基于PyTorch环境配置建议直接按官方README执行git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txtPyTorch版本建议不低于1.8CUDA版本与显卡驱动要匹配。如果机器没有NVIDIA显卡训练会非常慢可以尝试Google Colab或云GPU。训练命令如下python train.py \ --data ../dataset/CCPD.yaml \ --weights yolov5s.pt \ --img 416 \ --batch 16 \ --epochs 100 \ --workers 4 \ --cache \ --multi-scale参数说明如下表这些参数在车牌这类单一类别小目标任务中需要重点调整参数建议值说明--img416输入图像边长越小训练越快但车牌过小容易漏检--batch16取决于显存6GB显存建议812GB以上可以到32--epochs100单类别任务100轮基本收敛超过150轮容易过拟合--multi-scale开启每10个batch随机缩放输入增强小目标鲁棒性--patience20验证集指标连续20轮不提升就早停节省时间--cache开启提前把图像缓存到内存加速数据读取注意显存消耗--weightsyolov5s.pt建议使用COCO预训练权重做迁移学习不要随机初始化训练过程会输出mAP、Precision、Recall等指标。车牌检测的mAP0.5一般能到98%以上但如果出现mAP很高但实际测试漏检的情况多半是验证集分布与训练集太接近。另一个要注意的是--hyp超参数文件YOLOv5默认的hyp.scratch-low.yaml里包含hsv_h、hsv_s、degrees等增强参数。车牌颜色是重要的先验信息默认的色调增强幅度较大可能把蓝牌增强成绿牌建议把hsv_h从默认值调低到0.01degrees旋转角度设到5-10度之间因为实际车牌不会出现90度旋转。3.3 检测效果排查漏检和误检分别看哪里训练完成后如果发现漏检优先看测试图像中车牌的真实尺寸。如果车牌像素宽度小于20个像素YOLOv5s的特征图下采样32倍后只剩下不到1个像素的信息这是结构性漏检调参无法解决只能提高输入分辨率或使用更大模型。误检则通常把车灯、车标、深色区域当成车牌原因是背景与车牌颜色相似度高。这时需要增加负样本可以从CCPD测试集里截取不含车牌的图像加入训练集并在CCPD.yaml中设定background目录。YOLOv5本身不区分正负样本目录需要把所有背景图放到images/下并生成空的标签文件。如果推理时检测框抖动明显可以开启TTATest Time Augmentation或多帧平滑但这些都是后处理技巧根本还是要保证检测框紧贴车牌边缘。训练结束后的最佳权重在runs/train/exp*/weights/best.pt后续识别阶段的输入就依赖这个模型输出的坐标框。4. LPRNet车牌识别端到端字符识别与CTC解码4.1 LPRNet网络结构与CTC原理LPRNet是面向车牌识别的轻量级卷积循环神经网络核心思想是不做字符分割直接输入整张车牌图像输出变长的字符序列。网络主干是一系列卷积层和最大池化层用来提取视觉特征然后接入循环层通常是双向LSTM或GRU建模字符之间的时序依赖最后通过CTC损失函数对齐输入序列与输出标签。中国车牌固定为7个字符省份汉字字母字母/数字组合新能源车牌为8位但LPRNet的设计允许输出变长序列因此也适用于其他国家的车牌格式。为什么不用传统的字符分割方案传统方法先找字符间隙再用单个字符分类器逐个识别问题是车牌铆钉、污渍、边框和倾斜透视都会干扰分割结果。LPRNet把字符识别建模为一个序列标注问题CTC在训练时自动学习特征帧与字符之间的对齐关系不要求每一帧都有明确的字符边界这大大提升了对模糊车牌的容错能力。车牌底色差异蓝、绿、黄不影响LPRNet的特征提取因为字符区域的颜色信息在网络深层已经弱化网络更关注字符形状。LPRNet的输入尺寸一般设为宽94像素、高24像素。这个比例接近真实车牌的宽高比。车速很快时图像存在运动模糊网络需要一定的数据增强来模拟模糊效果常见做法是训练时随机添加高斯模糊、运动模糊、对比度扰动和仿射变换。4.2 LPRNet训练参数与数据准备先定义字符集。中国车牌字符集合包括省份简称汉字、24个字母除去I和O、10个数字再加上新能源车牌的特殊要求总共约70个类别。provinces 京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼 letters ABCDEFGHJKLMNPQRSTUVWXYZ digits 0123456789 charset provinces letters digits训练LPRNet前需要把检测模型输出的车牌裁剪图作为输入。CCPD文件名第七段能直接提供真实车牌字符但需要自己写映射函数将编码转为字符串。训练时推荐使用Adam优化器初始学习率1e-3batch size设为128或256输入统一resize到(94, 24)。损失函数使用torch.nn.CTCLoss需要传入预测序列、目标序列、输入长度和目标长度。import torch import torch.nn as nn criterion nn.CTCLoss(blank0, zero_infinityTrue) # log_probs: (T, N, C)T为序列长度N为batchC为类别数 # targets: (N, S)S为目标序列长度 # input_lengths: (N,) 每个样本的输入序列长度 # target_lengths: (N,) 每个样本的目标字符数 loss criterion(log_probs, targets, input_lengths, target_lengths)blank0必须与网络输出层中空白字符对应的通道索引一致。LPRNet输出层维度是字符集大小1多出的1个通道是CTC的blank标记。训练时要对车牌图像做适度形变增强例如随机旋转±5度、随机亮度调整、随机添加噪声这能让模型更好地应对检测框没贴合车牌边缘的情况。另外CCPD中的车牌字符分布并不均匀某些省份简称出现次数很少训练时可以对低频字符做加权采样否则模型会对高频字符过拟合低频省份字符识别率偏低。4.3 字符表与解码顺序推理阶段需要把网络输出的概率序列转换为最终车牌字符串。CTC解码常见做法是贪心解码每一步取最大概率的类别然后合并相邻相同类别最后删除blank。这个策略在车牌识别场景中已经够用因为车牌长度固定且字符间隔清晰不需要beam search。def ctc_greedy_decode(pred): # pred: (T, C) 概率矩阵 last None result [] for t in range(pred.shape[0]): char_idx pred[t].argmax().item() # 跳过blank if char_idx ! 0 and char_idx ! last: result.append(char_idx) last char_idx return result解码后得到的索引列表需要映射回字符集注意charset中索引0对应第一个汉字但CTC的blank占用了通道0映射时要错位。实际项目中经常出现的问题是省份汉字被识别成字母这是因为汉字的笔画复杂、类内差异大而训练数据中汉字样本相对较少。缓解方法是在数据增强时对字符区域做随机裁剪人为引入一定的字符形变让网络看到更多汉字细节。LPRNet本身也支持使用额外的分类头对车牌类型蓝牌、绿牌、黄牌进行辅助识别这个多任务学习技巧能提高整体识别稳定性但会略微增加模型复杂度。5. 检测与识别串联推理坐标裁剪、故障排查与性能优化5.1 从检测框到识别输入的坐标裁剪细节串联推理时最容易出错的是坐标尺度不一致。YOLOv5的detect.py输出的是原始图像像素坐标而LPRNet要求输入是车牌区域的裁剪图。直接使用detect.py的坐标裁剪时要把检测框向外扩10%到20%的余量因为YOLOv5预测的水平框往往紧贴车牌边缘裁剪后可能会截掉字符的上下边界导致识别准确率下降。扩边操作在推理代码中实现。import cv2 import torch def crop_plate(image, box, expand_ratio0.15): x1, y1, x2, y2 box w, h x2 - x1, y2 - y1 dx, dy int(w * expand_ratio), int(h * expand_ratio) x1 max(0, x1 - dx) y1 max(0, y1 - dy) x2 min(image.shape[1], x2 dx) y2 min(image.shape[0], y2 dy) plate image[y1:y2, x1:x2] plate cv2.resize(plate, (94, 24)) plate cv2.cvtColor(plate, cv2.COLOR_BGR2GRAY) plate torch.from_numpy(plate).float().unsqueeze(0).unsqueeze(0) / 255.0 return plate灰度化是可选的。LPRNet输入是三通道或单通道都能训练但灰度图能减少光照颜色干扰蓝牌和绿牌的底色差异在经过灰度转换后依然保留亮度差不影响字符形状识别。注意cv2.resize的插值方式缩小车牌图像时用cv2.INTER_AREA可以保留更多边缘细节默认的双线性插值会导致字符边缘发虚。另外检测模型输出的是多个候选框需要先按置信度过滤conf 0.5再按坐标排序。如果一帧图像中出现多辆车要对所有检测框依次裁剪识别最后按车牌字符串去重或按跟踪ID关联。5.2 识别结果中的常见错误模式与对策实际运行中识别错误主要集中在三种情况。第一是颜色车牌的误识别新能源绿色车牌和黄色教练车牌字符颜色不同LPRNet在灰度输入下要依靠字符亮度区分如果光线太强或反光严重字符与底色对比度下降模型会把数字5识别成6或3。对策是在训练数据中对亮度通道做更大的随机扰动或者把输入从灰度改回RGB让网络利用颜色信息。第二是检测框偏移引发的截断错误字符第一个字被裁掉一半此时LPRNet往往会输出长度不足7的结果。在解码后加一个长度校验长度为6或7时正常输出长度小于6时用更大expand_ratio重新裁剪识别。第三是蓝色车牌与绿色车牌在灰度图中难以区分字符边界典型表现是把字母P识别成D或者把0识别成O。这里有一个实用技巧后处理阶段可以约束字符位置类型第1位必须是省份汉字第2位必须是字母第3到7位允许字母或数字在第2位解码到数字时用聚类算法修正。错误现象根因对策省份汉字识别错误汉字样本少、笔画复杂低频字符过采样增加裁剪增强数字5/6/3混淆低对比度、字符模糊亮度扰动增强改用RGB输入识别结果长度不足7检测框截断字符扩大裁剪比例二次识别字母O与数字0混淆字符形状高度相似后处理按位置规则约束5.3 从CPU推理到TensorRT的加速路径车牌识别的实际部署环境差异很大可能是停车场闸机旁的Jetson设备也可能是x86服务器。纯CPU推理YOLOv5sLPRNet组合单帧处理时间大约150到300毫秒其中检测占大头。如果使用TensorRT在Jetson上部署可以把检测模型转换为FP16精度推理时间缩短到10毫秒级别。转换过程使用trtexec工具或torch2trt库转换前确保算子和动态shape设置正确。trtexec --onnxyolov5s.onnx \ --saveEngineyolov5s_fp16.engine \ --fp16 \ --minShapesimages:1x3x416x416 \ --optShapesimages:1x3x416x416 \ --maxShapesimages:8x3x416x416trtexec参数中的minShapes/optShapes/maxShapes要匹配部署时的batch需求如果实际推理batch1动态shape范围可以设得更窄TensorRT优化效果更好。LPRNet结构简单参数量不到10MB在CPU上单帧识别只需10-20毫秒一般不需要单独做TensorRT转换。但要注意检测模型输出和LPRNet输入之间的数据拷贝开销推理时尽可能让两个模型使用同一块内存区域避免反复拷贝。如果只用CPU且对速度要求不高可以考虑将YOLOv5替换为--img 320输入并开启--half精度在精度损失小于1个百分点的情况下获得近一倍的加速。把输入分辨率、推理精度、裁剪余量三个参数按实际场景调一遍通常能找到速度和准确率的平衡点。本文还有配套的精品资源点击获取
返回列表