尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

石油泄露目标检测数据集:VOC/COCO/YOLO格式转换与YOLOv8训练实战

发布时间:2026/9/29 23:55:09

资讯中心
01
ARTICLE

石油泄露目标检测数据集:VOC/COCO/YOLO格式转换与YOLOv8训练实战

石油泄露目标检测数据集:VOC/COCO/YOLO格式转换与YOLOv8训练实战
简介YOLO石油泄露目标检测数据集面向计算机视觉学习者与工业安全巡检场景包含1000张真实场景高质量图片数据场景丰富且由LabelImg标注标注框质量高。文件按VOC(xml)、COCO(json)、YOLO(txt)三种标签格式分类存放于独立文件夹可直接投喂YOLO系列深度学习模型训练免去自行转换格式的繁琐步骤。压缩包内共2000个文件以xml与txt标签文件为主另含6个HTML环境搭建与训练教程、3个Python数据集划分脚本及1个yaml配置文件整体约117.16MB目录结构清晰便于按需取用。附赠Linux/Windows双系统YOLO环境搭建与训练教程并提供训练集、验证集、测试集划分脚本支持自定义比例一键拆分图片与标签。已有658人学习适合需要在课程实践、毕业设计或油田巡检项目中快速落地目标检测方案的研究者与开发者。1. 石油泄露目标检测数据集1000张图、三种标签一次到位先看清它能干什么“石油泄露目标检测数据集”听起来只是1000张图片加标签但实际拿到手你会发现它同时给了VOC、COCO和YOLO三种格式的标注文件还附带划分脚本和训练教程这在目标检测数据集里算得上“全家桶”配置。目标检测项目里真正消耗时间的不是模型调参而是数据整理标签格式不统一、划分不合理、类别索引错位每一样都能让你在训练刚开始就反复翻车。本文围绕这套石油泄露检测数据集把三种格式的差异、划分脚本的用法、YOLO训练流程和常见坑位一次讲透。适合手里有自定义检测需求、需要在海洋溢油监测或石油管道巡检场景做污染目标定位的工程师也适合想通过一套完整数据集把YOLO训练流程跑通的初学者。2. VOC、COCO、YOLO三套标签同一个泄漏框的三种写法与转换实操2.1 XML、JSON、TXT三套格式的字段差异与选型逻辑做目标检测离不开标注格式而VOC、COCO、YOLO是三类最常遇到的标签“方言”。VOC格式以XML文件存储每个文件对应一张图片文件里每个object节点描述一个目标包含name、pose、truncated、difficult以及bndbox子节点bndbox里放的是xmin、ymin、xmax、ymax四个绝对像素坐标人眼直接可读。COCO格式把整批标注合并成一个JSON文件外层是images、annotations、categories三个数组annotations里每条记录一个实例核心字段是image_id、category_id、bbox和segmentationbbox采用绝对像素的[x, y, width, height]写法注意它和VOC的xmax/ymax是两套坐标体系互相转换时务必先换算宽高。YOLO格式则是每张图片对应一个同名TXT每行描述一个目标五个数字依次是类别ID、归一化中心x、归一化中心y、归一化宽、归一化高所有坐标值都在0到1之间。把三套格式放在一起对比选型逻辑才清晰。VOC的XML适合在LabelImg里做增量标注COCO的JSON适合交给pycocotools做评估和多任务训练YOLO的TXT文件最小、零依赖是当前YOLOv5、YOLOv8、YOLOv11训练框架的输入主流。实际项目里常见做法是统一用CVAT或LabelImg完成标注再按框架需求导出对应格式。这套石油泄露数据集直接把三份标签都配齐省掉的就是这层转换也意味着你不管用哪个检测框架都不用重新改标签。下面是三套格式的核心差异后面做转换时随时回看。格式文件形态坐标体系类别记录主要消费方VOC每图一个XML绝对像素xmin/ymin/xmax/ymax类别名字符串LabelImg人工标注、数据查验COCO整个集合一个JSON绝对像素[x, y, w, h]或分割点类别ID数字pycocotools评估、实例分割YOLO每图一个TXT归一化中心点及宽高类别ID从0开始连续YOLO系列训练、TensorRT部署石油泄露场景里有个现实问题标签里的框往往不是规则矩形因为泄露区域在海面上会随水流扩散边缘呈弥散状。如果标注时把大片海水背景一起框进去训练出来的模型在真实巡检画面里很容易把暗色水纹误判成泄露。所以拿到标签后建议先做的事情之一就是抽几张图检查框的贴合度而不是直接开训。2.2 从VOC到YOLO坐标换算与Python脚本实现数据集里配好的VOC标签没必要改动但如果你想用YOLO框架训练就得有一份能跑的转换脚本。转换逻辑不复杂把bndbox四个角点转成中心点与宽高再除以原图宽高完成归一化。下面是核心逻辑适配石油泄露这类单张图多个目标的情况。import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, class_names, out_txt_path): tree ET.parse(xml_path) root tree.getroot() img_w float(root.findtext(size/width)) img_h float(root.findtext(size/height)) lines [] for obj in root.findall(object): name obj.findtext(name) if name not in class_names: continue cls_id class_names.index(name) xmin float(obj.findtext(bndbox/xmin)) ymin float(obj.findtext(bndbox/ymin)) xmax float(obj.findtext(bndbox/xmax)) ymax float(obj.findtext(bndbox/ymax)) cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) with open(out_txt_path, w) as f: f.write(\n.join(lines))这段代码有两个关键点必须说明。第一个是class_names列表的顺序必须和后续训练用的data.yaml里的names字段保持一致否则类别ID对不上关系。石油泄露这类数据如果只有oil_spill一个类别那顺序无所谓但若标注里同时有油罐、管道、船只等目标顺序一旦改动所有TXT的类别索引全部偏移。第二个是img_w和img_h一定要取原图尺寸而不是预处理缩放后的尺寸代错了坐标就全错了。石油泄露图片的特点是背景是海面或暗色土壤目标是大片灰度差异不明显的色块很多标注框宽高比例悬殊。YOLO格式里宽高都是归一化后的0到1小数训练时不会因为框大小悬殊产生加载问题但会影响anchor匹配。所以这类场景我一般建议后续训练时使用自动anchor重算不要直接沿用默认值。2.3 从COCO到YOLO类别重映射是一个高频暗坑COCO格式里categories的category_id是原始编号可能跨度很大而YOLO要求类别ID必须连续且从0开始。直接把category_id写进TXT模型训练时读到的标签会错位到完全不同的语义。转换时必须先建立一张重映射表。import json import os category_map {1: 0, 2: 1, 3: 2} # 原始COCO id - 连续YOLO id def coco_to_yolo(coco_json, out_dir): with open(coco_json, r) as f: data json.load(f) image_info {img[id]: img for img in data[images]} anns {} for ann in data[annotations]: anns.setdefault(ann[image_id], []).append(ann) for image_id, ann_list in anns.items(): img image_info[image_id] w, h img[width], img[height] txt_name os.path.splitext(img[file_name])[0] .txt lines [] for ann in ann_list: cat_id ann[category_id] if cat_id not in category_map: continue cls_id category_map[cat_id] x, y, bw, bh ann[bbox] # COCO的bbox是x,y,w,h cx (x bw / 2) / w cy (y bh / 2) / h bw_norm bw / w bh_norm bh / h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw_norm:.6f} {bh_norm:.6f}) with open(os.path.join(out_dir, txt_name), w) as f: f.write(\n.join(lines))这里的bbox是绝对像素的x、y、w、h不是VOC那套xmin、ymin、xmax、ymax所以中心点计算是x加上半宽不是两端相加再除二。不少从VOC转过来的老手在这里翻过车两个公式长得很像语义完全不同。代码里category_map需要按实际分类逐一核对先打印COCO JSON里的categories数组人工确认后再固化成映射不要再随手改。转换完成后建议做一次抽检随机挑出三到五张图把TXT里的坐标反画回原图上肉眼确认框与泄露区域吻合。用OpenCV几行就能实现这一步是整个转换流程里成本最低、价值最高的质检环节能拦住绝大部分低级错误。注意坐标反画时如果框出现在图外或大面积偏移先回到原图和TXT逐行比对不要急着怀疑训练框架。3. 图片与标签的同步切分1000张图的训练/验证/测试划分脚本拆解3.1 不做样本泄漏为什么划分要在转换和训练之前想清楚石油泄露检测项目里我见过最多的翻车现场不是模型结构选错而是train/val/test切分时样本泄漏。所谓样本泄漏就是同一来源的图片同时出现在训练集和验证集评估指标虚高一到真实巡检现场立刻现形。石油泄露数据往往来自同一段无人机视频的连续抽帧或同一片海域的多角度拍摄相邻两张图画面高度相似如果划分时不做去重val分数会失去参考意义。划分脚本在一套完整数据集里之所以重要就是因为它把“随机但不泄漏”这件事程序化。常见做法是先用文件名做shuffle再按比例切分。但光shuffle不够如果图片来自视频抽帧且文件名带帧号一定要按视频源或时间段分组而不是对单帧做完全随机抽样。把随机种子固定、把划分比例参数化是防止每次重跑导致实验不可复现的最朴素手段。3.2 划分脚本的输入输出与随机种子控制这套数据集附带的划分脚本核心逻辑通常是这样扫描images目录下的所有图片按比例切分到train、val、test三个集合同时把同名的三种格式标签一起迁移到对应子目录。下面这段代码演示主流程重点在于三个集合与同名标签的同步。import os import random import shutil random.seed(42) # 固定随机种子保证每次划分结果一致 train_ratio 0.7 val_ratio 0.2 test_ratio 0.1 image_dir images out_root dataset_split files [f for f in os.listdir(image_dir) if f.lower().endswith((.jpg, .jpeg, .png))] random.shuffle(files) n len(files) n_train int(n * train_ratio) n_val int(n * val_ratio) split_map {} for i, f in enumerate(files): if i n_train: split train elif i n_train n_val: split val else: split test split_map[f] split参数说明seed固定后每次划分结果一致这比反复随机划分、实验不可复现要稳妥得多。train_ratio、val_ratio、test_ratio三个比例之和必须为1具体数值看样本量调整1000张图我一般用8:1:1或者7:2:1如果样本来源单一test可以只留50到100张更多图喂给训练。接下来是同步复制图片和标签文件for img_name, split in split_map.items(): base, ext os.path.splitext(img_name) src_img os.path.join(image_dir, img_name) dst_img os.path.join(out_root, split, images, img_name) os.makedirs(os.path.dirname(dst_img), exist_okTrue) shutil.copy2(src_img, dst_img) for sub_dir in [labels_voc, labels_coco, labels_yolo]: if sub_dir labels_coco: continue # COCO是单JSON单独复制见下方说明 ext_map {labels_voc: .xml, labels_yolo: .txt} src_label os.path.join(sub_dir, base ext_map[sub_dir]) if os.path.exists(src_label): dst_label os.path.join(out_root, split, sub_dir, base ext_map[sub_dir]) os.makedirs(os.path.dirname(dst_label), exist_okTrue) shutil.copy2(src_label, dst_label)这里有一个容易忽略的细节VOC是xml后缀YOLO是txtCOCO是单个JSON三种格式不能放同一个目录里按同名扩散否则txt互相覆盖。常见做法是维护labels_voc、labels_yolo两个顶层目录COCO的JSON单独切出对应的image_id子集后重写一个val.json和train.json。不要把整个COCO JSON复制到每个划分目录里那会造成验证集里混有训练图片的标注。3.3 划分后的核对清单五秒钟发现切分翻车完成划分后别急着训练先执行三条核对逻辑对比三个集合图片数量之和与总数是否一致随机抽五张训练图确认标签存在且非空再确认val和train没有同名文件。用几行Python就能完成train_files set(os.listdir(dataset_split/train/images)) val_files set(os.listdir(dataset_split/val/images)) test_files set(os.listdir(dataset_split/test/images)) assert len(train_files) len(val_files) len(test_files) len(files) assert len(train_files val_files) 0 assert len(train_files test_files) 0这个断言写起来不到五条但能把划分脚本常见的重复分配、漏分配一次拦完。石油泄露数据的文件名如果带帧序号这一步还能看出来你抽的是帧还是视频源。如果发现某张图片没有对应标签建议回到转换脚本检查看VOC的XML里是不是空object节点。空目标图片在部分框架里会被自动当作背景样本少量没问题数量太多会把正样本比例冲淡模型倾向输出大量背景预测。4. 用YOLOv8训练石油泄露检测模型目录结构、训练命令与必调超参4.1 建立YOLO标准目录与data.yaml配置拿到划分好的数据集后下一步就是把数据和训练框架接在一起。我以YOLOv8为例因为yolov8训练自己的数据集这个流程在工程里覆盖最广代码仓库自带数据校验和评估逻辑。先看目录结构这是最容易出问题也最容易被忽略的环节petrol_spill_yolo/ ├── train/ │ ├── images/ │ └── labels/ ├── val/ │ ├── images/ │ └── labels/ ├── test/ │ ├── images/ │ └── labels/ └── data.yamldata.yaml是训练入口字段不多但一个都不能错path: /home/user/petrol_spill_yolo train: train/images val: val/images test: test/images nc: 1 names: [oil_spill]path字段建议写绝对路径换用户或换服务器时相对路径很容易踩坑。nc是类别数这里按单一类别oil_spill举例如果数据集里还有船只、管道等目标要按实际类别数填写。names的顺序就是类别索引顺序和之前转换脚本里class_names的顺序必须一一对应顺序颠倒时模型不会报错但预测结果的语义全部错位这一点很多人在评估阶段才反应过来。4.2 训练命令与超参选择训练命令在ultralytics工具包里已经封装得很干净真正费心的是参数。下面给一份适配石油泄露场景的启动命令yolo detect train \ modelyolov8n.pt \ datapetrol_spill_yolo/data.yaml \ epochs100 \ batch16 \ imgsz1280 \ patience15 \ lr00.001 \ seed42参数说明modelyolov8n.pt是官方预训练权重网络会自动下载到本地追求更高精度可换成yolov8s.pt或yolov8m.pt。batch16在单卡3090或V100上比较稳妥显存紧张时降到8但尽量不要低于4否则BatchNorm统计不稳训练中期容易出现loss突然变为nan。imgsz1280针对石油泄露目标小、灰度差异低的特点是比较实用的输入尺寸如果遥感原图分辨率极高先确认显存能撑住撑不住就回退到640配合关键帧裁剪。训练命令里有一个容易被忽略但值得专门调的点是anchor。石油泄露在画面里往往只占很小一块默认anchor对小目标召回偏低。可以直接让框架自动重算yolo detect train \ modelyolov8n.pt \ datapetrol_spill_yolo/data.yaml \ epochs100 \ batch16 \ imgsz1280 \ auto_anchorTrueauto_anchor会依据标签框的真实宽高分布重新计算先验框。如果验证集recall训练多轮后还上不去优先怀疑anchor与目标尺度不匹配。这个参数调整成本很低但效果往往比盲目增加epoch明显。4.3 中断恢复与训练日志判断训练到一半被任务抢占或者想降低学习率续跑是常有的事。YOLOv8支持从断点继续yolo detect train \ modelruns/detect/train/weights/last.pt \ datapetrol_spill_yolo/data.yaml \ epochs200 \ resumeTrueresumeTrue会读取last.pt里的epoch计数、优化器状态和学习率调度状态。注意如果此时改动过data.yaml里的nc或names续跑会报维度不匹配这是框架在保护你避免新旧数据语义不一致时继续训练。训练过程中看loss曲线不要只盯第一个epoch。如果train_loss持续下降而val_loss横盘甚至上升说明模型过拟合了。1000张图的石油泄露样本不算多100个epoch足够看到分化过拟合时优先考虑增强数据增强、增大weight_decay或使用更大的模型配合合成数据三个方向同时试比闷头加epoch有效得多。训练完成后runs/detect/train目录下会有weights/best.pt和last.pt两个权重文件best.pt对应验证集指标最好的轮次last.pt对应最后一轮实际使用和继续训练都以best.pt为准。5. 石油泄露数据集训练排障五个反复出现的高频问题记录5.1 验证集mAP长期为0训练loss却正常下降现象训练loss稳步下降看起来一切正常但每轮结束输出的验证集mAP始终是0precision和recall也都接近0。抽检验证集图片时发现模型输出了大量框但和标签完全不重叠。原因最常见的是转换脚本里类别索引错位训练时读到的标签语义和验证集不一致。比如VOC里的类别名顺序和data.yaml的names不一致或者COCO转YOLO时category_map映射错误导致验证标签的类别ID在训练语义里指向别的类别模型学到的是另一种分布。解决回到转换脚本先打印任一标签文件的完整内容再用反画框脚本把标签画到原图上人工核对。确认类别名和顺序完全匹配后再重新转换替换标签文件后重新训练。不要直接在训练中临时打开数据增强看效果那样只会把问题复杂化。5.2 训练中期BN崩溃loss突然变成nan现象前二十个epoch训练正常loss从2.1下降到1.2附近某个epoch开始loss突然出现nan之后所有指标全部失效。原因这是典型的yolo训练中bn崩溃。当batch_size过小或某个批次内绝大多数标签框面积接近0时BatchNorm层的方差统计趋于不稳定训练过程发散。石油泄露数据如果做了比较激进的随机裁剪容易产生空标签或极小的框进一步诱发这个问题。解决先把batch_size调回16或更大不要小于8。如果显存实在有限采用梯度累积保证参与归一化的样本量足够。同时检查数据增强配置关掉针对小目标的过度裁剪把空标签图片从训练集中过滤掉。必要时可以分阶段训练前50个epoch冻结骨干网络只训练检测头等loss稳定后再解冻。注意bn崩溃后不必从头重训用崩溃前的last.pt配合resumeTrue同时调整batch_size和优化器参数多数情况下可以接回来。5.3 海上小目标漏检率特别高recall上不去现象训练收敛后对包含大面积海水背景的验证图片进行预测模型只能检测出面积较大的泄露区域小面积油膜或油带几乎全部漏检。原因输入分辨率不足和anchor尺度不适配是两大主因。石油泄露的形态往往是长条状油带或离散油膜在imgsz640的输入下只占几十个像素小目标特征在下采样过程中被磨掉了。解决优先把imgsz调到1280或更高配合图片切块训练。切块时保留overlap避免泄漏区域恰好被切到两块的交界处。推理时适当降低置信度阈值从默认0.25下调到0.1再用NMS合并重叠框。对于真正的高分辨率遥感影像建议采用切块推理后再拼接而不是把整张大图直接缩放送进网络。5.4 VOC转YOLO后推理框偏移到图像边缘现象训练过程中没有明显报错但推理结果里所有检测框都偏向右下角且宽高比例和真实目标不一致。原因坐标换算时把归一化除数弄错了。最常见的是在批量处理脚本里用了处理后的宽高替代原图宽高或者把x、y坐标和VOC的xmin、ymin混用。另一个容易忽视的问题是标签文件路径和图片文件不同名导致某个标签被重复读取或漏读。解决写一个反画验证脚本把TXT的五个数字换算成绝对坐标用OpenCV的rectangle画到原图上逐张检查。这个脚本建议在整个数据集转换完成后固定保留后续每次新增标注数据都跑一遍比靠肉眼抽查稳妥得多。如果批量转换时用过的图片尺寸记录方式不统一优先从json元数据或xml原图节点里重新读取宽高不要沿用上一次的全局变量。import cv2 def draw_yolo_label(image_path, txt_path, class_names): img cv2.imread(image_path) h, w img.shape[:2] with open(txt_path, r) as f: for line in f: parts line.strip().split() if len(parts) 5: continue cls_id, cx, cy, bw, bh map(float, parts) xmin int((cx - bw / 2) * w) ymin int((cy - bh / 2) * h) xmax int((cx bw / 2) * w) ymax int((cy bh / 2) * h) cv2.rectangle(img, (xmin, ymin), (xmax, ymax), (0, 0, 255), 2) cv2.putText(img, class_names[int(cls_id)], (xmin, max(ymin - 5, 0)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imshow(check, img) cv2.waitKey(0)5.5 划分脚本重跑后同一张图出现在训练集和验证集现象更新了一批标注数据后重新执行划分脚本发现某些图片文件名同时出现在train和val目录里训练指标虚高真实场景表现差。原因划分时只做了基础shuffle没有按视频源或拍摄场景去重。石油泄露数据如果来自无人机巡检视频同一段飞行轨迹抽出的相邻帧画面高度相似随机划分天然会把相似的帧分到两个集合。另一个原因是文件重名不同子目录下的图片用简单文件名拼接后产生覆盖。解决划分前先给每张图片建立唯一标识包含来源视频或拍摄批次信息按标识分组后再划分。具体做法是把图片列表先按source_key聚合每个组整体划入同一个集合。文件名规范化也值得做一次全部改成类似spill_2025_shot001_0001.jpg这种带来源的命名后续任何脚本都不会因为同名覆盖而翻车。6. 训练完成后别急着跑混淆矩阵读取、推理验证与部署导出技巧训练结束后runs目录里会生成confusion_matrix.png、results.csv等一系列评估文件。很多人只看一眼mAP就收工其实混淆矩阵更值得细看。yolo混淆矩阵总合不唯一是正常现象因为矩阵默认做了行归一化每一行代表这个类别真实样本被预测到各个类别的比例行和列加起来没有固定意义别把行归一化的矩阵当多分类准确率来读。读矩阵时重点看主对角线数值和背景列的误检率石油泄露模型常见问题是把暗色水纹预测成oil_spill这时背景列的数值会很高需要回去调整负样本或增加背景类图片。推理验证环节我会用一段小脚本对验证集里置信度低但真实存在泄漏的图片做统计评估当前阈值是否合适。石油泄露漏检的代价比误检高实际部署时把置信度阈值从0.25降到0.15会明显提升recall代价是少量误检对于这类场景是划算的取舍。如果希望保持高precision则上调阈值并配合后续的形态学过滤把面积过小的检测框剔除。部署导出也是容易被忽略的一步。模型训练完直接挂到服务器推理可以但到了边缘端还是建议导出ONNX再转TensorRT或OpenVINOyolo export modelbest.pt formatonnx imgsz1280导出时imgsz要和训练时保持一致否则检测框坐标会因letterbox换算不一致产生偏差。导出后先用onnxruntime跑一次单图推理和PyTorch原始结果对比确保数值一致性在可接受范围再进TensorRT的精度校准流程。我自己的习惯是每次训练结束后把data.yaml、训练命令和混淆矩阵截图一起存档标注清楚当时的类别顺序和imgsz。这套东西看似琐碎但三个月后回看能让你快速判断当时的模型为什么是那个效果也方便给后续项目做起点。石油泄露检测这类环境监测场景数据往往来自不同光照、不同水域训练集分布和真实部署总有差距保留好每一次实验的上下文比临时翻代码要可靠得多。希望这些经验对你有帮助。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。