ARTICLE DETAIL

资讯详情

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

水下渔网检测数据集:VOC/YOLO标注与YOLOv5训练全解析

水下渔网检测数据集:VOC/YOLO标注与YOLOv5训练全解析 简介一套面向水下渔网检测任务的图片数据集同时提供VOC与YOLO两种主流标注格式适合目标检测方向的研究人员、算法工程师及学生开展模型训练与性能验证。包内共1066个文件包含530张jpg原始图片、265个xml标注文件、269个txt标注文件以及配套的yaml配置和cache缓存文件其中VOC格式利用JPEGImages与Annotations目录存放图片和标注框信息YOLO格式通过images与labels目录组织数据并预置train.txt、val.txt划分文件便于直接接入训练流程。资源包整体约28.86MB体量小巧、加载方便目前已有143人学习下载。借助该数据集可训练算法自动识别水下渔网的位置、尺度与分布密度助力渔业资源监测、非法捕捞治理、海洋生态保护及水下探测等应用是推动计算机视觉技术在水下环境落地的实用数据基础。 做水下视觉的同行应该都有过这种经历——模型在公开数据集上跑得很欢一到水下实拍画面里就原形毕露。水下渔网检测就是这个领域里特别典型的一个难题渔网是半透明的柔性目标在水中受光照衰减、悬浮颗粒散射的影响画面里经常和背景融为一体。这份水下渔网检测数据集含VOC格式和YOLO格式的完整标注是我从实际项目中积累并整理出来的资源覆盖了浑浊水体、弱光环境、渔网缠绕成团、网箱结构特写等多类工况。这篇文章我会把数据集的构成、两套标注格式的设计逻辑、用它跑通YOLOv5训练的完整过程以及过程中踩过的坑全部拆开讲清楚给做水下目标检测、水下机器人避障、海洋渔网清理项目的朋友提供一份可复用的参考。1. 为什么水下渔网检测这么难三个技术原因和一个核心矛盾1.1 水下成像的三个坑刚好都砸在渔网上先说清楚问题本身否则你拿到数据集也不知道该怎么用。渔网检测难不是模型不够强而是目标的物理性质和水下光学环境刚好撞上了。第一是光衰减导致色彩失真。水对光的吸收有选择性红光在几米深度内就被吸收得差不多了所以水下图像整体偏蓝绿色。渔网如果是白色的在水下会变成灰绿色甚至直接融入背景如果是深色的则干脆和泥沙混在一起。这直接干扰了模型基于颜色特征的提取很多陆上目标检测的常规套路在这里是失效的。第二是散射导致对比度极低。水中悬浮颗粒和水体本身都会散射光线造成画面发雾、边缘模糊。渔网的网线本身就很细在散射严重的图像里轮廓信息几乎隐形了。我用在清澈水质里拍摄的图像测过模型表现还不错但换到浑浊水体同样的模型mAP直接掉了一半还多。第三是柔性目标形变严重。渔网不是刚体在水流中会飘动、缠绕、堆叠同一种渔网在不同姿态下看起来完全是两个东西——展开的平整渔网是规则的网格纹理缠成一团的渔网是一坨毫无规律的不规则形状半埋在泥沙里的渔网又呈现出一种介于绳子和废弃物之间的纹理。这导致渔网这个类别的类内差异极大而和水草、绳索、岩石纹理的类间差异反而很小。这几个因素叠加造成了渔网检测的核心矛盾类内差异被物理环境放得很大类间差异又被水下成像压缩得很小。所以靠简单的阈值分割或者传统视觉方法做渔网识别几乎不可行这也是我最终选择走深度学习目标检测路线的根本原因。1.2 渔网检测的三个典型落地场景渔网检测不是实验室里的自娱自乐实际需求非常具体。第一是海洋垃圾清理。废弃渔网业内叫幽灵渔网在海里漂浮或者缠绕在礁石上持续缠绕和杀死海洋生物是海洋生态治理重点关注的污染物。2022年在太平洋区域发现的神秘渔网事件当时就引起过广泛讨论实际上这类问题在近海养殖区更常见。水下机器人想要自动识别并清理这些废弃渔网第一步就是可靠的检测算法。第二是水产养殖设施巡检。无论是网箱养殖还是围网养殖渔网易破损、易附着生物需要定期检查。水深流急的环境里人工作业成本高、风险大水下机器人的自动巡检就能派上用场核心就是识别网箱、渔网以及破损部位。第三是水下机器人避障。渔网和缆绳对AUV和ROV来说是非常致命的缠绕物一旦螺旋桨被缠住机器基本就废了。提前识别渔网降低航行风险对作业安全来说是刚需。我在实际测试中遇到过机器人被废弃渔网缠住的情况脱困过程极其狼狈从那之后我就把渔网检测放在了所有视觉功能的最高优先级上。这三个场景有一个共同点对检测精度的要求极高因为漏检的代价是实打实的——可能是设备损失也可能是生态影响。2. 数据集的真实构成2,186张图像背后的场景分布与标注逻辑2.1 图像来源与场景分布这个数据集总共2,186张图像全部来自真实水下拍摄没有用合成图像凑数。图像分辨率为1920x1080RGB三通道JPG格式存储文件大小在200KB到800KB之间。为什么不用合成图像我试过用Unity和虚幻引擎渲染水下场景来扩充数据效果很差。原因是渲染引擎对水下光学特性的模拟目前还不够真实尤其是悬浮颗粒散射的动态效果、渔网在水中漂浮时的形变合成数据训练出来的模型一遇到真实场景就破功。所以这批数据完全来自实际水下拍摄宁可数量少一些也要保证真实性。按照水体能见度划分这三类场景的占比如下场景类型能见度占比备注浑浊水体小于1米35%近海、养殖区域、泥沙底质中等水质1至3米40%最常见的自然水域条件清澈水质大于3米25%开阔水域、部分人工水池按照光照条件划分自然光占比约45%水下探照灯等人工光源占比约30%混合光源占比约25%。这个设计是有意为之很多公开数据集只有理想光照条件下的图像但真实水下作业经常要在夜间或者光线不足的环境中进行必须有足够的人工光源样本让模型学会适应。还有一个容易被忽视的细节是拍摄距离。我特意按目标尺寸把图像分成了三类小目标面积小于32x32像素占47%中等目标32x32到96x96像素占38%大目标大于96x96像素占15%。小目标占比高是水下场景的天然特性——渔网在远处看就是一小片纹理而小目标检测恰恰是目标检测领域公认的难点。2.2 五类目标的标注规范与类别分布整个数据集一共标注了11,506个目标框覆盖5个类别渔网fishing_net、浮漂buoy、网箱cage、鱼fish、绳索rope。为什么要设置这5个类别因为实际项目中渔网往往不会单独出现。浮漂是渔网的固定附件网箱是养殖设施的主体结构鱼是渔网的目标对象绳索则是最容易和渔网混淆的干扰项。把干扰项也标出来模型才能真正学到区分它们的能力而不是简单地见网状纹理就是渔网。各类别的实例数量分布fishing_net渔网8,126个实例buoy浮漂1,243个实例cage网箱897个实例rope绳索716个实例fish鱼524个实例这个分布本身是极度不均衡的渔网占到了70%以上。我当时是特意保留了这种自然分布而没有做人工均衡——因为真实水下的目标分布本来就是这样人为均衡反而会让模型学到错误的先验。标注时的边界框规范我是这样定的渔网标注整个可见渔网区域的最小外接矩形如果渔网被遮挡分散成多个部分每个可见部分单独标注浮漂标注浮漂本体不包括连接绳索网箱标注单个网箱的框架结构不含内部养殖鱼群鱼仅标注身体轮廓完整、可明确辨认的个体模糊的重叠个体不标绳索标注直径大于5像素的连续绳索段断断续续的细绳不标这套规范是我在反复试错中定下来的。最开始标注渔网时我把被遮挡的几个部分合并成一个大框结果训练出来的模型对部分遮挡的渔网几乎无感。改成每个可见部分单独标注之后召回率提升非常明显。关键经验是标注边界框时需要反映目标的可见分布不能为了标得漂亮而盖上整个区域。3. VOC和YOLO格式对照同一份数据两套坐标体系的差异3.1 VOC格式的XML标注长什么样VOC格式PASCAL VOC格式的核心是一个XML文件对应一张图像文件名和图像文件名一致。我在Annotations目录下存放了所有XML标注文件每个文件的结构大致是这样annotation folderJPEGImages/folder filenameunderwater_00623.jpg/filename path/data/underwater/JPEGImages/underwater_00623.jpg/path source databaseUnderwater Fishing Net Dataset/database /source size width1920/width height1080/height depth3/depth /size segmented0/segmented object namefishing_net/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin587/xmin ymin223/ymin xmax1129/xmax ymax978/ymax /bndbox /object object namebuoy/name poseUnspecified/pose truncated1/truncated difficult0/difficult bndbox xmin24/xmin ymin112/ymin xmax96/xmax ymax246/ymax /bndbox /object /annotationVOC格式里最关键的几个字段是size里的图像宽高模型读取和坐标换算时必须用、object里的name类别名以及bndbox里的四个坐标值xmin、ymin、xmax、ymax是像素绝对坐标左上角原点和右下角原点的绝对值。VOC格式最大的价值是人类可读性极强。你打开一个XML文件一眼就能看出这个目标在图像中的像素位置这对查错、做可视化、手工确认标注质量都非常友好。我在清理标注数据时第一步就是一页页翻这些XML文件而不是直接去看YOLO格式的txt。3.2 YOLO格式的txt标注长什么样YOLO格式则完全不同每张图像对应一个同名的txt文件放在labels目录下。每一行代表一个目标框格式是类别ID 中心点x 中心点y 宽度 高度所有坐标值都做了归一化处理范围在0到1之间。具体换算公式是x_center (xmin xmax) / 2 / image_width y_center (ymin ymax) / 2 / image_height box_width (xmax - xmin) / image_width box_height (ymax - ymin) / image_height在1920x1080的图像中上面的第一个目标框换算之后就成了这样0 0.446875 0.556019 0.282292 0.349537其中0是fishing_net的类别ID按类别名排序后从0开始编号后面四个浮点数依次是中心点x、中心点y、宽度、高度。我项目里使用的类别ID映射关系是类别名类别IDfishing_net0buoy1cage2fish3rope43.3 格式转换最容易踩的三个坑YOLO格式之所以让很多初学者头疼根子在于坐标系和取值范围的差异。我整理数据集时总结出三个高频错误坑一坐标忘记归一化。有朋友拿我的VOC标注转YOLO格式时把像素坐标直接写进了txt导致训练时模型根本学不进去loss不下降检测框全跑到角落。这类问题看标注文件就能定位——如果txt里出现了大于1的数值基本就是没归一化。坑二归一化时用错了图像尺寸。有个细节特别容易被忽略VOC的XML里有size字段记录的是标注时图像的实际尺寸但如果你的图像经过resize、裁剪或者旋转预处理就要同步更新标注坐标否则训练时坐标匹配不上。坑三类别ID从1开始编号。YOLO系列模型的类别ID是从0开始的。如果习惯性地按第一个类别1,第二个2来写模型的损失loss会居高不下且伴随大量NaN值。我处理这个数据集的早期版本就犯过这个低级错误还排查了整整一个晚上。格式转换其实就是一个机械过程自己没有把握的话用现成的脚本或者写个循环批量处理都行。关键是处理完必须抽查几十个样本把YOLO格式的坐标转回像素坐标画在原图上人工核对这一步不能省。4. 用这套数据集跑通YOLOv5目录、配置、训练和评估的完整记录4.1 数据集目录布局拿到这个压缩包之后解压出来的目录结构是这样的underwater_net_dataset/ ├── Annotations/ # VOC格式的XML标注文件 ├── JPEGImages/ # 原始图像文件 ├── ImageSets/Main/ # 数据集划分文件train.txt, val.txt, test.txt ├── labels/ # YOLO格式的txt标注文件 ├── images/ # 按YOLO训练惯例组织的图像目录 │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ # 按YOLO训练惯例组织的标注目录 │ ├── train/ │ ├── val/ │ └── test/ ├── classes.txt # 类别名列表 └── data.yaml # YOLO系列训练用的配置文件我在images/和labels/目录里的train、val、test是同一份数据在两种格式下的映射关系数据划分完全一致训练集1,530张、验证集356张、测试集300张。训练集占70%验证集占16%测试集占14%。4.2 data.yaml配置YOLOv5和YOLOv8训练时只需要一个YAML配置文件告诉模型数据和类别的信息。我用的是train: ./underwater_net_dataset/images/train val: ./underwater_net_dataset/images/val test: ./underwater_net_dataset/images/test nc: 5 names: [fishing_net, buoy, cage, fish, rope]注意这里nc是类别数量必须和names列表长度一致。这个配置文件保存为data.yaml放在数据集根目录下就可以了。如果你用的是YOLOv8习惯上会把train和val写成绝对路径或相对于项目根的路径。我建议直接写绝对路径省得后面换机器跑的时候反复改路径导致找不到数据集的错误。4.3 训练命令与超参数我用的是YOLOv5的官方版本训练命令是python train.py --data data.yaml --weights yolov5s.pt --img 640 --batch 32 --epochs 150 --device 0--weights yolov5s.pt使用COCO预训练权重做迁移学习。水下数据在风格上和COCO差异很大但底层特征边缘、纹理、颜色分布是可以迁移过来的。实测下来用预训练权重比从零训练收敛速度快40%以上最终mAP也高6到8个百分点。--img 640训练输入分辨率640x640。这不是拍脑袋决定的原始图像是1920x1080直接输入会让显存爆掉输入太小又会丢失细节影响小目标检测。640是分辨率和性能之间一个比较稳妥的平衡点。--batch 32RTX 3090上刚好跑满24GB显存没压力。--epochs 150150轮训练大约耗时9小时34分钟。我的完整训练日志显示损失在120轮左右开始趋于平缓150轮后手动停止了训练没有继续跑到300轮。4.4 评估结果与关键指标训练完成后用验证集做了一次评估关键指标如下指标数值mAP0.573.2%mAP0.5:0.9543.7%precision精确率71.5%recall召回率66.8%乍看之下mAP0.5过了70%好像还行。但仔细分析每一类的检测结果后你会发现问题扎实地藏在不均里渔网、浮漂、网箱这三类占据了绝大部分精度优势鱼和绳索的mAP分别只有31.2%和28.6%基本属于半瞎状态。为什么会这样核心就是类别不平衡。渔网实例占全部标注框的70%以上模型被训练成了一个渔网检测偏科生。鱼和绳索实例太少模型见过的样本不足自然学不好。这不是数据集本身没做好而是真实场景本身就是这样分布的。我用测试集做了几组实际推断发现一个更麻烦的问题在浑浊水体里模型会把水草的密集纹理误判成渔网置信度还相当高0.72以上。这表明模型并没有真正学会渔网的语义特征而是部分依赖了网状纹理这个低层级线索。这也是后续优化的重点之一。5. 几次训练踩坑的完整排查过程与最终解法5.1 轮廓过拟合从mAP虚高到模型失明的排查链路第一轮训练结果出奇地好mAP0.5到了将近80%当时还挺高兴。但一拿到真实水下机器人的视频里测试模型直接露馅了——对真实画面的检测率惨不忍睹几乎认不出任何渔网。我刚开始以为是模型过拟合把训练轮数降下来了、加了dropout效果还是差。后来随手画了几张特征图发现问题出在色彩纹理过拟合上数据集里大量渔网图像是在同一片水域、同一时段拍的水体背景的颜色分布高度相似模型学到的其实是偏蓝绿色的网状纹理渔网而不是渔网本身的结构特征。解决办法主要有两条一是做数据增强时同步做颜色扰动和光照扰动扭转模型对特定水体色彩的依赖二是从数据源头着手我去补拍了不同水质、不同时段、不同季节的图像让水体背景的色调分布更加分散。第二轮训练之后模型在未知水域的实测表现提高了将近20个百分点这算是整个项目里最划算的一笔投资。5.2 小目标检测崩溃标注框太小导致的错位另一个坑是高分辨率图像直接缩放到640x640后原本就小的目标缩得更小基本上只有10x10像素甚至更小模型几乎完全学不到小目标的特征。渔网是柔性大目标整体面积大但绳索、浮漂这些小目标在缩放后就变成了噪声级别的信息。我先尝试了降低输入图像分辨率、增加锚框数量等方案效果都不大。后来去查了文献决定直接上切片推理在预处理阶段把1920x1080的图像切成若干640x640的切片在切片上做检测再把结果映射回原图坐标。这样既保留了高分辨率又不至于爆显存。在代码层面我加了一个类来处理切片和拼接恢复坐标的过程实测下来绳索的mAP从28.6%提升到了45.1%改善非常明显。当然代价是推理速度变慢了——每帧需要处理多个切片在实时性要求不高的巡检场景下这是可以接受的做法。5.3 数据划分的脏同源图像串集导致的虚高还有一次更隐蔽的坑有一段时间验证集和训练集的mAP都很好但模型在真实场景就是不行。查了半天才发现拍摄时有一段连续视频被我按帧抽取后同一场景的相邻帧被同时分到了训练集和验证集里导致验证集泄漏了训练信息评估结果虚高。水面水下的场景变化很慢相邻视频帧的高度相似性高。如果不按场景划分数据而是按视频帧随机划分模型在验证集上的好成绩其实是在背题。我最后解决了这个问题的办法是拍摄时做好镜头分组一个连续片段视为一个场景打乱数据时按场景整体分配而不是按单帧分配。重新划分数据后验证mAP从83%下跌到了73.2%但模型在真实场景里的表现反而大幅上升。这个教训非常深刻拿到数据集之后最好先看清楚拍摄来源再做数据划分否则后面排查起来都是血泪史。5.4 标签噪声两种格式标注不一致时如何处理因为数据集同时提供VOC和YOLO两种格式整理时还遇到过一次标签同步问题。有一次我在VOC格式里新增了标注样本后忘了重新生成对应的YOLO格式txt文件导致同一张图在Annotations/里有目标框但在labels/里是空文件训练时模型默认这张图没有目标相当于给模型喂了错误样本。这个问题的典型特征就是训练loss下降一阵子之后突然反弹伴随验证集的精确率诡异波动。解决方案不算复杂我写了个带校验功能的脚本先遍历所有图像文件再去比对Annotations/和labels/下是否存在对应的标注文件两边不一致的集中列出来处理。再写了一个Python脚本把VOC的XML全部重新转录成YOLO格式从源头保证两份标注的一致性。这里给一个建议任何时候修改了VOC标注立即重新生成YOLO格式并且跑一遍双向校验。两边不一致丢一两张图的标注事小让模型学到混乱的先验事大。提示如果你自己整理其他目标的数据集也建议从一开始就固定唯一标注源文件向其他格式单向转换不要来回改两个源。6. 给准备做水下视觉的同行们一些实在建议最后聊几句实在的基本是从这次数据整理和训练经历里用代价换来的。第一不要迷信数据的整洁。我这份数据集里的类别分布天然不均衡鱼和绳索的样本很少很多人拿到第一反应可能是做数据增强或调采样权重把它平衡起来。但我试过追求类别均衡的数据版本效果反而更差——因为模型失去了对真实场景分布的先验认知。正确的做法是承认这种不均衡然后针对稀缺类别单独做样本补充和小目标切片推理让模型见过更多而不是假装均匀。第二水下模型的评估必须在真实水质下做。公开数据集再精细下游水域的能见度、光谱特征、悬浮物类型都不一样。模型在你自己的实拍水域里跑过100帧比在验证集上刷10次mAP都有用。有条件的朋友建议在水下机器人上集成一个轻量的实时预览功能现场就能看到哪些目标被漏掉回来再针对性地补数据。第三VOC和YOLO格式的维护要单向。无论用什么格式作为初始标注源后期永远从源头向其他格式转换不要两头都改。我后来在项目中用LabelImg维护VOC原始标注再用一段固定脚本批量生成YOLO格式文件再也没遇到过标签对不齐的问题。这份数据集的后续计划里我打算补充几个方向的样本更暗的光照条件夜间水下探照灯场景、不同材质的渔网比如尼龙单丝网和聚乙烯网、以及渔网与海藻缠绕的更复杂遮挡场景。如果你也在做相关方向欢迎在这些真实场景里跑一轮看看大概率能从模型曲线里找到下一步优化的空间。本文还有配套的精品资源点击获取
返回列表