资讯中心

用YOLOv5做车牌识别Python毕业设计:从训练到视频流全流程

📅 2026/10/12 13:28:29
用YOLOv5做车牌识别Python毕业设计:从训练到视频流全流程
简介面向毕业设计与计算机视觉学习的YOLOv5车牌识别项目基于PyTorch框架实现车牌实时定位与字符识别适合Python方向需要完成AI项目的学生。压缩包共78个文件包含19个Python源码、9个YAML模型配置、5个预训练权重以及测试图片、示例视频、Dockerfile等整体约345.91MB目录结构清晰便于检索。已有1504人学习内容覆盖从深度学习基础、YOLOv5网络结构到模型训练与微调、图像预处理、目标检测、OCR车牌识别、性能评估和可视化展示的完整链路。除训练与检测脚本外还附带tutorial.ipynb教程、运行说明和依赖清单可快速搭建环境并复现实验。具体涉及数据标注与增强、训练集/验证集划分、超参数调整、平均精度(mAP)评估等实操细节能够支撑从数据准备到模型部署的毕业设计全流程。1. 用YOLOv5做车牌识别Python毕业设计先搞清楚你在交付什么先说结论这题目不是「用Python写个车牌识别程序」而是「用YOLOv5训练检测模型再用Python把检测框加工成车牌号最后串成视频流」。三个环节缺一个答辩都会被追问到底。我做这个方向踩过最深的坑是以为YOLOv5能直接输出「京A12345」。实际它只告诉你「哪里是车牌」字符识别、去重、视频流调度全得自己在Python里接。网上能搜到不少免费的yolo5车牌识别Python源码多数只到单图识别视频流和字符纠错是空的。适合两类人选了题还没动工的本科生想用目标检测切入安防方向、需要完整闭环练手的人。全程不要求你懂深度学习原理但要求按「环境—数据—训练—排错」完整走一遍。2. 把运行环境立住Python、YOLOv5依赖与第一次跑通检测做这个课题「能搜到免费源码」和「能跑起来」是两回事。我见过太多同学卡在第一步Python装的是最新版、torch和显卡对不上、YOLOv5 clone下来缺依赖。先花半天把环境立住后面所有步骤才有意义。这一章从选型到命令把环境问题一次说清。2.1 为什么毕业设计选YOLOv5而不是YOLOv8或传统图像处理YOLOv5是Ultralytics维护的开源目标检测框架纯Python生态用yaml文件驱动训练配置代码结构对新手非常友好。选它有四个实际理由一是中文资料最多报错一搜就能找到解决方案二是显存要求低一张入门级显卡就能训练三是训练产物weights、results.png可视化程度高答辩好讲四是它可以平滑导出ONNX后面讲部署也有素材。相比之下YOLOv8的封装更高层训练脚本更简洁但如果老师追问「yaml里每个字段什么含义」v5那种直白的配置反而更好解释。传统OpenCV边缘检测加轮廓筛选的方案在固定机位、光照稳定的停车场出入口能用一到夜间、雨天、斜拍就直接翻车而且没有「训练」这个环节撑不起一个目标检测类的毕业设计。至于HyperLPR这类开源车牌识别库它把检测和字符识别做成了一体能直接返回车牌字符串但你的题目锁定了YOLOv5重点在「训练检测模型」这个动作上拿现成库替换检测层会让课题失去核心工作量。还有一种被经常拿来对比的硬件方案臻识车牌识别一体机配置工具所代表的嵌入式一体机走的是硬件封装路线和纯软件毕设不是一条赛道。所以结论是YOLOv5做检测层Python做识别和调度层是这个题目里最合理、也最好交代的组合。检测层的训练和调参是你自己的工作量识别层的字符处理是你自己的加分项。2.2 最小依赖安装conda环境、pip安装与版本避雷先说版本避雷这是最容易踩的坑Python不要装3.11以上的最新版选3.8到3.10之间。原因很简单PyTorch对太新的Python版本支持总是慢半拍很多「pip install之后import torch报错」的玄学问题换了Python 3.9就自己好了。如果你使用的是vscode配置Python环境记得把解释器显式指向conda创建的虚拟环境不然终端能用、编辑器里不能用的情况很常见。最小安装命令如下conda create -n yolo5plate python3.9 -y conda activate yolo5plate git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txt逻辑说明前面四行是创建并激活独立的Python 3.9虚拟环境避免和系统Python互相污染第五行安装YOLOv5官方仓库声明的全部依赖。需要留意的是requirements.txt里的torch默认版本是跟随环境的如果你的机器有NVIDIA显卡先装GPU版torch再装其余依赖可以避免pip把torch版本解析成CPU版pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install -r requirements.txt参数说明cu118对应CUDA 11.8这个版本对主流显卡驱动兼容性好。没有NVIDIA显卡的机器直接用CPU版torch也能跑通流程只是后面训练会非常慢。装完后验证一下python -c import torch; print(torch.__version__, torch.cuda.is_available())能看到torch的版本号GPU机器输出True说明环境OK。这一步卡住最常见的原因是conda源没配好导致下载慢或者显卡驱动版本过低报错信息里有明显的CUDA字样就先去查驱动。2.3 用预训练权重跑通第一张图环境通了但别高兴太早环境装完先做一次完整的推理验证。YOLOv5官方仓库自带一张测试图和yolov5s.pt预训练权重第一次clone下来直接跑python detect.py --weights yolov5s.pt --source data/images/bus.jpg --conf-thres 0.4逻辑说明--weights指定权重文件--source指定输入图片--conf-thres是置信度阈值高于0.4的目标才会被画框。跑完后输出在runs/detect/exp目录下能看到图片里的行人、公交车、红绿灯都被框出来了。这里要特别提醒yolov5s.pt是在COCO数据集上训练的COCO里面没有「车牌」这个类别所以这一步只是验证「YOLOv5检测流程能跑通」不代表「车牌识别已经能用了」。很多读者在这里容易误判看到图片里车被框住就以为大功告成——实际上距离输出车牌号还差一个训练步和一个识别步。这一步得到的结果里车子能框住车牌框不住是正常的。跑通之后建议把源码目录完整备份一份后面所有操作都在副本里进行。理由很现实训练过程会改配置、覆盖权重留一个干净的原始目录相当于给自己留一颗后悔药排查问题时可以直接对比「原始代码能跑我的代码不能跑」到底差在哪。提示后续训练产生的runs目录会越来越大建议在clone的仓库根目录建一个.gitignore把runs/和数据集目录都忽略掉避免误提交和磁盘写满。3. 车牌数据集准备从公开数据到自采抽帧标注与转换一个不少环境通了下一步是数据。车牌识别效果好不好七分看数据这句话在毕设场景里尤其真实。检测模型不需要你喂几万张图但需要你的数据分布覆盖答辩演示时的真实情况。3.1 数据从哪来公开车牌数据集与自采视频抽帧的配比公开数据集最常用的是CCPD全称Chinese City Parking Dataset。它是学术场景下车牌检测的标准数据集覆盖不同天气、不同角度、不同光照下的车辆图像且直接带车牌标注框。毕设用它在授权上没有障碍但要注意两点一是它的标注格式不是YOLO原生格式拿回来要转换二是CCPD里的场景和你在校园、小区里答辩演示的机位不一定一致纯用它训练演示时可能漏检。所以常见做法是「公开数据打底自采数据补缺」。公开数据取2000到4000张做训练主集自采用手机在停车场出入口拍10分钟视频Python脚本按每5帧存一张挑出100到300张有效画面补进去。自采数据的价值不在数量在于它能覆盖你答辩现场的真实光线、真实车牌角度、真实背景。网上很多免费python源码大全类的资源站点会打包「数据集标注脚本」下载之前先检查标注格式很多是用labelImg的VOC格式xml导出的而YOLOv5要的是每张图对应一个txt格式不统一会在训练时报一堆「no labels found」的错。3.2 labelImg标注画框、保存与VOC转YOLO格式标注工具用labelImg最省事它是Python写的图形化标注工具安装命令pip install labelImg labelImg打开后界面左侧是工具区操作流程是打开图片目录Open Dir→确认标注格式PascalVOC→右键拖动画出车牌矩形框→在类别弹窗里输入plate→点Save保存。保存后每个xml文件里包含图片尺寸、目标类别、矩形框的左上右下坐标。但YOLOv5训练时不认xml只认txt格式的归一化标注所以需要一个转换脚本。下面的脚本把PascalVOC的xml转成YOLO的txtimport xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(xml_file, class_names, out_dir): tree ET.parse(xml_file) root tree.getroot() img_w int(root.find(size).find(width).text) img_h int(root.find(size).find(height).text) if img_w 0 or img_h 0: return out_lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_names: continue cls_id class_names.index(name) box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) x_center (x1 x2) / 2 / img_w y_center (y1 y2) / 2 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h out_lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) out_txt out_dir / (xml_file.stem .txt) out_txt.write_text(\n.join(out_lines)) class_names [plate] xml_dir Path(annotations) out_dir Path(labels) out_dir.mkdir(exist_okTrue) for xml_file in xml_dir.glob(*.xml): voc_to_yolo(xml_file, class_names, out_dir)逻辑说明脚本从xml里读出图片宽高和每个目标的边界框坐标把左上右下坐标换算成YOLO要求的中心点加宽高的归一化格式类别名转成索引写进txt。注意坐标一定要除以当前图片的实际宽高不能写死一个值不同图片尺寸不一样写错会导致标注全部偏移。还需要注意如果xml里没有object标签脚本应该跳过而不是写出空txt。如果你的数据集是从公开渠道下载的COCO格式json转换逻辑类似但解析结构不同可以去搜「coco转yolo格式脚本」找一个标注类别与你的类别对应的版本改一下类名和路径就能用。这类脚本网上很多但核心就一句话类别索引从0开始、坐标必须归一化这两个变量搞对转换就不会错。3.3 数据清洗三原则模糊帧、绿牌比例与「只标车牌一个类」数据准备里有三个原则越是新手越容易在这里走弯路。第一个原则是检测层只标plate一个类。网上有不少教程让你把省份汉字、字母、数字都框出来标成31个类甚至更多。这是把检测和字符识别搅在了一起标注量爆炸不说训练出的模型很难收敛因为省份汉字只有几个像素在640×640的输入下基本是噪点。YOLOv5这一层只需要知道「车牌在哪个框里」字符识别是在检测框内单独处理的两层分开每个环节都能调好。第二个原则是蓝牌绿牌都要有。新能源绿牌是8位字符蓝牌是7位两者宽度、字符间距都不一样。训练集里如果绿牌占比低于20%模型会把绿牌的框整体缩一圈直接导致后面的字符识别裁到半个字符。我一般会把绿牌比例拉到30%以上蓝绿比控制在7比3左右。第三个原则是模糊帧不要全删。很多同学做数据清洗时把模糊、过曝的图全部删掉结果训练集干净得很测试视频里一遇运动模糊就漏检。保留10%到20%的模糊样本相当于在训练时给模型做了数据增强。用Albumentations库可以再补一层运动模糊和亮度对比度增强模拟雨天和夜间场景增强代码很短import albumentations as A transform A.Compose([ A.MotionBlur(p0.3), A.RandomBrightnessContrast(p0.5), A.HueSaturationValue(p0.2), ])逻辑说明这段增强只用了四个变换重点在MotionBlur和RandomBrightnessContrast分别模拟运动模糊和明暗变化。p值表示这个变换在每次随机增强中生效的概率0.3代表三成概率触发。实际训练时YOLOv5自带Mosaic等增强这里的增强主要用于离线扩充自采的小数据集不要和训练内置增强叠加得太重。4. 训练与调参让YOLOv5在车牌场景下收敛的最小配置数据准备好训练就是一遍遍试参数的过程。这一章给出一套我常用的最小配置按这个组合跑车牌单类检测大概率在前50轮就能看到明显收敛。4.1 数据集yaml配置与目录结构YOLOv5训练前要写一个yaml文件告诉训练脚本数据在哪里、一共有几类。先建立目录结构plate_dataset/ images/ train/ val/ labels/ train/ val/images里放图片labels里放对应的同名txt标注文件训练集和验证集分开。用脚本按9比1随机划分图片再保证每张图片对应的txt跟着移动。这个结构是YOLOv5硬性要求的目录不对会在训练开始就报「image not found」。然后是plate.yamlpath: /home/yourname/yolov5/plate_dataset train: images/train val: images/val nc: 1 names: 0: plate参数说明path建议写绝对路径因为train.py的工作目录是yolov5仓库本身写相对路径经常因为路径解析错位找不到数据train和val填的是相对path的目录名nc是类别数这里只有车牌一类所以是1names的索引和转换脚本里的class_names顺序一一对应第0个是plate。4.2 训练命令与三个必调参数训练命令如下python train.py \ --data plate.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --device 0 \ --multi-scale参数说明分三组来看。第一组是数据与权重--weights yolov5s.pt表示用官方预训练权重做迁移学习。车牌检测的迁移效果很明显预训练模型已经学会了边缘、纹理、车这类基础特征在小样本上微调就能收敛到可用水平。如果不用预训练权重300轮都未必能到0.85的mAP。第二组是输入尺寸与训练轮次--img 640是常用的平衡点。车牌在监控画面里通常占比较小img太小会丢失细节img太大显存吃紧且训练变慢。如果你的目标是白天停车场这类固定机位640够用路测那种车牌像素低的小目标场景可以试896或960但batch要相应减半。--epochs 100对单类检测通常够用训练到后30轮时val的loss还在降就说明数据量大、还没收敛用--resume继续训练。第三组是硬件与策略--device 0指定第一块GPU。没有GPU就去弄一个云端免费笔记本或租个入门卡CPU跑100轮单类检测会把时间拉长到几十个小时论文实验记录里也难看。--multi-scale是必开项它让模型在训练中随机缩放输入尺寸对小目标检测的能力提升非常明显代价只是训练时间略增。显存不够时优先减batch而不是关multi-scale。4.3 训练过程监控loss曲线和mAP怎么判断收没收训练开始后所有中间产物都存在runs/train/exp目录下。重点看两个东西results.png里的损失曲线以及best.pt。results.png包含box_loss、cls_loss、obj_loss、mAP等子图。单类检测里最需要盯的是obj_loss它反映模型对「有没有目标」的置信度。obj_loss如果一路不降基本是数据没配对要么labels目录里没有txt要么yaml里数据路径错。box_loss在前30轮快速下降后30轮缓降这是正常形态如果val的loss在某个epoch开始反弹而train的loss还在降就是过拟合把epochs停在那之前即可。mAP部分重点看mAP0.5这个值在0.85以上检测框基本可用。mAP0.5:0.95偏低说明框的定位边界不够精细可以换yolov5m权重或把img调大再训一轮。训练结束的best.pt就是答辩演示要用的权重detect.py直接指定它即可。4.4 推理与导出从单图到视频再导出一个ONNX训练完成后用最佳权重在视频上验证python detect.py --weights runs/train/exp/weights/best.pt --source test_video.mp4 --conf-thres 0.3 --save-txt逻辑说明--source换成你自己的测试视频--conf-thres设0.3会比默认0.25更严格减少抖动导致的误检--save-txt会把每个检测框的位置和置信度存成txt方便后面按帧调试字符识别。如果测试视频里车牌能稳定框住就说明检测层基本达标。想在部署层面加一点答辩亮点可以用官方导出脚本转ONNXpython export.py --weights best.pt --include onnx参数说明--include onnx表示导出ONNX格式。导出成功后在runs/train/exp/weights下会生成best.onnx它可以脱离PyTorch环境用ONNX Runtime或OpenCV的dnn模块加载。毕设不强制导出但讲清楚「检测模型训练完成后转成通用部署格式」这件事答辩的含金量会明显不一样。5. 车牌识别必踩的坑检测与字符识别的五个翻车现场数据、训练、推理都跑通才算进入这个课题真正磨人的阶段。下面的问题我都在实际调试中遇到过按现象→原因→解决写。注意这些坑是环形出现的修好了检测字符识别的问题又冒出来解决了白天场景晚上又给你漏检。如果你一个都没遇到说明测试场景太干净换个视频再验证一次。5.1 现象一训练mAP到0.9视频里车牌还是漏检成串现象验证集上mAP0.5到0.9可视化检测框也准但换到自己拍的视频部分帧车牌完全没框出来连着几十帧漏检。原因训练集里车牌占画面比例普遍较大而视频里车辆远、车牌小模型没见过这种尺度另一个常见原因是推理阈值过高视频里车牌模糊一帧导致置信度降到阈值以下。解决训练阶段开--multi-scale并加入小目标样本具体做法是把车牌高度小于整图高度10%的图片单独挑出来复制扩容到训练集。推理阶段把--conf-thres降到0.15左右让模型把模糊帧也框出来。多出的误检框不用怕后面用去重和跟踪把同一辆车的多框合并。检测框连贯性优先于单帧精度这是视频场景的第一原则。5.2 现象二检测框出来了字符识别结果完全不能用现象视频上检测框稳定但输出车牌号时乱码一串汉字全错数字和字母偶尔对。原因这个坑最隐蔽——很多人把YOLOv5当成了端到端车牌识别。YOLOv5的输出只有框坐标、置信度和类别根本没有字符序列。把它当黑匣子输入图片就想要车牌号结果自然是空的。通用OCR比如PaddleOCR对车牌这种字体受限、字形特殊的场景直接用效果很差。解决检测框拿到后先做预处理再喂OCR按框宽高比判断蓝绿牌蓝牌宽高比约3.14绿牌更宽约3.5框稍微向外扩10%避免裁到字符转灰度图后用大津法二值化有倾斜时做透视矫正。OCR输出后用规则过滤第一位必须是省份汉字第二位必须是大写字母其余位在数字和大写字母不含I和O中选择不合格的结果直接丢弃。能在答辩现场把这条链路讲清楚比贴一个跑了三天的训练曲线更有说服力。5.3 现象三夜间和逆光下检测框来回抖现象白天检测框很稳夜间或逆光时同一个车牌这一帧框大了下一帧框偏了检测框闪烁。原因光照突变让同一个目标的置信度在阈值附近跳动YOLOv5对帧的处理又是独立的单帧输出之间没有任何时间连续性。解决推理前对每一帧做CLAHE对比度增强压低过曝和暗部不均的影响再用简单的IoU跟踪器做帧间匹配IoU大于0.3认为同一目标对框坐标做指数平滑。我不建议一上来就用DeepSORT车牌检测的目标类别单一、场景固定一个几十行的IoU匹配器就够了加复杂跟踪器反而带来更多调参包袱。5.4 现象四训练报错CUDA out of memory现象训练到第一个epoch就崩日志末尾出现RuntimeError: CUDA out of memory。原因batch、img、缓存三者的显存消耗超出显卡容量。8G显存跑batch16、img640、默认缓存全开很容易爆Windows下还常见num_workers多进程导致的内存叠加。解决先把batch减到8或4--cache False关掉图像预加载num_workers设成0或2。如果还爆把img降到416。注意batch减半后学习率不用跟着动YOLOv5会根据batch自动调整真正要防的是为了保住batch把multi-scale关了那个损失比显存更痛。5.5 现象五绿牌识别率明显低于蓝牌现象蓝牌检测框和识别都正常绿牌要么框偏要么识别结果少一位字符。原因绿牌是8位字符比蓝牌长且车牌宽度样式不同训练集里绿牌占比低模型对绿牌的宽度和边缘回归不准。字符识别模块如果不区分蓝绿牌按蓝牌的7位槽位去切绿牌最后一位字符就会被切丢。解决数据层把绿牌占比提到30%以上标注时绿牌框必须完整包含左右边缘识别层先按检测框的宽高比区分蓝绿绿牌走8位字符槽位蓝牌走7位。这一步做完成功率会明显拉开差距因为大多数开源源码只按蓝牌写了逻辑你把它补全本身就是答辩的亮点。6. 把单图识别串成视频流跳帧、去重和字符纠错的进阶做法检测和单帧识别都稳定之后最后一个环节是把它们串成一个能连续输出的系统。大部分毕设代码停在了「对视频每一帧做detect」结果同一个车牌被连续输出几十次答辩演示时满屏重复观感很差。先加跳帧和去重import cv2 cap cv2.VideoCapture(demo.mp4) fps cap.get(cv2.CAP_PROP_FPS) frame_skip max(1, int(fps // 15)) recognized [] frame_id 0 while True: ret, frame cap.read() if not ret: break if frame_id % frame_skip 0: plates detect_and_recognize(frame) for p in plates: if p not in recognized: recognized.append(p) frame_id 1逻辑说明跳帧用frame_id % frame_skip控制每秒保留约15帧参与识别避免结果在时间上冗余。recognized列表保存已输出的车牌字符串但更稳妥的做法是记录输出时间戳同一车牌在5秒内不重复输出超过时间再出现视为新车。再讲字符纠错这是提升最终准确率最便宜的手段。常见做法是把检测结果按规则校验省份简称集合是现成的约束PROVINCE_CHARS 京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼校验逻辑说明位一必须命中省份简称位二必须是大写字母其余位必须来自数字加去除I/O的大写字母集合。校验失败直接丢弃这一帧的结果宁缺毋滥。视频场景下丢掉一帧只是少一次输出不会影响整体识别正确率。这个课题做到这里你已经不是「跑通了别人的源码」而是「搭出了一个能解释、能排错、能改进的系统」。我交毕设前做的最后一件事是把所有演示视频统一成15帧每秒再测试因为答辩电脑性能不可控帧率一高画面就卡一卡就会被追问「你的算法是不是算不动」。我也养成了一个习惯每次改参数前备份当前权重和配置改坏了随时回滚真到答辩前夜这个习惯能救你一次。希望帮到你。本文还有配套的精品资源点击获取

看完文章,想为自己的企业也做一次专业网站诊断?

尧图顾问免费为您评估现有网站,并给出建站/改版建议与报价方案。

免费获取方案