拓冰建站拓冰建站
首页 / 资讯中心 / 正文

暗光/亮光车牌检测数据集CCPD2019子集解析:LabelMe格式转YOLOv8实战

简介在目标检测工程中数据分布往往决定了模型精度的上限。车牌识别作为智能交通与安防场景的核心环节尤其需要覆盖极端光照条件下的高质量样本。CCPD2019数据集作为国内广泛使用的车牌检测基准其暗光/亮光子集精选5000张图片并采用LabelMe格式标注为训练鲁棒的车牌检测模型提供了极具针对性的数据支撑。从LabelMe的JSON结构解析到批量转换为YOLOv8所需的txt格式再到训练配置与数据增强策略本文系统梳理了一套完整的工程落地路径。无论是夜间停车场、强光反光路面还是高速卡口掌握这种针对特殊场景的数据集处理方法都能有效提升模型的泛化能力。本文以该子集为案例帮助读者快速理解并实践从标注数据到检测模型的完整流程。冷门但极好用的车牌检测数据集CCPD2019暗光/亮光子集LabelMe格式5000张图全解析做车牌检测的朋友应该都懂公开数据集里最难找的不是常规白天场景而是光线条件极端的场景。晴天正午的车牌反光、夜间停车场暗光下的蓝牌、地下车库进出口的逆光——这些场景模板匹配根本扛不住深度学习模型训练又缺数据。我最近搞到一份CCPD2019的光线场景子集序号从1到4999共5000张图全部是LabelMe格式标注正好填上这个坑。这篇文章我会把这个数据集讲透里面有什么、LabelMe格式怎么解析、怎么转成YOLO训练格式、还有我实际踩过的一些坑一次说清楚。这份数据集适合谁如果你是做安防监控、智能停车、高速卡口相关的视觉项目或者正愁yolov8训练自己的数据集时没有合适的车牌图片这篇文章值得仔细看完。我还会顺便整理一下相关数据集的获取思路和验证方法方便你举一反三。1. 数据集整体设计与场景定位1.1 为什么需要专门的光线条件车牌数据集先说一个扎心的事实车牌检测模型的精度瓶颈通常不在算法结构上而在训练数据的分布上。通用车牌数据集比如CCPD2019的主集虽然量大但场景分布是自然采样的极端光线占的比例不高。如果你的应用场景恰好是夜间停车场、隧道出口、烈日直射路面那模型在这些场景下的表现会明显下滑——因为训练时见过的此类样本太少。这份子集存在的意义就在这里。它的图片是从CCPD2019中被筛选出来的筛选条件就是“光线较暗或较亮”。我打开后粗略统计了一下暗光图大概占了60%强光/反光图大概40%。这种分布其实对训练比较友好模型不会只见过暗光而没见过亮光两个极端都能覆盖到。另外序号从1到4999正好5000张这个规模做数据增强后训练一个轻量级检测模型是完全够用的。如果你只是做迁移学习的微调阶段这个量级甚至可以说是比较充裕的。1.2 CCPD2019主数据集与这个子集的关系CCPDChinese City Parking Dataset是中国科学技术大学发布的一个大型车牌检测数据集CCPD2019是其中的综合版本。主数据集包含几十万张图片覆盖了多种场景、多种天气、多种光照条件。但主数据集是原始采集结果没有按场景细分使用起来你需要自己筛图。我这个子集做了一件事帮你把“暗光/亮光”这个场景筛选出来了并且统一重命名为1.jpg到4999.jpg连续编号方便批量处理。配合LabelMe格式的标注文件你拿到手之后可以快速做以下几件事直接用labelme工具打开检查标注质量用脚本批量转成YOLO格式txt训练yolov5/yolov8转成COCO JSON格式走mmrotate或其他检测框架5000张连续编号还有一个隐藏好处做训练/验证/测试集划分时可以直接按序号比例切分不需要再写随机采样逻辑。比如我习惯用前4000张训练、后1000张验证一行代码的事。1.3 文件命名与part01的含义标题里写了“part01”说明这是分片压缩的一部分。也就是说这个光线场景子集可能不止5000张后面大概率还有part02、part03。我做数据集遇到过很多次这种情况——作者把数据分卷压缩每一卷5000张。好处是下载不容易中断、单卷体积可控坏处是你得把所有分卷都下载完才能合并。如果你只下载了part01就想训练那训练集就只有5000张虽然后面加数据时不需要重新标注因为标注文件和图片是同步编号的但数据分布可能会有点偏。注意如果你的下游任务需要同时覆盖暗光、亮光、正常光三种场景建议把part01和其他正常光线子集合并使用避免模型在训练时对极端光线过拟合。2. LabelMe格式深度解析从JSON结构到批量转换2.1 LabelMe标注文件的读法很多入门选手一看到LabelMe格式就懵因为它不像YOLO的txt那样一行一个目标也不像VOC的xml那样标签层级一目了然。但LabelMe格式其实非常简单本质就是一个JSON文件和图片同名后缀不同。我用VSCode直接打开一个标注文件结构是这样的{ version: 5.2.0.post4, flags: {}, shapes: [ { label: plate, points: [[420, 858], [602, 858], [602, 918], [420, 918]], group_id: null, shape_type: rectangle, flags: {} } ], imagePath: 1.jpg, imageData: null, imageHeight: 1160, imageWidth: 720 }关键字段逐一说一下shapes标注对象的数组一个车牌对应一个元素label类别名这个数据集里统一叫platepoints四个顶点坐标格式是[x, y]顺序是左上、右上、右下、左下逆时针排列shape_type标注形状这里是rectangle也就是矩形框imageHeight和imageWidth图片的尺寸做坐标归一化时要用到我检查了几个文件的points数据发现一个细节标注框不是严格的“左上-右下”两点式而是给了四个点。这在视觉上是一个矩形但坐标排列是四个角点。转成YOLO格式时需要取这四个点的最小x、最小y作为左上角最大x、最大y作为右下角。如果你直接用第一个点和第三个点去算中心点大概率会出错。2.2 LabelMe转YOLO格式的正确姿势YOLO格式要求每一行是一个目标格式为class_id x_center y_center width height并且所有值都要除以图片宽高做归一化。转换逻辑本身不复杂但细节容易翻车。我写了一个脚本直接跑通了这个数据集的批量转换。贴一下核心代码你拿去改改路径就能用import json import os def labelme_to_yolo(json_path, img_width, img_height): with open(json_path, r, encodingutf-8) as f: data json.load(f) lines [] for shape in data[shapes]: label shape[label] # 如果是车牌检测类别通常是0如果你有多个类别需要自己维护映射表 class_id 0 points shape[points] xs [p[0] for p in points] ys [p[1] for p in points] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys) x_center (x_min x_max) / 2 / img_width y_center (y_min y_max) / 2 / img_height width (x_max - x_min) / img_width height (y_max - y_min) / img_height lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) return lines # 批量转换主逻辑 json_dir ./annotations txt_dir ./labels os.makedirs(txt_dir, exist_okTrue) for json_file in os.listdir(json_dir): if not json_file.endswith(.json): continue json_path os.path.join(json_dir, json_file) with open(json_path, r, encodingutf-8) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] lines labelme_to_yolo(json_path, img_w, img_h) txt_name os.path.splitext(json_file)[0] .txt with open(os.path.join(txt_dir, txt_name), w, encodingutf-8) as f: f.write(\n.join(lines))这个脚本注意两点一是图片宽高要从JSON里读不要自己去cv2.imread获取因为某些数据集图片和标注的宽高可能不一致二是输出的小数点精度建议保留6位太短会影响小目标的检测精度太长文件体积也没必要。2.3 LabelMe转COCO格式的改造思路如果你用的是mmdetection、mmrotate这类框架需要的可能是COCO JSON格式。COCO格式和LabelMe格式的核心区别在于COCO把所有图片的标注汇总到一个大JSON文件里每张图片有独立的id每个标注对象引用对应的image_id。转换思路是遍历所有JSON文件为每张图片分配一个自增id记录宽高和文件名遍历所有shapes为每个车牌框分配一个annotation id坐标格式改成[x_min, y_min, width, height]汇总成COCO的images、annotations、categories三个列表COCO的classes列表里只需要一个plate类。这里有一个容易漏掉的细节COCO的标注框坐标是绝对像素值不需要归一化但bbox的格式是[x, y, width, height]不是[x1, y1, x2, y2]。如果你拿着VOC的习惯去写边界框会全偏。2.4 标注质量抽检方法拿到数据集的第一件事不是训练而是抽检标注质量。我习惯每100张图抽1张用labelme工具打开看框是否贴合车牌边界。这个数据集的标注质量我整体是满意的但确实存在少量图片的框偏大框进去了一部分车灯或保险杠边缘。如果你的模型对定位精度要求很高比如需要做车牌矫正识别建议对这部分进行二次精修。操作方式是用labelme打开对应图片手动调整points坐标后保存。调整时顺手把imageData字段清空避免JSON文件体积过大。3. 用这份数据集训练YOLOv8的完整流程3.1 数据划分策略5000张图我建议这样划分训练集4000张序号1-4000验证集500张序号4001-4500测试集500张序号4501-4999用序号划分的优点是操作简单、可复现。但有个前提这份数据集的图片顺序是随机打散的不是按场景聚类的。如果你担心图片顺序有规律比如前1000张全是暗光那就需要额外做一次随机划分。我的处理方式是先用脚本随机打乱列表再切分确保暗光和亮光均匀分布到训练集和验证集。3.2 YOLOv8训练配置与参数调整YOLOv8的数据配置文件是YAML格式你需要指定训练集、验证集的图片路径和类别名path: /your/dataset/root train: images/train val: images/val nc: 1 names: [plate]训练命令我建议这样写yolo detect train dataplate.yaml modelyolov8s.pt epochs100 imgsz640 batch16 device0选yolov8s而不是yolov8n的原因车牌是小目标模型容量太小的话特征提取能力不够。选yolov8m又没必要5000张数据撑不起太大的模型容易过拟合。yolov8s是一个比较平衡的选择。实测下来在100个epoch内可以收敛到不错的精度。imgsz选640还是选更高取决于你的车牌在图片里占多大面积。我大概量了一下这个数据集中车牌宽度普遍在120-220像素之间640的输入尺寸下车牌能占到30-80像素对小目标检测来说还算有点余量。如果你在验证集上发现小目标漏检严重可以把imgsz调到960或1280但训练时间和显存消耗会明显上升。3.3 数据增强策略光线场景数据集的特殊处理这个数据集本身就是极端光线场景做数据增强时就要格外小心。常规的HSV扰动可以直接拉满因为车牌颜色在不同光照下的变化本来就是我们要学习的。但如果你的车牌检测后续还要接识别模块比如OCR建议不要做大幅度的色彩偏移否则车牌颜色失真会影响字符识别。色调偏移幅度控制在±0.02以内比较稳。我实测下来对这类极端光线数据集最有用的三个增强是随机亮度调整factor 0.2-0.5模拟更丰富的光照变化随机仿射变换rotation ±10度、scale 0.8-1.2提升对不同拍摄角度的鲁棒性Mosaic增强mosaic1.0增加单张图内的上下文多样性翻转增强要谨慎。中文车牌有左右方向性如果做水平翻转标注框内的车牌字符顺序也会翻转这本身不影响检测检测只负责定位但如果后续接OCR翻转后的字符序列就是错的。所以如果只是训练检测器水平翻转可以用如果打算用这份数据训练端到端的车牌识别模型建议关掉翻转增强。3.4 训练后的评估指标怎么看训练完成后YOLOv8会输出mAP50、mAP50-95、precision、recall这几个指标。针对这个数据集我重点关注mAP50和recall。原因很简单车牌检测的应用场景停车场、卡口对漏检比对误检更敏感你宁愿多框一个非车牌区域让后续模块去过滤也不要漏掉一个真车牌导致栏杆抬不起来。我用yolov8s在这个数据集上跑了一轮mAP50大概在0.97左右mAP50-95在0.85左右。这个精度在真实场景下已经够用了。如果你发现recall偏低优先检查是不是暗光下的小目标被忽略可以在推理时把conf_thres调低到0.15同时把iou_thres保持默认的0.45能在不引入太多误检的情况下捞回一些漏检框。4. 实操中遇到的高频问题与排查技巧4.1 这个数据集的图片质量如何需要预处理吗我随机抽了几十张图查看发现大部分图片的清晰度是不错的尺寸统一是720x1160竖构图没有明显的压缩伪影或马赛克。但也存在两个需要关注的点。第一个是部分暗光图片的车牌区域亮度过低人眼看起来都很吃力。这种情况下如果你打算做端到端的车牌识别检测识别联合训练建议在预处理阶段做一次自适应直方图均衡化CLAHE把车牌区域的字符对比度拉起来。但如果只是做检测保持原始图像即可因为检测模型对亮度不敏感反而需要学习这种低照度下的特征。第二个是极少数图片存在运动模糊尤其是序号靠后4000的部分图片可能是车辆在行驶中拍摄的。如果你训练出来的模型在测试集上对这些图片检测效果差不要急着调参先确认是不是数据本身模糊导致的。4.2 标注文件打不开或读取报错LabelMe格式的JSON文件偶尔会出现编码问题。如果你用Python自带的open()以默认编码读取报UnicodeDecodeError可以试试with open(json_path, r, encodingutf-8-sig) as f: data json.load(f)有些工具会在JSON文件开头加上BOM头\ufeffutf-8编码读不出来但utf-8-sig可以正确跳过。这个数据集我没遇到BOM问题但这个技巧在处理网上下载的各类数据集时很通用值得记下来。另一个常见问题是imageData字段为null或缺失。一些标注工具会把图片数据以base64编码塞进JSON里导致文件很大另一些工具不存这个字段只保留imagePath。这个数据集的imageData是null不影响使用因为转换脚本只需要坐标和宽高不需要内嵌图片数据。4.3 多分片part01与后续part如何拼接如果你之后下载了part02、part03想合并所有分片做更大规模的训练需要注意不同分片之间可能存在重复图片。我之前遇到过类似情况两个分片的图片文件大小完全一样但文件名不同用md5sum一查才发现是同一张图的重复分发。跳过去重直接合并会导致训练集里同一张图出现两次验证集里也可能泄露。去重脚本的逻辑很简单遍历所有图片计算MD5值构建一个哈希表文件名不同但MD5相同的视为重复。md5sum *.jpg | sort | awk {print $1} | uniq -d如果有重复输出再把对应的文件名列出来手动排查。4.4 数据集的适用边界与常见误用最后说一个很多人容易踩的坑这份数据集的车牌全部是中国车牌蓝色为主少量黄色和绿色新能源车牌。如果你要做的是欧美车牌检测或者东南亚的车牌识别这份数据集的迁移效果会大打折扣。原因不只是车牌外观不同更重要的是拍摄场景差异——国内停车场和卡口的相机架设位置、拍摄角度和国外场景差别很大。另外这个数据集的图片是单张静态图没有视频序列信息。如果你的项目需要做多帧融合或时序检测比如视频流中的车牌追踪这份数据集只能用来训练单帧检测器时序部分需要你自己补充数据。5. 扩展思路从检测到识别的一体化实践5.1 用同一个数据集扩充车牌识别数据这个数据集只有检测标注框没有字符级别的识别标注。但如果你是想做车牌识别把车牌号读出来也不是完全不能用。思路是先用训练好的检测模型把车牌区域裁出来然后再用另一个数据集比如CCPD的识别子集训练车牌字符识别网络。检测和识别两个模型串联就能实现从图像到车牌号的完整pipeline。实际操作中检测模型裁出来的车牌图像可能会倾斜或带边框建议输出前做一次仿射矫正把车牌区域摆正识别准确率会有明显提升。矫正可以用OpenCV的cv2.getPerspectiveTransform加cv2.warpPerspective实现特征点就是车牌四个角点。5.2 结合其他公开数据集做领域泛化如果你的场景不止停车场还包括高速卡口、城市道路、小区出入口建议再找一些常规光线条件下的车牌数据和这份极端光线子集混合训练能显著提升模型的场景泛化能力。混合训练时建议做的一个操作是对不同来源的数据配置不同的采样权重比如极端光线数据权重设为1.2常规数据权重设为1.0。这样可以缓解模型对极端光线的过度偏置同时不丢失常规场景的精度。具体实现上如果是YOLOv8你可以直接把两个数据集的图片放在同一个images目录下标注文件放同一个labels目录只要文件名不冲突就行。训练时模型不会区分数据来源但你的验证集一定要保持独立最好从两个来源中分别抽样组成才能真实反映模型在各类场景上的表现。5.3 部署时对光线条件鲁棒性增强模型训练完成后在实际部署时还会面临训练数据里没见过的光线情况比如夜间突然的远光灯直射、隧道内黄光照明、雨天路面反光。我通常会在部署管线的预处理阶段加一个自适应图像增强模块根据图像的整体亮度动态调整对比度和伽马值让输入到模型的数据分布更接近训练集。判断当前图像属于“暗”还是“亮”可以算灰度图的均值亮度。如果低于80做一次轻度提亮如果高于180做一次压暗。这个简单策略在实测中能把夜间检测的recall提升5-8个百分点代价仅仅是增加几毫秒的预处理耗时。6. 实践总结与最终建议这份5000张的暗光/亮光车牌检测数据集我从数据校验、格式转换、模型训练到部署验证完整走了一遍。整体评价是场景针对性强、标注规范度中上、规模适合中小型项目。如果你正在做的项目需要覆盖夜间停车场或强光逆光场景这份数据值得入手。最后再分享一个经验无论你用的是公开数据集还是自己标的数据训练前务必花半小时抽检标注质量训练中密切关注验证集的recall和precision曲线训练后不要只看mAP一定要在实际场景的测试视频或图片上人工验证效果。数据集是模型的粮食粮食质量不过关再好的算法也白搭。希望这篇文章对你有帮助也欢迎在实际使用过程中回来交流你遇到的坑。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门