ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

广告牌识别数据集:COCO标注与YOLO训练实战

广告牌识别数据集:COCO标注与YOLO训练实战 简介目标检测是计算机视觉的基础任务之一其核心在于通过标注数据让模型学会定位和识别特定物体。实际工程中数据集的质量与格式往往决定模型上限。COCO JSON作为通用标注规范将图像、目标、类别结构化组织兼容多数检测框架是训练YOLO等主流模型的常用输入形式。高质量的数据集能显著提升模型收敛速度与泛化能力尤其在智慧城市、广告监测、合规巡检等场景中准确识别广告牌对户外广告评估、违规私设排查、线下零售分析等应用至关重要。本文围绕广告牌识别数据集解析其规模划分、COCO标注细节并演示如何转换为YOLO格式、配置环境与训练参数同时针对训练常见问题给出排查思路帮助读者从数据准备到模型部署快速落地一套实用的广告牌检测方案。1. 这个数据集到底是什么解决什么问题广告牌识别数据集累计8157张图片其中训练集7137张全部统一为640×640分辨率标注格式是coco json。简单说这是一份专门用来训练“广告牌检测模型”的现成数据覆盖商场外墙、写字楼玻璃幕墙、道路两侧、建筑围挡等常见场景下的广告牌目标。对于做目标检测、智慧城市、广告监测、合规巡检这类项目的团队来说这份数据集可以直接作为训练底料省掉大量网上搜集图片和人工标注的时间。广告牌识别看起来是个小众方向实际需求量一点也不小。我接触过的客户里有做户外广告效果评估的需要统计某个路段短期内出现了哪些广告牌、分别投放了多久有做城市规划管理的需要根据街景影像识别违规私设广告牌还有做线下零售分析的想通过商场外立面的广告投放情况反推品牌活动热度。这些需求背后都需要一个能稳定框出广告牌的检测模型而模型的第一步就是高质量的数据。1.1 数据集规模与划分逻辑8157张图片7137张作为训练集剩下的1000张左右一般用于验证和测试。从比例看训练集占比大约87.5%验证和测试加起来约占12.5%。这个划分思路在深度学习项目里很常规训练集负责让模型学习特征验证集用来挑超参和做早停测试集则留到最后评估真实泛化能力。可能有人会问7100多张训练图够用吗先说结论做单类别广告牌检测这个量级是够用的。原因有两点。第一广告牌在画面里通常尺寸比较大纹理特征和边缘结构相对清晰模型不用花太多数据量去学极细微的差异。第二训练集里覆盖了商场、建筑、道路旁等多个子场景天然具备场景多样性比单纯收集几百张同类图硬训练要稳妥得多。当然如果想进一步提升精度可以在这个基础上做数据增强或者引入同分布的补充图片做半监督迭代。分辨率统一成640×640也是经过考虑的。YOLO系列的默认训练尺寸就是640×640coco预训练权重也是在这个输入尺度下刷出来的。直接用640×640可以减少训练时的resize损失也不用额外操心多尺度策略。如果原图比例不是1:1需要做letterbox填充这一点拿到图片之后最好先看一眼实际宽高比避免目标被过度挤压变形。1.2 “不止是一堆jpg”标注格式决定了训练上限coco json格式是目标检测领域最通用的标注格式之一。很多人只关心图片数量忽略了标注格式其实后者才是真正决定模型效果上限的东西。这套数据集里每个广告牌都用多边形或多段线标注了边缘同时还带有矩形框bbox、类别id、面积等结构化信息这意味着它不仅能训练普通的目标检测模型还能扩展做实例分割。另外从标题看标注类别是统一的“广告牌”没有再加上“商场广告牌”“路边广告牌”“楼顶广告牌”这类细分。这个设计我觉得是合理的。单类目标检测在工程上更容易收敛模型只需要学“什么是广告牌”这一个概念。如果强行拆成多个子类反而可能因为类间差异大、样本不均衡导致训练不稳定。等模型跑通了后续完全可以用同一个检测框接入分类头做二次细分效果通常更好。2. COCO json标注格式深度拆解COCO格式是一套JSON组织规范最早来自微软的Common Objects in Context数据集。它把图像、目标、类别三部分拆开存放逻辑清晰也能兼容绝大多数检测框架。你拿到这份数据集后如果打算改造成其他格式比如YOLO的txt格式必须先搞懂JSON里每个字段的含义否则很容易在转换时踩坑。2.1 顶层结构images、annotations、categories一份标准的COCO json文件最外层通常包含五个字段info、licenses、images、annotations、categories。其中后三个是核心训练脚本也主要解析这三个字段。images数组里每个元素代表一张图片核心字段包括id、file_name、width、height。id是图片唯一标识annotation里通过image_id关联到对应图片所以这个id不能有重复。file_name一般是相对路径下的文件名使用脚本读取时要注意拼接实际目录。annotations数组里每个元素代表一个目标实例也就是一个具体的广告牌。关键字段有id标注实例的唯一标识、image_id关联到哪张图、category_id类别id单类数据集通常是1、bbox矩形框坐标、area多边形面积、segmentation多边形顶点坐标、iscrowd是否为密集目标。特别注意bbox的格式是[x, y, width, height]x和y是左上角坐标单位是像素不是归一化坐标。categories数组则是类别定义。对于这个数据集就是一类名称为“billboard”或者“advertisement”id为1。如果你的训练脚本里类别索引和这个不一致会直接导致标签错位训练时loss可能异常。2.2 坐标体系和多边形标注的细节bbox用的是绝对像素坐标image_id对应的图片宽高是多少x和y就在0到width/height之间。这一点跟YOLO格式不同YOLO标签是归一化的中心点坐标和宽高。所以COCO转YOLO的时候必须把图片宽高带进去做除法。segmentation字段比较有意思。一个广告牌通常是不规则四边形或者带弧形边缘所以分割标注里会存一组[x1, y1, x2, y2, ...]的扁平数组。这组坐标同样是绝对像素值转成YOLO分割格式时也需要除以宽高归一化。如果你只做检测不分割直接用bbox字段就可以不需要处理segmentation。还有个小坑是area字段。COCO格式要求area必须和segmentation围出来的面积一致很多工具生成的JSON里area可能只是bbox的宽乘高虽然不影响检测训练但一些严谨的评估脚本会拿它做过滤所以如果你打算上传结果或者做严格评测最好重新计算一次真实面积。2.3 代码示例快速解析一份COCO JSON新手拿到JSON文件第一步不是急着训练而是先可视化检查。我自己习惯先写个快速脚本把一张图片和它的标注框画出来肉眼确认坐标没问题再继续。下面是一段简单的Python解析代码import json from PIL import Image, ImageDraw with open(annotations.json, r, encodingutf-8) as f: data json.load(f) img_info data[images][0] img_path images/ img_info[file_name] img Image.open(img_path).convert(RGB) draw ImageDraw.Draw(img) anns [a for a in data[annotations] if a[image_id] img_info[id]] for ann in anns: x, y, w, h ann[bbox] draw.rectangle([x, y, x w, y h], outlinered, width3) img.save(check_visual.jpg) print(f图片数量: {len(data[images])}标注数量: {len(data[annotations])})这段代码会把第一张图的检测框画出来。如果能正常框住广告牌说明JSON坐标解析没问题如果框的位置明显偏移大概率是坐标没除以缩放比例或者原图被resize过但标注没跟着变。2.4 JSON格式常见问题与修复建议我处理过不少外部数据集COCO JSON最常出问题的点有三个一是file_name和实际文件名对不上大小写或者路径层级不一致二是category_id从0开始而不是从1开始这会导致模型训练时类别数搭错三是bbox的值偶尔出现负数或超出图片宽高通常是标注工具在裁剪时留下的小尾巴。遇到这类问题先用脚本做一轮全量校验比盲目训练划算得多。校验内容包括所有image_id都能在images里找到、所有category_id都在categories里定义、所有bbox坐标都大于等于0且不超过图片尺寸。如果发现几百条异常框可以用规则自动过滤掉但要注意别把有效目标也一起删了特别是贴边的大广告牌有时就是会稍微超出图像边缘一点。3. 用这个数据集训练你自己的广告牌检测模型数据集拿到手下一步就是训练。目前最省事的路线是用YOLOv8原因很简单生态成熟文档多预训练权重容易下载训练命令也短。下面我按完整流程走一遍从环境搭建到指标解读都过一遍。3.1 环境准备与依赖安装建议用Python 3.8到3.11之间的版本显卡驱动和CUDA尽量提前装好。然后安装ultralytics库pip install ultralytics装好之后可以顺手验证一下版本yolo --version如果这一步报错大概率是环境变量或者Python版本问题。我之前遇到过Python 3.12下某些依赖编译不过的情况降回3.10就正常了。接着把数据集解压最好整理成下面这种目录结构dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yaml如果你拿到的是COCO JSON就需要先把JSON拆分成train和val两个JSON文件再分别转换成YOLO格式的txt标签。这一步很多人会卡住我给一下具体的转换思路。3.2 从COCO JSON转换到YOLO格式YOLO格式的标签文件是每个目标一行内容为class_id x_center y_center w h全部是归一化坐标。转换逻辑不复杂核心是读入COCO JSON通过image_id找到对应图的宽高然后做一次坐标换算。下面是一段可用的转换脚本核心部分import json import os def coco_to_yolo(coco_path, img_dir, out_dir): with open(coco_path, r, encodingutf-8) as f: data json.load(f) img_id_to_info {img[id]: img for img in data[images]} for ann in data[annotations]: img_info img_id_to_info[ann[image_id]] img_w img_info[width] img_h img_info[height] x, y, w, h ann[bbox] # 转为归一化的中心点坐标 x_center (x w / 2.0) / img_w y_center (y h / 2.0) / img_h w_norm w / img_w h_norm h / img_h cls ann[category_id] - 1 # YOLO类别从0开始 txt_name os.path.splitext(img_info[file_name])[0] .txt txt_path os.path.join(out_dir, txt_name) with open(txt_path, a, encodingutf-8) as f: f.write(f{cls} {x_center:.6f} {y_center:.6f} {w_norm:.6f} {h_norm:.6f}\n)注意这里做了category_id - 1因为COCO的类别id通常从1开始而YOLO类别索引从0开始。如果数据集的categories数组里只有一类id为1那转换后所有标签的class_id都是0没问题。如果有多类务必提前确认id和类名的对应关系。还有一个容易忽略的点一张图片可能对应多行标签所以txt文件要用追加模式打开或者先一次性收集好所有annotation再统一写入。用上面的代码时记得先清理out_dir里的旧txt避免重复标签叠加。3.3 创建data.yaml并启动训练转换完成后在数据集根目录下新建data.yamlpath: /absolute/path/to/dataset train: images/train val: images/val nc: 1 names: [billboard]如果不想写绝对路径也可以直接用相对路径但建议在训练前用print(os.path.exists(...))验证一遍。路径写错是最常见的报错原因YOLO训练启动后直接报“Dataset not found”。然后启动训练yolo train datadata.yaml modelyolov8s.pt epochs100 imgsz640 batch16这里我用的是yolov8s预训练权重。广告牌检测不算超难任务用s模型已经能获得不错的精度和速度平衡。如果你的显卡显存不够batch调到8也可以只是训练时间会相应拉长。3.4 训练参数怎么选epochs、batch、imgsz、pretrained关于训练参数我根据实际经验给几个建议。epochs默认100是比较稳妥的起点。广告牌只有单类数据集也不算小80到120个epoch足够收敛。如果训练到后期发现验证集mAP还在缓慢上升可以再加到150但注意不要过拟合。判断过拟合的依据是训练集loss持续下降但验证集loss不再下降甚至反弹。batch大小取决于显存。24GB显存跑yolov8s640分辨率下batch可以开到32甚至648GB显存老老实实开16。batch过小会导致BN层统计不稳定训练过程会抖动比较厉害。imgsz直接用640和预训练权重保持一致。如果训练完了想提升小目标检测效果可以尝试用imgsz960再finetune几个epoch但推理时也要同步调大输入尺寸速度会降低。pretrained建议使用官方coco预训练权重。它虽然不包含广告牌类别但模型已经学到了通用的边缘、纹理、形状特征从这些特征出发再微调比从头训练收敛更快、精度更高。除非你要完全复现论文里的随机初始化效果否则不要轻易关闭预训练。3.5 训练结果怎么看mAP、precision、recall训练结束后ultralytics会在run目录下保存results.csv和对应的验证结果图。核心指标就几个precision所有预测为正样本的框里真正是广告牌的比例。recall所有真实广告牌里被模型成功找出来的比例。mAP50IoU阈值0.5时各类别AP的平均值适合看整体检测效果。mAP50-95IoU阈值从0.5到0.95逐步提升后再平均对框的定位精度要求更严格。对广告牌检测这类任务我一般先看mAP50因为这个指标更贴近“框得准不准、找得全不全”的直观感受。mAP50-95如果比mAP50低很多说明预测框的边界不够贴合可能需要优化回归损失权重或者用更小的anchor。但以YOLOv8的anchor-free设计来看这类问题已经少了很多。4. 从训练到落地应用场景与部署要点模型训练完最终目的是落地到实际业务里。广告牌识别覆盖的场景很广不同场景难点还不一样这里我拆开分析一下。4.1 商场和建筑外立面场景商场广告牌的特点是大、规整、光照充足。尤其是一楼沿街的灯箱广告白天晚上都有清晰边缘模型检测起来相对轻松。难的反而是玻璃幕墙上的广告位因为玻璃会反光广告牌边缘和背景融为一体模型容易把玻璃上的倒影也当成广告牌。针对这个问题训练时如果数据集里反光样本占比不高建议额外收集一些玻璃幕墙背景下的广告牌图片或者用亮度抖动、高斯模糊、模拟反光这类增强手段硬造一些训练样本。还有一种方案是在检测后加一个边缘过滤逻辑真正的广告牌通常有明确的矩形边界或灯箱压边条而倒影边缘是模糊的。4.2 路边和建筑围挡场景路边广告牌包含了灯杆旗、公交站牌广告、人行道立牌、高炮广告等这类目标最大的问题是尺度变化剧烈。有的广告牌在画面里占据三分之一的面积有的只占几十个像素。如果你发现模型对路边小广告牌漏检明显可以考虑两个方向一是用更高的输入分辨率重新训练比如960×960二是在训练时开启多尺度增强让模型适应不同的目标尺寸。建筑围挡广告是另一个高频场景。工地围挡通常是一条长条形的喷绘布上面可能印了多个品牌信息。检测模型如果只框整块围挡无法满足客户“逐个品牌统计”的需求这种情况下可能需要把单个广告画面再拆成独立样本重新标注训练。4.3 轻量化部署建议广告牌检测往往要跑在边缘设备上比如无人机、巡检机器人、街景采集车上不太可能全依赖云端GPU。部署时YOLOv8的s模型可以直接导成ONNX或TensorRT格式。以yolov8s为例640输入下在Jetson Orin这类设备上能跑到30到60FPS完全满足实时巡检需求。导出ONNX的命令很简单yolo export modelbest.pt formatonnx imgsz640如果你的设备支持TensorRT再进一步转成engine格式推理速度还能提升不少。实际部署时注意两个问题一是输入图像的预处理必须和训练时一致letterbox填充的边长要算对不能简单resize二是后处理阶段的NMS阈值要结合实际场景调太严格会把重叠的大广告牌漏掉太宽松会出现大量重复框。5. 数据处理与训练中的常见问题排查这个环节是我自己踩坑最多的地方也是网上提问最多的地方。我挑几个典型问题集中说一下按“现象-原因-解法”的方式整理。5.1 训练集loss降不下来怎么办很多人把数据准备好扔进YOLO训练发现跑了50个epoch训练loss还是居高不下。此时先别急着调超参第一步检查标签是否正确。用可视化脚本在训练集上画几张图看看标注框是否落在广告牌上。如果标注没问题再看数据本身是否存在矛盾样本。比如同一张图里有些广告牌被标注了有些漏标了模型会感到迷惑。尤其当漏标的是画面里显眼的大广告牌时模型既想在那个位置出框又受到“正样本”信号的干扰loss自然压不下去。解决办法是用半自动工具把低置信度区域抽出来人工复核补齐漏标框。另一个常见原因是类别不平衡。广告牌单类问题不突出但如果训练集里小目标占比过高模型的loss会被大量小目标主导导致大目标学不好。此时可以适当增加大目标的权重或者用focal loss变体。5.2 错误标注会导致训练集loss降不下来吗会而且影响比大多数人想象中严重。我在一个街景数据集上做过实验故意把5%的标注框坐标往旁边随机偏移20像素训练出来的模型mAP50直接掉了将近4个百分点而且验证loss在中后期开始抖动。原因是模型倾向于学习一个平均位置偏移样本在梯度更新时反复拉扯最终让边界框回归变得不稳定。这给我们的教训是宁可数量少一点也要保证标注质量。买数据集或外包标注后务必做标注质量抽检。抽检比例建议在10%以上。一旦发现系统性偏移比如某个标注员习惯把框外扩5像素就要全部返工重标光靠训练时的数据增强救不回来。5.3 训练集和验证集划分的正确姿势训练集和验证集划分看似简单实际上有讲究。图片来自同一商场、同一道路的连续帧时如果直接随机划分会出现训练集和验证集包含相似画面导致验证指标虚高。正确做法是按场景或者按视频序列划分保证同一个场景只出现在一个集合里。以这个广告牌数据集为例如果原始数据里有多个拍摄地点建议把地点作为一个key做stratified split每个地点按比例随机分配到train和val里而不是对每张图做全局随机。这样验证集才能真正反映模型在没见过的新地点上的表现。还有一个细节验证集大小不需要太大100到200张就能给出稳定评估结果。把更多数据留给训练集对模型精度的提升更直接。5.4 标注框边界不齐的小技巧有时数据集的标注框是自动生成的边界会贴不齐广告牌的实际边缘有的框大了10%有的框小了5%。这种标签噪声在训练时不容易被发现但推理时会影响mAP50-95的分数。我的做法是训练前用脚本做一次“框裁剪比例”校验计算每个bbox的面积和对应segmentation面积如果COCO JSON里有segmentation偏差超过20%的样本抽出来看。对小比例误差可以用统计修正比如统一收缩外扩的边距但前提是确认误差方向一致。写在最后的项目心得这个广告牌识别数据集从我用类似数据训练过多个项目的经验来看属于那种刚上手就有不错效果的数据资源。它最大的价值不是数量堆得多高而是把商场、建筑、路边这几类典型场景一次性覆盖了还用了coco json这种通用性强的标注格式。我自己实际操作时有个习惯拿到任何数据集第一件事永远是可视化检查而不是直接跑训练。这个习惯帮我避开了很多隐藏雷区。数据集的表面统计数字都能美化但标注框到底贴不贴目标、类别对不对、有没有漏标只有画出来才看得出来。无论是7137张训练图还是1000张验证图先抽个几十张看一眼心里就有底了。另外如果你打算把这个数据集用在更复杂的场景里比如倾斜广告牌检测、夜间灯箱识别、动态视频流检测我建议量力而行先从单帧检测做起把baseline跑通再逐步叠加难度。模型训练是一个不断和数据较劲的过程把基本功做扎实了后面的一切都会顺很多。本文还有配套的精品资源点击获取
返回列表