ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

7053张YOLO车牌检测数据集:从数据体检到训练部署完整指南

7053张YOLO车牌检测数据集:从数据体检到训练部署完整指南 简介目标检测是计算机视觉的核心任务之一而车牌检测因目标刚性、类别单一、标注标准成为入门与工程落地的理想场景。本文围绕一份包含7053张图像及YOLO格式标签的车牌检测数据集系统讲解从数据预处理、标签校验、数据集划分到基于YOLOv8的模型训练与推理调参的全流程同时介绍mAP、precision、recall等关键评估指标并讨论ONNX、TensorRT等部署方案及检测与OCR识别的衔接。无论你是刚接触YOLO的开发者还是正在评估车牌识别项目数据规模的工程师都能从中获得可复用的实践方法。本文旨在帮助读者避开常见陷阱高效构建可用的车牌检测模型。 不管你是做智慧停车、高速收费、安防闸口还是单纯的自动驾驶感知车牌检测几乎是每个目标检测工程师一定会遇到的落地场景。最近在整理硬盘时翻出一个压缩包yolo算法-车牌检测数据集-7053张图像带标签-.zip这是以前做车牌识别项目时反复调过的一份数据。7053张带标签的车牌图像YOLO格式的txt标签单类目标解压出来就能直接喂给yolov5或yolov8跑训练。这篇文章我会从解压数据开始把数据体检、训练流程、推理调参、以及部署时踩过的坑完整拆开讲一遍适合刚接触目标检测、想找一份合适数据集练手的朋友也适合那些打算做车牌检测项目、正在评估训练数据规模的工程师参考。1. 为什么说车牌检测是所有目标检测项目里“最划算”的练手场景1.1 车牌检测的本质一个典型的单类刚性目标检测车牌检测这个任务本质上就是告诉算法“图里有没有车牌车牌在哪个位置”。它和行人检测、车辆检测最大的区别在于类别少通常只有license_plate一个类别目标刚性车牌是矩形金属板不会像人或动物那样有大幅姿态变化纹理标准字体、颜色、宽高比都相对固定。这些特性决定了它是一个非常适合用来理解目标检测全流程的场景。但别小看这个“看似简单”的任务真实场景里车牌检测会遇到大量棘手情况倾斜、遮挡、夜间低光照、运动模糊、双层车牌、一张图里同时出现多个车牌、车身贴纸干扰等等。正因为目标本身标准化、复杂程度又足够才让这个场景既能让新手快速跑通也能让有经验的人持续优化。1.2 7053张图这个规模处在什么位置很多人拿到数据集第一个问题就是7053张到底够不够我直接给结论对于单类车牌检测7053张是足够训练出一个可用模型的规模当然前提是标注质量靠谱、场景多样性够。横向对比一下常见公开数据集你就有概念了。数据集图像数量类别数定位PASCAL VOC 2012约11540张20类通用目标检测MS COCO train2017约118287张80类通用目标检测大规模基准本数据集7053张1类单类车牌检测从数量上看COCO 11万张图训80个类别平均下来每个类别对应的有效图像也就几千张而这个数据集7000多张全部用来学习车牌这一个目标数据量完全够用。从实际项目经验看车牌检测这种刚性目标5000张以上已经能收敛到不错的精度低于2000张才需要考虑大规模数据增强或迁移学习。1.3 解压前先想清楚这份数据回答的是“检测”还是“识别”问题这里必须先泼一盆冷水这是一个检测数据集不是识别数据集。标签只框出了车牌的位置没有做字符级标注。也就是说训练之后模型能告诉你“哪里有车牌、车牌框有多大”但不能告诉你“车牌号码是多少”。检测和识别是两条完全不同的技术路线——检测是目标定位识别是光学字符识别OCR。很多人拿到车牌数据集就直接往OCR方向想这是最大的误区。如果你要做的是“车牌号是什么”需要的是字符级标注的车牌数据集或者先通过检测模型把车牌区域裁出来再接一个OCR模型。搞清楚这份数据能回答什么问题后面才不会白折腾。2. 打开压缩包后先别急着训练数据体检比模型更重要2.1 目录结构与标签格式先确认是哪一代YOLO格式解压之后第一件事不是立刻开训练而是先看目录结构。典型的YOLO目标检测数据集长这样dataset/ ├── images/ │ ├── train/ # 训练图片 │ └── val/ # 验证图片 ├── labels/ │ ├── train/ # 训练标签 │ └── val/ # 验证标签 ├── data.yaml # 数据集配置文件 └── README.md # 说明文档每个标签文件与对应的图片文件同名后缀为.txt。打开一个标签文件内容是一行行数字0 0.5672 0.4185 0.2134 0.0812这一行的五个数字分别代表class_id类别编号、x_center目标框中心点的x坐标归一化值、y_center中心点的y坐标归一化值、width框宽归一化值、height框高归一化值。所有坐标值都在0到1之间用的是相对于图片宽高的比例。这里要确认一个关键信息这份数据到底是YOLOv5的格式还是YOLOv8的格式。其实yolov5、v6、v8、v9、v11这些版本对txt标签的读取方式是通用的只要目录符合上述结构直接改data.yaml就能用。如果遇到标签格式不统一的情况多见于老项目里带VOC格式的xml文件需要先转一遍yolo格式再训练。2.2 用一段脚本体检数据三类脏数据最常见下载来的数据集不一定是干净的。我每次拿到新数据集都会先跑一遍体检脚本主要查三类问题。第一空标签文件。有些图片明明有车牌但标签文件是0字节说明标注时漏标了有些图片确实没有车牌标签文件为空也正常。判断方式是随机抽取若干空标签文件人工看一眼对应图片。第二坐标越界或非法值。标签里的x_center、y_center、width、height应该是0到1之间的浮点数如果出现负数、大于1、width或height为0说明标注时出了问题。第三图片与标签不匹配。比如labels目录下有的txt文件在images目录下找不到对应图片或者图片损坏打不开。可以用下面这段Python脚本快速体检import os from pathlib import Path from PIL import Image dataset_root Path(dataset) label_dirs [labels/train, labels/val] for label_dir in label_dirs: label_path dataset_root / label_dir if not label_path.exists(): print(f[缺失] {label_path} 目录不存在) continue for txt_file in label_path.glob(*.txt): # 对应图片路径 img_path dataset_root / images / label_dir.split(/)[1] / (txt_file.stem .jpg) if not img_path.exists(): print(f[图片缺失] {txt_file} 找不到 {img_path}) continue # 检查图片是否可打开 try: with Image.open(img_path) as im: im.verify() except Exception as e: print(f[图片损坏] {img_path}: {e}) # 检查标签内容 lines txt_file.read_text().strip().splitlines() if len(lines) 0: print(f[空标签] {txt_file}) for line in lines: parts line.split() if len(parts) ! 5: print(f[格式错误] {txt_file}: {line}) continue try: nums [float(x) for x in parts] except ValueError: print(f[非数字] {txt_file}: {line}) continue cls, x, y, w, h nums if not (0 x 1 and 0 y 1 and 0 w 1 and 0 h 1): print(f[坐标越界] {txt_file}: {line}) if w 0 or h 0: print(f[零宽高] {txt_file}: {line})我建议你把这份脚本存起来以后任何数据集到手都跑一遍。我在实际项目里遇到过训练到一半loss突然变成nan排查了好久最后发现是某个标签文件里混入了中文标点导致解析失败。2.3 EXIF旋转问题最容易忽略的暗坑体检脚本能查出大部分问题但有一个坑它查不出来——JPG图片的EXIF旋转信息。现在很多手机和相机拍摄的照片会在JPG文件头里写入一个方向字段告诉看图软件“我拍摄时是竖着的你要旋转90度才能正常看”。但目标检测框架在读图时不一定都去解析这个字段有的库会自动旋转有的不会。如果框架读图自动旋转了而标签坐标还是按照原始像素位置标定的那训练时就会出现一个奇怪的现象loss正常下降准确率也不低但验证时框的位置整体偏移总是差90度。解决方法是训练前先把所有图片统一转正去掉EXIF旋转信息重存为不带旋转标记的JPG或PNG。可以用图片处理工具批量处理也可以在数据加载阶段统一处理。这个坑在公开数据集里不常见但在自己收集的数据里非常普遍提前处理能省下大量排查时间。2.4 数据划分训练集、验证集、测试集各司其职检查完数据质量后还要确认目录里的数据划分是否合理。如果压缩包里已经分好了train和val目录可以直接用如果所有图片都在一个目录里就得自己划分。我的习惯比例是训练集70%、验证集20%、测试集10%。训练集用来学习参数验证集用来在训练过程中监控过拟合、挑选最佳模型测试集完全不参与训练和验证只在最后评估一次用来估算模型的真实泛化能力。划分时要注意随机性最好先shuffle再切分。有些数据集是按拍摄时间或地点组织的如果直接按目录顺序切可能出现训练集全是白天、验证集全是黑夜的情况导致指标失真。可以按图片文件名做随机采样也可以使用sklearn.model_selection.train_test_split来做。import os import random from pathlib import Path import shutil image_dir Path(dataset/images) labels_dir Path(dataset/labels) img_files list(image_dir.glob(*.jpg)) list(image_dir.glob(*.png)) random.seed(42) random.shuffle(img_files) train_ratio, val_ratio 0.7, 0.2 n len(img_files) n_train int(n * train_ratio) n_val int(n * val_ratio) for i, img in enumerate(img_files): if i n_train: subset train elif i n_train n_val: subset val else: subset test os.makedirs(image_dir / subset, exist_okTrue) os.makedirs(labels_dir / subset, exist_okTrue) img.rename(image_dir / subset / img.name) label labels_dir / (img.stem .txt) if label.exists(): label.rename(labels_dir / subset / label.name)3. 训练完整流水线从写YAML到最佳权重生成3.1 环境搭建用conda创建干净虚拟环境数据检查完毕就可以开始搭训练环境。我推荐用conda创建独立虚拟环境避免和系统Python环境或其他项目冲突。conda create -n yolo python3.10 -y conda activate yolo pip install ultralytics这里直接装ultralytics即可它会自动把yolo命令安装到环境中。ultralytics的PyPI包已经内置了yolov8、yolov9、yolov10等模型的训练和推理能力不需要再单独去GitHub克隆仓库。PyTorch版本建议根据显卡驱动情况选择。有NVIDIA显卡的先去NVIDIA官网确认CUDA版本然后安装对应版本的PyTorch。没有独立显卡的可以先装CPU版把流程跑通但训练速度会慢很多一张7053张图片的数据集在CPU上可能要训练十几个小时GPU则几十分钟。3.2 写YAML三行配置搞定数据集路径在数据集根目录下创建data.yaml文件path: /absolute/path/to/dataset train: images/train val: images/val test: images/test nc: 1 names: 0: license_platepath是数据集根目录的绝对路径train、val、test都是相对于这个根目录的相对路径。nc是类别数量这里只有车牌一个类别写1。names是类别名列表编号从0开始。写YAML时最容易犯的错是路径写错。如果path写了相对路径而当前工作目录又不在数据集目录训练时会直接报错找不到图片。我建议一律写绝对路径省心。3.3 训练命令每个参数背后都有讲究环境配好、YAML写好就可以启动训练yolo detect train datadata.yaml modelyolov8s.pt epochs100 imgsz640 batch16 nameplate_exp这里逐个解释参数含义modelyolov8s.pt加载预训练权重。s代表small版本是速度与精度的平衡点。用预训练权重做迁移学习比随机初始化从头训练收敛快得多效果也更好。如果你是新手建议从yolov8s开始显存紧张的话可以换yolov8n追求更高精度可以换yolov8m或yolov8l。epochs100训练轮数。对于单类检测通常50到80轮就已经收敛100轮是保险值。训练过程中可以观察loss曲线和mAP曲线如果连续多轮mAP不再提升就说明模型已经收敛。imgsz640输入分辨率。车牌属于中小目标默认640通常够用。如果你的应用场景里车牌比较小可以尝试imgsz960或imgsz1280但显存占用会显著增加训练时间也变长。实际项目里我建议先用640跑一版再针对性调高。batch16批大小一次处理16张图片。批大小受显存限制如果报CUDA out of memory就减到8或4如果显卡性能强可以用32甚至64。nameplate_exp实验名称训练结果会保存在runs/detect/plate_exp目录下。训练结束后在runs/detect/plate_exp/weights/目录下会生成两个权重文件best.pt和last.pt。best.pt是验证集上表现最好的模型last.pt是最后一轮的模型。实际使用时拿best.pt。3.4 学会看指标mAP50、mAP50-95、precision、recall训练过程中终端会周期性打印指标很多人直接忽略其实这些数字直接反映了模型质量。precision预测为车牌的框中真正是车牌的比例。数值高代表误报少。recall所有真实车牌中被模型找出来的比例。数值高代表漏检少。mAP50IoU阈值取0.5时所有类别的平均精确率。这是最常用的粗粒度指标反映一个模型是否“大概框对了”。mAP50-95IoU阈值从0.5到0.95、每隔0.05取一次的平均精度。这是一个更严格的细粒度指标对框的定位精度要求更高。车牌检测这种单类刚性目标正常情况下mAP50可以训练到0.95以上mAP50-95训练到0.75到0.85之间就算很不错了。如果mAP50还不到0.8大概率是数据有问题或者训练参数不合适而不是模型能力不够。训练完成后用下面命令看结果曲线yolo detect val modelruns/detect/plate_exp/weights/best.pt datadata.yaml它会输出更加详细的验证指标并且在runs/detect/plate_exp/下生成混淆矩阵、PR曲线、F1曲线等可视化图表。这些图能帮你判断模型的短板在哪里。4. 训完不等于能用推理调参与部署避坑实录4.1 单图推理conf和iou两个参数决定了你会不会被打训练完第一件事就是拿一张没见过的图片测一下效果。用Python接口写一个最简单的推理from ultralytics import YOLO model YOLO(runs/detect/plate_exp/weights/best.pt) results model.predict(test_car.jpg, conf0.35, iou0.45, saveTrue)conf是置信度阈值只有置信度高于这个值的检测框才会保留。iou是NMS阈值用于抑制重叠的检测框。调参经验如果漏检严重有车牌但没检测到把conf往下调比如0.25或0.15漏检通常是因为模型对某类样本置信度不够高。如果误检严重检测到一堆不是车牌的区域把conf往上调比如0.5或0.6这类情况在复杂背景、车身贴纸多的时候比较常见。iou默认0.45一般不用动。如果出现同一个车牌被框了两次的情况可以适当提高iou阈值。我给出的经验值是车牌检测场景conf设置在0.3到0.5之间iou保持0.45左右。实际项目里我会先跑一批图片统计漏检和误检的比例再微调。4.2 视频流推理卡顿不是模型不够快是使用方式有问题模型在单张图片上可能只需要几十毫秒但放到视频流里就可能出现卡顿、丢帧。很多人的第一反应是换更小的模型但其实大部分时候问题出在使用方式上。最常见的错误是直接用cv2.VideoCapture逐帧读取逐帧调用model.predict()。每帧都做一次完整的前向推理即便模型只有几十毫秒的推理时间加上图像解码、预处理、后处理跑到几十帧每秒的视频上就会非常吃力。优化手段按优先级排列跳帧处理。视频流里相邻帧的内容高度相似车牌位置变化不大。每3帧或每5帧检测一次中间帧用上一次的检测结果做目标跟踪或不处理流量压力立刻降下来。降低推理分辨率。视频帧通常只有1080P甚至更低把输入resize到640或416推理速度能提升一倍以上车牌这种大目标在小分辨率下依然能检测到。导出TensorRT或ONNX模型。用TensorRT在NVIDIA显卡上部署推理速度能比PyTorch原生快2到4倍。换轻量模型。如果上面几条都做了还是不够快再考虑从yolov8s换成yolov8n。4.3 部署导出ONNX、TensorRT、NCNN三种场景怎么选训练好的best.pt不能直接上生产一般要导出成推理框架能加载的格式。Ultralytics提供了极其简单的一键导出# 导出ONNX适合跨平台通用部署 yolo export modelbest.pt formatonnx dynamicTrue # 导出TensorRT引擎适合NVIDIA显卡GPU部署 yolo export modelbest.pt formatengine device0 # 导出NCNN格式适合移动端/嵌入式部署 yolo export modelbest.pt formatncnn我的选型经验服务端GPU部署优先TensorRTformatengine这个格式是NVIDIA的加速推理引擎速度最快。服务端CPU部署或跨平台需求ONNX配合ONNX Runtime或OpenVINO运行。OpenVINO在Intel CPU上有额外优化速度提升也很明显。边缘盒子、ARM开发板、移动端NCNN或RKNN。NCNN是腾讯开源的移动端推理框架对ARM平台做了针对性优化如果你的设备是瑞芯微的芯片用RKNN格式又更合适。导出过程中最常见的报错是opset版本问题老版本ONNX Runtime不支持新版opset。如果不确定目标环境可以在导出时手动指定opset12yolo export modelbest.pt formatonnx opset12这个兼容性更好对环境要求更低。5. 这份数据集的边界与进阶从检测走向识别5.1 想把“车牌号”也识别出来需要两步走如果你最终目标不是框出车牌位置而是读出车牌号码那就需要接OCR。成熟的方案是两步走第一步用训练好的YOLO模型检测并裁出车牌区域。这里要注意裁剪时建议在检测框基础上向外扩展一些像素把车牌边框附近的字符也包含进去能明显提升OCR准确率。第二步把裁剪后的车牌小图送入OCR模型。常用的开源方案有PaddleOCR、HyperLPR、或者自己训练的CRNN/语义分割模型。以PaddleOCR为例拿到车牌裁剪图后可以先做预处理再识别import cv2 from paddleocr import PaddleOCR ocr PaddleOCR(use_angle_clsTrue, langch) # 从YOLO结果中裁剪车牌区域 box results[0].boxes.xyxy[0].cpu().numpy().astype(int) x1, y1, x2, y2 box plate_crop frame[y1:y2, x1:x2] # 车牌区域往往较小先放大再送OCR plate_crop cv2.resize(plate_crop, None, fx2, fy2, interpolationcv2.INTER_CUBIC) result ocr.ocr(plate_crop, clsTrue)车牌OCR和通用OCR有本质区别车牌字符常用特殊字体如中国的车牌字体是专用的通用OCR识别蓝底白字时容易出错。如果要做正式项目建议用专门的超分预处理或车牌字符集微调OCR模型。这里就体现出检测数据集的价值了它能帮你精准定位车牌区域把复杂的全图识别问题降维成小图识别问题OCR的准确率会大幅上升。5.2 数据增强策略把7053张图扩展成70000张训练集只有7053张图如果发现泛化能力不足最直接的办法是做数据增强。注意数据增强要符合车牌的业务特征不能瞎加。透视变换模拟车辆从不同角度经过摄像头的场景车牌会发生梯形畸变。这对真实场景非常有帮助。亮度对比度扰动模拟白天逆光、夜间灯光、阴天等光照变化。高斯噪声和运动模糊模拟摄像头传感器噪声和车辆高速行驶时的拖影。随机旋转角度控制在±30度以内超过这个范围车牌的语义特征会发生改变。用albumentations库可以方便地组合这些增强import albumentations as A train_transform A.Compose([ A.RandomBrightnessContrast(p0.5), A.Perspective(scale(0.05, 0.1), p0.3), A.MotionBlur(blur_limit5, p0.2), A.Rotate(limit30, p0.4), A.HueSaturationValue(hue_shift_limit10, sat_shift_limit20, val_shift_limit20, p0.3), ], bbox_paramsA.BboxParams(formatyolo, label_fields[class_labels]))这里有一个我踩过坑的提示车牌颜色本身是具有区分度的特征比如新能源绿牌、大型车黄牌、小型车蓝牌颜色纹理差异巨大。如果做检测任务增强时过度调整色调影响不大但如果你后续要接OCR或车牌颜色分类色相偏移要控制在很小的范围否则训练出来的模型会“不认”绿色车牌。5.3 数据集的局限与后续采集重点所有公开或半公开数据集都有局限性这份7053张的车牌数据集也不例外。使用前先评估它的样本构成我总结了几条重点车牌类型是否均衡。如果全部是蓝牌那么对黄牌、绿牌、白牌的泛化效果可能就比较差。特别是新能源绿牌近年来占比越来越高必须要单独补充样本。场景是否覆盖夜间、雨天、逆光。监控摄像头拍得的车牌在夜间往往存在反光、模糊白天效果很好的模型到夜间可能断崖式下降。是否包含双层车牌。大型货车、客车的黄牌是双层的字符布局不同于单层蓝牌检测框的宽高比差异很大。很多模型在单层车牌上表现很好遇到双层车牌就乱了。我在做停车管理项目时第一版模型只用白天样本训练上线后夜间的漏检率接近三成。后来补充了夜间红外、补光灯下的样本并做了专门的暗光增强后漏检率才降到可接受的范围。这个经历说明数据集的规模只是下限数据分布与真实场景的匹配度才是决定模型上线效果的关键。5.4 从单类检测走向多任务车牌检测只是入口最后说一个进阶方向。车牌检测的模型训好之后其实可以顺带衍生出其他任务充分利用这套数据车牌颜色分类。不需要额外标注可以根据车牌检测框内部的颜色分布做分类蓝牌、黄牌、绿牌、白牌对停车管理场景很有价值。车牌倾斜校正。检测框虽然是矩形但实际车牌可能有一定倾斜角度。在检测框内再做一次角度回归或透视校正能够为后续OCR提供更正的输入图。多目标联合检测。把车牌检测和车辆检测、车身颜色识别放到同一个模型里做多任务学习共享骨干特征跑一次推理同时得到多个结果。这在算力受限的边缘设备上是比较实用的思路。写在最后的一些个人经验从拿到yolo算法-车牌检测数据集-7053张图像带标签-.zip到训练出一个能用的检测模型整个流程并不复杂。真正决定模型上线效果的不是算法本身而是数据质量、数据分布、以及部署细节这三件事。我在实际项目里用类似规模的数据集第一版就做到了mAP50在0.94左右部署到边缘设备后能满足一般闸口场景的需求但后来发现最难的不是训练而是持续补充极端场景的数据。最后分享一个小技巧训练多组对比实验时用不同的name参数比如nameplate_640、nameplate_960、nameplate_yolov5比改完代码再重新跑一遍要方便得多所有日志和权重会分开存放结果对比一目了然。这个压缩包适合用来入门和做原型验证但要真正上生产还得根据自己场景去补充数据、调整参数。把检测、识别、部署这套流程完整跑通之后你再去接触其他单类目标检测项目基本就是“换一套数据重新走一遍流程”的事。本文还有配套的精品资源点击获取
返回列表