海面溢油检测数据集:1817张图与3871个框的YOLO实战指南
发布时间:2026/9/28 16:39:39来源:尧图网络
简介本资源为面向目标检测学习者的海面石油原油泄漏检测数据集适用于环境监测、海上应急响应等场景下的模型训练与算法验证适合具备一定深度学习基础、正在开展单类别目标检测实践的开发者与研究人员。压缩包共2000个文件以1817个xml标注文件和183个txt标注文件为主分别对应Pascal VOC与YOLO两种格式另含1817张jpg图片整体约79.05MB可直接用于YOLO系列或VOC兼容框架的训练流程。数据集仅设oil_spillage一个类别累计标注框3871个部分图片包含多个泄漏点标注由labelImg完成框位与类别信息一致可靠。目前已有283人学习下载可作为单类别检测任务的练手素材帮助读者快速搭建训练管线、验证多目标识别效果并在此基础上进行数据增强与模型调优。1. 海面溢油检测数据集1817 张图、3871 个框单类目标检测的落地起点海面石油原油泄漏检测这件事难的不是模型结构而是拿到一批标注干净、格式对得上、能直接喂进训练管线的数据。这份资源给的就是这么一批东西1817 张 jpg 原图配套 1817 个 Pascal VOC 的 xml 和 1817 个 YOLO 的 txt标注类别只有一个——oil_spillage总框数 3871。单类、双格式、框数大于图数意味着不少画面里同时存在多个溢油区域这对训练一个能识别多目标的检测器是好事。它适合两类人一类是想快速跑通海面溢油检测 demo 的算法工程师另一类是拿它做数据增强、格式转换、小样本微调实验的研究者。下面按「这是什么 → 怎么用 → 坑在哪」的顺序拆开讲中间给可直接抄的代码和参数。2. VOC 与 YOLO 双格式拆解从 xml 到 txt 的坐标映射2.1 两种格式到底差在哪Pascal VOC 的 xml 是「绝对坐标 图像尺寸」的描述方式每个object里有name、bndbox的xmin/ymin/xmax/ymax坐标是像素值原点在左上角。YOLO 的 txt 是「归一化中心点 宽高」的描述方式每行class_id cx cy w h五个值全部除以图像宽高落在 0~1 之间。这份数据集两种都给了好处是你不用自己写转换脚本坏处是——如果你不核对很容易出现 xml 和 txt 对不上的情况尤其是当有人手动改过其中一份。单类数据集里class_id恒为 0对应oil_spillage。3871 个框分布在 1817 张图上平均每张 2.13 个框说明有相当一部分图是单框另一部分是多框。多框场景对 YOLO 的 anchor 匹配和损失计算是有影响的后面第 4 章会讲。2.2 用脚本核对 xml 与 txt 是否一致拿到数据集第一件事不是训练是核对。下面这段脚本遍历所有 xml 和 txt把 xml 里的框转成 YOLO 格式再和 txt 里的逐行比对容差设 1e-4。import os import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, img_w, img_h): tree ET.parse(xml_path) root tree.getroot() boxes [] for obj in root.findall(object): name obj.find(name).text bnd obj.find(bndbox) xmin float(bnd.find(xmin).text) ymin float(bnd.find(ymin).text) xmax float(bnd.find(xmax).text) ymax float(bnd.find(ymax).text) cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h boxes.append((name, cx, cy, w, h)) return boxes def check_pair(xml_path, txt_path, img_w, img_h, tol1e-4): voc_boxes voc_to_yolo(xml_path, img_w, img_h) with open(txt_path) as f: yolo_lines [l.strip().split() for l in f if l.strip()] if len(voc_boxes) ! len(yolo_lines): return f数量不一致: {xml_path} vs {txt_path} for (name, cx, cy, w, h), line in zip(voc_boxes, yolo_lines): _, tcx, tcy, tw, th line if abs(cx - float(tcx)) tol or abs(cy - float(tcy)) tol \ or abs(w - float(tw)) tol or abs(h - float(th)) tol: return f坐标不一致: {xml_path} return None # 假设图片尺寸已知实际可从 jpg 读取 img_w, img_h 1920, 1080 for f in os.listdir(annotations_xml): if f.endswith(.xml): stem f[:-4] err check_pair(fannotations_xml/{f}, flabels_yolo/{stem}.txt, img_w, img_h) if err: print(err)逻辑说明voc_to_yolo把 xml 的绝对坐标转成归一化中心点格式check_pair逐行比对。参数tol是浮点容差设 1e-4 是因为标注工具写出的浮点精度通常到小数点后 6 位1e-4 足够容忍舍入误差又不会放过真实错误。img_w和img_h必须从对应 jpg 实际读取不能硬编码因为海面图像可能来自不同采集设备分辨率不统一。2.3 目录结构怎么组织YOLO 训练管线对目录有约定常见做法是dataset/ images/ train/ val/ labels/ train/ val/ data.yamldata.yaml里写train: images/train、val: images/val、nc: 1、names: [oil_spillage]。注意nc是类别数单类就写 1不要写成 0。names用列表顺序和 txt 里的class_id对应这里只有 0 号所以列表只有一个元素。提示如果你的 YOLO 版本要求names用字典形式如{0: oil_spillage}按版本文档改但这份数据集本身只提供 txt不绑定任何框架。3. 训练管线搭建从 data.yaml 到第一个 checkpoint3.1 划分训练集与验证集1817 张图不算大验证集比例建议 10%~15%即 180~270 张。划分时要注意如果同一片海域、同一时段的图片被分到两边验证指标会虚高。常见做法是按文件名前缀或采集批次分组后再划分而不是纯随机。下面这段脚本按文件名排序后每隔 7 张取 1 张做验证保证分布均匀。import os, shutil, random src_img images_all src_lbl labels_all dst dataset random.seed(42) files sorted([f for f in os.listdir(src_img) if f.endswith(.jpg)]) val_idx set(range(0, len(files), 7)) # 每7张取1张 for split in [train, val]: os.makedirs(f{dst}/images/{split}, exist_okTrue) os.makedirs(f{dst}/labels/{split}, exist_okTrue) for i, f in enumerate(files): split val if i in val_idx else train stem f[:-4] shutil.copy(f{src_img}/{f}, f{dst}/images/{split}/{f}) shutil.copy(f{src_lbl}/{stem}.txt, f{dst}/labels/{split}/{stem}.txt)参数说明random.seed(42)保证可复现range(0, len(files), 7)的步长 7 对应约 14% 验证集。如果你的数据有明显批次差异把sorted换成按批次分组再取。3.2 训练命令与关键参数以 YOLOv8 为例常见训练命令yolo detect train \ datadataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/oil \ nameexp1参数逐个说modelyolov8n.pt是 nano 版预训练权重单类小数据集够用显存紧张时优先选它imgsz640是输入分辨率海面溢油区域如果偏小可以提到 1024但显存翻倍batch16在 8GB 显存上跑 640 分辨率通常没问题lr00.01是初始学习率微调场景可以降到 0.001patience20是早停耐心值验证指标 20 轮不升就停。epochs100对 1817 张图偏多实际可能 50~70 轮就收敛看mAP50曲线。3.3 训练中该盯哪些指标mAP50和mAP50-95是主指标但单类数据集还要看precision和recall的平衡。海面溢油检测里漏检recall 低比误检precision 低代价更大所以如果 recall 明显低于 precision可以调低置信度阈值或增加正样本增强。box_loss和cls_loss的下降曲线也要看如果cls_loss早早降到接近 0 而box_loss还在震荡说明分类太容易、定位没学好可能是标注框质量参差。注意YOLO 训练日志里的instances是当前 batch 的正样本数单类数据集里这个值波动大是正常的因为有的图 1 个框、有的图 5 个框。4. 避坑与排查标注、格式、训练里的五条血泪经验4.1 现象训练报错「Label class X is not in names」原因txt 里的class_id超出了data.yaml的names范围。这份数据集只有oil_spillage一类class_id应该是 0但如果有人把 VOC 的类别名直接写进 txt 或用了别的工具转换可能出现 1 甚至更大的值。解决跑一遍全量扫描统计所有 txt 里出现过的class_idawk {print $1} labels/train/*.txt labels/val/*.txt | sort -u输出应该只有0。如果有其他值要么改data.yaml的names要么把异常 txt 挑出来重标。4.2 现象mAP 一直上不去loss 不降原因xml 和 txt 的坐标对不上或者图片和标注文件名不匹配比如图片叫xyxr_oil_311.jpg标注叫xyxr_oil_311.txt但内容对应的是另一张图。这份数据集的文件名列表里有xyxr_oil_311.txt、xyxr_oil_134.txt等命名规律是xyxr_oil_加编号核对时务必确认图片和标注的编号一致。解决用第 2.2 节的脚本全量核对同时检查图片和标注的 stem 是否一一对应。常见错误是复制时漏了某张图的 txt导致训练时该图被当成负样本。4.3 现象验证集指标远高于训练集原因验证集和训练集来自同一批次、同一海域分布几乎一样甚至验证集图片在训练集里出现过重复文件。1817 张图里如果有重复或近似重复随机划分会把它们分到两边。解决划分前先做去重用感知哈希或简单的文件 MD5 查重。如果发现重复只保留一份。另外按采集批次分组划分而不是纯随机。4.4 现象小目标漏检严重原因海面溢油区域在整幅图中占比很小640 分辨率下可能只有几十个像素。YOLO 的 P3 特征图 stride 是 8太小的目标在浅层特征上就丢了。解决把imgsz提到 1024 或 1280同时开启mosaic和copy_paste增强YOLOv8 默认开 mosaic。如果显存不够用batch8配合梯度累积。另一个办法是切片推理SAHI把大图切成小块分别检测再合并。4.5 现象训练到一半 loss 突然变 NaN原因学习率太大、batch 太小导致梯度爆炸或者某张图的标注框宽高为 0xml 里xminxmax或yminymax。这份数据集是人工标注偶尔会出现拖拽失误产生的零面积框。解决先扫描所有 txt检查是否有w0或h0的行awk $40 || $50 {print FILENAME: $0} labels/train/*.txt labels/val/*.txt有的话删掉该行或修正标注。训练侧把lr0降到 0.001加warmup_epochs3并在data.yaml同级加ampFalse排除混合精度问题。5. 进阶技巧用 3871 个框做增强与难例挖掘5.1 按框数分层采样3871 个框分布在 1817 张图上意味着有的图只有 1 个框有的图有 5 个以上。训练时如果不对多框图加权模型会偏向单框场景。一个实用技巧是给每张图算一个权重权重正比于框数在自定义 dataloader 里按权重采样。YOLO 官方管线不直接支持但可以在生成 txt 列表时重复多框图的文件名变相提高采样概率。import os def build_weighted_list(label_dir, out_file, repeat_thresh3): lines [] for f in os.listdir(label_dir): if not f.endswith(.txt): continue with open(os.path.join(label_dir, f)) as fh: n len([l for l in fh if l.strip()]) # 框数超过阈值的图重复计入 repeat 2 if n repeat_thresh else 1 img_path fimages/train/{f[:-4]}.jpg lines.extend([img_path] * repeat) with open(out_file, w) as fh: fh.write(\n.join(lines)) build_weighted_list(labels/train, train_weighted.txt, repeat_thresh3)参数说明repeat_thresh3表示框数 ≥3 的图重复一次实际可按框数分布调整。out_file是给自定义 dataloader 用的图片路径列表YOLO 官方训练不读这个文件但你可以用它做离线分析或迁移到其他框架。5.2 用验证集做难例挖掘训练完第一版模型后在验证集上跑推理把漏检和误检的图挑出来人工复核标注。常见做法是导出预测结果和真值的对比图按confidence排序优先看低置信度但真值存在的样本。这些样本往往对应小目标、低对比度或海面反光干扰把它们加回训练集或复制一份加权能明显提升 recall。yolo detect predict \ modelruns/oil/exp1/weights/best.pt \ sourcedataset/images/val \ conf0.25 \ save_txtTrue \ save_confTrue \ projectruns/oil/predconf0.25是推理置信度阈值比训练时的默认值低目的是尽量多召回方便找漏检。save_txtTrue会把预测框写成 YOLO 格式和真值 txt 对比就能定位差异。5.3 一个我踩过的坑第一次用这份数据集时我直接拿 xml 转 txt 的脚本跑了一遍没核对结果训练到 30 轮发现 mAP 卡在 0.4 不动。回头查才发现有十几张图的 xml 里xmax小于xmin转换后宽高为负YOLO 直接把这些框当无效样本丢了。从那以后我每次拿到新数据集都强制先跑一遍坐标合法性检查xmaxxmin、ymaxymin、0cx1、0w1四个条件缺一不可。这份数据集整体质量不错但人工标注的东西后悔药不如提前查。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网