尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

车牌识别数据集+YOLOv11训练全攻略:从标注格式到避坑实践

发布时间:2026/9/28 18:39:46

资讯中心
01
ARTICLE

车牌识别数据集+YOLOv11训练全攻略:从标注格式到避坑实践

车牌识别数据集+YOLOv11训练全攻略:从标注格式到避坑实践
简介面向计算机视觉车辆检测场景的中国车牌号识别数据集覆盖车牌数字与字母的常见组合标注格式已适配YOLOv11可直接用于目标检测模型的训练、验证与迁移学习适合正在做智慧交通、车辆识别或毕业设计的开发者与学习者。压缩包共2000个文件约17.18MB其中542张JPG车牌图像配有1457个TXT格式的YOLO标注文件另含1个YAML配置文件可直接写入YOLOv11项目读取类别与路径信息整体目录结构紧凑清晰。该数据集已有950人学习使用数据规模对于快速验证模型和算法调优比较合适。下载后即可获得已对齐的图像与标注对免去自行采集样本、手工标注和格式转换的繁琐工作方便直接开展车牌识别训练、评估与二次标注尤其适合需要尽快跑通YOLOv11流程的中级开发者。1. 车牌识别数据集1458张YOLOv11标注图能解决什么问题做车牌识别最耗精力的往往不是模型训练而是数据本身。这个数据集把最脏的活提前干完了1458张中国车辆车牌图片全部配好YOLOv11格式的txt标签识别对象覆盖数字0-9和字母A-Z共36个类别。解压后改一个data.yamlyolo detect train就能跑起来是速度最快的一条验证路径。适合三类人被标注工具折磨的车牌识别开发者、用YOLO系做目标检测的毕设课设项目、想在YOLOv11上快速验证训练流程的算法工程师。注意边界数据集不含省简称汉字完整输出“粤B12345”这种结果还需要后续补汉字标注或后处理这一点先记住后面会展开讲。下面按数据格式、训练配置、踩坑、验证增强四块拆透保证拿到手当晚上手。2. 数据格式与目录结构1458张图是怎么组织的2.1 图片文件名、标签文件与对应关系数据集里的图片文件名长这样1481_jpg.rf.14d0c1c37bb508dc94e22790b98dfb24.jpg 1477_jpg.rf.bf08c1582a9527d951c6f56484c3f57e.jpg带rf后缀是从Roboflow平台导出的典型特征jpg是原图格式后面那串是防止重名的uuid。文件名本身不含标注信息不能从名字猜车牌内容。每张jpg对应一个同名txttxt里存着YOLO格式的标注行。标准的一行长这样8 0.4862 0.5513 0.1854 0.0652五个字段分别是类别id、框中心x坐标、框中心y坐标、框宽、框高。x、y、w、h全部是归一化到0-1之间的相对值和图片实际像素无关。这个设计是为了适配不同分辨率输入YOLO训练时统一缩放到imgsz指定尺寸标注不会变形。下载解压后第一件事是确认图片和标签是不是一一对应。我一般先跑一段快速统计脚本import os from pathlib import Path img_dir Path(images) label_dir Path(labels) imgs list(img_dir.glob(*.jpg)) labels list(label_dir.glob(*.txt)) print(f图片数量: {len(imgs)}) print(f标签数量: {len(labels)}) missing [] for img in imgs: txt label_dir / (img.stem .txt) if not txt.exists(): missing.append(img.name) print(f缺标签的图片: {len(missing)}) for name in missing[:10]: print(name)脚本逻辑很简单遍历images目录下所有jpg用img.stem取出去掉扩展名的主文件名再去labels目录找同名txt。打印前三行是典型的rf前缀文件名从uuid前面那几位能看出原始命名规律。参数上只有img_dir和label_dir两个路径需要改成你实际解压的目录。缺标签数量如果大于0先别急着训练后面第4章有对应处理方案。2.2 车牌识别里的类别设计为什么是36类中国车牌由汉字省简称、字母、数字三部分组成但这份数据集的标注范围收敛在数字和字母上数字0-9共10类字母A-Z共26类加起来正好36类。省简称不在标注方案里这是这个资源最重要的一个边界。类别id怎么分配常见做法是数字0-9对应id 0-9字母A-Z对应id 10-35。这样一张“京A·12345”的车牌检测目标会被拆成“A”“1”“2”“3”“4”“5”六个独立检测框而不是一个整体车牌框。这种按单字符检测的方案在车牌识别里很常见好处是字符类别固定、样本均衡坏处是后续还得把单字符结果拼回完整车牌。为了训练时能看懂类别建议先把映射表存一份。命令行的类别显示和data.yaml里的names都靠它类别id内容类别id内容0数字018字母I1数字119字母J2-9数字2-920-25字母K-P10字母A26-35字母Q-Z11-17字母B-H--注意字母I和数字1、字母O和数字0在视觉上高度相似这是后面训练时最容易翻车的混淆点第4章会专门说怎么处理。2.3 解压后先理顺目录结构下载的压缩包打开后图片可能全堆在一个文件夹里旁边还带着.classes、_darknet.labels这类配置文件。直接拿去训练不行YOLO对目录结构有硬性要求。先整理成标准结构dataset/ ├── data.yaml ├── train/ │ ├── images/ # 训练图片 │ └── labels/ # 训练标签 ├── valid/ │ ├── images/ # 验证图片 │ └── labels/ # 验证标签 └── test/ ├── images/ # 测试图片 └── labels/ # 测试标签如果原始图片都在一个目录写个简单脚本按比例拆分。这里把原图放在all_images、标签放在all_labelsimport random import shutil from pathlib import Path src_imgs Path(all_images) src_labels Path(all_labels) out Path(dataset) for sub in [train, valid]: (out / sub / images).mkdir(parentsTrue, exist_okTrue) (out / sub / labels).mkdir(parentsTrue, exist_okTrue) imgs sorted(src_imgs.glob(*.jpg)) random.seed(42) random.shuffle(imgs) split int(len(imgs) * 0.9) train_imgs imgs[:split] valid_imgs imgs[split:] for img in train_imgs: shutil.copy2(img, out / train / images / img.name) lbl src_labels / (img.stem .txt) if lbl.exists(): shutil.copy2(lbl, out / train / labels / lbl.name) for img in valid_imgs: shutil.copy2(img, out / valid / images / img.name) lbl src_labels / (img.stem .txt) if lbl.exists(): shutil.copy2(lbl, out / valid / labels / lbl.name)random.seed(42)固定随机种子保证每次划分结果一致方便复现。split int(len(imgs) * 0.9)是训练集占比图片多可以提到0.951458张图用0.9比较稳验证集还能剩下140多张。标签文件缺失的图片我会直接跳过而不是报错因为YOLO反正也读不到对应标注。2.4 标签自检坐标越界与类别越界标注文件是从Roboflow导出的理论上格式干净但保不齐有个别文件损坏或者被二次编辑过。训练前扫一遍标签能省掉半夜训练报错的麻烦from pathlib import Path def check_labels(label_dir: Path, nc: int 36): bad_lines 0 for txt in sorted(label_dir.glob(*.txt)): for line_no, line in enumerate(txt.read_text().splitlines(), 1): parts line.split() if len(parts) ! 5: print(f{txt.name}:{line_no} 字段数异常: {line}) bad_lines 1 continue cls int(parts[0]) coords [float(v) for v in parts[1:]] if cls nc: print(f{txt.name}:{line_no} 类别id越界: {cls}) bad_lines 1 if any(c 0.0 or c 1.0 for c in coords): print(f{txt.name}:{line_no} 坐标越界: {line}) bad_lines 1 print(f扫描完成, 异常行数: {bad_lines}) check_labels(Path(labels))字段数必须等于5多一个空格拆出空串都不行类别id必须小于nc越界说明混入了另外一套标注体系的类别归一化坐标必须在0-1之间越界训练时会被当成非法框丢掉。这三个检查覆盖了90%以上的数据格式问题。3. 用YOLOv11把模型训起来从配置到推理3.1 环境准备训练基于Ultralytics框架装一个包就行pip install ultralytics版本上建议直接用最新的Python环境最好3.10以上。装好后先验证CUDA对GPU是不是可用import torch print(torch.cuda.is_available())输出True走GPUFalse也没关系1458张图的数据量用CPU跑起来就是慢一些一个epoch可能要几分钟到十几分钟选yolo11n.pt这种nano模型还能忍。训练前确认下磁盘剩余空间中间权重和日志大概占几百MB这个体量不吃紧。3.2 编写data.yamlYOLOv11沿用Ultralytics的配置方式data.yaml是唯一必须手写的文件。按照第2章整理的目录结构来写path: ../dataset train: train/images val: valid/images nc: 36 names: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z]path是数据集的根目录用相对路径时以当前工作目录为基准我习惯把data.yaml放在dataset外面一层所以写成../dataset。train和val的值是相对于path的目录YOLO会自动去对应目录下找images和labels子文件夹。nc: 36和names列表顺序必须严格对应names里的索引就是类别id第0个元素对应id0第35个元素对应id35。如果把字母Z放错位置训练出来的模型会把所有的Z都认成倒数第二个字母。3.3 训练命令与关键参数最简训练命令是这样yolo detect train modelyolo11n.pt datadata.yaml epochs100 imgsz640 batch16 device0第一次运行会自动下载yolo11n.pt预训练权重网络慢的话可以先手动下载放到当前目录。epochs100对1458张图的数据集是合理起点车牌字符检测任务不算复杂一般60-80轮mAP就稳定了100轮是为了看后期是否过拟合。imgsz640是输入分辨率车牌字符属于小目标后面避坑章节会讲怎么调。device0指定GPU没有GPU就改成devicecpu。显存不够就降batch8G显存跑batch16加imgsz640有点紧张降到batch8或者imgsz512都能缓解。注意batch太小时BN层统计不稳定一般不低于4。训练结束后结果在runs/detect/train/目录下runs/detect/train/ ├── weights/ │ ├── best.pt # 验证集mAP最高的权重 │ └── last.pt # 最后一轮权重 ├── args.yaml # 本次训练的全部参数 ├── results.csv # 每轮指标 └── confusion_matrix.pngbest.pt是后续推理和导出要用的last.pt通常是训练中断后恢复用的。3.4 训练过程看什么CLI界面每轮会输出一串指标box_loss、cls_loss、dfl_loss、precision、recall、mAP50、mAP50-95。对车牌识别来说重点盯cls_loss和mAP50。如果cls_loss在某一轮突然升高大概率是学习率骤降或某些难样本在起作用不一定是模型坏了。我习惯看训练结束后的results.png曲线确认mAP50在最后几十轮是平缓上升而不是振荡。best.pt按mAP50选择不是按总损失选这一点很多人忽略。训练集准确率再高也没用验证集上的mAP才是真实水平的估计。3.5 用训练好的模型推理验证训练完拿几张没参与训练的车牌图验证一下yolo detect predict modelruns/detect/train/weights/best.pt sourcetest/images saveTruesaveTrue会把带预测框的结果图存到runs/detect/predict/。打开图片看三件事一是框的位置是不是刚好包住单个字符二是类别标签是不是对的三是置信度分数。如果置信度普遍低于0.5说明训练还不充分或者数据有干扰。后续要部署的话先导出ONNXyolo export modelruns/detect/train/weights/best.pt formatonnx imgsz640ONNX格式可以转TensorRT或ONNX Runtime这一步对边缘设备部署是标准流程。imgsz要和训练时保持一致否则尺寸变化会影响精度。4. 避坑手册训练车牌识别时的五个常见问题4.1 训练时提示No labels found现象启动训练后日志出现WARNING No labels found in .../train训练过程不报错但loss始终不降。原因YOLO找标签的路径是train目录下与images平级的labels文件夹如果标签直接在train下或者放在images里就会扫不到。另一个常见原因是标签扩展名写成了.txt但实际文件是.txt带空格。解决先检查目录结构是否符合第2.3节的规范再用第2.1节的脚本核对图片与标签数量。两者都正常就用find train -name *.txt | head看下标签文件是不是真的在train/labels下。目录结构没问题最后检查data.yaml的path相对路径是不是写对了../dataset少一个点就找不到目录。4.2 标签类别id越界导致训练崩溃现象训练开始不久报错IndexError: index 36 is out of bounds for axis 0 with size 36或者loss直接变成nan。原因数据集中混入了标注时多余类别比如某个字符被标成了id36或更大超出nc范围。Roboflow导出数据偶尔会把背景类或者冗余类也带进来。解决用第2.4节的标签自检脚本全量扫一遍把所有cls nc的标签行找出来。处理方式两种如果多余类别数量很少直接删掉这些行如果数量较多说明类别体系对不上要重新梳理映射关系。我遇到过一次标签里混了汉字省简称的标注id直接是36删掉后发现是标注工具残留。4.3 检测框框住整个车而不是单个字符现象推理结果里矩形框包住了整块车牌甚至框住了半个车头字符之间没有独立框。原因这是标注粒度问题。训练数据里如果一部分框比较大、包住了几个相邻字符模型学到的框尺度就不稳定。YOLO的anchor会根据标注框的宽高分布自动调整但训练标签里大小尺度差距太大时小字符目标会被大的候选框盖过去。解决统计标签框的宽高比把明显异常的大框过滤掉重标。检查方法是写脚本统计每个框的w和h分布正常字符框的宽高比集中在0.4到0.8之间如果出现w超过0.3归一化后的框大概率是标注时框选了多个字符。对于少量异常样本可以直接删掉这些图片让模型学剩下的干净数据。4.4 数字0和字母O、数字1和字母I识别混淆现象训练指标看起来不错推理时数字0偶尔被识别成字母O数字1被识别成字母I。这类混淆在单车牌多字符场景下特别影响整牌拼接结果。原因视觉上O和0几乎一样1和I只有一个衬线区别模型的特征提取本身就容易混淆。加上数据集中0和O、1和I的出现频率不平衡模型对少数类别的决策边界就偏向多数类。解决常规做法是在后处理阶段做映射比如识别结果为O时输出为0识别结果为I时输出为1。中国车牌字符集中实际上不使用字母I和O所以可以放心把这两类的预测结果都映射回数字。另一个方向是训练时加大cls_loss权重但实测效果不如后处理来得直接。如果数据量够把字母O和I的样本单独挑出来做数据增强也能缓解部分混淆。4.5 关闭翻转增强车牌镜像问题现象训练时mAP上升缓慢验证集指标始终比训练集低一大截而且推理时经常把字符方向弄反。原因YOLOv11默认开启左右翻转增强fliplr0.5意味着每两张图里有一张会被水平镜像。车牌上的字符翻转后变成反写形态“B”翻转后视觉上像左右颠倒的B模型被迫同时学习正写和反写两种特征等于把任务难度翻倍。解决训练时显式关闭翻转增强yolo detect train modelyolo11n.pt datadata.yaml epochs100 imgsz640 batch16 fliplr0.0fliplr0.0关闭水平翻转对车牌识别几乎是必设参数。这一点在文档里不容易察觉默认行为也不会在日志里提示是典型的黑匣子坑。从那以后我每次训练车牌数据都强制检查参数配置里有没有关闭fliplr。5. 验证与增强让模型在真实场景更稳5.1 从混淆矩阵和PR曲线读结论训练生成的runs/detect/val/confusion_matrix.png是判断模型真实水平的第一手材料。横纵轴都是36个类别对角线上的值越高越好。重点看非对角线区域的集中点如果大部分错误集中在小范围比如0和O之间后处理映射就能解决如果错误分散在多个字符间说明数据量不足或者图像质量太差靠后处理兜不住需要补数据。PR曲线主要看拐点位置拐点越靠近右上方说明模型在低置信度下也能保持较高准确率适合部署时把置信度阈值调低来提升召回率。5.2 车牌场景的数据增强建议除了关闭fliplrYOLOv11的数据增强参数还有几个值得动。hsv_h和hsv_s控制色调和饱和度扰动默认值0.015和0.7基本不用改车牌颜色在蓝底白字、黄底黑字之间变化这点扰动有助于泛化。mosaic默认开启四张图拼一张对检测小目标有帮助但如果车牌图里部分字符被切到拼接边缘反而会引入无效标注。显存够的话保持默认显存紧张就设mosaic0.5降低概率。translate和scale可以稍微开大点模拟摄像头在不同距离拍到的车牌尺寸变化。从效果验证来讲最终看的不是训练集loss而是拿一批真实拍摄的、没有参与训练的车牌图跑一遍统计单字符识别准确率和整牌拼接成功率。单字符准确率达到95%以上整牌正确率一般能到90%左右剩下的误差基本发生在模糊图和极端角度图上。这个数据集作为起步资源完全够用但真实场景里遇到新能源绿牌、双层车牌、夜间反光还是要自行扩充数据。回到开头说的边界汉字省简称这个缺口是肉眼可见的。如果项目要求输出“粤B12345”这样的完整车牌第一步先在这个数据集上把36类字符模型训稳第二步单独收集省份汉字样本重训一个汉字分类模型第三步在后处理里按位置拼接。我自己的习惯是先把单字符检测做到稳定再考虑端到端的车牌识别方案因为单字符方案的每个环节都能独立验证出问题也好定位。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。