ARTICLE DETAIL

资讯详情

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

从零构建街景门牌号数据集:YOLOv8检测与OCR落地实践

从零构建街景门牌号数据集:YOLOv8检测与OCR落地实践 简介街景门牌号数据集是一份面向计算机视觉与深度学习研究者的标准图像识别资源核心任务是从街景图像中自动识别门牌号码可用于智能导航、自动驾驶车辆和智慧城市等真实场景的技术验证。压缩包共7个文件、约885MB其中3个zip分别存放训练、验证与测试图像2个json对应提供标注信息2个csv则包含数据列表与样例提交结果整体结构清晰便于按模型训练流程取用。该资源对训练卷积神经网络等图像识别模型尤其适用训练集、验证集与测试集严格分离可有效防止数据泄漏JSON标注可辅助完成目标定位与字符识别样例提交文件则能引导新手上手构建预测结果配合常用data_loader工具即可完成批量读取与预处理。目前已有517人学习下载适合希望以真实场景数据开展深度学习实践、进行算法对比或参加相关竞赛的AI学习者与开发者。 先说一个我真实碰到的场景。之前给一个做同城配送的团队做地址纠偏模块聊到街景门牌号数据集的时候发现大家的第一反应都是“这东西不就有吗”可真到用的时候又都摇头。用户填写的地址精确到了“某路某号”地图上却经常定位到几百米开外快递员到了附近还得停下来打电话问路。想用模型自动识别门牌号来完成纠偏翻遍公开的目标检测数据集几乎找不到专门针对街景门牌号的资源。就算偶尔在通用目标检测集里翻到几张带门牌的街景大图标注也不统一要么只画了框没给文本要么画的框把整面墙都包了进去根本没法直接用来训练。所以我自己动手从数据采集到标注再到模型训练和部署走了一整轮做成了一个真正可用的街景门牌号检测数据集。这篇文章会把这条路完整记录下来数据从哪来、怎么标、清洗时踩过哪些坑、怎么用YOLOv8把检测模型训出来以及最后怎么接OCR落地。适合正在做目标检测、OCR或者地理信息相关项目的朋友参考尤其是那些准备从零构建自己数据集的人。1. 为什么门牌号值得单独做一个数据集从业务需求和技术特点说起1.1 门牌号是“最后一公里”场景里最关键的锚点导航定位解决的是“经纬度在哪”的问题但现实中绝大多数业务关心的是“这栋楼到底是几号”。外卖和快递员根据坐标到达附近之后真正要找的是门牌号市政维护要更新地址库靠的也是一张一张包含门牌号的街景照片应急调度需要快速定位报案人说出的地址同样少不了门牌信息。问题在于门牌号是刻在物理世界里的“文本”定位系统不会自动告诉你这一户是几号。如果能把街景图像里的门牌号自动读到再和逆地理编码结果做交叉验证就能把几百米的定位误差压缩到具体楼栋级别。这个能力在物流调度、外卖配送、网约车上下车点推荐里都是刚需。可惜的是通用目标检测数据集里没有人认真对待门牌号。因为在一张街景图里门牌号往往只占几十个甚至十几个像素属于典型的小目标数据集的构建者通常也不会专门给门牌号单独做一个类别。就算COCO这类大型数据集里有些样例数量也不够模型学习到足够强的特征。自己做数据集不是炫技而是因为业务需要的数据形态公开市场里根本没有。1.2 门牌号检测和通用目标检测根本不是一回事很多初学者会问直接用现成的YOLO权重把检测类别从80类改成1类不就行了实际上没那么简单。门牌号检测有其非常特殊的难点可以看成是目标检测和OCR的交叉地带。目标尺寸极端门牌号在街景图里常常只占很小一块区域YOLO默认特征图对这类小目标不太友好。类内差异极大同样的门牌号不同城市、不同年代、不同建筑风格字体、颜色、材质、悬挂高度完全不同甚至同一条街上都可能出现白底黑字、铜字、LED灯箱等好几类形态。环境干扰严重反光、树枝遮挡、车辆停放、墙面污渍、视角偏斜这些噪声在门牌号场景里是常态。检测和识别需要联动只画出一个框还不够业务上需要框里的具体文本所以数据集不能只标类别还要转录文本这给标注工作增加了不少成本。我整理了一张对比表方便看清楚差异维度通用目标检测人/车等街景门牌号检测目标尺寸较大占据画面明显比例极小常被背景淹没类别数几十上百类通常1类但形态多样标注成本画框类别画框转录文本记录属性场景复杂度相对固定光照、视角、遮挡变化极大下游要求类别正确即可文本内容要准确关系到地址匹配所以与其说街景门牌号数据集是一个“目标检测数据集”不如说它是一个为“检测OCR”链路专门设计的资源。2. 数据从哪来街景影像的采集路径与合规注意事项2.1 三个主流来源及优缺点构建数据集第一步是解决图像来源。我试过几种方式各有取舍一是利用地图平台的公开街景影像。现在很多地图产品都提供了街景浏览能力可以通过官方开放能力获取合规的图像数据。优点是覆盖面广、视角统一可以很方便地收集不同城市、不同道路等级的数据。缺点是采集时间不一定可控而且需要仔细阅读平台的服务条款不能为了做数据集就随意抓取和重分发更不能把含有人脸、车牌等个人信息的完整街景图直接公开。二是自己组织采集。用运动相机或手机固定在车前沿道路行驶拍摄视频再按帧抽图。这种方式的好处是完全掌握拍摄时机和拍摄路线可以针对白天、傍晚、阴天等不同条件主动收集坏处是成本高、周期长而且自己拍摄的视角通常偏低门牌号容易被绿化带和停靠车辆挡住。三是整理已有的开源图像数据。部分开源街景数据集、城市影像数据集提供了可商用的图像可以筛选出含门牌号的样本。优点是可以快速起步缺点是标签噪声偏高往往需要大量人工复查。我的建议是三条路并行先用开源数据搭出第一批样本验证标注规范和训练流程再用地图平台影像扩充覆盖范围最后用自采数据补齐特殊场景。这样能在成本和效果之间取得平衡。2.2 采集的多样性与数量规划数据量不是越多越好但多样性不足一定会导致泛化崩盘。我第一版数据集只收了三四个路段的图训练出来在测试集上表现尚可换到另一条没见过的街道直接漏检严重。原因是门牌的底色、字体、悬挂方式几乎被限定在了那几条路的风格里。所以采集阶段要刻意拉开多样性城市级别老城区、新城区、郊区、道路等级主干道、支路、小区内部路、建筑类型居民楼、商铺、写字楼、厂房、拍摄时段白天、傍晚、夜间、天气晴天、阴天、雨后。每一维度都要有足够的样本量。关于数量我要给一个比较现实的参考值纯检测模型最少不能低于3000张含门牌的街景图标注框总量建议在1.5万个以上如果后续还要做端到端文本识别最好再翻一倍。别想着几百张就能训出稳定模型门牌号的类内差异太大数据量不够模型只会去死记背景而不是真正学会“找到墙上那块牌子”。2.3 合规与隐私处理这块我会说得很直接做数据集可以但前提是符合规范。街景图像天然包含人脸、车牌、行人等大量个人相关信息如果你有公开发布数据集的计划必须做到以下几点只能通过官方开放接口或明确授权渠道获取图像不爬取、不绕过平台限制。公开前对所有人脸和车牌做模糊化处理。对图像重采样时尽量裁剪掉无关的可识别个人信息。如果数据集用于商业项目务必确认图像来源的授权范围。我自己的做法是只保留对门牌号检测有训练价值的街景区域并且把整个数据集的访问权限控制在项目内部对外发布时只提供脱敏后的版本。这样既不影响模型训练也把风险降到最低。3. 标注规范设计门牌号数据集不只是画框3.1 标注字段设计很多人以为标注门牌号就是框一下“这里有个号码牌”这是做这个数据集时最需要扭转的认知。门牌号数据集的核心价值在于“框文本上下文属性”三者联动所以我自己在YOLO标注格式之外单独维护了一份JSON索引每个标注对象包含以下字段字段类型说明image_idstring图像唯一标识bbox[x1, y1, x2, y2]门牌号区域坐标像素级textstring门牌号上的原始文本例如“12号”“A-203”is_completebool门牌号是否完整可见font_typestring字体类别如印刷体、宋体、黑体、艺术字backgroundstring背景类型如墙面、玻璃、石材、金属occlusionstring遮挡情况无遮挡、轻微、严重weatherstring天气情况用于后续按条件筛选数据检测时bbox和text是刚需其他字段初期不必全部标注但建议在标注工具里增加属性项方便后续做数据分析和疑难样本挖掘。比如训练后如果发现“玻璃反光”场景下漏检率显著偏高你就可以通过weather或background字段把对应样本筛出来针对性补充数据。3.2 门牌号标注的几种难搞情况标注规范需要提前定好否则标到一半就会因为标准不一致返工。我整理了三种最常见的分歧场景第一种叫“多门牌并存”。一栋楼入口旁可能挂了多个门牌或者同一面墙上有新旧两个门牌号。我的规则是只要清晰可见、语义独立的门牌都分别标注如果多个号码刻在同一块金属牌上作为一个整体框处理text记录完整内容比如“12-1802”。第二种叫“斜挂和弧面”。门牌不是正对着镜头是常态尤其是弧面墙上的门牌四个角不在同一个平面上。标注时不要为了追求方正而框到背景应该贴近门牌实际的可视区域宁可让框稍微包含一点边缘也不要为了对齐把半个墙面框进去。第三种叫“遮挡和反光”。如果门牌被树枝或车辆挡了三分之一但仍能辨认出关键数字标记is_completefalsetext照常填写如果完全看不清数字就不标不要强行猜测。模板上写“不允许靠脑补做标注”这是保证数据质量的一条铁律。3.3 标注工具选型标注工具我试过LabelImg、X-AnyLabeling和Roboflow。列个对比工具支持类型效率备注LabelImg矩形框类别低适合几十张图的小项目功能单一X-AnyLabeling矩形框文本属性高支持OCR预标注适合批量做门牌号数据Roboflow全套流程中在线工具格式转换方便但数据要上传我在实际项目中用得最多的是X-AnyLabeling。原因在于它内置了OCR能力可以先用一个已经训练好的文字检测模型自动生成候选框人工只需确认位置、修正边界并转录文本。这相当于把标注工作从“纯手工画框”变成了“校对”效率能提升不少。不过要注意自动生成的候选框经常把广告牌上的电话号、商店招牌里的数字也框进来这些都是干扰项需要人工删除。4. 数据清洗、质量抽检与格式转换决定模型上限的隐形工作4.1 清洗规则标注完成后别急着训练直接训练大概率会被脏数据带偏。清洗规则我建议按下面几条来第一去除重复图。从视频抽帧得到的数据经常有大量相邻帧高度相似用感知哈希算法计算图像相似度把相似度超过阈值的帧剔除保证训练图像之间没有过强的相关性。第二剔除模糊图和严重曝光图。门牌号检测依赖清晰纹理模糊度和过曝图放进训练集只会让模型学到错误特征可以直接靠人工快速筛查一遍。第三检查标注框偏移。有的框画得大而空把门牌周围的墙面也包进去了这种框的IoU与真实目标不匹配需要在后处理里统一瘦身。第四转录错误复查。数字之间的混淆是重灾区比如“0”和“O”、“1”和“I”、“8”和“B”需要安排一次全量文本复查最好让标注人员交叉复核。4.2 数据集划分策略训练、验证、测试集划分有个非常容易被忽略的坑必须按区域划分不能按图像随机划分。原因在于同一街道的连续帧外观几乎一样如果训练集和测试集都含有同一条街的图像模型本质上是在“背”这些场景验证分数会虚高。真到了新街道上效果立刻打回原形。按街道或区域划分之后训练/验证/测试大致按8:1:1或7:2:1分配具体要保证验证集里能看到训练时没见过的建筑风格和拍摄角度。4.3 格式转换与自动检查标注软件导出的格式五花八门最后统一转成YOLO检测格式最省心。YOLO每张图对应一个同名txt每行是“class x_center y_center width height”坐标归一化到0到1。格式很简单但批量转换时很容易出问题我写了个简单的Python脚本做自动校验核心逻辑是读取所有txt检查每个框的坐标是否越界、宽高是否过小、是否存在空的标签文件有异常就打印文件名和行号。import os label_dir labels for name in os.listdir(label_dir): if not name.endswith(.txt): continue path os.path.join(label_dir, name) lines [l.strip() for l in open(path, encodingutf-8)] if not lines: print(fempty: {name}) continue for line in lines: parts line.split() if len(parts) ! 5: print(fbad format: {name} - {line}) continue _, x, y, w, h parts x, y, w, h map(float, [x, y, w, h]) if not (0 x 1 and 0 y 1 and 0 w 1 and 0 h 1): print(fout of range: {name} - {line}) if w * h 0.001: print(ftoo small: {name} - {line})这样的脚本花不了多少时间但能拦住绝大多数低级错误。把这一层质量控制做在前面后面训练阶段能省下大量排查问题的时间。5. 基于YOLOv8的训练实战与调参记录5.1 目录结构与配置文件清洗好的数据按下面的结构组织street-address-dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yamldata.yaml配置如下path: /path/to/street-address-dataset train: images/train val: images/val test: images/test nc: 1 names: [house_number]5.2 训练命令与参数选择我用的是YOLOv8训练命令如下yolo detect train \ datadata.yaml \ modelyolov8m.pt \ imgsz1280 \ epochs200 \ batch16 \ device0 \ cos_lrTrue \ patience30几个参数需要重点解释一下。imgsz1280是我在这个数据集上最重要的调参决定。门牌号在默认的640分辨率下只有二三十个像素卷积特征提取后基本就没了。把输入分辨率提到1280之后小目标保留的特征明显增加mAP50的提升非常可观。代价是显存占用和训练时间都翻倍如果你的显卡只有8GB显存建议用m模型加梯度累积或者对长图做切片训练而不是硬撑。modelyolov8m.pt是起点。我试过从yolov8n开始训速度快但精度明显不够边框回归偏软改yolov8l以后精度有提升但训练周期拉得太长性价比一般。对于门牌号这种背景规律强、目标对比度相对清晰的对象m模型已经够用先把m跑通再决定要不要换更大的模型。cos_lrTrue和patience30是常规设置。余弦退火可以避免后期学习率震荡早停则是在验证集指标连续30轮不涨时自动停止可以省时间。5.3 训练过程中踩过的坑第一个坑是数据增强导致的“伪标签噪声”。YOLOv8默认开了Mosaic增强会把四张图拼接在一起。门牌号的框本来就小拼接后目标更容易被截断模型学到不少中间被切断的门牌特征导致推理时对部分遮挡的门牌更容易漏检。我最后的做法是保留Mosaic但调低概率同时增加轻微HSV扰动减少不自然的拼接比例。第二个坑是类别不平衡被忽略。虽然类别只有1个但不同字形和背景类型的数量差异非常大。墙面白底黑字占了八成铜字金属牌只有零星几十个结果模型对铜字的检测几乎失效。我重新平衡了数据对少数类样本做了复制和轻微仿射变换让模型至少能见过足够多的“非典型”门牌。第三个坑是夜间和逆光场景。白天数据训练出来的模型在夜间街景上效果差得离谱因为门牌在夜间要么被灯光照亮要么完全隐没在黑暗里。后来我单独收集了两个小时的夜间视频帧混入训练集并用图像增强模拟曝光不足的情况效果才有明显改观。6. 部署应用与后续迭代从检测框到可用地址6.1 检测OCR联动的落地链路模型训练完只完成了第一步。业务系统真正需要的是一个字符串“XX路XX号”所以需要把“门牌号检测”和“文本识别”串起来。标准链路是检测模型输出每个门牌号的边界框裁剪出对应小图再交给文本识别模型。识别模型我直接用了训练好的PaddleOCR没有自己重新训因为门牌号字符集就是数字和少量字母、中文通用OCR已经能覆盖。这里关键的一步是后处理检测框经常会把“XX路XX号”里的路名也框进来需要在文本清洗时只保留数字和必要的连接符比如“12-203”保留“XX路”去掉。全角数字转半角、剔除乱码字符这些细节也不能省。有了识别结果再和逆地理编码返回的道路信息做拼接比如逆地理编码给到道路名“建设路”识别结果是“12号”最后就能产出“建设路12号”这就是一个可以直接用于地址库更新的结构化字段。6.2 实际部署中的失效模式部署之后一定要监控失败样本。我跑了三周发现失效模式主要集中在三类一类是夜间灯箱门牌。灯箱周围的光晕会让检测框偏大OCR识别时把发光边框也当成字符的一部分读出一堆乱码。解决办法是在识别前对裁剪图做二值化预处理或者提高检测框的IoU阈值。二类是老旧墙面上的手写门牌。这类门牌颜色和墙面接近检测模型容易漏检。在部分区域可以接入多帧融合连续几帧都检测到相似位置的疑似门牌就视为候选再用OCR确认。三类是商店招牌上的电话号码被误检成门牌。因为它们也是一串数字、也是贴在临街墙面特征非常接近。处理方式是在数据集中加入“广告牌电话”负样本让模型学会区分“门牌号”和“非门牌号数字区域”。这也是为什么我在标注时花了很多精力去清理干扰项负样本的质量直接影响这个问题的严重程度。6.3 后续扩展方向这套数据集和训练流程做扎实之后后续可以往几个方向扩展。一是做多任务模型在检测门牌号的同时预测门牌的背景类型和字体属性用这些属性辅助文本识别和后处理。比如识别出背景是玻璃就可以针对玻璃反光做专门的数据增强。二是跨城市泛化。门牌号的形态在不同城市差别很大可以按城市划分出测试集专门评估模型在没有见过的新城市里的表现用结果指导数据采集方向。三是尝试端到端方案。检测OCR串联链路有一个问题门牌框和文本之间是割裂的一旦检测框不准识别结果就崩。后续可以尝试把门牌号检测做成旋转框检测或者直接用多模态模型把“找门牌号读文字”合并成一个任务。这些方向都需要在数据集层面提前布局多保存原始图像和结构化标注别急着把中间产物删掉。我个人在这套流程里最深的体会是数据集的构建过程不是一个一次性的“体力活”它更像是给模型做一套量身定制的训练环境。标注规范、清洗策略、样本均衡这些环节每一个单独拿出来都不难但放到一起就决定了模型最终的上限。门牌号数据集尤其如此目标小、场景杂、文本信息又极其敏感不在数据层面死磕后面无论怎么调参都是在浪费时间和算力。本文还有配套的精品资源点击获取
返回列表