ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

海面原油泄漏检测数据集:1800张VOC+YOLO双格式实战指南

海面原油泄漏检测数据集:1800张VOC+YOLO双格式实战指南 简介这份资源面向从事计算机视觉与目标检测的开发者、环保监测研究人员及高校学生提供海面石油原油泄漏检测的标注数据集可用于训练和验证油污识别模型服务于海洋环境监测与应急响应场景。压缩包共2000个文件以1817个VOC格式xml标注文件和183个YOLO格式txt标注文件为主另附说明文档整体约79.05MBjpg图片与标注一一对应标注工具为labelImg。数据集仅含oil_spillage单一类别共3871个标注框说明部分图像存在多个泄漏点适合训练多目标检测模型。目前已有283人学习下载。读者可据此直接开展YOLO或Pascal VOC流程的模型训练省去自行采集与标注成本并借助多框样本提升模型对复杂海面场景的识别能力。1. 海面原油泄漏检测数据集1800 张 VOCYOLO 双格式到底能干什么海上溢油事故的应急响应窗口通常只有几个小时卫星和无人机拍回来的影像如果靠人眼逐帧筛查等发现油膜扩散边界时清污船已经错过了最佳拦截位置。海面石油原油泄漏检测数据集 1800 张 VOCYOLO 格式解决的就是这个环节——它把「海面油膜」当作一个标准的目标检测任务来标注让你能直接拿 YOLO 系列模型训练出一个自动圈出油膜区域的检测器。这个数据集同时提供 VOC 的 XML 标注和 YOLO 的 TXT 标注意味着你不需要自己写格式转换脚本Pascal VOC 那套老工具链和 YOLOv5/v8/v11 的训练管线都能直接吃进去。适合谁做海洋遥感监测的算法工程师、环境应急方向的研究生、以及想拿一个真实场景数据集练手目标检测全流程的开发者。1800 张不算大但海面溢油这个场景的类内差异极大——薄油膜、厚油块、乳化带、太阳耀斑干扰、云影误判——这些恰恰是通用数据集给不了的边界样本。2. 拆开这个数据集VOC 与 YOLO 双格式的目录结构和标注逻辑2.1 拿到压缩包先看什么目录树与文件命名规律解压之后你大概率会看到类似这样的结构不同整理者命名习惯略有差异但核心目录逃不出这几类oil_spill_dataset/ ├── JPEGImages/ # 所有 jpg 原图1800 张左右 ├── Annotations/ # VOC 格式 XML与 JPEGImages 一一对应 ├── ImageSets/ │ └── Main/ # train.txt / val.txt / test.txt 划分文件 ├── labels/ # YOLO 格式 txt与图片同名 └── data.yaml # YOLO 训练配置文件先做三件事数图片数量、数 XML 数量、数 labels 数量。三者不一致是数据集最常见的翻车点。用一条命令就能查# 分别统计三个目录的文件数确认是否对齐 echo images: $(ls JPEGImages/*.jpg 2/dev/null | wc -l) echo xml: $(ls Annotations/*.xml 2/dev/null | wc -l) echo labels: $(ls labels/*.txt 2/dev/null | wc -l)如果 labels 比 images 少说明有图片没有对应的 YOLO 标注训练时 YOLO 会把这些图当作「无目标」背景图处理少量可以接受大量缺失就必须排查。如果 XML 比 images 多通常是标注后删了原图但忘了删 XML需要清理。2.2 VOC XML 里到底存了什么读懂 bndbox 的四个坐标VOC 格式的标注核心在object节点里一个海面油膜目标对应一个objectannotation folderJPEGImages/folder filenameoil_00342.jpg/filename size width1920/width height1080/height depth3/depth /size object nameoil_spill/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin412/xmin ymin236/ymin xmax1187/xmax ymax803/ymax /bndbox /object /annotationxmin/ymin/xmax/ymax是像素绝对坐标原点在左上角。difficult1表示这个目标难以识别比如被浪花遮挡的薄油膜训练时可以选择忽略。truncated1表示目标被图像边缘截断。海面溢油场景里油膜经常延伸到画面外truncated标记的正确性直接影响模型对边界目标的回归质量。2.3 YOLO TXT 的归一化坐标为什么你的框总是偏YOLO 格式每行是class_id x_center y_center width height全部归一化到 0~10 0.4164 0.4810 0.4036 0.5250换算关系是x_center (xmin xmax) / 2 / img_widthwidth (xmax - xmin) / img_width。这里最容易踩的坑是——XML 里的size宽高和图片实际像素尺寸不一致。有些数据集整理时做了缩放但没更新 XML导致转换出来的 YOLO 框整体偏移。验证方法很简单import cv2 import xml.etree.ElementTree as ET def check_annotation_consistency(img_path, xml_path): 检查 XML 中记录的尺寸与图片实际尺寸是否一致 img cv2.imread(img_path) h, w img.shape[:2] tree ET.parse(xml_path) root tree.getroot() size root.find(size) xml_w int(size.find(width).text) xml_h int(size.find(height).text) if xml_w ! w or xml_h ! h: print(f[不一致] {img_path}: 图片({w}x{h}) vs XML({xml_w}x{xml_h})) return False return True这个检查脚本建议在训练前对全部 1800 张跑一遍输出所有不一致的文件列表。如果只有零星几张直接剔除如果大面积不一致说明整个数据集的 XML 尺寸字段不可信需要以图片实际尺寸为准重新生成 YOLO 标签。2.4 类别定义与 data.yaml一个类别也要写对海面溢油检测通常是单类别任务data.yaml长这样path: ./oil_spill_dataset train: ImageSets/Main/train.txt val: ImageSets/Main/val.txt nc: 1 names: [oil_spill]nc是类别数names是类别名列表。注意 YOLO 的class_id从 0 开始如果你的 TXT 里出现了1而nc1训练会直接报索引越界。有些数据集整理者把「油膜」和「疑似油膜」分成两类那nc就要改成 2names也要对应。拿到数据集第一件事就是确认类别数和 TXT 里的最大 class_id 是否匹配。3. 从 VOC 到 YOLO转换脚本、划分策略与三个必调参数3.1 自己写一个可靠的 VOC→YOLO 转换脚本虽然数据集号称双格式但实际拿到的 YOLO 标签未必和 VOC 完全对齐。我一般会自己跑一遍转换确保可控import os import xml.etree.ElementTree as ET import cv2 def voc_to_yolo(xml_dir, img_dir, out_dir, class_map): xml_dir: XML 标注目录 img_dir: 图片目录用于读取实际宽高 out_dir: 输出 YOLO txt 目录 class_map: {oil_spill: 0} 类别名到 id 的映射 os.makedirs(out_dir, exist_okTrue) skipped [] for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue xml_path os.path.join(xml_dir, xml_file) img_name xml_file.replace(.xml, .jpg) img_path os.path.join(img_dir, img_name) if not os.path.exists(img_path): skipped.append(img_name) continue img cv2.imread(img_path) h, w img.shape[:2] tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_map: continue # 跳过 difficult 目标避免噪声标签干扰训练 difficult obj.find(difficult) if difficult is not None and int(difficult.text) 1: continue 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, w)) xmax max(0, min(xmax, w)) ymin max(0, min(ymin, h)) ymax max(0, min(ymax, h)) if xmax xmin or ymax ymin: continue x_center (xmin xmax) / 2.0 / w y_center (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{class_map[name]} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}) out_path os.path.join(out_dir, xml_file.replace(.xml, .txt)) with open(out_path, w) as f: f.write(\n.join(lines)) print(f转换完成跳过 {len(skipped)} 张无对应图片的 XML) return skipped voc_to_yolo(Annotations, JPEGImages, labels_new, {oil_spill: 0})几个关键处理difficult1的目标直接跳过海面溢油里这类目标通常是浪花遮挡的碎油膜强行训练会让模型学到噪声坐标裁剪到图像边界内防止个别标注越界导致 YOLO 训练时 loss 爆炸空标签文件也要生成YOLO 会把空 txt 当作纯背景图这对抑制误检有帮助。3.2 训练集/验证集划分别用随机划分海面溢油数据有个特点——同一片海域、同一次事故的影像往往连续多帧画面高度相似。如果随机划分训练集和验证集里会出现几乎一样的图验证指标虚高实际部署时性能断崖式下跌。正确做法是按「事故批次」或「拍摄时段」划分import os import random def split_by_group(img_dir, label_dir, out_dir, ratio(0.8, 0.1, 0.1)): 按文件名前缀分组划分避免同批次影像泄漏到验证集 假设文件名格式为 oil_batch_frame.jpg groups {} for f in os.listdir(img_dir): if not f.endswith(.jpg): continue parts f.replace(.jpg, ).split(_) batch parts[1] if len(parts) 1 else default groups.setdefault(batch, []).append(f) batches list(groups.keys()) random.shuffle(batches) n len(batches) n_train int(n * ratio[0]) n_val int(n * ratio[1]) train_batches batches[:n_train] val_batches batches[n_train:n_train n_val] test_batches batches[n_train n_val:] for name, batch_list in [(train, train_batches), (val, val_batches), (test, test_batches)]: with open(os.path.join(out_dir, f{name}.txt), w) as f: for b in batch_list: for img in groups[b]: f.write(os.path.join(img_dir, img) \n) print(ftrain: {len(train_batches)} 批, val: {len(val_batches)} 批, test: {len(test_batches)} 批)如果你的数据集文件名没有批次信息退而求其次的做法是按图像相似度聚类后再划分用感知哈希pHash做粗聚类即可汉明距离小于 5 的归为一组。3.3 三个必调参数imgsz、batch、mosaic拿到 1800 张海面溢油图训练时这三个参数直接决定你能不能跑出可用模型。imgsz海面油膜在卫星/无人机影像里往往占据较大面积但边界模糊。imgsz640是默认值但如果你的原图是 1920×1080 且油膜细节丰富建议提到960或1280。代价是显存占用翻倍一张 24G 卡跑 YOLOv8m 在imgsz1280时 batch 只能给到 4。实测经验海面溢油检测里imgsz从 640 提到 960mAP50 通常能涨 3~5 个点因为薄油膜的纹理特征在低分辨率下会被池化掉。batch小数据集不要用大 batch。1800 张图batch16或batch8配合accumulate更稳。大 batch 会让 BN 层的统计量偏向少数批次海面场景里云影和太阳耀斑的分布不均匀大 batch 容易导致 BN 崩溃——现象是训练几个 epoch 后 loss 突然变 NaN。如果遇到先把 batch 降到 8再把lr0从 0.01 降到 0.001。mosaicYOLO 默认开启 mosaic 增强把 4 张图拼成 1 张。海面溢油场景里mosaic 会引入大量非海面区域比如把两张海面图和两张岸边图拼在一起导致模型学到「岸边也是背景」的错误先验。建议在训练后期关闭 mosaic# 前 80% epoch 开 mosaic后 20% 关闭 yolo detect train datadata.yaml modelyolov8m.pt epochs200 imgsz960 batch8 \ mosaic1.0 close_mosaic40 lr00.001close_mosaic40表示最后 40 个 epoch 关闭 mosaic让模型在真实分布上做微调。这个技巧在海上小目标数据集上几乎是标配。4. 训练与验证用 YOLOv8 跑通海面溢油检测的完整命令4.1 环境准备与预训练权重选择YOLOv8 的安装不再赘述直接说权重选择。海面溢油检测属于「背景单一、目标形态多变」的任务从 COCO 预训练权重微调是标准做法。yolov8n太快但精度不够yolov8x在 1800 张图上容易过拟合。我的建议是yolov8m或yolov8l前者在 24G 卡上imgsz960能跑batch8后者需要降到batch4。# 安装 ultralytics pip install ultralytics # 验证环境 yolo checksyolo checks会输出 CUDA 版本、显存、PyTorch 版本。如果 CUDA 不可用训练会回退到 CPU1800 张图跑 200 epoch 大概需要三天不可接受。确保torch.cuda.is_available()返回 True。4.2 启动训练完整命令与参数注释yolo detect train \ data./oil_spill_dataset/data.yaml \ modelyolov8m.pt \ epochs200 \ imgsz960 \ batch8 \ lr00.001 \ lrf0.01 \ momentum0.937 \ weight_decay0.0005 \ warmup_epochs3 \ mosaic1.0 \ close_mosaic40 \ mixup0.1 \ copy_paste0.1 \ degrees10.0 \ translate0.1 \ scale0.5 \ fliplr0.5 \ flipud0.0 \ hsv_h0.015 \ hsv_s0.7 \ hsv_v0.4 \ project./runs/oil_spill \ nameexp01 \ patience50 \ save_period20逐项说明lr00.001比默认的 0.01 更保守小数据集上更稳lrf0.01是最终学习率因子200 epoch 后 lr 降到 0.00001warmup_epochs3让前 3 个 epoch 学习率从极小值线性上升防止初始梯度炸掉flipud0.0关闭上下翻转因为海面影像上下翻转后天空跑到下面不符合真实分布degrees10.0做小角度旋转增强模拟无人机不同航向角hsv_s0.7饱和度增强幅度较大因为海面油膜在不同光照下颜色差异明显。4.3 看训练曲线哪些指标值得盯哪些是噪声训练启动后runs/oil_spill/exp01/下会生成results.csv和results.png。重点看四个指标指标含义海面溢油场景的正常范围box_loss边界框回归损失前 20 epoch 快速下降之后缓慢收敛到 0.5~1.0cls_loss分类损失单类别任务通常降到 0.1 以下mAP50IoU0.5 时的平均精度1800 张图YOLOv8m 通常能到 0.75~0.88mAP50-95IoU 从 0.5 到 0.95 的平均通常比 mAP50 低 15~25 个点如果box_loss震荡剧烈检查标注框是否有大量重叠或极小框宽高小于 5 像素。海面溢油里远距离的薄油膜可能只有十几个像素宽这类目标建议在转换阶段就过滤掉或者单独做一轮高分辨率训练。4.4 验证与推理用混淆矩阵和 PR 曲线判断模型是否可用训练结束后跑验证yolo detect val \ model./runs/oil_spill/exp01/weights/best.pt \ data./oil_spill_dataset/data.yaml \ imgsz960 \ batch8 \ conf0.25 \ iou0.5 \ plotsTrueplotsTrue会生成混淆矩阵、PR 曲线、F1 曲线。海面溢油检测最需要关注的是误检率——模型把太阳耀斑、云影、白浪花误判为油膜。混淆矩阵里如果背景被大量误分为oil_spill说明conf阈值设低了或者训练集里负样本无油膜的海面图不够。解决办法在data.yaml里加入纯背景图空 txt比例控制在 10%~15%。推理单张图yolo detect predict \ model./runs/oil_spill/exp01/weights/best.pt \ source./test_images/ \ imgsz960 \ conf0.3 \ saveTrue \ save_txtTruesave_txtTrue会输出每张图的检测框坐标方便后续和 GIS 系统对接把像素坐标转成经纬度。5. 避坑与排查海面溢油数据集训练中最容易翻车的五件事5.1 现象训练 loss 正常下降但验证 mAP 始终在 0.3 以下原因训练集和验证集划分时发生了数据泄漏或者验证集里的图片在训练集里出现过同一批次连续帧。海面溢油影像的帧间差异极小随机划分必然导致这个问题。解决按拍摄批次或时间段重新划分确保同一批次的图只出现在一个集合里。用感知哈希检查训练集和验证集之间是否存在汉明距离小于 5 的图片对有就重新分配。5.2 现象模型把太阳耀斑和白云全部框成油膜原因训练集里缺少负样本。1800 张图如果全部包含油膜模型没见过「无油膜的海面」就会把任何亮色区域都当成目标。解决加入 150~250 张纯海面背景图无油膜、有云、有耀斑生成对应的空 txt 文件。训练时这些图只参与背景损失计算能显著降低误检。如果找不到纯背景图可以从现有图片里裁剪不含油膜的区域作为负样本。5.3 现象训练到第 50 个 epoch 左右 loss 突然变成 NaN原因BN 层统计量崩溃通常由过大 batch、过高学习率或标注框坐标越界引起。海面溢油数据集里如果有几张图的标注框超出图像边界xmax widthYOLO 在计算 loss 时会产生极大梯度。解决先跑一遍坐标越界检查第 2.3 节的脚本清理越界标注把batch降到 8 或 4lr0从 0.01 降到 0.001加warmup_epochs5。如果还崩在data.yaml里把nc和names再核对一遍确保 TXT 里的 class_id 没有超出范围。5.4 现象推理时小油膜全部漏检大油膜框得很准原因imgsz太小或者训练时 mosaic 增强导致小目标被缩得更小。海面溢油里远距离薄油膜可能只占原图的 1%~2%在imgsz640下经过 32 倍下采样后只剩几个像素特征完全丢失。解决把imgsz提到 960 或 1280在data.yaml里开启rectTrue做矩形训练减少 padding 对小目标的影响如果显存不够用yolov8m代替yolov8l把省下的显存用于提高分辨率。另外可以在训练后期关闭 mosaicclose_mosaic40让小目标以原始尺度参与微调。5.5 现象验证集 mAP 很高但部署到实际视频流上检测结果闪烁严重原因单帧检测没有时序平滑海面波浪导致油膜边界在帧间跳动模型对同一片油膜的框时大时小。解决在推理后处理阶段加跟踪算法如 ByteTrack 或简单的 IoU 匹配对连续帧的检测框做平滑。如果只是做离线筛查可以对同一视频段的多帧检测结果做非极大值抑制NMS的时序版本——把相邻帧的框按 IoU 合并取置信度最高的作为最终输出。这个后处理能把视频里的闪烁降低 70% 以上。6. 把 1800 张图用透小数据集的进阶技巧与验证习惯1800 张图在目标检测里属于小数据集但海面溢油这个场景的特殊性在于——它的背景相对单一海面、天空、云目标形态却极其多变薄油膜、厚油块、乳化带、油水混合物。这意味着你不能靠堆数据量取胜得靠「把每一张图用透」。第一个技巧是分层采样验证。不要只看整体的 mAP50把验证集按油膜面积占比分成三档小目标面积 5%、中目标5%~20%、大目标 20%分别统计每档的召回率。我见过太多模型整体 mAP 0.85但小目标召回率只有 0.4部署到无人机巡检时远距离油膜全部漏检。分层统计能让你提前发现这个问题针对性补充小目标样本或提高imgsz。第二个技巧是用测试时增强TTA榨干精度。YOLO 支持推理时开启 TTA对同一张图做多尺度、多翻转推理后融合结果yolo detect predict \ model./runs/oil_spill/exp01/weights/best.pt \ source./test_images/ \ imgsz960 \ augmentTrue \ conf0.25 \ saveTrueaugmentTrue会做水平翻转和三个尺度的推理mAP 通常能再涨 1~2 个点代价是推理速度降到原来的 1/3。离线筛查场景值得开实时视频流不建议。第三个技巧是定期用新数据做增量验证。海面溢油检测模型最怕的是「过拟合到某一片海域的光照条件」。我一般会留出 100~200 张完全不同海域、不同季节、不同传感器的图作为「外部测试集」不参与训练和调参只在模型定稿前跑一次。如果外部测试集 mAP 比验证集低超过 15 个点说明模型泛化能力不够需要加更多样的训练数据或更强的颜色增强。最后一个习惯每次训练完把 best.pt 在 10 张典型图上跑一遍人眼看框。指标是黑匣子人眼才是后悔药。我踩过最深的坑是一个 mAP 0.91 的模型在薄油膜上框得完美但把一条白色泡沫带稳定框成油膜——验证集里恰好没有泡沫带样本指标完全看不出来。从那以后我每次定稿前都会手动过一遍典型样本尤其是那些「看起来像油膜但不是」的负样本。这个习惯花不了十分钟但能帮你省掉一次线上翻车。希望帮到你。本文还有配套的精品资源点击获取
返回列表