☰
无人机俯拍下的占道经营识别:YOLO数据集构建与模型训练实战
2026/10/21 23:04:17 网站建设 项目流程

去年在某片区试点无人机街道巡检,第一次拿到那批正射影像的时候,我其实有点傻眼。从百米高空往下看,整条商业街的摊位、遮阳伞、行人全都叠在一起,跟地面摄像头拍到的画面完全是两个世界。地面相机能看清人脸、招牌、货架上的商品,但无人机拍到的更多是一个个俯视的轮廓。那些平时一眼就能认出来的“占道经营”,在俯视图里需要重新学习。这篇想聊的就是这个项目里的核心部分:用无人机俯拍数据训练YOLO识别模型,以及为了支撑这套模型,前后整理的一万多张街道航拍图、十几万个标注框所踩过的各种坑。项目代号按我们的数据期数来算,刚好可以叫第10437期,内容涉及占道经营识别、数据集构建、模型训练和实际部署,适合正在做智慧城市巡检、算法岗或者无人机应用落地的朋友参考。

1. 先想清楚:无人机俯拍的“占道经营”到底长什么样

1.1 视角变了,目标的定义就得变

地面摄像头视角下的占道经营是什么?通常是行人视角或者斜仰角,能看清摊位的立面结构,比如货车车厢打开、货架层板、挂着的商品袋、摆出来的路牌,甚至能看清摊主的动作。这类数据在以前的监控识别里积累了不少成熟方案。

但无人机是正射视角或者接近正射的斜视视角。你在图上能看到的,是一个摊位的“顶视图”:遮阳伞的圆形轮廓、推车的矩形边框、塑料凳和货箱拼成的块状区域、铺在地上的花色布面。这些东西远远不如立面特征那么“有辨识度”,尤其是当树荫、高楼投影、车辆遮挡叠在一起的时候,单个目标经常只剩半截轮廓。

所以做这个项目的第一件事,不是急着拉框训练,而是重新定义“占道经营”在俯视图里的可视化特征。我当时的做法是把目标拆成几个可标注的组成部分:

  • 货架或摊位主体:这是最核心的目标,对应桌子、推车、柜体等有明确边缘的物体
  • 遮阳伞或雨棚:往往比摊位本体大,颜色鲜艳,特征突出,但容易和正常停放的遮阳伞混淆
  • 外摆货物堆:包括纸箱、水果筐、塑料箱等,通常成团出现,边界不一定整齐
  • 三轮车:既是运输工具,也是常见摊位载体,在俯视图里呈现为带有车厢的矩形
  • 聚集人群:这个不是“占道经营”本身,但行人聚集密度和摊位活跃度强相关,可作为辅助判断信号

这个类别设计不是拍脑袋定的。我做过三轮对比试验:如果只用一个“vendor”大类去标所有摊位,模型收敛很快,但精度上限很低,因为雨棚、推车、货物堆的形态差异实在太大,模型被迫在同一个类别里拟合多峰分布;如果把类别拆得太碎,比如单独分“水果筐”“衣架”“烧烤架”,标注成本暴涨,而且相邻类别之间混淆得厉害。最后折中的方案就是上面这五类,既有区分度,又不会让标注员频繁纠结。

1.2 像素分辨率是绕不过去的第一道坎

无人机航拍图的GSD,也就是每个像素对应的地面尺寸,直接决定了你能否“看清”目标。我们当时的飞行高度在80到120米之间,搭载的是常见的1英寸传感器云台,出图分辨率约2000万像素,算下来GSD大约在8到12厘米每像素。这个水平下,一个2米见方的摊位至少能占到20到25个像素的宽度,对目标检测来说刚刚够用。

但这里有个坑:很多航拍任务为了追求拼图效率,会把重叠率调得很高,出图却做大幅压缩。压缩后的JPG如果质量系数低于85%,摊位边缘会出现明显锯齿,小目标的特征会糊成一片。我们在第10437期这批数据上的做法是全部保留原图输出,只对存储做无损压缩或者低压缩率的WebP转换。看起来只是存储成本的问题,实际上直接关系到标注质量和模型表现,前期这点不该省。

还有一点是关于“什么值得飞”。我们在试点过程中发现,并不是所有街道都适合无人机识别。新建的宽阔主干道,两侧退线空间充裕,占道经营的形态和地面无异;反而是老城区狭窄街巷、商业步行街、学校周边这些区域,摊位密集、遮挡复杂、目标尺度多变,数据价值最高。所以在规划飞行路线时,我会建议优先覆盖这些“高价值路段”,而不是平均用力。

2. 数据集这套“地基”是怎么打的

2.1 标注规范是如何从混乱到定稿的

第10437期数据集前后标注了不止一遍。第一遍用的是个人经验直接拉框,结果问题非常典型:三个标注员对“占道经营”的边界理解完全不同。有人把整条摊位连同后面的门脸一起框进去,有人只框商品覆盖区域,还有人把路边停着的小货车也当成摊位。

这个混乱其实源于一个核心问题:标注的到底是“行为”还是“物体”?占道经营是一种行为状态,但检测模型只能看到静态对象。最终我们定的规则是“框可识别的实体,而不是框行为”。也就是说,模型的任务是找到“疑似经营设施”,是否真的构成占道,在业务侧再结合位置信息判断。

具体标注规则可以给大家参考:

  • 摊位主体框定其可见的顶部轮廓,不包含后方建筑门脸,也不包含夸大延伸的地面阴影。
  • 遮阳伞/雨棚独立标注,即使它紧贴摊位主体;因为它在俯视图中的视觉特征太强,和摊位合并反而会稀释特征。
  • 严重遮挡的目标,只要有可见部分超过整体三分之一,就标出来;低于这个比例的归入“难例”清单,暂时不标。
  • 三轮车和摊位重叠时,两者的框都保留,交叠区域不做避让,交给模型自己去学。
  • 目标出现在图像边缘,如果超过一半的面被切掉,不标;小于一半被切掉,可以标。

这套规则出来之后再返工,质量明显提升。还有一个提升效率的技巧:先让YOLO预训练模型跑一遍初检,生成一批候选框,标注员在候选框基础上做修改,而不是从零开始画框。一轮下来单人每天的标注量至少翻了一倍,而且边界一致性更好。

2.2 训练集、验证集、测试集的划分差点翻车

做目标检测的人都知道数据要划分,但这个项目里的划分方式暗藏风险。无人机巡飞是按航线连续拍片的,同一家摊位会出现在连续好几帧图像里,相邻帧之间的重叠度很高。如果随机划分数据集,同一摊位的不同帧会同时进入训练集和验证集,验证指标会虚高——模型实际上“见过”这些目标,只是换了位置和角度而已。

这属于典型的数据泄漏。处理办法是按“空间连续段”分组,不能按单张图划分。我们把同一航线段连续拍照形成的图像序列归为一组,整个组只能落在训练、验证、测试三者之一。这样一来,验证集里的目标跟训练集里的目标真正来自不同的地段和不同的拍摄批次,评估结果才可信。

另一个要刻意控制的是拍摄条件的分布。无人机数据在不同季节、不同时段拍出来的差异非常大:夏季遮阳棚密集,冬季以推车和临时帐篷为主;白天阳光下阴影清晰,傍晚灯光亮起后目标轮廓会变化。所以第10437期里面的时段分布我是盯着比例来的,白天正常光、清晨逆光、夜晚辅助光照、阴天漫射光几类都要覆盖,不能让某一种光照占绝对主导。最终训练、验证、测试的比例稳定在8比1比1,但验证集里会保证每一类光照至少出现一次。

2.3 负样本和难例,比正样本更费心

很多人做数据集只关心正样本够不够多,但在这个场景里,负样本直接决定了上线后会不会被误报淹没。街道上有太多和“摊位”长得像的东西:遮阳伞下的露天餐饮座、快递驿站门口堆的包裹、人行道上临时放置的施工围挡、甚至排列整齐的环卫垃圾桶。

我们专门建了一个负样本池,里面是不包含任何标注目标的航拍片段,数量大概有三千多张。这些负样本单独参与训练,相当于告诉模型:“长成这样不是摊位,别报警。”效果立竿见影,早期误报率下降了四成。

难例处理就更考验耐心了。我会定期跑一次批量推理,把置信度在0.2到0.5之间的“模糊样本”全部捞出来,人工逐张看。这些不是简单标注错,而是真的像——比如一把红色的遮阳伞正下方停着一辆银色面包车,遮阳伞本身不构成经营,但视觉特征和一个摊位的顶视图非常接近。这类样本我们会单独归档,作为后续迭代时重点关注的案例。

3. 用YOLO训练识别模型时,参数和策略上的决定

3.1 模型规格和输入分辨率:为什么选了YOLOv8x和1280分辨率

模型选型上,一开始做实验用的是YOLOv8n,训练速度快、部署简单,但精度在无人机这种小目标场景里不太够。后来我测试了n、s、m、l、x五个规格,在最难的那批夜间数据上,小目标召回率从n到x整整提高了约17个百分点。代价自然是推理速度,不过在无人机巡检这种离线后处理为主的场景里,速度压力其实远小于实时视频流,x规格完全可行。

输入分辨率方面更是不能省。默认的640乘640会把很多目标压成极小的像素块,信息丢失严重。我直接把训练和推理分辨率统一提到了1280,这个选择的理由很直接:早期飞行数据的GSD按10厘米每像素算,一个2平米摊位在1280分辨率下还有40像素以上的尺寸,特征足够模型学到;如果继续拉到1920,精度提升已经不明显,但显存占用和推理耗时都会大幅增加,不太划算。

还有一个小细节:训练时输入分辨率统一为1280,推理切图时也要保持1280,不能说训练用大图、推理用小图,也不会说训练用小图、推理用大图。我见过不少项目在这一点上不一致,结果精度上下浮动得很厉害。

3.2 Mosaic增强在小目标场景下需要调低

YOLO默认的Mosaic增强把四张图拼接在一起训练,对大目标检测效果很好。但放到无人机俯拍这种以小目标为主的数据上,Mosaic会不断把目标缩小,因为拼接后每张子图按比例缩小了。目标本来就只有二三十个像素,Mosaic一缩,直接变成十几个像素,特征近乎消失,模型很难学到有效信息。

这是我第一次训练精度卡住不动的核心原因之一。调整方式是把Mosaic关闭,或者把概率从默认的1.0降到0.2左右,同时开启Copy-Paste增强。Copy-Paste能把小目标原尺寸粘贴到其他图上,对密集小目标场景特别友好。改完之后验证集mAP涨了大概4个点,解决得很明显。

另一个值得开的增强是随机裁剪局部放大。无人机大图里往往有相当一部分区域是没有目标的道路、屋顶、绿化带,直接整图训练会浪费时间。按1280窗口滑切后,再做一定比例的“目标密集区域放大”增强,相当于人为制造了一批更大尺度的样本,能帮助模型适应不同飞行高度带来的视角差异。

3.3 训练过程里的loss曲线和参数调整教训

我用的超参组合是batch size 16、epochs 300、cosine学习率衰减、AdamW优化器。这个小目标场景里,300轮看起来多,实际要到第220轮左右mAP才进入稳定平台期,早了容易欠拟合。

训练过程中最值得盯的其实不是总的train loss,而是拆分出来的box loss和cls loss。我碰到过一次box loss在训练后期反复震荡的现象,排查下来是部分标注框边界不齐导致的——有些标注员在树荫遮挡边缘习惯多扩一两像素,同一个目标的框在不同帧里宽窄不一。模型在拟合这些嘈杂的坐标时会来回摆动,表现为box loss震荡。

处理方法是重新校准了一批模糊边界样本的标注框,并统一了“以可见轮廓最大内接矩形为准”的规则。重新训练后,box loss曲线平稳很多,最终验证集上的mAP@0.5到了0.91,mAP@0.5:0.95大概0.67。

还必须说一个评估上的习惯:我最开始只盯着mAP看,后来加入了一个“业务阈值下的精确率和召回率”指标——也就是固定置信度阈值的情况下,看实际输出结果中有多少值得人工复核、真实目标被漏掉多少。mAP高不代表部署好用,毕竟业务不是看曲线,而是看每张图弹出来的框到底准不准。

3.4 推理阶段的切图与拼接

无人机原图通常有几千乘几千像素,直接整图推理会爆显存,而且目标在缩放后太小。不得不把大图切成瓦片推理,然后再拼回坐标。切图重叠率我建议至少25%,避免目标恰好卡在瓦片边缘被切开。

按1280分辨率、30%重叠来切,一张典型的航拍正射影像会切成几十片。每片单独跑模型推理,再把所有检测框映射回原图坐标做NMS去重。一个坑是:同一个目标如果在相邻瓦片的重叠区被检测到两次,两个框的位置会略有偏移,如果最后NMS的IoU阈值调得太严,会出现同一个摊位输出两个框的情况。我们的做法是IoU阈值设在0.4,并且对边缘处的检测框降低置信度权重,这样处理下来重复框的情况基本消除。

4. 上线后哪些误检最让人头疼

4.1 路灯、树影、地面标线:夜间模式下的“幽灵摊位”

白天的模型迁移到夜间数据上,暴露出来的问题比想象中多。首先是路灯杆:杆身和灯臂的组合在俯视角度下,加上灯光照射形成的圆形光晕,和一把撑开的遮阳伞外形非常接近。初期夜间测试中,路灯的误检数量能占到全部误检的三成。

树影也是个大麻烦。茂密树冠在路灯照射下投射到地面的阴影,边缘有弧形边界,中心颜色深,形状经常被模型当成货物堆或者摊位。

这些问题的本质是模型没有见过“夜晚版本”的街道环境。解决办法没有捷径,只能补充夜间数据。我们专门安排了几次黄昏和夜间巡飞,把路灯、灯牌、地面反光这些场景逐步加进负样本和正样本;同时在后处理阶段加了“灯光区域掩模”的逻辑,对检测框中心和已知路灯坐标距离过近的结果做降权处理,类似“这个位置不可能是摊位”的先验过滤。叠加这两层之后,夜间误报率降到了可接受的范围。

4.2 高楼投影和车辆遮挡:目标“不完整”时怎么办

老城区的另一个老大难是高楼遮挡。上午和下午,高层建筑在地面投下长阴影,被阴影覆盖的区域对比度极低,摊位、行人的轮廓完全淹没。正午时分阴影最短,但摊位会被道路两侧停放的车辆遮挡——在俯视图里,一辆面包车停在摊位旁边,直接截断了摊位将近一半的面积。

这种情况下强行让模型把残缺目标检测出来是不现实的。我的处理是“移交跟踪逻辑”:不用单帧识别硬扛,而是把连续多帧的检测结果做时间维度的关联。同一个目标在某一帧被完全挡住,但在前后帧里可能露出主体,通过IoU和位置连续性追踪就能补全。

在业务侧,这个思路也打通了一个卡点。以前是“检测到目标才上报”,现在变成“对同一个疑似目标在连续帧中至少命中两次以上才上报”。误报率降了,漏报也减少了,因为不再依赖单帧的偶然性。

4.3 大图切块与多尺度目标的分配

处理航拍原图时,还有一个经常被忽视的问题是目标尺度差异。街道尽头靠近无人机正下方的目标比较大,画面边缘由于斜视关系目标被拉长变形,尺度差异可以到三倍以上。用单一分辨率推理,必然顾此失彼。

我用的是多尺度推理:对同一张瓦片同时跑1024和1280两种分辨率,把两组检测框合并之后再NMS。代价是推理时间增加了大约40%,但换来了边缘目标的召回率明显提升。特别是在斜视严重的画面边缘,1280分辨率下的小目标特征清晰很多,漏检率下降得比较实在。

5. 模型上线只是开始,数据迭代才是真正的护城河

5.1 每一次巡飞都要变成下一次训练的新样本

模型不是训练完就能一劳永逸的,尤其在这种高度依赖街景变化的场景。店面的装修风格会变,摊位的形态会随时间演变,季节更替会带来全新的遮阳设施。所以我在设计流程时,特意把“巡飞数据回流”做成了常规动作。

流程大致是这样的:无人机完成巡检后,图像数据进入预处理管线,先做去重抽帧,然后做一次已有模型的批量推理,把置信度低于阈值但又不是零的“弱目标”区域自动裁剪出来,进入人工审核队列。审核员只做一道题:“这张图里有没有疑似摊位设施?”有就入库待标注,没有就归类为负样本。整个周期做到月级别的迭代:每个月用新增数据做一次增量训练,再跑一遍回归测试,把模型版本更新上去。

这套流程看似简单,实际最难的是坚持。因为城市管理场景里,真正新增的硬样本可能一场巡飞只有几十张,完全不值得单独训练。但只要坚持季度级别的积累,连续两三个月的样本汇总下来,对模型在换季场景下的表现提升非常明显。

5.2 模型版本和数据版本都要可追溯

试运行阶段我们吃过一次大亏:一个调整过负样本池的数据版本,和一个旧模型参数被混在一起,导致一周的巡检结果整体偏离。排查了很久才发现是版本管理混乱。

从此以后,每次训练我都要固定三个版本号:数据版本、模型配置版本、训练代码版本。数据版本对应到具体的标注批次;模型配置版本包含超参数、数据增强开关、分辨率设置;训练代码版本防止代码回退导致结果不可复现。上线前还要跑一遍固定的扣留测试集,这个测试集长期不更新,专门用来监控模型是否出现退化。

5.3 后端流程和业务侧的证据闭环

识别系统在整个巡检流程里并不是终点,输出结果要和调度联动才有意义。我们的方案是:检测框附带GPS坐标、拍摄时间、所属航线段信息,自动生成一张裁剪出的目标快照,快照原图保存。处置人员拿到手的不是一个抽象坐标,而是一张可以直接判断现场情况的图片,还能通过相册时间线看同一位置过去一周的变化。

这个设计在业务侧很受欢迎——减少了大量“派人到现场确认”的环节。不过也要提醒一下:自动识别始终是辅助手段,最终认定需要人工复核,检测结果只作为线索,不作为处罚依据。这个边界从一开始就要定清楚,否则系统在业务侧会失去信任,一旦有一次明显误判,用户就对整个系统持怀疑态度。

5.4 回看这个项目,我会调整的几件事

如果要重来一遍,我会把更多时间花在数据规范上,而不是模型调参上。模型从0.85到0.91的精度提升,大部分靠的是数据修正,而不是算法优化。

具体来说,第一是标注规则的“最小化原则”要更早落实。宁可让标注员少框一点,也不要超框,因为超框会让模型学到背景噪声。第二是负样本池要动态维护,每跑一轮模型,就要把新的误检当成负样本补进去,形成负反馈循环。第三是巡检航线规划要对“典型困难路段”做定点热力覆盖,而不是每次均匀扫描,特别拥挤的老街、餐饮集中的夜市场、学校周边的高峰时段,这些场景的数据价值是普通路段的数倍。

这个项目做到现在,我最深的体会是:无人机视角下的占道经营识别,真正的技术难点不在“识别”,而在“定义”。定义清楚什么该框、什么不该框,定义清楚训练和验证的边界,定义清楚识别结果在整个业务流程里的位置,这些事情全部打通之后,YOLO训练本身反而是最轻松的一环。后续如果有新变化,我会优先考虑在业务侧的数据回流机制上继续优化,争取把模型的更新周期缩短到两周以内。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询