ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

YOLOv5车牌识别系统实战拆解:从训练到部署的完整指南

YOLOv5车牌识别系统实战拆解:从训练到部署的完整指南 简介一份基于YOLOv5的深度学习车牌识别系统毕业论文以docx文档形式呈现面向计算机、人工智能等专业需要完成毕业设计或研究目标检测应用的读者。论文针对私家车数量激增背景下传统人工车牌识别效率低、难以适应复杂环境的问题围绕交通管理、违停监测、高速收费等场景系统阐述了YOLOv5模型的实时检测原理与优势并完整设计了图像采集、预处理、模型训练、车牌定位、字符分割与字符识别等核心流程。文档基于Python和OpenCV等库给出实现思路帮助读者理解从车牌数据集准备、模型调优到识别结果输出的工程化方法为撰写毕业设计论文或搭建车牌识别原型系统提供直接参考。资源包共1个文件类型为docx约1.14MB内含摘要、目录、正文及参考文献等标准论文结构重点覆盖绪论、系统分析与设计、实现与测试等章节。目前已有1006人学习使用适合需要快速入门深度学习车牌识别选题并获取完整论文框架的学生和研究人员。1. yolov5 车牌识别项目拆解这份毕设资源真正能落地的地方在哪做车牌识别有一段时间的工程师应该都有体会这活儿表面看着就是“检测识别”四个字真把系统跑起来坑全在细节里。这份基于 yolov5 的深度学习车牌识别系统毕业设计资源来自一个完整的本科论文项目技术链路是 Python YOLOv5 MySQL覆盖了从模型检测、车牌定位、字符识别到 Web 管理后台的完整闭环。和市面上那些只给一段识别脚本的“教程”不同这套资源带着完整的论文正文适合正在做毕业设计、或者想在一周内搭一套能演示的车牌识别系统的从业者。先说结论这份资源的价值不在于 yolov5 本身的算法创新——它用的还是成熟的检测框架而在于整个系统的完整性。你拿到的不只是一个模型文件而是“图片上传→车牌定位→字符识别→结果入库→统计分析→地图展示”这一整条业务链路。对于需要交论文、交系统演示的人这份资源几乎是照着填就能用的模板。下面我按自己拆项目的习惯把技术选型、训练流程、字符识别后处理、系统联调踩坑这四块逐一拆开讲。2. 技术选型与整体架构为什么是YOLOv5MySQL在系统里扮演什么角色2.1 检测器选型YOLOv5不是最新的但它是毕设和中小项目最稳的选择做目标检测现在可选的东西太多了YOLOv8、YOLOX、RT-DETR、甚至端到端的DETR系列。但这份资源选的是 YOLOv5我拆完代码后发现这个选择其实是经过权衡的不是随便拍脑袋。YOLOv5 在工程落地上的优势有三个第一是生态成熟Ultralytics 仓库把训练、验证、导出、推理全封装成了命令行一个train.py跑到底不需要自己写训练循环这对新手极其友好第二是硬件门槛低yolov5s 模型权重只有 14MB 左右在一块普通的 GTX 1660 上就能跑到 60 FPS 以上CPU 上也能勉强跑推理第三是预训练权重丰富直接在 COCO 上训练好的yolov5s.pt可以作为迁移学习的起点哪怕你的车牌数据集只有几百张也能在几小时内收敛到能用的水平。我在实际项目中用过 YOLOv5 也用过 YOLOv8说实话如果是从零搭一套业务系统我反而更推荐 YOLOv5。原因在于 YOLOv8 把很多配置改成了参数化模式默认的超参数调起来反而没有 v5 那么直观而 v5 的data.yaml、hyp.yaml清清楚楚写在明面上每个参数都有人讨论过网上搜报错一搜一大把。这份资源用的就是这条成熟路线没有给自己找麻烦。2.2 检测与识别两条链路的职责划分很多初学者容易把“车牌识别”当成一个整体上来就想用一个大模型直接输出车牌号。实际上工程上几乎都是拆成两步先用目标检测模型找到“车牌在哪里”再用另一个模型或传统图像处理方法识别“车牌上的字符是什么”。这套系统的分工很明确。YOLOv5 只负责第一件事——在一张包含车辆的照片里框出车牌区域输出带置信度的边界框。第二步的字符识别论文里虽然没有给非常精细的代码但我拆解下来常规做法是两种一种是把车牌区域裁出来做灰度化、二值化、字符分割然后对每个字符单独分类。这是传统方案优点是每个字符的准确率可解释、可控缺点是分割一旦失败就全盘皆输。另一种是直接用 CRNN 这类序列识别模型端到端识别整块车牌。这套系统走的是前一种思路因为毕业设计要讲清楚每一步的原理传统分割法更容易在论文里画出清晰的技术路线图。数据库的职责在第三条链路识别出的车牌号、车辆类型、上传时间、所属地区这些信息要落库。文本里明说了用 MySQL原因很实在——开源免费、简单易上手对毕设场景来说 Oracle 和 SQL Server 都过重了。整个系统的数据流向是摄像头或图片上传 → YOLOv5 检测 识别 → 结构化结果写入 MySQL → Web 管理端从库里拉数据做统计和地图展示。2.3 环境搭建Python 版本、深度学习框架与依赖安装YOLOv5 对 Python 版本的要求不算苛刻3.8 到 3.10 都能跑但要注意 PyTorch 和 CUDA 的版本匹配。我建议直接用 Anaconda 创建独立环境避免把系统 Python 搞乱。常见的安装步骤是这样的conda create -n plate python3.8 conda activate plate pip install torch1.10.0 torchvision0.11.0 --extra-index-url https://download.pytorch.org/whl/cu113 pip install -r requirements.txt逻辑说明第一行创建 Python 3.8 的虚拟环境第二行激活它。第三行安装 GPU 版的 PyTorchcu113表示 CUDA 11.3 对应的版本如果显卡驱动不支持这个版本可以换成cu102或直接装 CPU 版。第四行安装 YOLOv5 的依赖文件requirements.txt里已经写好了 numpy、opencv、matplotlib 等必要的库。参数说明这里有个关键点——不要直接pip install torch那样默认装的是 CPU 版在 GPU 机器上会白白浪费显存。先确认自己的显卡型号和驱动版本再选对应的 CUDA 版本号。如果跑在纯 CPU 环境后面训练时把 batch size 调小、模型选 yolov5s 甚至 yolov5n也能跑只是速度会慢几十倍。MySQL 这边只需要建一个库、几张表。论文里给出的用户表、新闻表是为了配合 Web 管理端真正和识别结果相关的是车牌信息表核心字段无非是车牌号、车辆类型、识别时间、上传图片路径。建表语句直接用 Navicat 或命令行执行即可不需要复杂的表关系设计这符合毕设的体量。3. 训练自己的车牌数据集从标注到出模型的全过程与关键参数3.1 数据集的构建思路数量、来源与标注工具的选择要训练 YOLOv5 做车牌检测第一步是准备数据。这里先泼一盆冷水不要指望像 COCO 那样拿几万张图来训练车牌检测任务相对单一场景也集中一千张到两千张标注好的图片已经能训练出可演示的效果。数据来源方面三个渠道一是公开数据集像 GitHub 上有不少开源的中国车牌数据集CCPD 就是其中一个很典型的例子图片量大、场景覆盖广但这个数据集标注的是整张图里的车牌框直接拿来做 YOLO 格式训练很合适二是自己收集可以在学校停车场、路边停车位用手机拍摄不同角度、不同光照条件都拍一些三是数据增强对已有的图片做翻转、亮度调整、加噪声扩大样本量。标注工具我推荐 LabelImg它可以直接导出 YOLO 格式的 txt 文件。标注时只框车牌区域不要框车身标签名统一叫plate类别越少模型越好收敛。标注完成后的目录结构要严格按 YOLOv5 要求的格式组织datasets/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yaml逻辑说明YOLOv5 训练时通过data.yaml文件来定位图片和标签的路径images/train放训练图片images/val放验证图片labels目录下的 txt 文件和图片一一对应、文件名相同。txt 里每一行代表一个标注框格式是类别序号 x_center y_center width height这四个数值都是归一化后的比例值。参数说明标注好的 txt 里x_center 和 y_center 是框中心点相对图片宽高的比例范围在 0 到 1 之间。LabelImg 会自动算好这些值不需要手动改。但要注意如果标注完把图片 resize 了标签坐标必须重新算否则训练时会报错或者框完全错位。另外 data.yaml 里的nc参数要写 1表示只有一个类别。3.2 训练命令详解超参数、预训练权重与迁移学习YOLOv5 训练可以直接用官方仓库的命令行核心参数就那么几个。以 yolov5s 为例一个典型的训练命令是python train.py --img 640 --batch 16 --epochs 100 --data data.yaml --weights yolov5s.pt --device 0逻辑说明--img 640表示把输入图片统一缩放成 640×640 再喂给网络这是速度与精度的折中--batch 16是每个批次处理 16 张图显存不够就调小--epochs 100是训练轮数车牌检测任务 100 轮足够收敛--weights yolov5s.pt从这里开始。这里必须展开讲--weights yolov5s.pt这一步的含金量。这个参数是直接用已经在 COCO 数据集上训练好的权重作为初始化而不是从零开始随机初始化网络。迁移学习的好处是网络前几层已经学会了边缘、纹理、颜色等通用特征我们只需要在它的基础上微调让高层特征适应“车牌”这个特定类别。实际效果是用预训练权重几百张图片就能训出可用模型从零训练同样数据量下几乎不可能收敛。这也是为什么我常说深度学习项目里“数据不够迁移学习来凑”是第一条保命法则。参数说明--device 0指定用第一块 GPUCPU 训练改成--device cpu。还有一个容易被忽略的参数是--cache加上之后会把图片提前缓存到内存里训练时不用每次重新读硬盘能明显加快速度但内存消耗会变大。建议第一次先不加跑通了再加。训练过程中模型权重会自动保存到runs/train/目录下每轮结束都会输出 mAP、loss 等指标。3.3 数据增强与超参数调整提升泛化能力的关键YOLOv5 自带了一套数据增强策略默认配置在data/hyp.scratch.yaml文件里。训练时会自动对图片做随机翻转、缩放、色彩抖动、马赛克增强等操作。马赛克增强是 YOLOv5 的一个特色它把四张图拼接成一张图喂给网络相当于变相扩大了 batch size对小物体检测很有帮助。对于车牌这种特定场景有几个超参数值得手动调。hsv_h、hsv_s、hsv_v控制色调、饱和度、亮度的随机扰动幅度车牌在白天、黄昏、夜晚的色差很大把这三个值稍微调大能提升光照变化的鲁棒性。degrees控制随机旋转角度车牌在图片里不总是水平的我一般会设成5.0正负 5 度旋转太大反而会让文字变形不利于后续识别。训练完成后验证模型效果有两个文件要看。runs/train/exp/val_batch0_pred.jpg是验证集预测结果的可视化图能直观看到哪些车牌被框出来了、哪些漏了。runs/train/exp/results.png是训练过程中的 loss 曲线和 mAP 曲线看 loss 曲线是否下降、mAP 是否上升就能判断模型有没有训好。如果 mAP 一直上不去优先检查数据标注有没有错、类别数对不对而不是急着加训练轮数。推理阶段同样有一堆参数可以调python detect.py --weights runs/train/exp/weights/best.pt --source data/images/test/ --conf-thres 0.5 --iou-thres 0.45逻辑说明--source指定要检测的图片路径可以是一个文件夹或单张图片--conf-thres 0.5是置信度阈值低于 0.5 的检测框会被过滤掉实际使用中如果误检多就调高漏检多就调低--iou-thres 0.45是 NMS 的 IoU 阈值用于去除重叠的框。推理结果会保存到runs/detect/目录识别出的车牌框会用矩形画出来。参数说明这里有个血泪经验——conf-thres不要设成 0.9 这种激进值。车牌检测场景下人眼觉得“很明显”的车牌模型置信度可能只有 0.7。我一般从 0.25 开始试当跑实际场景时再逐步上调到 0.5。调节这个参数时盯着误报率和漏报率看而不是看置信度数值本身。4. 把检测框变成车牌号字符分割、识别与后处理的工程细节4.1 从检测框到字符区域的图像预处理流程模型输出的是车牌在整张图中的位置框下一步要在这个框内做字符识别。这一环节能跑通整个系统才算真正闭环。工程里我的处理流程是固定的几个步骤裁剪车牌区域 → 灰度化 → 高斯模糊去噪 → OTSU 二值化 → 找字符轮廓 → 按水平投影切分字符 → 逐字符识别。这套流程里最容易翻车的是二值化。车牌有蓝底白字、黄底黑字、绿底白字等多种配色单一阈值的全局二值化必然在某些色系上失效。我一般会先判断车牌底色再决定二值化的极性——蓝底车牌要把白色字符从深色背景中分离黄底车牌相反。不过更省事的做法是直接用 OTSU 自适应阈值它在大多数情况下能自动找到合适的分割点。import cv2 import numpy as np def preprocess_plate(plate_img): # 缩放车牌区域到统一宽度 plate_img cv2.resize(plate_img, (440, 120)) # 转灰度 gray cv2.cvtColor(plate_img, cv2.COLOR_BGR2GRAY) # 高斯模糊降噪核大小选 (3,3) 保留字符边缘细节 blurred cv2.GaussianBlur(gray, (3, 3), 0) # OTSU 自适应二值化 _, binary cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU) return binary逻辑说明cv2.resize把车牌区域统一缩放到 440×120这个尺寸是经验值能保证后续字符分割时每个字符的宽度适合画外接矩形。GaussianBlur用来去噪但核不要开太大(3,3) 就够再大会模糊掉字符边缘。cv2.threshold的THRESH_OTSU标志位让算法自动计算最优阈值相比固定阈值适应性更强。参数说明440×120不是随便定的。中国车牌标准尺寸是 440×140但实际识别时上下边缘常有干扰信息缩放成 440×120 相当于裁掉一部分上下边缘同时保持了字符的宽高比。如果不管字符宽高比直接压扁后面字符分割时很容易把相邻字符粘连在一起。4.2 字符分割投影法、连通域分析与字符宽高比过滤字符分割是这套流程里最“玄学”的环节。简单场景下用垂直投影法就能切开但遇到字符粘连、边框干扰、铆钉反光时一个字符切不开后面全崩。我自己的做法是投影法打底再用宽高比和面积双重过滤。垂直投影法的逻辑比较直观把二值化后的车牌图像按列统计白色像素数量得到一个投影直方图。字符与字符之间是有空隙的空隙处白色像素数会落到一个低谷甚至归零顺着这些谷底把图像切开就是字符。实现代码如下def split_chars(binary): # 统计每列白色像素数量得到垂直投影 col_sum np.sum(binary 255, axis0) # 找到投影为0的列即为字符间空隙 zero_cols np.where(col_sum 0)[0] # 按空隙切分字符区域 chars [] start None for i in range(len(col_sum)): if col_sum[i] 0 and start is None: start i elif col_sum[i] 0 and start is not None: if i - start 10: # 过滤掉噪点造成的假字符 chars.append((start, i)) start None # 处理最后一个字符到图像末尾的情况 if start is not None: chars.append((start, len(col_sum))) return chars逻辑说明np.sum(binary 255, axis0)按列求和返回一个长度等于图像宽度的数组每个元素是该列白色像素的个数。np.where(col_sum 0)找到所有全黑列这些位置就是字符间分割线。遍历过程中用start记录一个字符的起始列遇到空白列就结束当前字符。参数说明i - start 10这个条件非常关键。如果某段白色区域只有几个像素宽那大概率是噪点不是字符。中国车牌的标准字符宽度在压缩到 440 宽后大约为 30 到 40 像素“大于 10” 这个下限能过滤掉大部分干扰。但这也带来一个问题如果车牌字符之间有较大间隙被误判为分割点比如“京A·12345”中间的点符号切出的字符块数量就会不对。解决思路有两个一是把点符号也作为一个可识别的类别加进去二是在切完后判断字符块数量不是预期数量就放弃分割、返回失败标记。字符分割完成后的识别环节论文里没有展开讲但工程上最简单的方案是训练一个小型 CNN 分类器来识别单个字符。字符集合包括 31 个省份简称、24 个英文字母去掉 I 和 O、10 个数字总共约 65 个类别。用 PyTorch 搭一个三层的简单卷积网络每个字符的样本用分割出的字符图片做训练训练数据不够就去 CCPD 数据集里批量裁车牌、批量做字符分割来扩充。这一步如果嫌麻烦也可以用开源的 PaddleOCR 直接识别整张车牌区域效果也不错只是没法在论文里把原理讲得很细。5. 系统联调避坑从环境冲突到识别失败的常见问题与排查5.1 环境配置阶段版本不匹配是最大的时间黑洞现象pip install -r requirements.txt装完后跑train.py报错提示找不到torch的某个模块或者torchvision和torch版本对不上。原因YOLOv5 官方的requirements.txt对 PyTorch 版本没有硬性锁定而 PyTorch、torchvision、CUDA 三者之间有严格的匹配关系。比如 PyTorch 1.10 对应 torchvision 0.11装成 1.10 0.10 就会出现 API 不兼容。另外直接用pip install torch默认装 CPU 版和 GPU 版混用也会出问题。解决首先确定显卡驱动的 CUDA 版本nvidia-smi能看到。然后在 PyTorch 官网找到对应的安装命令不要直接 pip 装。我的固定做法是先用conda create隔离环境再按官网给的--extra-index-url参数安装这样能保证 torch 和 torchvision 是配套的。装完后跑一句python -c import torch; print(torch.cuda.is_available())输出True再往下走。5.2 训练阶段显存不够和 loss 不下降现象训练时抛CUDA out of memory或者 loss 曲线居高不下、mAP 始终在 0.5 以下。原因显存不够几乎是唯一原因但细节有好几层。输入图片尺寸设得太大比如--img 1280对显存的需求成倍增长batch size 开太大还有可能是显卡太老、算力不足模型根本跑不动。loss 不下降则通常不是超参数问题而是数据问题——标注框不准确、标签文件里类别号写错、数据集中混入了大量无效图片。解决显存不足第一刀切 batch size从 16 降到 8、4 直到能跑起来再逐步加回。第二刀切--img从 640 降到 416检测精度稍微损失但能跑。第三刀换轻量模型yolov5n 比 yolov5s 小一半。loss 不下降时我会先用可视化脚本把标注框画回原图肉眼检查十张图看到框位置不对的立刻删掉重新标。这一步绝对不能省——我见过一个项目 mAP 上不去排查半天发现标注软件导出的坐标是百分比值而脚本按像素值解析了整个训练集全错位。5.3 识别阶段中文省份简称识别率低字符分割粘连现象英文字母和数字识别准确率还行一到“京”“苏”“湘”这类中文就乱或者分割出来的字符块数量忽多忽少。原因中文省份简称的笔画密度大经过边缘提取和字符分割后笔画的断裂会导致字符被切成两块比如“湘”字可能被拆成“木”和“目”。而英文数字都是整体结构分割相对稳定。字符粘连的根源则是二值化时阈值选得不对把两个字符的边界黑区全变成了白像素。解决中文识别上不要依赖传统的轮廓特征匹配直接用 CNN 分类器训练中文类别。样本不够的情况下可以对同一个省份简称的字符多做平移、缩放、旋转增强把样本量翻倍。字符粘连问题要从源头解决——调整二值化的参数或者改用自适应阈值算法替代全局阈值。我在实际项目中会把分割后字符块数量异常的车牌图自动存进一个debug/文件夹每个星期集中看一次找出重复出现的失败场景再针对性补数据。5.4 部署阶段openvino 与 onnx 导出的边界现象模型训练好了想部署到服务器上export.py导出 ONNX 时报错或者导出了但推理速度没有提升。原因export 的过程本质是重写计算图YOLOv5 的某些自定义算子在不同版本间有差异。比如 v6.0 之后模型结构变了数据增强逻辑也变了导出的 ONNX 里可能包含不兼容的节点。另一个坑是推理后处理只能借用 NMS 实现。解决导出前先确认目标平台支持的算子版本导出后先跑一遍官方验证脚本确认输出和 PyTorch 推理结果一致再集成。推理速度方面如果是 CPU 环境ONNX Runtime 比 PyTorch 原生的 CPU 推理快 2 到 4 倍如果机器没装 AVX2 指令集还要单独装对应版本的运行时。GPU 上不建议用 ONNX直接用 PyTorch 的 TensorRT 加速更划算。如果想体验 GPU 算力注意租用服务时选带网卡型号的镜像并将系统盘数据盘设置为本地盘具体参数配置推荐CPU 8核、GPU RTX 3090 24GB、内存 32GB、镜像选 PyTorch 1.10 CUDA 11.3。这一套组合训 yolov5s图批次 16 跑一轮大概 30 秒100 轮不超过一小时。6. 提升识别率的进阶技巧数据增强、模型轻量化与恢复训练数据增强方面车牌场景下最有效的手段不是调hyp.yaml而是针对性地生成“困难样本”。我处理过一个项目停车场出口闸机的识别率在晴天有 98%一到下雨天就掉到 70%原因是训练集里没有含雨滴的车牌照片。后来我写了个脚本对已有的车牌图片批量添加模拟雨线、雾化、模糊效果把这类增强图混入训练集后雨天识别率直接回到了 95%。类似的还可以模拟泥浆溅射、强光反射这些在真实停车场里都是高频干扰。增强后的图片不要全塞进训练集按 1:4 的比例混合原始图片比较合适。模型轻量化是另一个提升系统吞吐量的手段。yolov5s 在 GPU 上没问题但很多学校实验室的机器没有独立显卡CPU 推理一张 640×640 的图要 1 到 2 秒完全不够实时。轻量化有两个台阶第一是换成 yolov5n参数量是 s 的一半精度损失很小第二是剪枝把权重小于阈值的卷积核直接去掉再微调几轮恢复精度。剪枝后的模型大小能再压一半CPU 推理时间能压缩到 500 毫秒内。如果项目允许用非 YOLOv5 方案也可以用轻量级的 ncnn 框架部署手机端车牌识别但这里不做展开。恢复训练是一个值得单独说的技巧。YOLOv5 在训练中断后可以用之前的权重文件接着训不用从头开始python train.py --img 640 --batch 16 --epochs 50 --data data.yaml --weights runs/train/exp/weights/last.pt --resume逻辑说明--resume参数会从runs/train/exp/weights/last.pt断点恢复继续训练时优化器的状态、学习率调度都会接着之前的进度走不会出现从头开始那种“训练了 50 轮突然中断就白费”的情况。配合这个参数之后之前的训练记录会被完整保留。参数说明这里的--epochs 50是“追加 50 轮”而不是“总共 50 轮”脚本会从当前轮数接着算。恢复训练之前最好确认数据集的划分没有变化如果加了新数据就必须重新分配训练集和验证集否则新旧数据混在一起会让验证指标失真。另外一个非常实用的验证技巧是在测试集上统计每个省份简称的单独准确率。总体识别率 98% 听起来不错但细拆下去往往会发现“粤”字的识别率只有 70%因为广东车牌基数大模型见得多而偏远省份的简称见得少。这时候针对性补几张该省份的车牌照片加上数据增强比盲目加大量通用样本更有效。说起来还有个教训值得讲。早期我做车牌识别项目时总觉得模型效果不行就是网络结构不够好于是反复换模型、调通道数折腾了一个月毫无进展。后来导师点了一句“你去看看失败的图到底长什么样”我才发现九成识别失败都发生在图片模糊、车牌倾斜超过 30 度的场景。从那以后我每次训练完强制自己把val_batch0_pred.jpg和置信度低于 0.6 的样本图全部导出来过一遍先从数据源头找问题再谈模型结构。这套习惯帮我在后面的好几个项目里省了大量无效调参时间希望也能帮到你。本文还有配套的精品资源点击获取
返回列表