☰
无人机视角河道违建检测数据集:VOC+YOLO双格式构建全复盘
2026/10/21 15:08:36 网站建设 项目流程

接手这个河道巡检项目时,我第一件事不是打开训练脚本,而是先把已有航拍图片从头翻了一遍。翻完之后说实话有点泄气——河道两边的违规建筑,和普通农房、集装箱、临时工棚混在一起,从无人机视角往下看,大多数目标都小得可怜,有的整栋建筑只占画面宽度的3%左右,人眼不放大都容易漏。这也让我意识到,项目能不能做成,关键不在模型训练那一步,而在于有没有一份真正贴合“无人机视角+河道场景”的违规建筑数据集。这次要聊的,就是一份“无人机视角智慧河道巡检河道违建检测数据集”,VOC+YOLO双格式、1034张图片、1个类别,从数据整理到格式转换、从训练参数到踩坑实录,完整复盘一遍。

这份数据集解决的最核心问题很直接:给目标检测模型提供“什么算违建、违建长什么样”的样本。它适合三类人参考:一是做水利信息化或者智慧城市巡检的算法工程师,二是刚入门目标检测、想找一份结构清晰的双格式数据集练手的学生,三是负责无人机巡检业务落地、需要评估数据价值的项目管理人员。接下来我按实际做项目的顺序来拆解。

1. 这份数据集解决的是什么问题

1.1 河道巡检的痛点不在“航拍”,而在“看完这些照片”

很多没真正跑过河道巡检项目的人,会以为难点在无人机飞行本身。其实飞起来太简单了,设定航线、一键起飞,一个上午能拍完几十公里河道。真正的瓶颈是数据回来之后怎么办。一段10分钟的视频抽帧出来可能有一千多张图片,一个中等规模的河段巡检任务往往积累上万张照片。让巡查人员一张张看,眼睛很快就花了,而且人眼在连续看几百张高度相似的河面图片之后,对异常目标的敏感度会急剧下降。我印象很深的是项目初期做人工筛查,一个经验丰富的巡查员一天最多认真看完两千张图,再往后基本就是在“完成任务式”地翻页。

河道违规建筑在无人机视角下有很强的特殊性。它不像道路上违章停车那样轮廓清晰、形态统一,而是各种形态都有:河滩上的彩钢瓦棚子、河道管理范围内的活动板房、岸边堆料场边的临时砖混房,甚至还有用防水布搭的半永久棚。这些建筑从正上方看,轮廓不规则,颜色和泥土、植被、硬化地面混杂在一起,加上水面的反光、树冠的遮挡,背景复杂度比一般的地面目标检测场景高不少。

这种情况下,目标检测模型的价值就体现出来了。模型可以不知疲倦地处理一万张图,把疑似目标框出来,把“人眼盯图”变成“人审模型结果”,巡检效率能提升一个量级。但模型要用起来,前提是有一份和真实业务场景同分布的数据集来训练和验证。如果拿通用目标检测数据集(比如日常物体检测那种公开数据)直接训练,效果会非常差,因为无人机俯拍视角下的建筑形态、尺度、背景和普通地面视角完全是两个世界。这份数据集的价值,正是补齐了“无人机视角+河道场景+违规建筑”这一特定组合的样本缺口。

1.2 数据集规格与适用范围

先看整体规格,我用表格列一下核心信息:

项目内容
图片数量1034张
目标类别1类:违规建筑/河道违建
标注格式VOC XML + YOLO TXT 双格式
适用算法Faster R-CNN、SSD、YOLO系列、MMDetection等
采集视角无人机俯拍/倾斜俯拍
场景覆盖城市河道、乡村河段、河滩、岸边管理区

单类别检测看起来比多类别简单,但实际做下来会发现,类别少反而让标注标准更关键。因为就一个类别,漏标一个目标、多标一个误框,对模型的影响都是直接的。前面说了,这个数据集包含1034张图片,属于中小规模数据集。训练一个基于预训练权重的YOLO模型完全够用,但要达到很高的泛化能力,后续还得结合数据增强和迭代扩充。

适用场景上,这一类模型可以直接用于无人机实时巡检的违规建筑初筛,也可以部署到后端服务器做批量排查。如果你做的是“岸线占用检测”“河道违章建筑识别”这类业务,这个数据集可以直接当训练集跑一轮;如果你做的是更细的违建分类(比如区分违建类型),这个数据集可以作为负样本或基础检测的前置模型数据。

2. 数据集的构建流程:从原始航拍到可用训练样本

2.1 数据采集与初筛:视频抽帧比单张拍摄更高效

无人机巡检数据的采集,我强烈建议用视频录制后抽帧的方式。实际飞巡检航线时,一个架次可能覆盖好几公里河道,如果用连拍照片的方式,存储压力大,而且很容易把大量相似画面存下来,浪费标注时间。视频抽帧的好处是可以按需控制抽帧密度——直飞段每隔3到5秒抽一帧,在疑似违建区域悬停或减速飞行时,可以更密集地抽帧。一份5分钟的4K视频,按每秒1帧抽,能拿到300帧,挑出其中画质合格、目标有代表性的50到80帧,比直接拍几百张照片要高效得多。

初筛阶段必须做三件事。第一是剔除模糊帧,无人机飞行中抖动、转弯、快速变焦都会导致画面模糊,这类图直接删掉,否则标注时边界框都没法画准。第二是剔除大面积无目标帧,如果一张图里只有水面和植被,完全没有建筑类目标,从训练角度看价值不大,保留一部分负样本让模型学“什么是背景”是必要的,但比例要控制,整份数据集里纯背景图我一般控制在10%以内。第三是检查色彩一致性,不同无人机、不同天气拍出来的图色调差异可能很大,如果数据集里全是晴天正午拍的图,到了阴天部署效果就会崩,初筛时要有意识地保留不同光线条件的样本。

2.2 标注目标怎么定义:别小看“1个类别”

标注之前有个问题必须先回答清楚:什么算违规建筑?这个不定义清楚,一百张图之后标注标准就会飘。业务上说的河道违规建筑,指未经批准在河道管理范围内修建的建筑物、构筑物。但落到图像上,这个定义需要转化成视觉可判别的规则。

我的标注规则是这么定的:凡是出现在河道管理范围内的彩钢瓦棚、活动板房、砖混房屋、简易搭建物,只要不是明显作为水利设施(闸房、泵站)或桥梁道路结构存在的,都标为违规建筑。同时,对于有争议的目标——比如一半被树冠遮挡的棚子、已经明显废弃坍塌的建筑物,标注时宁可不标也不要标错。这个“宁缺毋滥”的原则在单类别数据集里尤其重要,因为误标一个目标会把模型的置信度判断带偏。

标注矩形框时也要讲究。无人机俯拍视角下,很多建筑是倾斜的,矩形框应该贴着建筑主体的外轮廓,把完整的建筑实体框进去,但不要为了把周围散落的杂物也包进去而扩大框。扩大框本身不痛不痒,但会让模型学到“违建周边包含大量背景”的错误模式,在推理时框就会偏大,业务上就会把很多非目标区域圈进来。标注工具我用的是LabelImg,小巧直接,打开图片、画框、输类别名、保存XML,一天标两三百张是正常速度。如果有熟悉X-AnyLabeling的也可以用,支持交互式分割辅助标注,效率会高一些,但对电脑配置有点要求。标注完成后还需要至少找另一个人花半天时间把全部图过一遍,重点检查两类问题:漏标的目标、边界框严重偏离实际轮廓的目标。这种双重复核非常必要,一个人连续标注久了,标准会不知不觉偏移。

2.3 数据增强策略:1034张的样本如何扩大有效性

1034张图在深度学习项目里,属于“能跑通但不够富余”的规模。要让模型训得稳,数据增强是必须做的。但增强不是越多越好,要贴着业务场景来。

几何增强方面,我个人建议做水平翻转、随机旋转(10度以内小角度就行,旋转太大会把矩形框的语义搞乱)、随机缩放。色彩增强方面,HSV色域扰动是标配。因为无人机在不同光照下拍出来的色调差异很大,模型如果能对色偏鲁棒,实际部署时就不容易被傍晚的暖光、雾天的灰蒙影响。Mosaic增强(把四张图拼成一张训练)对改善小目标检测很有帮助,这个在YOLO系列里已经是内置选项了,可以默认开启。

不过有两点要注意。第一,验证集不要做任何增强,用原始图片验证,否则指标虚高,部署时对不上真实效果。第二,增强策略里不要加入“随机裁剪”这种容易把目标切坏的增强——无人机俯拍下的建筑经常贴着图边缘,随机裁剪很容易把半个建筑留在图里,标签坐标倒是会自动调整,但语义上你等于给模型看了大量“半截建筑”,反而增加误检。切分数据集时,像这种同一条河道连续帧抽出来的图片,要放到同一个集里,不要让训练集和验证集出现场景重叠,否则验证结果会显得比真实情况好很多。

3. VOC和YOLO双格式的核心差异与转换落地

3.1 两种格式到底差在哪

数据集的工程价值很大程度上体现在格式上。VOC格式和YOLO格式是目前目标检测领域最常见的两种标注格式,它们的底层表达方式差异很大,了解这个差异才能正确写转换脚本。

VOC格式本质是一个XML文件,里面保存着图片尺寸、目标类别、边界框的绝对像素坐标。边界框用xmin、ymin、xmax、ymax四个值表示,单位是像素。好处是直观、可读性强,用ET库解析或者直接打开看都能理解;坏处是文件体积大、解析速度慢,在训练管线里不够高效。

YOLO格式则是一个纯文本TXT文件,每一行描述一个目标:类别ID、中心点x坐标、中心点y坐标、宽度、高度。这里的坐标全部是归一化的,范围是0到1,即用绝对像素坐标除以图片宽高得到。这样做的好处是模型输入图片尺寸无论怎么变,标注都不需要跟着改,训练管线读取效率高。坏处是普通人直接看TXT文件很难理解里面数字的含义。

人工标注阶段用VOC格式,因为可读性最好、工具支持最多;模型训练阶段用YOLO格式,因为效率和框架兼容性最高。准备一份VOC+YOLO双格式数据集,就是让你从标注到训练之间不需要再回头做格式适配,直接可以开训。

3.2 格式转换脚本的完整实现

转换脚本我用Python来写,核心逻辑是解析XML里的目标框坐标、归一化后写入TXT。下面是完整实现,这个脚本可以直接复用到你自己的数据集上:

import os import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, output_dir, class_names): """ 将单个VOC XML标注文件转换为YOLO TXT格式。 class_names: 类别名称列表,顺序决定类别ID。 """ os.makedirs(output_dir, exist_ok=True) tree = ET.parse(xml_path) root = tree.getroot() img_name = root.find('filename').text img_w = int(root.find('size').find('width').text) img_h = int(root.find('size').find('height').text) yolo_lines = [] for obj in root.iter('object'): name = obj.find('name').text.strip() if name not in class_names: continue class_id = class_names.index(name) box = obj.find('bndbox') xmin = float(box.find('xmin').text) ymin = float(box.find('ymin').text) xmax = float(box.find('xmax').text) ymax = float(box.find('ymax').text) # 边界保护,防止坐标越界或负值 xmin = max(xmin, 0) ymin = max(ymin, 0) xmax = min(xmax, img_w) ymax = min(ymax, img_h) x_center = (xmin + xmax) / 2.0 / img_w y_center = (ymin + ymax) / 2.0 / img_h w = (xmax - xmin) / img_w h = (ymax - ymin) / img_h # 过滤异常宽高,避免写入无效标注 if w <= 0 or h <= 0: continue yolo_lines.append(f"{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}") txt_name = os.path.splitext(img_name)[0] + '.txt' with open(os.path.join(output_dir, txt_name), 'w', encoding='utf-8') as f: f.write('\n'.join(yolo_lines))

使用时只需要准备一个类别列表,比如这份数据集里就是class_names = ['illegal_building'],然后遍历所有XML文件调用函数即可。我在批量转换之后一定会做一步自动校验:写一个脚本检查转换出来的TXT文件里是否有越界坐标、目标数是否和XML一致、是否有图片文件但缺TXT或反过来有TXT但缺图片。这一步骤花不了十分钟,但能过滤掉大量低级错误。

代码里有两个细节我特别说明一下。第一,坐标边界保护不是多此一举,个别标注工具画框时鼠标稍微拖出图片边缘几像素,就会产生负值坐标,不修正的话YOLO训练时会遇到坐标归一化后小于0的情况,轻则警告重则训练报错。第二,过滤宽高为0的框很重要,有些XML里存在空目标框,训练脚本读到这种标注会计算出NaN损失直。

3.3 目录组织与训练前的三项检查

拿到双格式数据集之后,目录组织方式直接影响训练脚本能不能跑通。建议按下面的结构来组织:

dataset/ ├── JPEGImages/ # 原始图片 ├── Annotations/ # VOC XML标注 ├── ImageSets/ │ └── Main/ │ ├── train.txt │ ├── val.txt │ └── test.txt ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/

JPEGImages和Annotations是VOC格式的标准布局,images和labels是YOLO格式的标准布局。ImageSets/Main下的txt文件维护训练集、验证集、测试集的图片名列表。切分比例我建议按8:1:1或者8:2来,图片数量少的话,验证集和测试集的绝对数量一定要够用,我一般保证验证集不少于100张,太少的话评估指标波动会很大。

训练前有三项检查必须做。第一项,用脚本统计每个图片的标注数量,如果大量图片只有0个目标,说明负样本偏多,模型会倾向于全图输出低置信度,适当剔除一些纯背景图平衡一下。第二项,统计所有目标框的宽度和高度分布,用一个小脚本画出来看看小目标占比。无人机视角下违规建筑经常是宽高只占图片5%以内的小目标,这种目标比例高的话,后面训练就要考虑用更高分辨率输入。第三项,人工抽20张转换后的YOLO格式图,写个可视化脚本把归一化坐标还原到图上画框,确认转换没有坐标偏移。这个可视化检查永远比直接看数字靠谱。

4. 用这份数据集训练模型的关键参数与评估思路

4.1 模型选型:小模型不一定省心

基于这份1034张、1个类别的数据集,我实际测试过多个YOLO系列的模型。对于这个数据规模,我一向的建议是优先尝试中小型模型:YOLOv8n、YOLOv8s、YOLOv5s都是比较稳的起点。推理速度上,这些模型在一块普通消费级显卡上都能跑几百FPS,部署到边缘设备(比如机载的Jetson系列或者轻量级算力盒子)也能达到实时或准实时。模型越大,在数据量不变的情况下越容易在小训练集上过拟合,表现就是训练损失很好看、验证集mAP也不错,但一换场景就垮。

不过“小模型一定好”也是误区。如果实际部署设备算力比较强,或者你对检测精度要求高,YOLOv8m甚至YOLOv8l也可以试。在数据规模1000张出头的场景下,我建议的做法是直接用预训练权重做迁移学习,然后跑一组对比:同样的训练配置下,分别用n、s、m三个规格训一版,用相同验证集对比mAP和推理延迟。这个操作成本不高,但能帮你选出一个和你的算力、业务要求最匹配的配置,避免拍脑袋选型。

4.2 训练参数怎么定:imgsz 640还是1280

训练参数里,输入分辨率是第一个要决策的。默认的640x640对很多场景够用,但前面统计过,这份数据集里小目标占比不低,640输入下一个小目标只有20x20像素左右,特征很弱。我的实践经验是:如果显存够(8G以上),训练和推理都直接用1280x1280输入,检测小目标的能力提升非常明显。如果显存只有6G,那就用640x640把batch size调小一点,配合Mosaic增强,效果也能接受,千万不要在6G显存上硬开1280,不然batch size只能设为1,训练会慢到怀疑人生。

有了预训练权重后,我用YOLOv8的命令行训练方式跑,配置文件里主要参数这样定:

yolo detect train \ data=data.yaml \ model=yolov8s.pt \ imgsz=1280 \ epochs=120 \ batch=8 \ lr0=0.01 \ momentum=0.937 \ weight_decay=0.0005

epochs设120算是保守但稳妥的起点。数据量小,模型收敛快,太少的epoch可能还没充分学完特征,太多的epoch又容易过拟合。这个项目里我试过把epochs加到200,mAP不再提升,训练后期明显在拟合训练集细节了。batch大小根据显存调到能装得下为止,8是个安全值。lr0用默认的0.01就行,如果你用的是预训练权重,初始学习率不宜太大,0.01已经够激进,再大很容易造成前期震荡。

4.3 评估单类别模型时最容易忽视的指标

很多朋友看到单类别数据集,就觉得评估只看一个mAP够了。实际业务中,比我更关注的是两个细分指标:召回率和误检率。河道巡检场景里,漏检一个违建意味着这个点没被复查到,是实际管理上的漏洞;而误检顶多是给审核人员多一个需要确认的框,成本低得多。所以在训练目标上,我会偏向把Recall拉高,允许Precision稍微掉一点。

训练完看混淆矩阵时,我每次都会单独统计在“小目标”(比如目标面积占图片面积小于3%)这个子集上的召回率。这个指标在模型评估工具里不直接显示,需要自己写脚本按标注面积过滤统计。如果小目标召回率低于大目标,说明模型对远处、小尺寸建筑还是不敏感,可以尝试更高分辨率、更多小目标增强样本或者把推理时的检测阈值调低一些。阈值调低会引入更多误检,但在业务上可以用“人工复核”来兜底,巡检场景里这个取舍是合理的。

部署阶段我还会开一个“二次筛选”逻辑:模型输出所有置信度高于0.15的框(这个阈值远低于常规的0.25或0.5),让这些框进入人工审核列表。实际效果是每1000张航拍图会产生30到60个待人工确认的框,其中很多是误检,但漏检率极低。相对于让一个人全量看图,这个工作量已经降低了90%以上。

5. 基于这份数据集的实战踩坑记录

5.1 漏检的重灾区是“小目标”

我在第一次把训练好的模型放到真实巡检数据上测试时,发现一个让我很意外的现象:那些相对完整的大棚子、大工棚几乎都能正确检测出来,但违建中最常见的半简易建筑——河滩上那种10平米左右的小彩钢瓦棚、用铁皮和木头拼起来的临时小屋,漏检率非常高。回看数据集的标注统计,这类目标的框在640分辨率下只有40x40像素左右,特征信息很少。

解决这个问题的组合拳有三步。第一步,把训练输入分辨率从640提到1280,小目标对应的像素翻倍,模型能学到更多纹理细节,这一步效果立竿见影,小目标召回率提升了约10个百分点。第二步,在数据增强里增加“小块随机抠图放大”的操作,这是对小目标增强比较有效的手段之一。第三步,如果仍然不够,就把这类小目标单独多收集一些样本补进数据集,采样时特意找那些在画面里占比很小的违建图,让模型对“远处小建筑”的样本量不再稀缺。

5.2 误检来源往往是背景太“像”

另一个常见的坑是误检。我在某次巡检数据上跑模型时,发现一个很稳定的误检源:河道边的排水泵站和闸房。这些合法水利设施在外观上和违规建筑太像了,都是方正的小体量砖混或钢结构房屋,从无人机正上方看几乎没有区别。模型把它们框出来是合理的,但业务上就是误报。

这类背景误检,单纯加数据不一定能完全解决,因为合法建筑和违规建筑的视觉差异可能真的就体现在位置管理属性上,而不是图像特征上。我的处理办法是在模型后接一个位置过滤规则:提前录入河道管理范围内的合法设施点位,模型输出的目标如果和已知合法设施的重叠度超过一个阈值,自动丢弃。说到底,目标检测只能做到“视觉相似性判断”,业务合规性判断需要叠加地理信息。这也是在实际项目中很重要的认知。

5.3 跨区域泛化:这份数据集的边界在哪里

最后想聊一个很多人不会提前想到的坑。用这份数据集训练出来的模型,在采集数据的同一条河段上效果不错,但直接拿去给另一条不同地貌特征的河段检测,效果会打折扣。原因是不同区域的河道差异很大:北方一些河段两岸是硬化的堤防,建筑和堤岸边界分明;南方一些河段植被茂密,违建可能藏在竹林后面只露出一个屋顶尖;还有一些采砂堆场区域的临时建筑,密集而且互相遮挡,检测难度又不一样。

所以这份1034张的数据集更适合作为“基线数据集”,而不是“终点数据集”。项目落地时,需要在新场景里补充采集一批图片做增量训练,哪怕是补充一两百张新场景的标注图,都能让模型在新区域表现提升一大截。针对这种情况,我在实际项目里有一个经验:每到一个新区块,先飞一架次,收集几百张图片,让模型在这些图上做预测,再把高置信度框导出成“预标注”,人工修正后补入训练集,迭代三轮左右,模型在新区域的稳定表现就能达到可用水平。这个循环越跑越快,数据集的规模也会从1034张慢慢长大到几千张,泛化能力越来越稳。

我个人在实际操作中的体会是,数据集的价值不只在当前这一版,更在它的格式规范和迭代机制。VOC+YOLO双格式让团队里不同分工的人都能顺利接手:标注的同学用VOC对着图片检查没问题,训练的同学拿着YOLO直接跑脚本不用改代码。1034张、1个类别的规模看起来不起眼,但把“标注标准统一、格式切换顺畅、模型选型合理、评估指标贴合业务”这几件事做扎实,这套流程跑通之后,后面再扩充到多类别、多区域,都只是往管道里添数据而已。如果你正在做类似的项目,希望这篇复盘能帮你少走几步弯路。

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

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

立即咨询