无人机水流状态识别:7类分割数据集构建与模型训练实践

发布时间:2026/10/22 13:24:13
无人机水流状态识别:7类分割数据集构建与模型训练实践 干我们这行的都清楚水面看起来是一个样实际放到无人机视角上看远处翻涌的急流和贴着岸边缓缓流动的清水完全是两码事。前阵子我把手上这批无人机河流影像重新过了一遍把标注好的360张labelme格式数据整理成了一套可复用的水流状态识别分割数据集类别一共7种覆盖了从平静水面到剧烈白浪的常见水态。今天这篇就当是项目阶段总结把数据怎么来的、标注怎么定的、坑怎么踩的、模型怎么喂的都摊开聊一聊给准备做水域分割或者水情智能识别的人少走点弯路。这套数据集的定位很明确不做水陆分割而是专门做“水里面更细的分类”。也就是说模型要把一条河拆成不同水流状态的区域比如哪里是静水、哪里是急流、哪里出现了漩涡、哪里是跌水形成的白泡。360张图不少做分割数据集也基本够用尤其是配合预训练和增强之后能支撑起一个初版识别模型。适合读这篇的人包括无人机巡检工程师、做遥感AI应用的学生或研究员、还有搞数字孪生流域的团队。1. 项目概述与数据集设计思路1.1 为什么选无人机视角做水流类型识别传统的水文监测靠点位传感器和人工目视前者只能覆盖固定断面后者在宽阔水域或者危险河段根本没法靠近。无人机视角的天然优势在于“既高又稳”能在几十米到几百米的空中把一大段河道的水面纹理完整拍下来这恰好是水流类型识别最需要的全局信息。水面上的纹理直接反映了流速、水深和河床粗糙度例如平静水域表面光滑阳光反射呈镜面状急流区域因为流速大、紊动强水面上会形成密集的白色条纹和气泡。这些特征在无人机斜视或者俯拍视角下非常突出正好可以用图像分割模型逐像素区分。相比雷达测流等硬件方案纯视觉识别端的部署成本低、速度快而且能做到全河段覆盖和监测站点的定点数据形成互补。做数据集时我没有选普通网络图片而是全部用无人机实际航拍影像因为俯拍视角的透视关系、水面反光干扰、岸上植被遮挡等因素只有真实航拍数据才能包含。用网络上的平视摄影图训练换到无人机场景基本就废了。1.2 七类水流状态的定义与划分依据最开始我拿到一批河湖影像脑子里冒出来的分类维度可能有十几种比如按流速分、按水深分、按扰动程度分。但标注是最贵的类别定得越细不同标注员之间的扯皮就越多。最终我锁定了7类每一类在视觉上都有清晰的边界且在实际应用里面都承担着不同的水情含义。类别标识类别名称视觉特征典型成因与场景0背景非水体植被、河岸、砂石、桥梁、建筑等一切不属于水面的区域1平静水面表面光滑颜色均匀无明显纹路静水湖湾、水库库区、缓流河段2细微波纹有轻微起伏亮度有细小变化但无白泡微风作用下的开阔水面3规律流纹呈平行或带状纹路方向感明显均匀水深的顺直河道4急流/白浪白色泡沫覆盖纹理破碎且亮度高陡坡、浅滩、高流速区域5漩涡/回流呈环形结构水体旋转明显桥墩下游、河道弯曲与障碍物后方6跌水/水跃水面垂落伴随水花与强湍动拦水坝、落差处、阶梯状河床这里要特别讲一下类别0“背景”为什么单独列出来。分割任务的本质是像素级分类但无人机影像中河岸、植被、船只、桥墩会占据大量像素这些区域如果不单独标注模型就会把岸上纹理当成一种水流状态导致错误输出。所以我把背景强制纳入类别体系让模型先学会区分水与非水再进一步细分水内状态。那为什么不把“水草漂浮区”“泥沙浑浊水体”也加进来因为数据采集阶段碰到这种情况太少硬要凑成类别会导致样本极度不均衡。与其让模型在一个只有十几张图的类别上瞎学不如先集中精力把7类做扎实。后续如果扩充数据再考虑增加类别。1.3 数据集规模与格式选型360张影像labelme格式也就是每张原始图像对应一份JSON文件里面记录了每个多边形标注的形状顶点和类别标签。选择labelme作为中间格式主要原因是它轻量、灵活、对分割任务友好而且社区生态成熟转成COCO、VOC或者RLE格式都很方便。360这个数量不是随便拍的测试集而是我在数百张影像里逐张筛选、清洗之后的满足标注质量的有效帧。分割任务常见的数据量级从几百到几万不等如果是从零训练一个深层次模型360张确实偏少但在迁移学习场景下用预训练编码器加数据增强360张足够把水流状态分割的基线模型训练出来。我后面会把训练细节展开讲。用labelme还有一个现实原因我的标注团队分布在三台电脑上labelme是纯本地运行不需要搭建数据标注服务器任务下发放给每个标注员标注完把JSON文件收回来就行。对几十人规模的小团队来说这种离线模式效率很高而且不会受到网络同步冲突影响。2. 数据采集与预处理实操2.1 无人机采集参数与飞行规划采集是整个数据集质量的地基标注再认真原图糊了也是白搭。我当时用的是常见四旋翼无人机飞行高度定在50到120米区间。这个高度既能保证单张图像覆盖足够长的河道片段大约几十到上百米又不会让水面纹理小到无法辨认。飞行高度再低单帧覆盖太少岸线两侧的目标容易出框再高水面纹理出现混叠急流和波纹会分不清。云台角度我选择了两个方向正俯视90度和前下视约60到75度。正俯视视角最适合处理水陆边界和纹理分布前下视则能捕捉到跌水和波浪的高度信息两者混用可以增强模型对不同观察角度的鲁棒性。飞行航线沿河流行走保持侧向重叠率60%以上纵向重叠率70%以上这样相邻帧能覆盖同一水面区域的不同光照角度有利于后续做视频时序扩展。光照选择很关键。大晴天正午水面反光特别严重耀斑区域完全过曝细节丢失。我后来把采集时间限制在上午9点到11点、下午2点到4点此时太阳高度角适中水面的镜面反射会被压低波浪纹理和泡沫区域的对比度反而更高。如果一定要在中午飞就需要装上偏振镜。偏振镜能滤掉来自水面的偏振光代价是进光量下降约一档需要相应调整ISO和快门。飞行速度也要控制尤其在河道弯曲段无人机转弯时云台惯性容易造成画面倾斜或模糊。我设置的最大飞行速度是6米每秒拍摄快门不低于1/1000秒配合机械快门或者电子卷帘较小的机型基本能冻结住水面的瞬时纹理。2.2 图像筛选与清洗采集回来的原始素材往往超过一千张真正能进标注管线的只有一半左右。筛选标准有三条一是画面不能有明显运动模糊这在水面高速流动场景里很常见无人机对焦到远处山体时近处水纹就拖成一片二是不能有大面积高光溢出白色泡沫区域如果纯白到249以上的像素占比过大标出来也没法区分真实白浪和曝光过度三是同一河段尽量保留至少三张不同飞行方向或拍摄角度的影像防止模型产生视角偏向。我在清洗阶段专门写了一个小脚本统计每张图像的亮度直方图和拉普拉斯梯度方差。模糊图的Laplacian方差通常低于一个阈值直接淘汰。过曝图看亮度大于250的像素占比如果超过18%我会人工复核决定是否丢弃。这套流程做下来最后的有效帧基本都是纹理清晰、曝光均匀、内容多样化的。2.3 图像尺寸与存储格式统一不同无人机、不同相机设置拍出来的图像分辨率各不相同标注之前必须统一到一个标准。我采取的策略是长边缩放到1920像素短边保持原比例。这样做有三个好处一是减少标注时的大图卡顿labelme在打开四千万像素大图时会明显变慢二是统一分辨率能避免模型训练时因为输入尺寸差异产生大量resize变形三是为后续输出评估指标提供基准。统一后的图像保存为PNG无损格式labelme的JSON并不内嵌图像数据只保存路径所以图像文件、JSON文件必须保持同名且放在对应文件夹中一旦改名或移动路径JSON就打不开了。3. 标注规范与labelme使用详解3.1 labelme安装与基本操作标注工具不复杂Python环境下直接pip安装即可。用conda创建虚拟环境是必须的否则依赖冲突能让你折腾半天。下面是常见安装流程conda create -n labelme python3.8 conda activate labelme pip install labelme labelme打开后通过“Open Dir”指定图像目录labelme会自动加载目录下的图片。每张图需要按住鼠标沿着目标区域的边缘点击生成多边形顶点完成一个闭合形状后弹出标签选择框选好类别后自动保存到同名JSON文件。对于水陆边界不清晰的位置可以先将图像放大到200%到400%再沿着色差边缘逐点布置顶点。一个多边形至少需要6到8个点靠近边缘处点要密集一些曲线变化大的区域如果点太少转成mask后会出现锯齿或变形。3.2 七类别的标注策略与边界规定标注标准是整个数据集质量的生命线。对比几种分类最复杂的其实不是背景而是相邻流动状态之间的边界。第一条规定优先标注覆盖面积较大的区域。如果一块区域里夹杂着少量其他类别的碎片比如平静水面中心有一小块漂来的泡沫可以整体归入占优类别但前提是碎片面积小于该区域总面积的5%。如果大于5%就需要单独拆分多边形。第二条规定急流/白浪和规律流纹重叠时以“白色泡沫覆盖比例”作为判定依据。当一块区域内白色泡沫覆盖超过40%直接标为急流/白浪低于40%但有明显流向纹路的标为规律流纹。这条规则很有用因为流速和泡沫之间没有恒定公式可算只能用视觉上的可重复标准统一不同标注员的理解。第三条规定漩涡/回流往往依附于障碍物下游标注时要以螺旋结构的完整可见范围为准。如果中心水体都在图像范围内就把整个螺旋包括中心凹陷一起画进去。如果螺旋体部分在图像外宁可不标也不要把残缺区域硬标成漩涡否则模型会学着把画面边缘的某些纹理误判成旋涡。第四条规定跌水/水跃的边界从水面明显下垂处开始一直到水花溅落重新归于平面处结束。如果水花飞溅产生大量离散水珠这些水珠也纳入跌水类不要因为水珠不连续就拆成背景因为从图像上看它们依然是水体的一部分。3.3 LabelMe JSON的结构与转mask方法labelme生成的文件是JSON格式核心内容是“shapes”列表每个元素对应一个多边形包含label、points多边形的顶点坐标、shape_type通常为polygon。需要注意的是labelme默认将整张图的坐标记为绝对像素值不会自动归一化。这在后续转成mask时需要用图像宽高换算。实际训练分割网络时我们需要把JSON转成单通道索引图像或RGB标签图。可以用官方的labelme.utils.shapes_to_label函数示例代码如下import json import numpy as np import PIL.Image import labelme.utils def json_to_mask(json_path, img_width, img_height, label_map, output_path): with open(json_path, r, encodingutf-8) as f: data json.load(f) mask np.zeros((img_height, img_width), dtypenp.uint8) for shape in data[shapes]: label_name shape[label] if label_name not in label_map: continue label_index label_map[label_name] points np.array(shape[points]) # shapes_to_label返回的cls和lbl中lbl为每个对象的分层mask需要按label_index赋值 cls, lbl labelme.utils.shapes_to_label((img_height, img_width), [shape], {label_name: label_index}) mask[lbl 0] label_index PIL.Image.fromarray(mask).save(output_path)我习惯把label_map定义成label_map { background: 0, smooth_water: 1, ripple: 2, flow_lines: 3, rapid_whitewater: 4, vortex: 5, waterfall_jump: 6 }转出来的索引图再配合one-hot编码或者CrossEntropyLoss直接输入模型即可。要注意的是当同一像素被多个多边形覆盖时代码会由后遍历的形状覆盖先前的值所以标注时同一个多边形不能相互压叠。我要求标注员必须让每个多边形的边界要么闭合相接要么留至少2像素的间隙避免重叠标注导致mask里出现上一个类别的残余像素。这一步在多人协作时很容易忽略最后合并数据时要写脚本做像素级重叠检查。4. 数据质量保障与增强4.1 多人标注一致性校验360张图不是一个人标出来的而是三个人同时推进所以一致性校验不能省。我的方法分两层。第一层是标注员自检每完成20张图用脚本统计一下各类别的面积比例是否和人工预期相符如果某张图里急流类面积异常大要回看是不是把岸边砂石滩的纹理误标了。第二层是交叉抽检随机抽取15%的数据由第二人独立重新标注然后计算两类标注重叠区域的平均交并比mIoU。如果重叠部分的mIoU低于0.75就判定这批数据存在争议需要把标注员叫到一起重新看影像统一标准后再继续。我试过用像素级准确率来衡量标注一致性但像素级准确率会被大面积背景拉高参考价值不大。mIoU更合理因为它惩罚的是类别间混淆。在实际校验中最容易出现不一致的是“细微波纹”和“规律流纹”两者在俯视图里的差异比较微妙。后来我把细微波纹限定为波长较短、方向不明显的水面纹理把规律流纹限定为有连续长纹、方向一致性强的区域并把示例截图做进标注手册争议率立刻降了一半。4.2 数据增强策略360张原始图经过翻转、缩放、旋转之后一张图最多能变出8到12个新样本训练集规模能扩到接近3000张足够支撑一个轻量分割模型的基础训练。我会把增强分成几何类和色彩类两类分别处理。几何增强主要是水平翻转、小角度旋转、随机缩放、随机裁剪。水流状态本身没有朝向但无人机航拍时河道方向可能是任意角度所以水平翻转不会改变类别语义安全可用。旋转范围建议限制在±30度以内超过30度容易引入旋转插值导致的纹理混乱而且会把图像四角裁出过多非水域区域。色彩增强主要是亮度、对比度、饱和度的随机调整以及少量高斯噪声。水面反光程度变化很大这类增强能让模型对光照变化更鲁棒。但要注意的是不能做随机颜色翻转或者色调反转那样会把水面变成紫色、绿色完全脱离真实物理规律训练出来的模型一旦遇到真实河面误差会非常大。全部增强操作都要在RGB空间进行不要动到标注maskmask只做同步的几何变换。4.3 类别不平衡处理分割数据集极容易出现“背景占大头某一类占小头”的情况。我把360张图逐类统计了像素占比结果是背景约占整个数据集的65%平静水面约12%规律流纹约9%急流/白浪约6%细微波纹约5%涡流和跌水加起来不到3%。这个比例其实很符合实际情况背景区域天然较大而跌水和涡流在河段中只出现于局部位置。处理不平衡有两条思路。一条是数据层面给背景类做小幅裁剪把裁剪窗口强行集中到有水体纹理的区域相当于给模型“增加”少数类的训练权重。另一条是损失函数层面使用带权重的交叉熵损失或者用Dice Loss、Focal Loss让模型把学习重心放到稀有的涡流和跌水类上。我实际下来觉得Dice Loss搭配标准CrossEntropy一起用效果比单纯加权CE好。因为Dice Loss对类别无关天然能缓解不平衡。但Dice Loss梯度在某些极端情况下可能不稳定训练时要把它的权重因子调到0.3到0.5之间。5. 基于数据集的水流类型分割模型训练要点5.1 模型选型建议水流状态分割本质上是语义分割任务可选择模型范围很广。如果是做离线研究或者精度优先我推荐使用U-Net作为基线它在小数据集上非常稳健也可以直接上DeepLabV3或者SegFormer这些模型在公开数据集上的性能更强但对小数据集有过拟合风险。我的对比实验显示在360张原始图、未做大规模增强的情况下U-Net的mIoU能到68%DeepLabV3能到71%但DeepLabV3在训练集上的mIoU接近95%明显过拟合。增加增强后两者差距缩小到2个点左右所以我倾向于用小模型U-Net做产品化。如果是部署在无人机机载端或边缘计算盒子实时性优先可以考虑轻量化的MobileNetV3-Large结合ASPP头或者更极端的STDC网络。水流分割任务不需要极强的全局上下文边缘端的轻量网络反而能吃得住。5.2 训练流程与参数设置我采用的训练流程如下先把图像和mask裁剪成512x512大小再输入网络batch size为8初始学习率0.001采用Poly学习率衰减策略优化器使用AdamW权重衰减设为0.01。训练80个epoch前20个epoch只冻结编码器训练解码器之后解除冻结微调全部参数。数据划分上按图像文件夹进行随机划分其中70%训训练集15%验证集15%测试集。这里要强调千万别按像素划分要按图片划分因为同一张图的相邻像素高度相关混在一起会让训练集和测试集产生信息泄漏。评估指标除了mIoU还要逐类看IOU。我在测试集上得到的最终结果如下类别IoU背景96.2%平静水面85.7%细微波纹68.3%规律流纹72.5%急流/白浪74.1%漩涡/回流53.6%跌水/水跃48.9%涡流和跌水因为样本太少IoU偏低也在预料之中。后续要重点补充这两个类别的图像和标注而不是单纯堆总图数。如果总图上去了但这两类不变mIoU还是上不去。5.3 后处理与结果应用模型输出的置信度图转成最终掩膜后还会有一些零散的小区域误报。我用连通域面积过滤法凡是面积小于30像素的预测连通域一律剔除并把它们合并到周围最大的类别区域里。这个操作能去掉水面反光碎片带来的误检但要注意不要用在跌水这种真实标签本身就有大量分散水花的场景上否则会把真实正样本滤光。涡流类同理涡流中心可能有一大块平静像素如果过滤掉中心区域反而破坏了整体结构。后处理完的分割结果可以直接叠加在原始影像上生成水流类型专题图。配合河道GIS矢量数据可以统计每条河段急流长度、漩涡数量与位置、跌水区域面积等指标这些对水电站生态流量监测、河道救援风险等级评估、水上搜救路径规划都有直接参考价值。更进一步把多帧时序分割结果串联起来还能追踪漩涡的生消过程和白浪面积的变化趋势形成动态水情特征。6. 常见问题与避坑指南6.1 labelme格式相关的坑labelme格式本身很简单但用的过程中至少有四种坑我全遇过挨个说一下。第一个坑是路径分离。labelme的JSON中保存了imagePath默认是文件名而不是绝对路径。但如果有一次用Open File而不是Open Dir打开图片imagePath可能变成绝对路径。后续转格式时脚本通过拼接目录加文件名去读图就会失败。解决办法是统一用Open Dir操作并在切分数据时重写imagePath为相对路径。第二个坑是中文图片名。Windows系统下labelme可以正常打开中文图片但生成的JSON编码有时和后续代码默认的utf-8不一致读取时会报UnicodeDecodeError。我直接把所有图像和JSON文件统一改名为纯英文数字的组合比如river_001.jpg、river_001.json省掉一堆编码问题。第三个坑是polygon顶点数量过多。如果标一个长条形水流区域标注员会习惯性沿边缘堆上百个点这在视觉上很平滑但转成mask后会让解码过程变慢甚至在某些转换工具里触发内存暴涨。我要求每个多边形顶点不超过80个如果超过就用贝塞尔曲线拟合简化或分段拆分多边形。第四个坑是labelme自动生成的“flags”字段。这个字段在官方示例中常被忽略但在某些旧版本中flags里保存了额外的标签信息。如果第二次编辑JSON时不小心修改了flags可能会把标签名污染。我的建议是不要使用flags只使用shapes里的label字段。6.2 无人机采集过程容易踩的坑有人会想当然认为无人机采集就是去河边飞一圈实际上现场的问题比想象中琐碎。水面对气流很敏感低空飞掠时无人机旋翼下洗气流会直接吹皱水面产生原本不存在的波纹。我试过一次低空5米悬停下方水面被螺旋桨气流打出一片密集波纹模型学到的特征和自然水面完全不同。解决方案是至少保持30米以上飞行高度或者选择顺风方向拍摄让气流带走的扰动落到下游。另一个问题是镜面反光。水面的镜面反射不是均匀的太阳方向对应的高亮区和阴影区亮度差异非常大。如果只在一个方向飞模型学到的水体颜色带会过于单一。我采用“Z字形”航线来回飞让同一段河面分别以顺光和逆光两轮覆盖。这样模型在训练时才能见到水面在不同的光照条件下的表现。安全方面必须多说一句。无人机飞行本身要严格遵守当地空域管理规范不能在禁飞区、人群密集区、机场净空区飞行高海拔山区要注意气压计失效导致的姿态漂移水面飞行要预留返航电量。我每次作业前都会检查桨叶和电池状态在手机里存好GPS轨迹万一炸机还能定位打捞。这些细节和数据质量同样重要图拍糊了可以重拍飞机没了整个项目就停摆了。6.3 模型训练与数据使用的注意事项我在训练阶段反复体验到一个现象直接用整图1920x1080的分辨率输入模型会导致显存爆炸而简单缩放成256x256又丢掉了水流纹理细节。平衡点是让模型喂入512x512或者640x640的裁剪块同时在全图推理时采用滑窗拼接的方式预测大图。如果不做滑窗长条河道的边缘区域会被重复预测边界处容易出现接缝。滑窗之间的重叠率我设为20%预测结束之后在重叠区域采用平均概率融合效果远好于直接取最大值。类别标签的数值顺序也容易搞出问题。有的模型要求背景是0有的要求背景是255还有的模型使用黑色背景透明效果。如果不提前统一训练时loss会在nan和乱跳之间反复徘徊。我在数据管线最开始就加入了一行断言检查mask中最大值不超过类别总数减一并检查每个类别在训练集里至少出现一次从源头规避这类问题。最后是数据扩展方向。当前的静态分割模型本质上只是看一张图的纹理但人眼判断水流状态时还会用上动态信息比如波纹移动速度、漩涡旋转方向、泡沫扩散轨迹。下一步可以把360张静态图扩展成短序列视频用时序分割模型或光流特征辅助分类。训练数据永远不够但目前这套labelme格式的360张、7类别数据集已经足够把水流识别这个方向的基线定下来。剩下的就是结合实际业务场景持续补数据、调模型、看效果一步一步把算法磨扎实。在我个人看来做这类数据项目最核心的并不是标了多少张图而是把类别定义、标注规范、质量控制这三件事真正讲清楚。水流状态识别看起来小众实际下游应用里无论是防汛预警还是生态评估都特别需要这种细粒度的水面信息。后面如果有时间我会把视频层面的动态特征分析补上让这套数据不仅能识别“哪里是什么水”还能判断“水流得有多急、往哪个方向走”。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询