YOLOv5车牌识别Python项目实战:从模型训练到OCR字符识别

发布时间:2026/10/11 0:20:27
YOLOv5车牌识别Python项目实战:从模型训练到OCR字符识别 简介YOLOv5车牌识别Python毕业设计项目提供一套完整可运行的源码与配套资料面向计算机视觉与深度学习方向的学生和开发者用于解决车牌定位、字符识别等实际问题。压缩包共78个文件包含Python训练与检测脚本、预训练权重.pt/.pth、YAML模型配置、测试图片与视频、运行说明及依赖清单等整体约345MB目录结构清晰便于按模块查阅。已有1506人学习下载内容系统覆盖卷积神经网络原理、YOLOv5的Backbone/Neck/Head结构、数据标注与数据集划分、模型微调、图像预处理、实时目标检测、OCR车牌识别、mAP指标评估以及结果可视化完整呈现从原理到落地的实践路径。附带的预训练模型、测试样例和可迁移训练脚本能帮助读者快速复现识别效果并将方案拓展至其他目标检测项目是完成毕业设计或深入理解YOLOv5流程的高质量参考。1. yolo5 车牌识别 python 项目这套源码能把毕设做到哪一步做车牌识别毕设最怕的不是看不懂论文而是手里没有一套能直接跑起来的代码。这份基于 YOLOv5 的车牌定位与识别源码包正好踩在这个痛点上它把检测车牌位置、裁剪车牌区域、OCR 识别字符整条链路都串好了自带训练脚本、推理脚本、预训练权重、8 张测试图和一个运行说明文档。对时间紧的学生来说它是把深度学习理论落到 mAP 曲线和可视化边界框的捷径对刚接触目标检测的从业者它也是一份结构完整的 YOLOv5 工程范本。下面我会按先跑通、再训练、后避坑的顺序把每个参数为什么这么设、坑在哪一层讲清楚保证你照着走当天就能看到自己的第一个车牌框。2. 跑通环境与目录结构先让 detect.py 吐出第一个车牌框先给结论这份源码包解压后最快 10 分钟能跑出一张带边界框的检测图。前提是 Python 环境能装依赖、权重文件路径不被写死、工程目录别带中文。我拿到任何 YOLOv5 系源码的第一步永远是把项目放到纯英文路径下先读 requirements.txt再检查权重文件最后才碰推理命令。顺序反了时间会全耗在定位环境问题上。2.1 解压先看目录文件清单里哪些是核心哪些可删压缩包目录基本是 YOLOv5 官方骨架的裁剪版我用表格把关键文件的分工列出来避免你对着几十个文件发懵。路径作用优先级detect.py / test.py推理入口检测单张图或视频必看train.py / train1.py训练入口train1.py 是简化版必看read_yaml.py读取数据配置 yaml 的辅助脚本选看models/网络结构定义改结构才看utils/训练与推理工具函数选看weights/预训练权重目录必看记住里面 .pt 的实际文件名data/数据集配置与标注组织训练必看runs/训练与推理输出目录看结果用test0.jpg ~ test7.jpg8 张冒烟测试图先跑这批运行说明.txt作者给的启动指引必看simsun.ttc中文字体文件画中文标签用中文显示才用requirements.txt依赖包清单必看tutorial.ipynbJupyter 交互教程选看Dockerfile容器化部署配置可选这里面真正决定能不能跑起来的只有三样detect.py、weights 目录里的 .pt、requirements.txt。Dockerfile 是给 Linux 服务端部署准备的毕设答辩用不上留着也不碍事。hubconf.py 是给 torch.hub 远程加载用的接口本地推理可以忽略。test*.jpg 这 8 张图是冒烟测试集先把它们全部跑出框再谈后续训练。我给个经验顺序先跑 test0.jpg 这种车牌摆得正、光照正常的图把整条链路打通再换 test 系列里带倾斜角或强反光的难例看鲁棒性。一上来就去啃最难的那张容易误判成「模型不行」实际是链路没通。2.2 依赖安装与版本匹配Python 3.8~3.10 配 PyTorch 稳定版requirements.txt 里最典型的组合是 torch、torchvision、opencv-python、numpy、matplotlib、PyYAML再加 tqdm 和 seaborn 这类辅助库。YOLOv5 不同分支对 PyTorch 版本有最低要求我的经验是用 Python 3.8~3.10 配 PyTorch 1.13 到 2.x 之间的稳定版基本不会遇到算子不兼容。# 用国内镜像安装依赖避免默认源超时卡死 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple # 装完先自检版本确保 torch 和 cv2 都能 import python -c import torch, cv2; print(torch.__version__, cv2.__version__)第一条命令的-i参数指定了清华 PyPI 镜像国内网络环境下比官方源快几倍否则pip install torch这一步就能卡半小时。第二条是版本自检YOLOv5 的 focus 模块和 C3 模块内部依赖较新版本的卷积算子torch 版本低于 1.8 直接报错opencv-python 低于 4.5 时部分图像处理接口行为也不一致。无 GPU 的机器不是不能跑CPU 推理一张测试图大概要 2~5 秒训练就非常慢了一个 epoch 可能跑十几分钟不建议用 CPU 训完整模型。Windows 用户尤其注意pip install torch默认可能装成 CPU 版torch.cuda.is_available()返回 False 就是这个原因。解决方式是到 PyTorch 官网按你的 CUDA 版本选对应 wheel 重新安装而不是在环境变量上反复折腾。注意整个工程目录和测试图片路径不要出现中文或空格。cv2.imread对中文路径支持极差路径一杂就会静默读图失败最终效果是模型正常加载但输入全黑详见第 5 章。2.3 快速推理detect.py 参数表与第一张测试图依赖装完直接把 test0.jpg 喂给检测脚本python detect.py --weights weights/best.pt --source test0.jpg --conf-thres 0.4 --img 640这里--weights指向权重文件实际文件名以你压缩包里 weights 目录的 .pt 名称为准不要照抄我写的 best.pt。--source是输入可以是图片、视频文件或摄像头设备号。--conf-thres 0.4是置信度阈值低于 0.4 的检测框会被丢掉。阈值调低到 0.25 假框变多调高到 0.6 容易漏框车牌检测场景 0.4 起步比较稳。--img 640是推理分辨率必须和训练时的输入尺寸一致否则检测框的坐标会整体偏移。跑完结果默认写到runs/detect/exp目录打开里面的标注图能看到车牌框和置信度分数。这一步通过说明权重可加载、前向推理正常、绘图模块没报错。接着换 test1.jpg、test2.jpg 各跑一遍确认不同角度的车牌都能被框住再进入训练环节。顺带提一句如果权重里分了蓝牌、黄牌、新能源等多类detect 输出会带类别名如果训练时就只标了「车牌」一个类输出就只有一个 label。跑一次看终端打印的 class 列表就知道是哪一种这对后面第 3 章的数据配置很有参考价值。3. 车牌定位训练数据集组织与模型参数怎么设检测框跑得漂亮那是别人训练好的权重。毕设答辩老师大概率会追问「你自己的模型怎么训练的」所以训练链路必须走一遍准备数据集、写 yaml 配置、跑 train.py、盯 mAP 曲线。本章按这个顺序拆开讲。3.1 YOLOv5 结构CSPDarknet 与 PANet 怎么服务小目标车牌YOLOv5 的主干是 CSPDarknetNeck 是 PANetHead 在三个不同尺度上输出预测。主干负责提取图像特征Neck 做多尺度融合Head 输出边界框坐标和类别概率。对车牌这个具体场景最关键的是 PANet它把浅层的高分辨率特征和深层的语义特征反复融合让模型同时照顾大面积近景车牌和远处只占几十像素宽的小车牌。监控画面里的车牌往往是小目标这个特性直接决定漏检率。锚框anchor是另一个容易被忽略的变量。YOLOv5 默认锚框按 COCO 数据集统计COCO 里物体普遍接近方形而车牌宽高比在 3:1 到 4:1。直接拿默认锚框训练前几个 epoch 的 loss 下降会很慢而且框的宽度始终对不齐车牌边缘。train.py 默认会在训练启动时做一次 autoanchor 自适应聚类终端日志里出现 autoanchor 字样就是它在重新算锚框一般不用手动干预但你要知道这个机制存在别把训练前期的正常日志当成报错。输入分辨率也影响定位精度。车牌的宽高比已经够极端如果--img设成 320窄长车牌在特征图上可能缩到 4×4 像素以下特征直接被卷积稀释干净。我在实际项目里 640 起步显存允许的话上 960 对窄长车牌更友好代价是训练时间线性上涨。3.2 数据集与 yaml 配置YOLO 标注格式与 class 对不上就翻车YOLOv5 训练数据按 images 和 labels 两个目录组织每张图片对应一个同名 txt 标注文件。标注格式是 YOLO 归一化坐标每行代表一个目标# labels/train/00001.txt每行class_id x_center y_center width height 0 0.4825 0.6388 0.1523 0.0417这行数据的含义是类别 0车牌边界框中心点位于图片宽度的 48.25%、高度的 63.88%框宽占整张图的 15.23%框高占 4.17%。所有数值都归一化到 0~1这是 YOLO 格式和 COCO 格式最核心的区别。标注工具推荐 labelImg保存时选 YOLO 格式它会自动生成同名 txt 到指定 labels 目录。数据配置用一个 yaml 文件把路径和类别信息串起来train: data/plate/images/train val: data/plate/images/val nc: 1 names: [plate]nc: 1表示训练时只有「车牌」一个类别。如果数据集同时标了蓝牌、黄牌、新能源三类nc 就要改成 3names 对应写成[blue, yellow, green]。最容易翻车的点在这里标注文件里的 class id 从 0 开始names 列表也从 0 开始对齐。names: [blue, yellow]时标注里 0 代表蓝牌、1 代表黄牌一旦标反训练不报错但模型学出来的语义整个是错的。训练日志里样本数正常但 loss 不降先回来查这一层。数据集数量方面纯车牌检测任务干净标注的 3000~5000 张能训出可用的模型毕设想稳一点建议凑到 8000 张以上覆盖白天、夜晚、倾斜、遮挡各种情况。数据增强交给 YOLOv5 内置的 mosaic、翻转、HSV 扰动就够了不用自己写增强代码。3.3 训练参数epochs、batch、lr 怎么设结果看哪张图数据备好跑训练python train.py --data data/plate.yaml --weights weights/yolov5s.pt --img 640 \ --batch 16 --epochs 100 --device 0 --patience 20参数按车牌场景给出建议值参数建议值依据--img640兼顾小目标特征与显存占用--batch8~328G 显存建议 16OOM 就降到 8--epochs100车牌类别少50 轮能收敛100 轮更稳--device0指定第一块 GPUCPU 训练则留空--patience20连续 20 轮验证集无提升就早停--lr0默认 0.01若 loss 震荡手动降到 0.001--weights weights/yolov5s.pt表示在 COCO 预训练权重上做迁移学习这比从零随机初始化收敛快得多。--patience 20是早停策略连续 20 个 epoch 验证集 mAP 没有提升训练自动终止省电省时间。训练开始后盯runs/train/exp下的 results.png里面有 box_loss、obj_loss、cls_loss 和 mAP 四组曲线。正常情况 mAP 曲线在 30~60 个 epoch 之间会出现明显的爬升台阶之后趋于平缓。如果 mAP 一直贴在 0 附近回去查 data 配置的路径和标注格式十有八九是 yaml 里的 train/val 路径没对上或者标注 class 越界。训练完成后选 best.pt它是验证集上表现最好的权重不是 last.pt最后一个 epoch 的权重。把 best.pt 复制回 weights 目录重新跑第 2 章的 detect.py对比一下训练前后同一张测试图上的框差异这就是答辩时要展示的「训练效果」。4. 车牌字符识别OCR 衔接与预处理参数检测框拿到的是「这里有块车牌」毕设要交的是「京A12345」这串字符。这个源码包采用检测加识别两段式先裁车牌再识别字符。OCR 环节可以接 Tesseract也可以接 PaddleOCR但核心不在于选哪个引擎而在于检测框到 OCR 之间的衔接处理和字符后处理。本章按可复现的纯 OpenCV 加 OCR 路线讲透。4.1 从检测框到字符图裁剪、放大与缓存detect.py 在推理时已经拿到了边界框坐标你需要做的第一步是把这块区域从原图裁出来并适当放大。OCR 引擎对过小的字符图几乎无能为力这是最容易忽略的环节。import cv2 img cv2.imread(test0.jpg) # 假设 detect 输出的框坐标为 x1, y1, x2, y2 x1, y1, x2, y2 100, 200, 340, 260 plate img[y1:y2, x1:x2] # 放大 2 倍字符间的像素距离变大OCR 更容易切分字符 plate cv2.resize(plate, None, fx2.0, fy2.0, interpolationcv2.INTER_CUBIC) cv2.imwrite(plate_crop.jpg, plate)切片[y1:y2, x1:x2]的顺序是先行后列对应坐标系里是先 y 后 x写反会裁出一块完全错误的区域。fx, fy放大 2 倍是经验值放大太少字符间距不够放大太多边缘出现锯齿反而干扰 OCR。INTER_CUBIC适合放大场景比默认的 INTER_LINEAR 在处理弧形边缘时更平滑。如果一次要处理几十张图我不会把裁剪图临时落盘直接以内存数组形式传给 OCR 函数省掉磁盘 IO。落盘的唯一价值在调试阶段把裁剪图保存出来看一眼是倾斜、过曝还是字符粘连能立刻判断问题出在检测段还是识别段。4.2 透视矫正与二值化倾斜车牌的 image 预处理现实拍摄的车牌很少正对镜头透视变形会让 OCR 把字符边缘误判成噪声。常见做法是先对裁剪区域做透视矫正。简单的场景用边缘检测加四边形近似就够复杂背景还需要先定位车牌四角import cv2 import numpy as np plate cv2.imread(plate_crop.jpg) gray cv2.cvtColor(plate, cv2.COLOR_BGR2GRAY) # 高斯模糊去噪小图核 (3,3) 够用放大后可升到 (5,5) blur cv2.GaussianBlur(gray, (3, 3), 0) # OTSU 自适应二值化适用顺光逆光混合的数据 _, binary cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU) # 找外轮廓最大的近似四边形大概率是车牌区域 contours, _ cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for c in contours: peri cv2.arcLength(c, True) approx cv2.approxPolyDP(c, 0.02 * peri, True) if len(approx) 4: cv2.drawContours(plate, [approx], -1, (0, 255, 0), 2)GaussianBlur的核大小与图像尺寸挂钩小图用 (3,3)放大 2 倍后可以升到 (5,5)核太大会把字符边缘一并糊掉。THRESH_OTSU会自动计算最佳阈值比固定 127 稳定尤其是测试图中顺光和逆光同时存在时。approxPolyDP的 0.02 是逼近精度系数系数太大四边形顶点会少算系数太小边缘噪声会被当成顶点。拿到四个顶点后用cv2.getPerspectiveTransform加cv2.warpPerspective做矫正源点和目标点一一对应即可。这个步骤对倾斜车牌字符识别率的提升非常明显值得花时间调。4.3 字符后处理易混淆字母映射与正则校验OCR 输出天然带不确定性形近字符是最典型的误差来源0 与 O、1 与 I/l、8 与 B、Z 与 2。直接把原始输出当结果字符级准确率能掉十几个百分点。后处理必须做字符归一化和格式校验。import re char_map {O: 0, I: 1, l: 1, Z: 2, S: 5, B: 8} text ocr_result.strip().upper() for wrong, right in char_map.items(): text text.replace(wrong, right) # 常见车牌格式省份汉字 发牌机关字母 5~6 位数字字母 if re.fullmatch(r[\u4e00-\u9fa5][A-Z0-9]{5,6}, text): print(识别成功:, text) else: print(疑似误识别丢弃:, text).upper()统一大写保证映射表只写大写字母就能覆盖所有输出。映射表的顺序有讲究先替换 O→0再处理 Z→2彼此互不干扰但如果把数字替换规则写在前面后面 O→0 就会把原本正确的数字改坏。正则里\u4e00-\u9fa5匹配汉字省份简称[A-Z0-9]{5,6}限定主体长度。这一步看似只有几行代码实际是 OCR 准确率的最大杠杆加了正则后不合法的输出被直接丢弃而不是当正确答案交出去。5. 避坑排查环境、尺寸、字符混淆五类常见翻车这一章是我拆这套源码和做类似车牌项目时踩过的坑按「现象 → 原因 → 解决」三层结构写。你跑这套项目遇到同类问题可以对号入座。5.1 环境类显存 OOM 与 CUDA 版本不匹配现象训练刚跑两三个 step终端直接报CUDA out of memory。原因batch size 或 img 尺寸超过显存上限或者后台有多个进程抢占了 GPU 显存。8G 显存的卡跑 yolov5sbatch 16 很容易 OOM。解决先降 batch 再降 img。把--batch 16降到 8还不行就把--img 640降到 512。这时用nvidia-smi看一眼显存占用确认是不是有其他 Python 进程在占用。8G 显存跑 yolov5s 加 batch 8 加 img 640 是安全组合再往上就属于硬扛了。现象装完 PyTorch 后torch.cuda.is_available()返回 False。原因大概率装成了 CPU 版 wheel不是环境变量的问题。解决到 PyTorch 官网按 CUDA 版本选对应安装命令。比如 CUDA 11.8 就装torch2.1.0和torchvision0.16.0的 cu118 版本装完重新跑自检。不要先怀疑 PATH 或环境变量配置先把 wheel 选对这个顺序能省大量时间。5.2 检测类框偏移、漏检与锚框不匹配现象训练时 loss 在降但验证集 mAP 卡在 0.5 左右上不去检测框要么偏大要么偏窄。原因最常见的是训练和推理的--img不一致归一化坐标换算成实际像素时整体错位另一原因是默认锚框与车牌长宽比差太远模型前期学不到正确的框宽度。解决训练和推理统一--img 640训练日志里确认 autoanchor 是否完成重聚类。如果还不行手动在模型 yaml 里写一组适合车牌的细长锚值比如[[12,4],[28,10],[45,18]]这种宽高比明显偏长的候选。现象测试图里某个车牌没有被框出来。原因置信度阈值设太高或这块车牌处于遮挡、暗光区域模型没有足够信心。解决把--conf-thres降到 0.25 看能否出框。如果降阈值后才出框说明模型对该场景信心不足正确做法是补充这类图片进训练集重训而不是靠降阈值硬撑。--iou-thres 0.45控制 NMS 去重一般不用动。5.3 OCR 与显示类字符混淆、中文乱码与路径中文现象OCR 把「京A12345」识别成「京A12O45」。原因O/I/l/Z/S 这些字符和数字在图像上高度相似OCR 引擎本身难以区分。解决在后处理里加字符映射表和正则校验即第 4 章 4.3 节的做法。这两步不加字符级准确率会肉眼可见地掉。现象用 matplotlib 画检测图中文标签显示成方块。原因Matplotlib 默认字体里没有中文字符而源码包明明带了 simsun.ttc 却没有被加载。解决显式加载字体文件import matplotlib.pyplot as plt from matplotlib.font_manager import FontProperties font FontProperties(fnamesimsun.ttc) plt.text(x, y, label, fontpropertiesfont)fname指向资源包里的 simsun.ttc路径要跟当前工作目录一致否则一样报文件找不到。这个坑在英文标注时完全暴露不出来一旦把类别名换成「车牌」两个字框上的 label 立刻变成豆腐块。现象cv2.imread(测试图.jpg)返回 None。原因OpenCV 原生不支持中文路径。解决治本是把所有文件和路径改成英文治标用np.fromfile绕过 OpenCV 的路径解析img cv2.imdecode(np.fromfile(测试图.jpg, dtypenp.uint8), cv2.IMREAD_COLOR)imdecode的cv2.IMREAD_COLOR参数强制以 BGR 三通道读入灰度图也不会出错。这条对 Windows 用户尤其关键导出到「我的文档」的路径多半带着中文用户名属于最容易踩却最难察觉的隐性坑。6. 端到端批量验证从单图推送到文件夹批处理最后把前几章的链路压成一个批量脚本对 test0.jpg 到 test7.jpg 一次性跑完检测、裁剪和识别输出结果到 CSV写毕设实验报告时直接引用这批数据。import glob import os import cv2 from detect import run csv_lines [] for img_path in sorted(glob.glob(test*.jpg)): # run 的返回结构按你 detect.py 的实际实现调整 results run(weightsweights/best.pt, sourceimg_path, conf_thres0.4, imgsz640) name os.path.basename(img_path) csv_lines.append(f{name},{len(results)}) with open(result.csv, w, encodingutf-8) as f: f.write(image,plate_count\n) f.write(\n.join(csv_lines))这里有三个小技巧值得记住。第一用glob(test*.jpg)配合sorted()保证 8 张图的处理顺序稳定比手写 8 行命令省事得多。第二如果 detect.py 没有暴露可调用的模块接口最少的改动方式是在循环里用subprocess.run([python, detect.py, ...])调命令行入口虽然慢一点但完全不动源码风险最小。第三批量跑完不要覆盖上次的输出目录给 detect 加--name exp_batch参数或每次指定独立输出目录否则做 A/B 对比时新旧结果混在一起根本分不清哪批是哪批。把每张裁剪图和 OCR 结果也一并存档失败样本一眼就能定位是检测漏了还是识别错了。拆这类项目我记忆最深的教训是「单图跑通不算跑通批量跑通才算」单图链路上偶尔的侥幸成功在 8 张图批量场景下会被放大成各种问题。从那以后我每次拿到检测源码都会先做一次全量推理把置信度分布和每类 mAP 拉出来看再决定要不要继续往下改。这套习惯帮我避掉了很多返工希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询