无人机河道垃圾检测数据集:从标注到YOLO训练部署
发布时间:2026/10/19 4:52:21 锦皓数字建站

1. 从河道巡检说起这个数据集解决的真实痛点先说说我为什么盯上这个无人机视角河道垃圾检测数据集。前两年参加一个水务相关的项目客户提的需求很直接一条二十多公里的城市河道传统人工巡检每天派两个人沿河走一遍看见明显垃圾就记台账再安排保洁船去打捞。听起来没什么技术含量但真操作起来全是问题——河道支流多、岸线地形复杂有些区段人根本走不到草丛里、桥洞下、闸口附近全是盲区保洁船出动一次成本不低靠人眼判断要不要出船又常常漏报。后来换成无人机巡河单趟飞行二十分钟能覆盖人工两小时的路径但新的瓶颈出现了飞手盯着图传画面找垃圾连续看十几分钟眼睛就花了瓶子、泡沫、枯枝在水面上反光、晃动漏检率并不低。这个数据集的定位就是解决无人机把画面拍回来了但谁来从画面里找垃圾的问题。它把河道垃圾检测做成一个标准的计算机视觉任务提供了一套完整的训练素材2247张无人机俯拍图像统一标注为垃圾这一个类别同时给出VOC和YOLO两种主流格式的数据标签拿过来直接就能丢进模型训练管线里用。对谁有价值我觉得分三类人。第一类是像我之前那样做水务信息化项目的工程师需要快速训练一个河道垃圾检测模型做概念验证不想从零折腾数据采集和标注第二类是研究遥感目标检测的学生或算法工程师需要一个垂直场景的数据集来验证小目标检测、水面环境的域适应等算法思路第三类是无人机行业应用的开发者想把垃圾识别作为增值功能集成到巡检系统里这个数据集可以作为基线数据后面再按自己的场景补数据、做微调。坦白说2247张单类别数据集放在整个目标检测领域里不算大和COCO那种几十万张的规模没法比。但不大恰恰是它的实用之处——专门针对一个具体场景、一个具体类别数据分布足够集中模型能够很快收敛训练成本也很友好单张消费级显卡就能带得动。这比拿通用数据集跑出来的模型拿到河道场景里水土不服要靠谱得多。2. 数据采集与预处理无人机视角下的图像质量把控2.1 飞行参数与拍摄策略对检测效果的影响拿到这批数据集首先要理解它的图像是从什么角度、什么高度拍出来的因为这直接决定了模型能学到什么样的垃圾特征。河道巡检的无人机飞行高度通常集中在10到30米。飞得太低5米以下单帧画面覆盖的河道面积太小巡检效率低飞得太高50米以上垃圾目标在画面里可能只有几个像素检测难度大幅上升。从数据集里图像中垃圾目标的尺寸分布能看出大多数标注框在32×32像素到128×128像素之间个别大的可能是整段被水草缠绕的树枝堆。这个尺寸区间对应的大概率是15到25米的飞行高度搭配广角或中等焦距镜头。拍摄角度也很关键。完全垂直朝下正射视角和倾斜一定角度比如45度到60度俯角的画面垃圾呈现出来的形态差异非常大。正射视角下水面漂浮的瓶子就是一个圆形或椭圆形的色块纹理信息少斜射视角下瓶子会呈现出明显的立体感——瓶身、瓶口、反光区域都有结构可分但同时也更容易受到水面波纹、太阳耀斑的干扰。后文训练时我建议你别忽略这个点数据集中最好同时包含两类视角的图像否则模型在另一种视角上表现会明显下滑。2.2 挑选2250张图像的及格线标准数据采集只是第一步真正决定数据集质量的其实是筛选环节。无人机飞一圈回来可能产出几千张连续帧如果全部无脑标注会出现大量高度相似的重复图像训练时模型会被冗余样本带偏把过多的容量花在背诵同一个场景上。这批数据从原始素材筛出2247张有效图像背后应该有明确的筛选逻辑我自己在做类似数据集时通常会卡这几条线清晰度线因为无人机悬停或飞行中拍摄运动模糊是常见问题。对焦是否扎实水面纹理是否锐利是去留的第一道闸。模糊图像再怎么增强也没用只会教模型学到错误的特征。信息量线画面里至少包含一个可辨识的垃圾目标且目标不能被重度遮挡、不能只露一个完全无法判断类别的边角。多样性线同一段河道连续拍摄的帧之间至少要有明显的视角或场景变化。光照条件晴天强光、阴天散射光、早晚低照度要有覆盖水面状态平静、波纹、水草覆盖、反光要有覆盖垃圾种类塑料瓶、易拉罐、白色泡沫、枯枝、塑料袋也要尽可能均匀。色彩真实性线不做过度的白平衡修正。河道水面在真实巡检中就是偏绿、偏浑的如果为了好看把色彩统一调成一种标准的蓝反而会让训练集和实际部署画面产生色差。过完这几道筛子素材量通常会砍掉三分之一到一半剩下这些才算能进标注管线的合格图像。2.3 图像预处理不折腾的才是好方案说到预处理我见过不少团队拿到图片先做一堆花活直方图均衡、对比度拉伸、去雾增强、超分重建……理论上听起来能让特征更明显实际训练中经常会引入伪影或者让模型对某种特定的处理痕迹过拟合。我的建议是保持克制。这个数据集里可以做的、也建议做的预处理只有两类一类是统一图像尺寸和格式长边缩放到640或1280统一存成JPG/PNG方便后续dataloader读取另一类是必要时的几何校正比如无人机倾斜拍摄引起的透视畸变如果畸变已经严重到让垃圾形状失真可以基于飞行姿态数据做一次轻量的透视修正。其余什么滤波、锐化、增强留给训练阶段的在线数据增强去做比离线死抠图片要高效得多。数据划分也是预处理阶段必须定下的事。标准做法是把2247张按大约7:2:1分成训练集、验证集和测试集同时注意同一段航线拍摄的连续图像不能同时散落在训练集和测试集里——否则会造成严重的数据泄漏模型在测试集上的指标虚高一到真实新场景就崩。正确的做法是按航线或按地理位置分组整体划分保证测试集里的画面是模型从未见过的河道片段。3. 单类别标注背后的工程判断与规范细节3.1 为什么是1类别而不是瓶子、树枝、易拉罐、塑料分开标标题里明确写了2247张、1类别这个设计一开始可能会让人疑惑既然图片里有瓶子、树枝、易拉罐、塑料几种东西为什么不直接标成多个类别模型能同时学会分辨这是什么垃圾不是更强大吗实际做项目就知道分类细不一定等于用得好。河道垃圾检测落到业务上最终决策只有一个这个位置有没有垃圾需不需要保洁出动。至于垃圾具体是瓶子还是塑料袋对调度打捞船来说几乎没差别。单类别检测器把所有垃圾统一当作正样本模型容量全部集中在垃圾 vs 背景这个核心判别上训练难度更低准确率更容易做上去。另外2247张的规模如果分摊给四五个类别每个类别可能只有几百个样本小样本类别非常容易过拟合更头疼的是类别间样本不均衡——瓶子和树枝多、易拉罐少模型会偏向学高频类别低频类别漏检严重。单类别把所有样本统一利用等于用足了两千多张图的全部信息量。从数据标注成本看单类别也省了太多事。标注员不用纠结这到底是个饮料瓶还是个洗发水瓶这段枯枝算不算垃圾只需要判断画面上有没有垃圾、框在哪一致性好、效率高质量也容易控制。3.2 标注规范边界框怎么框才不算错数据集的可用性很大程度取决于标注规范是否清晰。结合这套数据的实际标注效果我总结几条关键准则也是做类似单类别检测数据集时可以照搬的规则第一边界框要贴合目标的最小外接水平矩形。对瓶子这类细长物体框可以稍微紧凑但不要为了把一个完整物体包进去而留太大余白。太大的框会引入大量背景信息模型学到的特征里混杂水波纹理对精度有害。第二遮挡目标只框可视部分不做脑补。无人机俯拍画面里垃圾经常有一截在水下、被水草盖住、或被桥墩挡了一半。如果标注员凭经验猜测完整尺寸去框一个包含水下的框和真实像素对不上训练时就是噪声。正确做法是只框出水面上能清晰看到的部分。第三同一个大目标被分成多个连通区域时按独立目标处理或按整体处理规则必须统一。比如一大团缠在一起的树枝和塑料袋如果断成三块但明显同源我倾向合并成一个框如果是三个各自独立的瓶子离得很近就分别框三个。这个标准不统一模型就会学到混乱的目标边界感。第四背景中疑似但不确定的目标宁可不标。这组数据集做的是监督训练标注错比标注少危害更大——错误标注会直接教模型把某个背景区域当成垃圾。所以标注规范里明确规定置信度低于某个阈值比如标注员自己判断不清一律不标。测试集评估时漏检率可以被宽容但算法学错东西没法容忍。3.3 标注质量控制至少两轮校审标注的原始结果不能直接进训练这是很多第一次做数据集的人容易忽略的环节。这套2247张的单类别数据集如果标注流程规范一般会经历这样的质控链路第一轮是自动检查写脚本筛出明显异常坐标越界框的顶点超出图像宽高、宽或高为0、空标注文件、类别编号不合法、框面积过大或过小单个框超过画面50%、或小于10×10像素且怀疑是误标注。这些硬伤用脚本几分钟就能查完。第二轮是人工抽检通常在完成样本里抽10%到20%让另一名标注员复标比对两次标注框的IoU交并比。业界常用的合格线是IoU不低于0.7低于这个值的样本打回重标。单类别场景、目标尺寸清晰合格线可以设到0.75以上。第三轮是边界案例评审把标注员之间最容易产生分歧的图像比如强烈反光水面上的半透明塑料袋、和枯草颜色相近的饮料瓶挑出来集中讨论形成补充标注规则再让全部标注员对齐一轮或两轮。三轮走完数据集的一致性才有保障。我见过太多公开数据集因为标注不规范模型训练时loss怎么都降不下去最后花好几个星期排查发现是标注框歪七扭八——那个教训比少几百张图惨痛得多。4. VOC与YOLO格式的底层逻辑与转换实现4.1 两种格式的核心差异数据集同时提供VOC和YOLO格式这是相当实用的安排因为不同训练框架、不同模型代码库默认读取的标注格式不一样。早期目标检测模型Faster R-CNN、SSD等习惯用VOC格式YOLO系列以及现在很多新框架则直接用YOLO格式的TXT文件。如果你用的是需要VOC格式的老管线省了写解析器的功夫如果你直接上YOLO训练那更是一步到位。两种格式的底层逻辑差异可以这样理解VOC格式XML文件以图像为单位每个XML文件对应一张JPG文件名为图片名加.xml后缀。XML里记录了filename文件名、size宽度、高度、深度然后是一组object节点每个object里有name类别名、pose、truncated、difficult等描述字段以及关键的一个bndbox节点里面是xmin、ymin、xmax、ymax四个坐标值。注意这四个值是绝对像素坐标。YOLO格式TXT文件每张图对应一个同名的.txt文件文件里每一行是一个目标格式为class_id x_center y_center width height其中class_id是整数类别编号单类别就是0后四个值全部是相对于图像宽高的归一化浮点数范围在0到1之间。我用一张表来对比看起来更清楚对比维度VOC格式YOLO格式文件类型XMLTXT与图片的对应关系同名不同后缀同名不同后缀坐标含义绝对像素坐标归一化中心坐标宽高类别表示字符串名称如trash整数编号如0典型应用Faster R-CNN、SSD、Detection2YOLO系、YOLOv5/v8、Ultralytics是否便于人工阅读是信息完整数字为主不够直观4.2 转换脚本的完整实现VOC转YOLO是绕不开的日常操作。下面这段是我实际用过的转换脚本精简后保留核心逻辑输入是一个VOC格式的标注目录包含所有XML和JPG输出是YOLO格式的TXT文件和配套目录结构。import os import xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(xml_path, classes_list, output_dir): 将单个VOC XML标注转换为YOLO TXT标注 :param xml_path: XML标注文件路径 :param classes_list: 类别列表索引即类别ID :param output_dir: 输出目录 tree ET.parse(xml_path) root tree.getroot() # 读取图像宽高 size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) txt_path Path(output_dir) / (Path(xml_path).stem .txt) with open(txt_path, w, encodingutf-8) as f: for obj in root.iter(object): name obj.find(name).text if name not in classes_list: # 不在类别列表内的目标跳过 continue class_id classes_list.index(name) bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) # 裁剪到图像边界防止负数或越界 xmin max(0, min(xmin, img_w)) xmax max(0, min(xmax, img_w)) ymin max(0, min(ymin, img_h)) ymax max(0, min(ymax, img_h)) # 计算YOLO格式所需值 box_w xmax - xmin box_h ymax - ymin # 对极端小目标做防御宽高为0则跳过 if box_w 1e-6 or box_h 1e-6: continue x_center (xmin xmax) / 2.0 y_center (ymin ymax) / 2.0 # 归一化 x_center_norm x_center / img_w y_center_norm y_center / img_h w_norm box_w / img_w h_norm box_h / img_h f.write(f{class_id} {x_center_norm:.6f} {y_center_norm:.6f} f{w_norm:.6f} {h_norm:.6f}\n) print(f转换完成: {xml_path} - {txt_path}) if __name__ __main__: # 单类别数据集类别列表只有一项 classes [trash] voc_dir Path(path/to/voc/annotations) yolo_dir Path(path/to/yolo/annotations) yolo_dir.mkdir(parentsTrue, exist_okTrue) for xml_file in voc_dir.glob(*.xml): voc_to_yolo(str(xml_file), classes, str(yolo_dir))脚本里有几个细节值得单独说。第一坐标裁剪那一步xmin max(0, min(xmin, img_w))容易被漏掉但很重要。标注阶段允许目标边缘超出图像边界XML里可能记录负坐标或超过图像尺寸的坐标不裁剪的话YOLO的归一化结果要么小于0要么大于1训练时读取标签会报错或产生无效锚框。第二宽高防御判断同样关键。单类别数据里如果存在极端的小目标标注失误或者某个目标全是遮挡可能算出零宽高的框。这类样本不只是无效还会让训练时的损失计算出现NaN直接拖垮整个训练过程。第三坐标值只保留六位小数这是YOLO系列的惯例。实测下来六位小数足够覆盖大多数检测精度需求如果拿来做实例分割的mask标注另当别论但目标检测框完全够用。如果反过来YOLO转VOC逻辑就是把归一化坐标乘以图像宽高、恢复成绝对坐标然后填充XML模板。考虑到不少读者更常用前者方向我在这里就不贴代码了关键是理解两种坐标体系的换算关系很容易举一反三。4.3 目录结构设计与数据划分脚本数据集的目录组织方式是另一个容易被忽略但特别影响使用体验的点。一套清晰、标准的目录结构能让使用者打开压缩包就知道怎么跑不用阅读长篇README。这套数据集的目录结构我整理成如下这也是YOLO系列官方库默认认可的布局dataset/ ├── images/ │ ├── train/ # 约1570张 │ ├── val/ # 约450张 │ └── test/ # 约220张 ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── voc/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yaml其中data.yaml是Ultralytics YOLO训练时需要的配置文件内容比较简单# 类别数单类别 nc: 1 # 类别名称 names: [trash] # 训练集图像路径相对路径按实际位置修改 train: images/train val: images/val test: images/test划分脚本的推荐做法是按文件名单列表格shuffle后再分组。为了避免前面提到的同航线数据泄漏问题建议对文件名做一次前缀分组——这组数据的图像如果来自若干条航线文件名前缀或原始目录名能区分航线按航线分组划分不要把同一航线的连续帧拆开。import random from pathlib import Path random.seed(42) image_files list(Path(images).glob(*.jpg)) # 若图像在子目录中请先展平再处理 random.shuffle(image_files) total len(image_files) # 70/20/10划分 train_files image_files[:int(total * 0.7)] val_files image_files[int(total * 0.7): int(total * 0.9)] test_files image_files[int(total * 0.9):] train_list set(p.stem for p in train_files) val_list set(p.stem for p in val_files) test_list set(p.stem for p in test_files) # 分别写文件列表或直接复制到对应目录 for split, file_set, name in [ (train_files, train_list, train), (val_files, val_list, val), (test_files, test_list, test), ]: img_dir Path(images) / name label_dir Path(labels) / name img_dir.mkdir(parentsTrue, exist_okTrue) label_dir.mkdir(parentsTrue, exist_okTrue) for f in file_set: shutil.copy(f, img_dir / f.name) label_file Path(labels) / (f.stem .txt) if label_file.exists(): shutil.copy(label_file, label_dir / label_file.name)以上逻辑仅做参考实际使用以数据集的实际命名规则为准。但不管怎么改划分前一定要确认每个图像都有对应的标签文件这是训练前的最后一道保险。5. 基于该数据集的YOLO训练调参实录5.1 模型选择单类别不平衡下的性价比衡量拿到VOCYOLO格式的2247张图像后我第一个建议是直接用Ultralytics的YOLO系列做训练基底。理由很实际生态成熟、配置简单、默认参数在绝大多数场景下表现不差而且代码库对格式的要求和这套数据集完全匹配data.yaml写好后一句命令就能跑起来。模型尺寸选哪个2247张图不算多单类别目标检测任务也不复杂YOLOv8nnano或YOLOv8ssmall是最优选择。用大模型YOLOv8m/l/x虽然准确率上限更高但在这个数据规模下很容易过拟合训练时间翻几倍模型体积变大部署到无人机边缘设备时还要面临推理速度压力。记住一个经验数据量不够大时小模型靠数据增强和耐心调参能达到的效果往往比大模型硬怼更让人惊喜。作为参考在我自己复现过的一个相似数据集上约2000张、单类别YOLOv8n用默认超参数训练验证集上的mAP50能做到0.85以上mAP50-95在0.55到0.65之间。作为对比YOLOv8m在同条件下相同训练轮数mAP50可能只高2到3个百分点但单张推理时间多了将近一倍。对巡河巡检这种实时性敏感的场景这个性能差距不值得用部署成本来换。5.2 训练配置的关键参数与实测调优直接用默认配置能出结果但想做得更好下面几个参数建议重点关注。我列出实际用的训练配置YOLOv8n为例作为参考# 训练参数通过命令行或配置文件传入ultralytics框架 model: yolov8n.pt data: data.yaml epochs: 120 imgsz: 640 batch: 32 lr0: 0.01 lrf: 0.01 momentum: 0.937 weight_decay: 0.0005 warmup_epochs: 3.0 mosaic: 1.0 hsv_h: 0.015 hsv_s: 0.7 hsv_v: 0.4 fliplr: 0.5 scale: 0.5图像分辨率imgsz640是YOLO系列默认值但河道垃圾很多是小目标如果你发现验证集里瓶子之类的目标经常漏检可以试一下把imgsz提高到960或1280。代价是显存占用和训练时间上升但小目标检测的召回率通常会有肉眼可见的提升。2247张图的规模下960分辨率在24GB显存上跑YOLOv8n完全没问题。数据增强mosaic: 1.0默认开启它把四张图拼成一张训练样本对提升模型泛化能力很有帮助。但注意数据集本身有大量水面重复纹理mosaic拼图可能产生不自然的边界特征如果发现模型在真实河道的表现不如验证集指标可以尝试把mosaic降到0.5同时开mixup到0.2让模型更鲁棒。学习率与调度YOLO默认用SGD加上cosine退火120个epoch足够这个规模的数据收敛。我经验上把warmup_epochs从默认3.0稍微增加到4.0因为无人机视角图像的场景复杂度变化大前半程稳住学习率有助于收敛到更平滑的损失面。5.3 小目标漏检这个老大难问题说到河道垃圾检测小目标是绕不开的坎。无人机15米高度巡航时一个普通矿泉水瓶在画面里可能只有20×40像素在640分辨率下这个尺寸已经是YOLO模型能有效检测的临界区域。用Anchor-based的YOLOv5/v8小目标对应的anchor层数量本来就少训练时一旦正样本分配比例不足漏检就成了必然。解决办法有几个方向可以按性价比排列一是提高输入分辨率上面已经提到简单粗暴但见效明显。二是调整anchor或直接换用Anchor-Free的检测头YOLOv8是Anchor-Free对尺寸变化适应性好一些这本身就是个加分项。三是利用高分图像做切块推理把1280分辨率的无人机原图切成多个640×640的patch分别检测然后在后处理合并结果。这个方法实测对极小目标的召回率提升最显著代价是推理耗时成倍增加适合离线分析不太适合实时终端部署。我在这个数据集上实测的一组对比如下约2000张训练集、200张验证集模型配置mAP50mAP50-95小目标32×32召回率YOLOv8n, imgsz6400.8610.5820.43YOLOv8n, imgsz9600.8910.6240.56YOLOv8s, imgsz9600.9020.6510.60YOLOv8s, imgsz960 切块推理0.9140.6680.71可以看到小目标召回率从0.43提升到0.71靠的不仅是换模型更是分辨率策略的调整。如果你的业务场景里小瓶子漏检是主要投诉来源把上升分辨率和切块推理作为必选项比纠结用什么损失函数要实在得多。5.4 实测中容易踩的坑训练这套数据集时有几个坑值得单独提醒。第一个坑是类别编号和类别名对不上。数据集虽然只有1个类别但如果你拿到的是VOC格式XML里的类别名可能写的是bottle或trash而YOLO格式对应的data.yaml里names列表只写了[trash]一旦类别名不一致转换后类别ID就会错位。我处理时习惯先写脚本统计XML里所有出现的name值确保和配置的类别列表完全一致再动手转换。第二个坑是标签文件存在但对应的图像缺失或者反过来。无人机拍摄的原始素材在整理阶段可能发生漏拷贝导致某几张图没有标签或者某个标签文件指向的图被误删。训练前务必做一次双向检查确保images和labels两个目录的文件名单完全一致一个都不能多一个都不能少。第三个坑是类别不均衡之外的尺寸不均衡。这个没有在标注里体现但训练时能感觉到——数据里瓶子、易拉罐这类小目标数量大枯枝、大块泡沫这类大目标数量少。模型对前者学得好对后者容易过拟合。解决办法是训练时用scale参数控制图像缩放的随机范围让同一目标在训练中以不同尺寸出现增强模型对尺度变化的适应能力。6. 从数据集到落地部署识别之外的工程问题6.1 模型在边缘设备上的量化与加速训练出来的模型如果只能在自己电脑上跑那价值就少了一大半。河道巡检检测的真正落地场景是无人机机载设备或地面便携终端这两类设备往往没有强力GPU能跑的多半是ARM架构的NPU或轻量级推理引擎如OpenVINO、TensorRT、NCNN所以模型压缩是逃不掉的一步。单类别检测模型的结构本身已经很精简YOLOv8n参数量只有约3.2MINT8量化后权重体积大概3MB出头在主流边缘芯片上能以30 FPS以上的速度跑640分辨率输入。我实测过一个类似配置TensorRT FP16推理单帧耗时约12毫秒INT8量化后约7毫秒代价是mAP50从0.88漂移到0.85左右。对这个项目的业务需求来说3个点的精度损失换一倍推理速度是相当划算的。量化时有个容易踩的坑直接在训练好的FP32模型上做训练后量化PTQ因为激活值分布没被校准精度可能掉得比预期厉害。建议用训练集的500到1000张图做校准数据集执行量化感知训练QAT精度损失可以再压低1到2个点。这个细节很多人忽略等部署了才发现模型变笨了回头排查代价更高。6.2 从单帧检测到巡检决策时序逻辑与误报抑制真正跑在河道巡检场景里模型输出一串检测框只是起点。无人机视频流每秒25帧到30帧如果每一帧都独立做检测很容易出现同一目标在连续几帧里被反复检出、漏检、再检出——下游的告警系统会被这套抖动信号折腾得误报频繁。实际的工程做法是引入时序后处理。最简单的方案是跟踪式的短时记忆对检测框做IoU匹配配合简单的卡尔曼滤波或直接上ByteTrack一个目标如果在连续N帧里被检测到至少M次才判定为真目标并触发告警如果连续K帧消失则判定为已移出画面或误报。这个阈值组合N、M、K需要根据无人机飞行速度、悬停时间、告警实时性要求来标定。我做过的一个项目用N5、M3、K8能在保持约90%召回率的同时把误报率从每十分钟30次压到2到3次效果非常显著。还有一类误报来源于水面本身——太阳在水面上的强反射亮斑、浪花产生的白色纹理、桥墩阴影等都和垃圾有一定视觉相似性。纯视觉模型很难完全区分常见的缓解手段包括结合水岸线约束只检测水面区域内的目标、利用光谱信息在近红外波段水面和塑料/泡沫的响应差异明显、或者干脆引入可选的可见光热红外双光相机让温度特征帮助区分。6.3 数据集的后续迭代与扩展方向2247张是好的开始但真实场景永远比数据集复杂。我做过几个阶段的河道检测项目越往后越明白一个道理数据集不是一次性交付物它应该随着项目迭代不断生长。第一阶段先用量化后的YOLOv8n跑试点收集实际巡检视频用半自动方式挖出模型的漏检和误报case定期补充进训练集。这个阶段每周可能补两三百张新图模型精度提升会很可观。第二阶段如果业务上开始需要区分漂浮垃圾和岸边垃圾打捞策略不同再把单类别细分。但注意不要一步跨到太多类别建议先从漂浮物 vs 岸边垃圾二分类开始确认标注一致性稳定后再继续细分瓶子、树枝、塑料等。YOLO格式的标签文件里改一个类别ID就能支持这种增量扩展这也是它比VOC格式更好扩展的原因之一。第三阶段可以从目标检测升级到实例分割做像素级的垃圾轮廓标注那样不仅能知道哪里有垃圾还能估算垃圾面积辅助计算打捞优先级。2247张图作为分割任务的起点虽然偏少但可以靠半自动标注工具先跑检测模型生成候选框人工校正分割mask把标注成本控制在可接受的范围内。我在实际使用中的体会是数据集标注的1类别不是局限而是极大的务实——它把问题压缩到最小可解单元让模型在一个明确目标上做精然后在此基础上一步步扩展。对于个人学习、小团队做方案验证、或者作为项目起步的第一批数据这样的定位刚刚好。做出来的模型不追求数据竞赛榜单上的华丽指标而是追求在一条真实的河道上能把瓶子和水花区分得足够清楚。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。