简介:这份目标检测数据集面向环境监控、工业现场安全检测方向的研究者与算法工程师,聚焦地面油污水渍的识别与定位任务。数据包共2000个文件,以1999个VOC格式xml标注文件和1个说明txt为主,压缩包约70.05MB,图片为jpg格式,同时提供Pascal VOC与YOLO两套标注,便于在主流检测框架间直接切换训练。数据集含2093张已增强图片,标注类别仅Spill一类,共2563个矩形框,平均每图约1.23个目标,标注由labelImg完成,规则统一、质量稳定。增强处理覆盖旋转、缩放、裁剪与颜色变换等,有助于提升模型对复杂环境的泛化能力。目前已有182人学习下载,适合用于搭建油污水渍检测基线、验证数据增强策略或开展环境监测预警实验,可作为该细分场景下开箱即用的训练与评测资源。
1. 地面油污水渍检测数据集:2093 张图、2563 个框,单类别 Spill 能直接开训吗
工厂巡检、加油站地面、机修车间这类场景里,油污水渍是个高频又容易被忽略的隐患。人工盯监控基本盯不过来,用目标检测做自动识别是常见思路,但真正动手时第一个卡住的往往不是模型,而是数据——网上现成的油污数据集少得可怜,自己标又费时费力。这份「目标检测地面油污水渍检测数据集2000张VOC+YOLO(已增强)」就是冲着这个缺口来的:2093 张 jpg 图片,配套 2093 个 VOC 格式 xml 和 2093 个 YOLO 格式 txt,单类别 Spill,总框数 2563,用 labelImg 按矩形框规则标注。它适合想快速跑通油污水渍检测 baseline 的算法工程师、做环境监控或工业现场视觉的学生和从业者,也适合拿它当单类别小目标检测的练手素材。下面按「这份资源是什么、怎么接进训练流程、哪里容易翻车」的顺序拆开讲。
2. 数据集结构与格式对齐:VOC 和 YOLO 双份标注怎么用
拿到一个数据集,先别急着写训练脚本,把目录结构和标注格式摸清楚,能省掉后面一半的调试时间。这份资源的核心价值就在于它同时给了 Pascal VOC 和 YOLO 两套标注,等于把格式转换这一步替你做了,但两套标注的坐标系和文件组织方式完全不同,用错一套就会出现框全飘到角落的玄学现象。
2.1 目录组织与文件对应关系
按项目说明,压缩包解压后大致是这样一种扁平结构(不同打包方式可能略有差异,以实际为准):
dataset/ ├── 说明.txt ├── xyxr_spill_2045.jpg ├── xyxr_spill_2045.xml ├── xyxr_spill_2045.txt ├── xyxr_spill_2048.jpg ├── xyxr_spill_2048.xml ├── xyxr_spill_2048.txt ├── ...图片、xml、txt 三者同名,靠文件名主干对应。这种命名方式的好处是转换脚本好写,坏处是所有文件堆在一个目录里,图片一多,文件系统检索会变慢,训练时 DataLoader 反复扫目录也吃亏。我一般会先跑一个整理脚本,按 8:1:1 切成 train/val/test 三个子集,图片和标注分别放到images/和labels/下,这是 YOLO 系列训练器最认的结构。
import os import random import shutil # 原始目录、输出目录、划分比例 src_dir = "dataset" out_dir = "spill_dataset" train_ratio, val_ratio = 0.8, 0.1 # 收集所有同名主干(以 jpg 为准) stems = [f[:-4] for f in os.listdir(src_dir) if f.endswith(".jpg")] random.seed(42) # 固定随机种子,保证可复现 random.shuffle(stems) n = len(stems) n_train = int(n * train_ratio) n_val = int(n * val_ratio) splits = { "train": stems[:n_train], "val": stems[n_train:n_train + n_val], "test": stems[n_train + n_val:], } for split, items in splits.items(): img_dir = os.path.join(out_dir, "images", split) lbl_dir = os.path.join(out_dir, "labels", split) os.makedirs(img_dir, exist_ok=True) os.makedirs(lbl_dir, exist_ok=True) for stem in items: shutil.copy(os.path.join(src_dir, stem + ".jpg"), img_dir) # YOLO 训练只认 txt,xml 留作备份或转其他框架用 shutil.copy(os.path.join(src_dir, stem + ".txt"), lbl_dir)这段脚本做了三件事:固定种子打乱、按比例切分、把图片和 YOLO 标签分别归位。random.seed(42)是关键,不固定种子的话每次划分结果不同,模型指标就没法横向对比。train_ratio和val_ratio按需改,单类别 2000 张量级,8:1:1 是比较稳的起点。注意这里只复制了 txt,xml 没动——如果你后面要用 MMDetection 或 Detectron2 这类吃 VOC/COCO 的框架,就得把 xml 也一起归位。
2.2 VOC 与 YOLO 标注的坐标差异
这是最容易翻车的地方。VOC 的 xml 里存的是绝对像素坐标,格式是左上角(xmin, ymin)和右下角(xmax, ymax);YOLO 的 txt 存的是归一化后的中心点坐标加宽高,格式是class_id cx cy w h,四个值都在 0~1 之间。两者不能混用,喂错了模型照样能跑,但 loss 降不下去,框会出现在莫名其妙的位置。
一个典型的 VOC xml 长这样:
<annotation> <filename>xyxr_spill_2045.jpg</filename> <size> <width>640</width> <height>480</height> <depth>3</depth> </size> <object> <name>Spill</name> <bndbox> <xmin>212</xmin> <ymin>156</ymin> <xmax>398</xmax> <ymax>301</ymax> </bndbox> </object> </annotation>对应的 YOLO txt 应该是这样一行(假设类别 id 为 0):
0 0.476562 0.476042 0.290625 0.302083换算关系是:cx = (xmin + xmax) / 2 / width,cy = (ymin + ymax) / 2 / height,w = (xmax - xmin) / width,h = (ymax - ymin) / height。这份数据集已经帮你转好了,但你要知道这个公式,因为一旦发现框偏移,第一件事就是拿一张图手算一遍验证。
提示:拿到数据集后先抽 5~10 张图,用可视化脚本把 YOLO 框画回原图,确认框贴合水渍区域再开训。这一步花五分钟,能避免训到一半才发现标注错位的血泪经验。
2.3 单类别 Spill 的标签映射
数据集只有一类 Spill,YOLO 的 class_id 就是 0。写data.yaml时类别名要和标注里的<name>严格一致,大小写都别改:
path: ./spill_dataset train: images/train val: images/val test: images/test nc: 1 names: ["Spill"]nc: 1和names长度必须对上,否则训练器会在加载时直接报错。单类别的好处是不用纠结类别不平衡,但要注意 2563 个框分布在 2093 张图上,平均每张 1.23 个框,意味着有相当一部分图是单框甚至个别图可能无框(增强后可能引入),训练前最好统计一下每张图的框数分布,无框图在 YOLO 里对应空 txt 文件,是合法的负样本,别误删。
3. 从零跑通训练:环境、配置与首轮验证
格式理清之后,就可以接训练流程了。这一章以 YOLOv8 为主线,因为它的数据加载对 VOC/YOLO 混合结构兼容性好、上手快,也是目前检索量最大的方案之一。整个流程分环境准备、配置、启动训练、看首轮结果四步,每一步都有容易忽略的参数。
3.1 环境配置与依赖版本
YOLOv8 依赖 ultralytics 包,Python 建议 3.8~3.11,PyTorch 按显卡 CUDA 版本装。Anaconda 环境下我一般这么起:
conda create -n spill python=3.10 -y conda activate spill # 按本机 CUDA 版本选对应 torch,这里以 cu118 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics opencv-python装完先验证环境:
yolo checks这条命令会打印 PyTorch、CUDA、设备信息。如果 CUDA 显示不可用,多半是 torch 版本和驱动不匹配,别硬训,CPU 训 2000 张图会慢到怀疑人生。ultralytics版本不同,训练参数名偶有差异,遇到KeyError先查官方文档对应版本的参数表,别照搬旧教程。
3.2 训练命令与关键参数
配置好data.yaml后,一条命令就能起训:
yolo detect train \ data=spill_dataset/data.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ lr0=0.01 \ patience=20 \ project=runs/spill \ name=baseline逐个说参数:model=yolov8n.pt用 nano 版先跑 baseline,速度快、显存占用低,确认流程通了再换 s/m/l;imgsz=640是输入分辨率,油污水渍在图上占比不一,如果水渍偏小可以提到 960 或 1280,但显存和速度要重新权衡;batch=16按显存调,8G 显存跑 640 一般能到 16;lr0=0.01是初始学习率,单类别数据量不大时这个值偏稳;patience=20是早停,20 轮指标不涨就停,省时间。epochs=100对 2000 张图通常够收敛,不够再加。
3.3 首轮结果怎么读
训练跑起来后,重点盯三个东西:loss 曲线、mAP、验证集的可视化预测图。runs/spill/baseline/下会有results.csv和weights/。用 pandas 快速看指标:
import pandas as pd df = pd.read_csv("runs/spill/baseline/results.csv") # 列名首尾可能有空格,先 strip df.columns = [c.strip() for c in df.columns] print(df[["epoch", "train/box_loss", "metrics/mAP50(B)", "metrics/mAP50-95(B)"]].tail(10))metrics/mAP50(B)是 IoU=0.5 时的平均精度,单类别任务里这个值最直观。如果它长期卡在 0.1 以下,八成是标注格式或路径配错了,回去查data.yaml的path是不是相对路径、labels目录里 txt 是否和图片同名。如果 mAP 能到 0.6 以上,说明数据本身质量过关,可以换更大模型或调增强参数继续压。
注意:验证集的可视化图在
runs/spill/baseline/val_batch*.jpg,一定要打开看。指标好看但框画歪的情况并不少见,尤其是增强后的图片,肉眼确认一遍比看数字靠谱。
4. 增强数据的坑与排查:为什么你的 mAP 上不去
这份数据集标了「已增强」,这是卖点也是隐患。增强能提升泛化,但如果增强方式和你的实际场景不匹配,反而会引入噪声。这一章集中讲几个高频翻车点,都是现象、原因、解决三件套。
4.1 增强图与原图混在一起,验证集泄漏
现象:训练 mAP 很高,换到真实场景或独立测试集就崩。原因:增强通常是对原图做旋转、缩放、裁剪、颜色变换生成新图。如果同一张原图的多个增强版本被随机分到了 train 和 val,验证集里就有训练集的「近亲」,指标虚高。解决:划分数据集时按「原图主干」分组,同一主干的增强版本必须整体进同一个 split。如果文件名里带了增强标记(如_aug1、_rot90),先按前缀归组再切分。上面 2.1 的脚本是按文件名主干切的,如果增强图改了名,需要先做一次分组映射。
4.2 裁剪增强导致标注框越界
现象:训练时报x, y, w, h超出 [0,1] 范围,或框画到图外。原因:裁剪增强后图片尺寸变了,但标注没同步重算,或者重算时没做边界裁剪。解决:写一个校验脚本,遍历所有 txt,检查四个值是否都在 0~1 且w,h > 0:
import os bad = [] for f in os.listdir("spill_dataset/labels/train"): if not f.endswith(".txt"): continue with open(os.path.join("spill_dataset/labels/train", f)) as fp: for i, line in enumerate(fp): parts = line.strip().split() if len(parts) != 5: bad.append((f, i, "字段数不对")) continue _, cx, cy, w, h = map(float, parts) if not all(0 <= v <= 1 for v in (cx, cy, w, h)) or w <= 0 or h <= 0: bad.append((f, i, line.strip())) print(f"异常标注 {len(bad)} 条") for b in bad[:20]: print(b)发现越界就手动修正或直接剔除该图,别让脏标注进训练。
4.3 颜色变换把水渍特征改没了
现象:模型对深色水渍敏感,对浅色或反光水渍漏检严重。原因:增强里的颜色抖动(亮度、对比度、饱和度)幅度过大,把油污水渍本身的颜色特征抹掉了,模型学到的是增强后的伪特征。解决:如果这份数据集的增强包含强颜色变换,训练时把 YOLO 自带的hsv_h、hsv_s、hsv_v调小甚至关掉,避免二次增强叠加。默认hsv_h=0.015、hsv_s=0.7、hsv_v=0.4,油污场景建议降到hsv_h=0.01、hsv_s=0.3、hsv_v=0.2试。
4.4 单类别下的背景误检
现象:地面反光、阴影、深色地砖被误判成 Spill。原因:单类别数据集缺少「难负样本」,模型没见过足够多的非水渍干扰。解决:从验证集误检图里挑出典型背景,作为负样本加入训练(空 txt 文件),或者用yolo detect predict跑一批无油污的地面图,把高置信度误检的图补进负样本集。这是提升单类别检测精度的常规操作。
4.5 图片和标签不同名导致静默丢样本
现象:训练日志里train: Scanning...显示的图片数比预期少。原因:YOLO 加载时按图片找同名 txt,找不到就跳过该图,不报错。增强过程中如果改名不一致,就会静默丢样本。解决:训练前跑一遍配对检查:
import os img_dir, lbl_dir = "spill_dataset/images/train", "spill_dataset/labels/train" imgs = {f[:-4] for f in os.listdir(img_dir) if f.endswith(".jpg")} lbls = {f[:-4] for f in os.listdir(lbl_dir) if f.endswith(".txt")} print("有图无标签:", imgs - lbls) print("有标签无图:", lbls - imgs)两边差集都应为空,不为空就补齐或删除。
5. 进阶技巧:用这份数据把单类别检测调到能落地
baseline 跑通只是起点,真正要落地到巡检或监控场景,还得在推理侧和训练策略上做几件事。这一章讲三个我实际用过的技巧,都是围绕这份 Spill 数据集展开的。
第一个是置信度门限的调整。YOLO 默认conf=0.25,但油污水渍检测里,漏检的代价通常比误检高——漏掉一处油污可能意味着环境风险,误检顶多多看几眼。所以推理时我会把门限降到 0.15~0.2,先把召回拉上来,再用后处理过滤明显不合理的框(比如面积过小或长宽比异常的)。命令很简单:
yolo detect predict \ model=runs/spill/baseline/weights/best.pt \ source=test_images/ \ conf=0.18 \ iou=0.5 \ save=Trueconf是置信度门限,iou是 NMS 的 IoU 阈值,油污水渍形状不规则、有时会连成一片,iou设太高会把相邻水渍合并,设太低又会重复框,0.5 是个平衡点,具体按你的场景微调。
第二个是切片推理应对小目标。如果监控画面分辨率高、水渍在图上占比很小,整图缩到 640 会丢细节。常见做法是切图推理(SAHI 那套思路),把大图切成带重叠的小块分别检测再合并。对这份数据集,可以先统计标注框的相对面积分布,如果大量框的w*h小于 0.01,就值得上切片。统计代码:
import os areas = [] for f in os.listdir("spill_dataset/labels/train"): if f.endswith(".txt"): with open(os.path.join("spill_dataset/labels/train", f)) as fp: for line in fp: _, _, _, w, h = map(float, line.split()) areas.append(w * h) areas.sort() n = len(areas) print(f"框总数 {n}") print(f"面积中位数 {areas[n//2]:.4f}") print(f"小于 0.01 的占比 {sum(a < 0.01 for a in areas) / n:.2%}")第三个是交叉验证选模型。单类别 2000 张图,单次划分的指标波动可能不小,用 5 折交叉验证能更稳地比较 yolov8n/s/m 哪个性价比最高。做法是把 2.1 的划分脚本改成按折生成不同的data.yaml,循环训练,最后看各模型在 5 折上的 mAP 均值和方差。方差小的模型泛化更稳,别只看单折最高分。
| 模型 | 参数量 | 640 推理速度(参考) | 适用场景 |
|---|---|---|---|
| yolov8n | 3.2M | 最快 | 边缘设备、实时巡检 |
| yolov8s | 11.2M | 中等 | 服务器端、精度优先 |
| yolov8m | 25.9M | 较慢 | 离线分析、追求 mAP |
这张表只是选型参考,实际速度受硬件和imgsz影响很大,务必在自己机器上实测。我一般先用 n 版把流程和门限调好,再换 s 版看 mAP 提升是否值得那点速度损失。
从那以后我每次拿到标注好的数据集,都强制先跑一遍配对检查和框可视化,再动训练脚本——这个习惯帮我挡掉过好几次「指标诡异但其实是数据错位」的翻车。希望这份拆解能帮你把这份油污水渍数据集顺利用起来。
本文还有配套的精品资源,点击获取