手把手教你构建街景门牌号数据集:YOLO训练实战与避坑指南 简介街景门牌号数据集专门面向计算机视觉领域的门牌号识别任务适用于图像分类、目标检测等方向的AI研究者和开发者可用于训练和评估自动识别街景门牌号的模型为智能导航、自动驾驶车辆、智慧城市等场景提供数据支撑。资源共7个文件压缩包整体约885MB包含3个ZIP图像数据包、2个CSV数据清单及提交样例、2个JSON标注文件。ZIP包将街景门牌号图像划分为训练、验证、测试三部分便于隔离测试集防止过拟合CSV文件提供样本提交模板与图像元信息JSON文件则包含门牌号码位置与类别标注。已有517人学习下载。数据完整度高可直接接入深度学习框架配合data_loader批量加载和预处理适合需要开展端到端门牌号识别实验或完成竞赛方案的中高级开发者。1. 街景门牌号数据集到底在解决什么问题大概两年前我接到一个挺头疼的需求做一个能自动识别临街商铺门牌号的小工具。甲方给的原始素材是一堆从街景视频里截出来的图每张图上都有门牌但位置、角度、光照、遮挡程度千奇百怪。当时第一反应是去找现成数据集但找了一圈发现像SVHN街景门牌号码这种经典数据集虽然学术上很权威放到真实业务场景里却不太够用——图上门牌太小、样本分布单一、背景过于干净跟实际街景里的复杂情况差太多。最后没办法只能自己动手搞了一套街景门牌号-数据集边整理边训练效果反而比预期好不少。这篇文章就想把我做这套数据集的完整过程、标注思路、训练细节和踩坑记录分享出来。如果你是做目标检测、OCR识别、街景理解或地图数据相关工作的想自己造一套高质量数据集来训练YOLO或类似模型这里面大部分经验应该可以直接拿来用。先说清楚这套数据集解决的核心问题有三个第一让模型在复杂街景里能找到门牌这个大目标而不是直接扔给OCR一整个画面第二用一套统一的标注规范把门牌检测任务和后续的文字识别任务解耦第三用可控的数据分布让训练过程更稳定避免模型在真实场景里泛化崩掉。2. 数据集整体设计与构建思路拆解2.1 场景定义与样本采集策略做数据集第一件事不是打开标注工具而是定义清楚什么算门牌。这个看起来很简单实际特别容易出分歧。比如墙上写的楼栋号算不算门牌临街商铺的招牌上挂着XX路88号算门牌还是算招牌大门口的立体字算不算我最后定的标准是在物理上独立存在、用于标识地址信息的牌匾或铭牌才标注为门牌。纯招牌文字不算贴纸打印的临时编号不算因为这些目标形态差异太大混在一起会让模型学得很困惑。采集策略上我用了三个渠道公开街景视频抽帧、自己拿手机在城市里沿街拍摄、以及从合作方拿到的脱敏街景图片。三条渠道的比例控制在6:3:1左右保证样本覆盖度。公开街景数据虽然量大但往往因为拍摄设备统一画面风格太一致模型容易过拟合自己拍的补足了不同天气、不同时段、不同手机镜头带来的色彩和纹理差异合作方的数据则提供了很多极端角度和晚上低照度的样本。抽帧时有一个细节如果视频帧率是30fps直接逐帧抽出来的画面在时间上高度相关很多帧之间的差异只有轻微的视角变化放进训练集里基本等于重复样本。我的做法是每隔30帧抽一帧同时用图片相似度算法做一次去重把结构相似度高于0.9的相邻帧干掉用这种方法把初始拿到的2万多张图压缩到8000多张有效样本。2.2 标注规范与格式选型标注规范是整个数据集的地基这一步如果偷懒后面训练、评测、迭代全都会很被动。我用的标注方案是目标检测方向框每个门牌目标用一个带旋转角度的四边形框框出来而不是传统的轴对齐矩形框。理由很简单——街景里的门牌基本都是挂在墙上的摄像角度稍微偏一点门牌在画面里就是斜的。用普通矩形框会把大量背景包进来模型学到的特征是矩形区域里有门牌的影子而不是门牌本身推理时框的位置就经常飘。标注格式我选了DOTA格式作为中间存储然后转成YOLO训练需要的形式。DOTA格式用四点坐标表示任意四边形配合一个表示角度的概念。对于门牌这种近似矩形的目标四点坐标比中心点宽高角度的参数化方式更直观标注工具支持度也更好。如果你只是做水平框检测不用旋转框那直接用YOLO格式class cx cy w h就好但后续如果发现检测效果遇到瓶颈可以考虑升级到旋转框方案。这里我踩过一个坑刚开始标注的时候标注员对门牌被树挡住三分之一这类情况是否标注有分歧。后来规定只要人能根据可见部分判断出这是个门牌就标注完整外接框完全看不见的标注为忽略区域ignore region。忽略区域在训练时要专门做掩码处理不然会教模型这里明明是门牌但你不能预测反而造成错乱。2.3 类别体系与标签平衡门牌数据集的类别设置我前后改了三版。最初想做得精细一点按门牌材质分类金属牌、亚克力牌、木质牌、石质牌。后来训练时发现根本没必要模型对材质的敏感度远低于对文字区域纹理的敏感度而且材质类别之间肉眼差异也不大标注成本却高了不少。最终版本只保留了门牌house_number这一个类但增加了一个附加属性文字方向。文字方向分成三类水平阅读大多数、垂直阅读竖排门牌多见于老街巷、角度倾斜门牌本身是斜的或拍摄视角造成。这个属性不是作为独立类别参与训练而是以分组标签的形式记录在元数据里方便训练完做分组成维度评估——比如看看模型在垂直门牌上的recall是不是明显低于水平门牌从而针对性补数据。单类设计还有一个额外的好处样本不均衡问题基本消失了。在目标检测任务里如果A类样本是B类的10倍模型会不由自主地偏向A类导致B类的召回率惨不忍睹。单类模型只需要关注门牌在哪儿配合一个简单的二分类判断在真实场景里反而更实用。实际测试下来单类检测器加后续OCR识别的pipeline比端到端多任务模型更稳。2.4 标注质量控制流程标注质量问题我在第一次做数据集时吃过亏。当时外包给标注团队回来一检查大约有8%的框偏移超过5个像素还有不少漏标。后来我搭了一套初标→质检→修正→抽检的流程初标由标注员完成质检员用专门的检查工具把标注结果叠加在原图上重点看框的边是否贴住目标边缘、角度是否对齐、有没有漏标修正版回来后我自己按5%的比例随机抽检抽检不合格就退回整批重做。这里有一个很实用的技巧每张图标注完成后把标注框裁剪出来单独拼成一张大图grid做人工巡检。因为当你连续看几百个裁剪出来的门牌图块时任何标注偏差都会变得非常扎眼比直接看整张图的效率高很多。这个裁剪巡检法后来我也一直沿用在其他数据集项目里收益很大。3. 核心细节解析怎么把数据变成YOLO能吃的样子3.1 数据清洗与预处理原始图片从街景视频里抽出来之后首先要做的是清洗。我写了个pipeline按顺序做以下几件事剔除完全模糊的帧用拉普拉斯方差做判断低于阈值的直接丢剔除光线极度过曝或过暗的帧用直方图统计判断剔除没有门牌的帧先用一个预训练的检测器粗筛保留置信度高于0.1的结果再人工确认。这个阶段不用太精确目标只是把明显无效的数据清掉。然后把所有图片统一缩放到1280×1280同时确保标注坐标跟着等比缩放。之所以选1280而不是640或1920是因为街景里的门牌很多属于小目标在画面中占比不到5%640分辨率下目标只有30多个像素特征太少模型很难学到有效信息1920分辨率能保留细节但显存占用太高训练速度太慢。1280是精度和训练效率的平衡点。缩放时还要注意一个细节原图宽高比如果不是1:1直接压缩会把门牌压变形导致文字扭曲、检测器学到的形状特征失真。正确的做法是等比例缩放后用灰色填充letterbox补齐到1280×1280标注坐标不变这样既不丢信息也不会扭曲目标。3.2 YOLO格式转换与数据划分数据转换这一步本身不复杂就是坐标格式的换算但容易出低级错误而且错误很难发现——模型训练loss不下降找半天原因发现是标注坐标搞错了。我自己封装了一个小函数把DOTA格式的四点坐标转成YOLOv8需要的归一化中心点坐标import numpy as np def dota_to_yolo(points, img_w, img_h): 将DOTA四点坐标转换为YOLO格式的(cx, cy, w, h) points: 8个数值 [x1, y1, x2, y2, x3, y3, x4, y4] img_w, img_h: 图片原始宽高 返回: (class_id, cx_norm, cy_norm, w_norm, h_norm) pts np.array(points).reshape(4, 2).astype(np.float32) x_min, y_min pts[:, 0].min(), pts[:, 1].min() x_max, y_max pts[:, 0].max(), pts[:, 1].max() cx (x_min x_max) / 2.0 cy (y_min y_max) / 2.0 w x_max - x_min h y_max - y_min # YOLO需要归一化到[0, 1] cx_norm cx / img_w cy_norm cy / img_h w_norm w / img_w h_norm h / img_h return (0, cx_norm, cy_norm, w_norm, h_norm)转换完成后数据划分我按7:2:1切分为训练集、验证集和测试集。有一个容易忽略的问题来自同一段街景视频的连续帧如果被同时分进训练集和验证集会造成数据泄漏——验证集的图像与训练集高度相似评估结果虚高。我的做法是按视频来源做分组划分同一个视频的抽帧全部进入同一个集合而不是按单张图随机划分。这个问题在业务场景里特别重要如果忽略了模型在真实数据上的表现会跟验证集结果差很多。3.3 数据增强策略门牌检测任务的数据增强不能直接套用常规检测任务的增强套餐。原因在于门牌的判定依赖文字的可读性如果把图像增强过头门牌文字变得模糊、扭曲或变形标注框里的内容就不是门牌了等于强行制造噪声。最有效的一组增强组合我实测下来是轻度随机亮度扰动±20%、轻度随机色彩抖动饱和度±15%、色相±5%、随机水平翻转注意门牌文字方向会翻转但这个影响可以接受因为检测器主要学外观纹理而不是语义内容、随机缩放0.5到1.5倍和随机平移±10%。像随机擦除random erasing这种增强手段用在门牌上会让文字区域直接缺失反而教坏模型不推荐。Mosaic增强YOLO自带的四图拼接可以开但要注意关闭crop类操作或者把拼接时随机裁剪的幅度调小否则门牌目标很容易被切掉一半。我试过Mosaic开启和关闭两种情况开启后小目标远处门牌的recall提升了约4个百分点收益是正面的。4. 实操过程用YOLOv8训练门牌检测模型4.1 环境搭建与关键参数配置训练在我的单卡RTX 3090上进行24GB显存对1280分辨率的YOLOv8训练来说足够。环境用ultralytics官方包版本锁在8.x。数据集的目录结构按YOLO惯例组织house_number_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yamldata.yaml这样写train: /path/to/house_number_dataset/images/train val: /path/to/house_number_dataset/images/val test: /path/to/house_number_dataset/images/test nc: 1 names: [house_number]训练命令我采用的是固定随机种子跑方便问题复现yolo detect train \ modelyolov8m.pt \ datahouse_number_dataset/data.yaml \ imgsz1280 \ epochs150 \ batch16 \ lr00.01 \ lrf0.01 \ optimizerAdamW \ seed42 \ patience20模型选yolov8m而不是s或者l我基于经验做权衡s参数量小、训练快但小目标检测精度明显不够l精度好但在1280分辨率下batch size必须降到8以下训练时间翻倍性价比一般。m是单卡训练时精度和速度最均衡的选择。4.2 训练过程观察与调整训练过程我建议重点盯两条曲线验证集的mAP50和mAP50-95。正常情况下mAP50从第10个epoch开始快速爬升到80个epoch左右趋于平缓mAP50-95的绝对值不会太高小目标数据集的mAP50-95普遍在0.3到0.5之间但它能反映定位精度——如果mAP50还可以但mAP50-95上不去说明框的位置不稳定边界贴合度不够这时候要考虑锚框设置或回归损失权重的问题。我训练时遇到过一个典型现象loss在30个epoch之前下降正常之后就震荡不降。检查学习率后发现问题——用默认的SGD在1280分辨率下loss容易震荡换成AdamW后从第35个epoch开始重新稳定下降。如果你的训练也遇到类似情况优先检查优化器和学习率不要一上来就去调网络结构。另外我习惯在训练到一半时手动跑一次推理挑几张验证集图片看看检测结果。这一步比看任何指标都直观模型有没有把招牌上的数字当门牌远处的小门牌能不能召回框有没有歪这些视觉检查能快速暴露出指标上看不到的细节问题。4.3 推理与后处理细节训练完成后推理端的处理也会影响最终效果。我在实际项目里把检测结果接了一个轻量级OCR模块流程是YOLO检测出门牌区域 → 做透视矫正因为很多门牌在画面里是斜的 → 送入OCR做文字识别 → 用正则表达式过滤识别结果比如只保留包含数字的文本。透视矫正在这一步很关键。因为检测框输出的是旋转矩形直接把这个旋转区域喂给OCR识别效果会受文字倾斜影响。我的做法是利用四点坐标计算透视变换矩阵把门牌区域矫正成正面视角后再送OCR。这一步操作大约能让OCR识别准确率提升15个百分点具体数值取决于原始图像中门牌的倾斜程度。5. 常见问题与排查技巧实录5.1 问题一训练损失不下降这是目标检测训练里最常见的幽灵问题。我在这个数据集上遇到的第一个损失不下降排查了半天发现是标注坐标转换出了问题——DOTA格式的坐标原点在左上角没错但某些标注工具的坐标原点在左下角转换后所有框的y坐标都反了模型在空转。所以建议开始训练前先手工验证10张图的转换结果把标注框画出来看一遍不要直接开跑。还有一种情况是前景背景类别极度不平衡。门牌在1280分辨率的图中占比太小负样本数量压倒性占优正样本的梯度被淹没。通过调整focal loss的alpha和gamma参数能改善我是把alpha设为0.75、gamma从默认的1.5提到2.0对提升小目标的收敛速度有帮助。5.2 问题二小目标漏检严重漏检的典型场景是远处的小门牌目标只有20×30像素大小。这个问题是结构性的光靠调参解决不彻底。我的排查思路按优先级排序首先是确认训练分辨率——1280分辨率下20像素的目标确实存在但不可分辨建议做一次标注目标尺寸分布统计如果大量目标长边小于32像素就只能提高输入分辨率或者做切片推理。其次是数据增强里加一个随机裁剪放大操作以目标为中心随机裁剪1.5到3倍的区域再放大后参与训练相当于让模型见过更多放大了的门牌。实测小目标recall提升了3个百分点左右。这个方法实现简单收益稳定推荐优先尝试。5.3 问题三验证集指标高但真实场景效果差这类问题的头号嫌疑人是数据泄漏原因就是我上面提到过的同源视频帧被分到了不同集合。换成按视频分组划分之后验证集和真实场景的差距立刻缩小。另一个原因是验证集图片太干净——如果我们手工删掉了那些严重遮挡、极端光照、运动模糊的图片验证集就会整体偏乐观。建议把一些难样本刻意留在验证集里宁可在验证时被虐也不要上线后被虐。5.4 避坑清单我把做这套数据集过程中最值得记的教训整理成一张速查表方便你对照环节易踩的坑正确做法数据采集同源视频帧大量重复抽帧间隔不少于30帧再做结构相似度去重标注规范目标定义模糊标注员标准不一致写明物理独立门牌才算歧义情况设忽略区标注质检只看单张图检查效率低用裁剪巡检法把门牌裁剪拼图批量检查数据划分同源帧跨集合导致验证集虚高按视频/场景分组划分不按单张随机划分数据增强随机擦除或过度扭曲使文字失真轻量亮度色彩扰动为主避免破坏文字结构训练配置小目标多但用640分辨率直接训练用1280输入配合Mosaic增强和焦距损失调节推理部署斜门牌直接送OCR识别率低先透视矫正再送入OCR准确率提升明显6. 扩展思路这套数据集的后续玩法数据集本身做完不代表事情结束了我后来基于这套数据还做了几个方向的延伸都很实用。第一个是基于检测结果直接生成门牌号码位置的GIS标注数据给地图应用用。把YOLO检测输出的坐标投影到对应的地理位置坐标自动生成门牌点人工只需要做确认而不是从零标注。第二个是给OCR模型做细粒度训练数据的思路。检测模型把门牌区域切出来之后如果某个门牌的文字特别小或者模糊OCR识别不准就可以把这些失败样本自动收集起来人工补充清晰版本形成一个迭代式的数据飞轮。这个循环跑起来之后识别准确率的提升会非常明显。之后再用同样的思路去扩展其他街景元素的检测比如红绿灯、路标、路灯杆。标注规范、训练流程、问题排查的思路都完全可以复用整个流程跑通后新增一个目标类别大概只需要一到两周。7. 总结做数据集是门槛活不是体力活回到开头说的那件事真正做完这套街景门牌号数据集之后最大的感受是数据集的好坏七成取决于前期定义和中期质控只有三成取决于采集了多少张图。很多人一上来就拼命爬数据反倒忽略了检测目标边界怎么定义标注标准怎么统一数据怎么划分才不泄漏这些基础工作。这些基础没打好数据越多模型越混乱。如果你也准备做自己的门牌号数据集或者要基于类似街景数据做目标检测我的建议是先花几天时间把标注规范和划分策略想清楚再用一个几百张的小样集跑通训练和评测全流程确认所有环节都顺了再上量采集。小样集跑通后后面加数据只是体力活不会再有方向性的返工。这套流程我后来在好几个项目里都复用了一遍每次都省了大量时间。本文还有配套的精品资源点击获取