资讯详情

资讯详情

YOLOv5车牌识别Python毕业设计:从环境搭建到避坑指南

简介面向计算机视觉方向毕业设计的YOLOv5车牌识别完整工程适合需要完成目标检测与OCR识别综合项目的本科生与研究生围绕车牌定位、字符识别、模型训练与部署等核心环节整合了深度学习、图像处理与光学字符识别技术。资源共78个文件约345.91MB包含19个Python源码脚本、9个YAML模型配置、5个PT权重文件、16张JPG测试图片、2段AVI演示视频以及运行说明与README文档其中源码覆盖数据标注、训练集划分、模型微调、边界框预测和可视化等模块权重文件可用于直接检测测试图片与视频便于快速验证效果。项目基于PyTorch搭建附带预训练权重和车牌数据集标注参考可直接运行detect.py进行实时检测或通过train.py在自定义数据集上微调模型并借助Tesseract等OCR模块完成车牌字符识别同时提供模型评估与调优思路帮助理解mAP、精确率、召回率等指标可根据评价结果调整学习率、批大小和迭代次数。已有1506人学习适合作为毕业设计的基础框架或深度学习教学案例。1. 把 yolo5 车牌识别做成 Python 毕业设计先想清楚这六件事把 yolo5 车牌识别做成 Python 毕业设计听起来是个目标检测题真正动手你会发现检测只是最顺手的一环字符识别和系统集成才是熬夜的重灾区。这个题目之所以被一届届学生选是因为它“看起来足够硬、做起来有清晰主线、答辩时有实物可展示”但掰开揉碎它其实要串起 Python 环境搭建、YOLOv5 模型训练、车牌字符识别、PyQt5 界面和摄像头调用这几块完全不同的技术栈。每一块单独拿出来都有教程整合到同一个项目里才是真正的难点。适合拿它做毕设的人有两类一类是已经有了物体检测基础、想用完整项目把技能焊死的另一类是刚开始接触深度学习、需要一条从零到一的可复现路径的。这两类人的坑不一样我会在后面的避坑章节分开说。如果你正打算用这个题目开题或者已经写了开题报告但还没跑通一个 demo这篇文章就是你动手前最该看完的清单。2. 搭建可复现的 Python 环境版本锚定与依赖安装的取舍2.1 为什么版本锚定比“装最新”更重要YOLOv5 的仓库名写的是 yolov5社区里习惯打成 yolo5。它本身的依赖不难装难的是和你本机的 CUDA、显卡驱动、PyTorch 版本形成一个互相兼容的组合。很多同学一上来就pip install torch torchvision装完最新版然后跑python detect.py直接报AssertionError: torch.__version__ 1.12.0 is incompatible with CUDA 11.6这就是典型的版本错配。我一般会建议毕设项目锚定一套“保守但不老”的组合Python 3.8 torch 1.13.1 torchvision 0.14.1 CUDA 11.6或 CPU 版 torch。这个组合在 YOLOv5 的 v6.0 到 v7.0 版本上都跑得通网上能搜到的各种“yolo5车牌识别 python毕业设计”源码也大多是围绕这套环境写的。用 conda 创建虚拟环境是最省心的做法因为系统自带的 Python 环境被你装乱之后后悔药只有重建环境而不是去猜哪个包被改过。conda create -n lpr python3.8 -y conda activate lpr pip install torch1.13.1 torchvision0.14.1 --index-url https://download.pytorch.org/whl/cu116 git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txt python detect.py --weights yolov5s.pt --source data/images/bus.jpg按顺序执行这五行命令第四行的pip install -r requirements.txt会装上 numpy、opencv-python、matplotlib、seaborn 这些 YOLOv5 依赖。第五行是验证安装是否成功的金标准如果能弹出那张 bus 的检测图说明环境链路通了如果报错九成是 numpy 版本和 torch 的 ABI 冲突把 numpy 降到 1.23.x 基本能救回来。另外YOLOv5 的requirements.txt里默认带有pycocotools它在 Windows 上安装经常需要 Visual C 构建工具这一步卡住的人最多。如果你不跑 COCO 评估可以直接把它注释掉并不影响训练和推理。2.2 YOLOv5 项目结构你只需要会调这三个入口刚拿到 YOLOv5 仓库新手会以为每个文件都要读懂其实不是。你只需要把train.py、detect.py、val.py三个入口弄明白这题就拿下了一半。train.py负责训练检测模型输入是标注好的数据集和模型配置detect.py负责推理输入是一张图、一段视频或摄像头画面val.py负责评估模型在测试集上的 mAP 等指标。对于车牌识别场景你还要多关注模型配置目录models/里的yolov5s.yaml这类文件它定义了网络的深度和宽度。做个车牌检测用yolov5s甚至yolov5n就够了不要一上来就上yolov5x那是给高精度竞赛准备的跑一次训练等你睡醒都未必结束。训练出来的权重默认放在runs/train/下推理结果默认输出到runs/detect/。这里有个容易踩的认知误区模型训练好之后detect.py会把检测框画在图片上但车牌识别要的不是“画出框”而是“读出字符串”。检测模型输出的只是车牌的位置信息从位置到车牌号中间还隔着一个字符识别模块。很多同学做到这里就卡住了以为 YOLOv5 已经把车牌号识别出来了其实没有。所以你在设计整个系统时要先把“检测”和“识别”拆成两个独立环节后面第 4 章我会专门讲这个衔接。3. 车牌检测模型训练从 CCPD 数据集到自定义数据集的完整流程3.1 CCPD 数据集怎么转成 YOLOv5 能吃的格式训练车牌检测模型最常用的公开数据集是 CCPDChinese City Parking Dataset它采集的是自然场景下的中国车牌包含蓝牌、黄牌、绿牌以及各种角度和光照条件下的样本。CCPD 的文件名自带标注比如025-95_113-154383_386473-386473_177454_154383_363402-0_0_22_24_27_33_43_62_73_89-101-1.jpg其中第三段154383_386473是车牌的矩形框格式是x1y1_x2y2第四段是车牌的四个角点。YOLOv5 的标注格式要求每行是class x_center y_center width height并且全部归一化到 0 到 1。你绝对不能直接拿 CCPD 的标注丢进去训练必须先做一次转换。import os import cv2 def ccpd_to_yolo(img_dir, label_dir, class_id0): # class_id0 表示车牌是第一个类别如果有背景类就往后排 imgs [f for f in os.listdir(img_dir) if f.endswith(.jpg)] for fname in imgs: parts fname.split(-) # CCPD 文件名第三段是车牌矩形框154383_386473 box_str parts[3] x1, y1 map(int, box_str.split(_)[0].split()) x2, y2 map(int, box_str.split(_)[1].split()) img cv2.imread(os.path.join(img_dir, fname)) h, w img.shape[:2] # 归一化到 [0,1]YOLOv5 要求的是中心点坐标 宽高 dw, dh (x2 - x1) / w, (y2 - y1) / h cx, cy (x1 x2) / 2 / w, (y1 y2) / 2 / h with open(os.path.join(label_dir, fname.replace(.jpg, .txt)), w) as f: f.write(f{class_id} {cx:.6f} {cy:.6f} {dw:.6f} {dh:.6f}\n)转换脚本的要点在于CCPD 的 bbox 是绝对像素坐标YOLOv5 要的是归一化后的中心点格式这两者的数学关系是cx (x1x2)/(2*w)不是x1/w。其次这里用的是文件名第三段的矩形框适合蓝牌这样接近水平的车牌。如果你处理的绿牌或者倾斜角度很大的车牌直接用 min/max 外接矩形会框进大量背景训练出来的模型定位会很飘这时候要用第四段四个角点去计算旋转框的最小外接矩形这种处理方式我会在避坑章节里细说。3.2 训练命令与关键参数跑通一次完整训练的配置数据集转换好之后你需要在 YOLOv5 目录下建一个数据集配置文件比如ccpd.yaml内容包含训练集和验证集的图片路径、类别数量、类别名。常见做法是把你转换出来的所有图片按 8:2 划分到train/和val/两个目录然后把路径写死。接下来执行训练命令。python train.py \ --data ccpd.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --workers 4 \ --device 0 \ --cache上面这行命令里--weights yolov5s.pt表示使用官方在 COCO 预训练好的权重做迁移学习这比从零开始训练快得多而且 mAP 更高。--cache会把图片提前加载进内存如果你内存不够 16G去掉它否则会直接内存溢出。若你的机器没有 NVIDIA 显卡把--device 0改成--device cpu同时建议--batch降到 8 或 4--img降到 480不然一个 epoch 够你等一集电视剧。训练完之后runs/train/exp目录下生成的weights/best.pt就是你要的检测权重。这里有一个很重要的参数直觉车牌这个目标相对整张图来说是小目标--img 640已经是最低配置降到 480 虽然能加快训练但远距离小车牌容易漏检。如果你的测试集里有很多摄像头远距离抓拍的车牌宁可训练慢一点也要用 640。而--batch 16的设定和显存直接挂钩6G 显存用 16 勉强能跑4G 显存就乖乖用 8不然一开始训练就报CUDA out of memory这属于最常见也最没有技术含量的翻车。4. 车牌字符识别把检测框变成可读的字符串4.1 两条路线对比LPRNet 端到端与逐字符分类检测模型输出的是车牌的矩形框接下来要把框里的图像识别成类似“京A12345”的字符串。业界和毕设里最常见的两条路线第一条是用 LPRNet 这类轻量级端到端识别网络输入一张车牌图直接输出完整字符串不需要预先分割字符第二条是先用投影法或轮廓法把字符切成单个再逐个做分类最后拼成字符串。以我的经验看毕设里 90% 的人最后用的是 LPRNet 或者其变体因为它在倾斜车牌上的鲁棒性明显好过“先切字再分类”的老方案。逐字符分类的问题在于字符分割这一步对二值化质量极其敏感车牌上有铆钉、有污渍、晚上补光灯一照投影分割就断掉一个字符被切成两半后面全乱了。LPRNet 的思路是把整张车牌图送进一个类似 CRNN 的网络用 CTC Loss 做序列对齐它不关心每个字符的精确边界只关心“这一串字符序列是什么”。这对新手友好很多而且推理速度极快一张车牌图在 CPU 上也就几毫秒。你也可以拿现成的 OCR 框架比如 PaddleOCR 的文本识别模型直接拿车牌训练集去微调。这算不上花哨但胜在省事。不过要提醒一点PaddleOCR 是中文通用 OCR识别“京A12345”这种短串没有专门为车牌调优直接用来跑长尾省份简称和新能源绿色车牌时错误率会比较难看。如果你论文里需要对比实验端到端自训练的 LPRNet 效果和说服力都更强。4.2 轻量字符识别模型数据准备与推理代码示例训练一个 LPRNet 需要的数据是“车牌图 字符串标签”的配对。常见做法是把 CCPD 里每个样本的车牌区域裁剪出来用 CCPD 文件名第八段作为标签那段是车牌字符序列。但也有个偷懒且好用的替代方案直接用大规模车牌开源数据集或者自己写脚本批量生成仿真车牌——使用真实的字体和车牌背景模板随机组合省份简称、字母和数字注意生成时加入透视变换、噪声和模糊来模拟真实场景。合成数据能帮你快速把模型框架跑通最后用几百张真实 CCPD 车牌微调一下效果就足够应付毕设演示了。import cv2 import numpy as np import torch from model import LPRNet # 假设你已经定义好 LPRNet 网络结构 def preprocess_plate(plate_img, out_size(168, 48)): # 统一缩放到固定尺寸高48宽168保证每个字符约有24像素宽度 plate cv2.resize(plate_img, out_size, interpolationcv2.INTER_AREA) gray cv2.cvtColor(plate, cv2.COLOR_BGR2GRAY) # 直方图均衡提升弱光车牌对比度 gray cv2.equalizeHist(gray) # 归一化到 [-1, 1]LPRNet 输入常用这个范围 gray (gray.astype(np.float32) / 255.0 - 0.5) / 0.5 return gray def infer_plate(plate_img, model, devicecpu): model.eval() x preprocess_plate(plate_img) x torch.from_numpy(x).unsqueeze(0).unsqueeze(0).to(device) with torch.no_grad(): logits model(x) # 输出形状 (batch, num_classes, seq_len) preds logits.argmax(1).squeeze().cpu().numpy() # 对序列做 CTC 去重和去空白符 chars [] prev None for p in preds: if p ! 0 and p ! prev: # 0 是空白类 chars.append(idx2char[p]) prev p return .join(chars)上面的推理代码里preprocess_plate做的事情是“固定尺寸 灰度 均衡化”这三个步骤缺一个都会让识别率明显下滑。infer_plate里对输出序列做了一个 CTC 解码的标准操作相邻重复字符只保留一个遇到空白类跳过。要注意idx2char这个映射表必须和训练时用的字符集完全一致否则输出直接乱码。这个字符集常规包含 31 个省份简称汉字、24 个字母I 和 O 通常不用加 10 个数字总共大约是 65 个类别加上一个 CTC 空白符。如果你要识别新能源车牌字符集会多一个“挂”或者绿牌专用的“D/F”等字母开启前先想清楚你的毕设重点在蓝牌还是绿牌不要想着一个模型通吃所有车牌类型。整个识别流程整合起来就是先用 YOLOv5 检测得到车牌框坐标然后用cv2.getPerspectiveTransform做一次透视矫正把倾斜车牌拉正最后裁剪出车牌图喂给 LPRNet。这里我提醒一句很多人直接拿 YOLOv5 输出的矩形框去裁剪四角带了一堆车身边缘LPRNet 的效果会打折扣。正确的做法是用 CCPD 的四个角点或者用轮廓检测找到车牌的四个顶点再做透视变换这一步能明显提升字符识别准确率。5. YOLOv5 车牌识别毕设避坑指南从环境到部署的 12 个实战记录5.1 环境与依赖torch 和 numpy 版本错配的经典翻车现象在 Windows 上用pip install -r requirements.txt装完 YOLOv5 依赖后运行python detect.py代码在导入 torch 阶段直接崩溃或者报ImportError: numpy.core.multiarray failed to import没有任何其他提示。这是 numpy 版本过高、和当前 torch 的 C 扩展 ABI 不兼容导致的。原因很简单torch 1.13.1 是围绕 numpy 1.23.x 编译的装成 numpy 2.0 后torch 在加载数组时找到不到旧版符号表。解决方法是把 numpy 固定到numpy1.23.5然后重新启动 Python问题立刻消失。如果你用的是 conda 环境进入虚拟环境再 pip 安装别把包装到 base 环境里不然下次换项目你又得体验一遍这个坑。5.2 数据与标注图像路径里的中文和空格是隐形杀手现象训练时数据加载卡在 0%或者cv2.imread返回 None没有报错程序继续往下走最后整个 batch 都是空图loss 直接 NaN。原因通常是你的数据集放在带中文的路径下比如D:\毕业设计\车牌数据集OpenCV 的 imread 在 Windows 上不支持中文路径。解决办法有两个一是把所有的目录和文件名改成英文字母和数字比如D:\lpr\ccpd_dataset这是最省事的二是如果原数据集文件名不能改用cv2.imdecode(np.fromfile(img_path, dtypenp.uint8), cv2.IMREAD_COLOR)替代cv2.imread但这种方式要改代码逻辑侵入性大。我的做法是先把整个数据集复制到一个纯英文路径下一劳永逸。5.3 训练与收敛小数据集硬训练等于在碰运气现象用 500 张车牌图片从零开始训练 YOLOv5训练到 50 个 epoch 后 mAP 还在 0.1 徘徊验证集上大量漏检有时检测框还会框住车灯。原因非常好理解500 张带标注的车牌图对于检测模型来说属于“小数据集”模型会把车灯的圆形特征和车牌的边缘特征混在一起。解决方法是先用官方 COCO 预训练权重yolov5s.pt再冻结 backbone 训练 30 个 epoch最后解冻全部层再训 50 个 epoch。具体命令是加一个--freeze 10前面 10 层参数不更新训练速度会快很多而且不容易过拟合。如果你发现 loss 在训练到一半时突然变成 NaN大概率是学习率太大把默认的 0.01 改成 0.001 重新跑。这部分多少带点玄学同一套超参数在不同数据集上表现差异很大所以改完参数一定要多跑几个对比实验答辩时这也是很好的素材。5.4 部署与打包PyQt5 界面卡死和摄像头无法打开现象在 PyQt5 界面上加了“打开摄像头”按钮点击之后窗口直接转圈无响应过几秒提示摄像头已被占用。原因是你把cv2.VideoCapture的读取操作放在了主线程里Qt 的事件循环被视频帧阻塞住了。解决方法是把摄像头读取放到一个 QThread 子线程里通过 signal 把每一帧传回主线程更新界面千万不要在主线程里写while True: ret, frame cap.read()。另一个高发坑是打包成 exe 时怎么都找不到模型文件报错FileNotFoundError: yolov5s.pt这是因为 PyInstaller 不会自动把.pt文件当成数据文件打包需要用--add-data runs/train/exp/weights/best.pt;.加上模型文件并在代码里用sys._MEIPASS定位解压后的临时路径。6. 验证模型与答辩加分技巧从指标到演示视频的最后一公里模型训完之后不要直接拿训练集说效果好要单独留出一批模型没见过的图片做测试并且学会看val.py输出的指标。YOLOv5 的验证命令会输出mAP0.5和mAP0.5:0.95两个值车牌检测属于目标相对固定、不需要极精确框的任务mAP0.5能达到 0.95 以上就算是很不错的水平。字符识别这边还要统计“整串识别准确率”——也就是车牌字符串一个字符都不能错的比例这个指标比每个字符的准确率要残酷得多但它才是答辩时老师真正关心的。我习惯写一个evaluate_lpr.py把测试集所有图片跑一遍输出检测框数量、漏检数量、识别错误数量并打印出具体的错误样例图片这样被追问的时候可以指着图里的失败案例说清楚失败原因比空谈指标有说服力得多。还有一个答辩演示的技巧现场跑摄像头识别很容易因为光线、距离、网络波动翻车所以我会准备三样东西一个是离线录好的车辆视频保证演示不会因为网络问题断掉另一个是提前生成好的测试结果图集把检测框、识别文本直接打印在图上最后一个是命令行窗口的实时日志让老师看到识别结果逐行输出。顺序上先播视频再演示摄像头最后展示指标图表把最可靠的环节放在前面。这套流程帮我顺利通过了中期检查和最终答辩也让我自己真正敢说这个项目是“跑通了的”而不是“训练跑完就结束”。最后想说如果你能坚持做到第六章这个位置你已经把检测、识别、界面、部署、评估这条链路完整的走了一遍这中间积累的调试能力远比那个“优良”的答辩成绩值钱。希望这篇东西能帮你少熬几个夜把时间花在真正让你长本事的地方。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →