简介:街景门牌号数据集专门面向计算机视觉领域的门牌号识别任务,适用于图像分类、目标检测等方向的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 \ model=yolov8m.pt \ data=house_number_dataset/data.yaml \ imgsz=1280 \ epochs=150 \ batch=16 \ lr0=0.01 \ lrf=0.01 \ optimizer=AdamW \ seed=42 \ patience=20模型选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. 总结:做数据集是门槛活,不是体力活
回到开头说的那件事,真正做完这套街景门牌号数据集之后,最大的感受是:数据集的好坏,七成取决于前期定义和中期质控,只有三成取决于采集了多少张图。很多人一上来就拼命爬数据,反倒忽略了"检测目标边界怎么定义""标注标准怎么统一""数据怎么划分才不泄漏"这些基础工作。这些基础没打好,数据越多,模型越混乱。
如果你也准备做自己的门牌号数据集,或者要基于类似街景数据做目标检测,我的建议是:先花几天时间把标注规范和划分策略想清楚,再用一个几百张的小样集跑通训练和评测全流程,确认所有环节都顺了,再上量采集。小样集跑通后,后面加数据只是体力活,不会再有方向性的返工。这套流程我后来在好几个项目里都复用了一遍,每次都省了大量时间。
本文还有配套的精品资源,点击获取