简介:这份钢丝绳破损与雷击缺陷检测数据集面向工业质检、电力巡检及目标检测方向的算法工程师与研究者,用于训练和验证钢丝绳表面异常识别模型。数据集共含1318张jpg图像,每张均配有Pascal VOC格式xml与YOLO格式txt标注,标注类别为leiji(雷击)与posun(破损),对应框数分别为691和822,总框数1513,采用labelImg矩形框标注,标注准确合理。压缩包为7z格式,内含2000个文件,以1318个xml与682个txt为主,整体约100.94MB,目录结构清晰,便于直接接入主流检测框架。目前已有458人学习下载,适合需要快速构建钢丝绳缺陷检测基线、开展数据增强与模型对比实验的读者参考使用。
1. 钢丝绳破损雷击缺陷检测数据集:1300张xml与txt标注到底怎么用
拿到一个压缩包,名字叫「钢丝绳破损雷击缺陷检测数据集1300张xml和txt标注文件.7z」,第一反应往往是先解压看看里面有什么。但真正决定这个数据集能不能用、值不值得投入的,不是图片数量,而是标注格式和类别定义。钢丝绳在役检测场景里,破损和雷击缺陷是两类外观差异很大的目标:破损多为断股、散股、局部磨损,边缘毛刺明显;雷击缺陷则常表现为烧蚀坑、熔痕、局部变色,边界模糊且和光照强相关。1300张的规模不算大,属于典型的小样本工业缺陷数据集,适合做YOLO系列或MMDetection的迁移学习验证,不适合从零训练大模型。xml通常是Pascal VOC格式,txt则是YOLO格式,两者一一对应意味着你可以直接跳过格式转换这一步,把精力放在类别平衡、数据增强和误检分析上。这一章先把「这是什么、能解决什么、适合谁」讲清楚,后面再拆解怎么解压、怎么校验、怎么训练、怎么避坑。
2. 解压与目录结构:7z在Linux和Windows下的正确打开方式
2.1 为什么7z解压经常翻车
.7z格式压缩率高,工业数据集里很常见,但它不像zip那样系统自带支持。Windows下用7-Zip或Bandizip没问题,Linux下如果只装了unzip,会直接报「cannot find zipfile directory」。我一般先在服务器上确认有没有p7zip,没有就装。另一个高频翻车点是中文文件名:压缩包在Windows下打包,Linux解压后文件名变成乱码,导致后续按文件名匹配xml和txt时对不上。解决办法是解压时指定编码,或者干脆在Windows下解压完再传到Linux。
# 检查是否安装p7zip which 7z || which 7za # Ubuntu/Debian安装 sudo apt-get install p7zip-full # 解压到指定目录,-o后面不要有空格 7z x "钢丝绳破损雷击缺陷检测数据集1300张xml和txt标注文件.7z" -o./dataset # 如果文件名乱码,尝试指定编码(部分版本支持) 7z x -mcp=936 "钢丝绳破损雷击缺陷检测数据集1300张xml和txt标注文件.7z" -o./dataset-o参数指定输出目录,等号或空格都可以,但目录名不要带中文,否则后续Python读取路径时容易出编码问题。-mcp=936是设置代码页为GBK,对Windows打包的压缩包有效,但不是所有7z版本都支持这个参数,失败就换Windows解压。
2.2 解压后先做三件事
解压完不要急着写训练脚本,先做目录清点和配对校验。典型结构是images/放jpg或png,annotations/xml/放VOC xml,annotations/txt/放YOLO txt。三者的文件名主干必须一致,比如steel_0001.jpg对应steel_0001.xml和steel_0001.txt。我见过不少数据集图片和标注数量对不上,或者txt里类别索引从1开始而不是0,直接训练会导致类别错位。
import os from pathlib import Path root = Path("./dataset") img_dir = root / "images" xml_dir = root / "annotations" / "xml" txt_dir = root / "annotations" / "txt" imgs = {p.stem for p in img_dir.glob("*.*") if p.suffix.lower() in (".jpg", ".png", ".jpeg")} xmls = {p.stem for p in xml_dir.glob("*.xml")} txts = {p.stem for p in txt_dir.glob("*.txt")} print("图片数量:", len(imgs)) print("xml数量:", len(xmls)) print("txt数量:", len(txts)) print("图片有但xml缺失:", len(imgs - xmls)) print("xml有但图片缺失:", len(xmls - imgs)) print("txt有但xml缺失:", len(txts - xmls))这段脚本用集合差集快速定位缺失项。如果缺失量在个位数,直接删掉对应样本;如果缺失几十张,说明压缩包本身不完整,需要重新获取。注意glob("*.*")会漏掉没有扩展名的文件,工业数据集里偶尔有这种情况,可以改成遍历os.listdir再判断。
3. xml与txt标注解析:VOC和YOLO格式的互转与校验
3.1 两种格式的字段含义
Pascal VOC的xml结构固定,关键字段是filename、size、object下的name和bndbox。YOLO的txt每行是class_id x_center y_center width height,全部归一化到0到1。钢丝绳破损雷击缺陷检测数据集里,类别通常就两类:破损和雷击,有的版本会细分断股、散股、烧蚀,但1300张的规模不建议分太细,否则每类样本不足,模型学不到稳定特征。
import xml.etree.ElementTree as ET def parse_voc_xml(xml_path): tree = ET.parse(xml_path) root = tree.getroot() size = root.find("size") w = int(size.find("width").text) h = int(size.find("height").text) objects = [] for obj in root.findall("object"): name = obj.find("name").text bbox = obj.find("bndbox") xmin = int(float(bbox.find("xmin").text)) ymin = int(float(bbox.find("ymin").text)) xmax = int(float(bbox.find("xmax").text)) ymax = int(float(bbox.find("ymax").text)) objects.append((name, xmin, ymin, xmax, ymax)) return w, h, objects w, h, objs = parse_voc_xml("./dataset/annotations/xml/steel_0001.xml") print("尺寸:", w, h) for o in objs: print(o)int(float(...))是为了兼容xml里写成123.0的情况,直接int("123.0")会报错。size字段有的数据集会写错,和实际图片尺寸不一致,训练时如果按xml的尺寸归一化,框会偏移。稳妥做法是用PIL或OpenCV读一次图片真实尺寸,和xml对比,不一致的样本单独列出来。
3.2 用脚本校验txt标注是否越界
YOLO格式要求所有坐标在0到1之间,且x_center ± width/2不能超出边界。工业数据集里标注人员手抖写出负值或大于1的值很常见,直接训练会让损失函数爆炸。
def check_yolo_txt(txt_path): issues = [] with open(txt_path, "r") as f: for i, line in enumerate(f): parts = line.strip().split() if len(parts) != 5: issues.append(f"第{i}行字段数不对: {line.strip()}") continue cls, x, y, w, h = map(float, parts) if not (0 <= x <= 1 and 0 <= y <= 1 and 0 < w <= 1 and 0 < h <= 1): issues.append(f"第{i}行坐标越界: {line.strip()}") if x - w/2 < -0.01 or x + w/2 > 1.01 or y - h/2 < -0.01 or y + h/2 > 1.01: issues.append(f"第{i}行框超出边界: {line.strip()}") return issues for txt in Path("./dataset/annotations/txt").glob("*.txt"): errs = check_yolo_txt(txt) if errs: print(txt.name, errs[:3])容差设0.01是为了避免浮点误差误报。如果越界样本超过5%,建议直接丢弃这些标注而不是裁剪,因为裁剪后的框可能只剩背景,反而引入噪声。
3.3 xml转txt的完整脚本
虽然数据集同时给了xml和txt,但你可能需要根据xml重新生成txt来验证一致性,或者调整类别映射。
import xml.etree.ElementTree as ET from pathlib import Path from PIL import Image CLASS_MAP = {"破损": 0, "雷击": 1} def voc_to_yolo(xml_path, img_path, out_path): tree = ET.parse(xml_path) root = tree.getroot() img = Image.open(img_path) w, h = img.size lines = [] for obj in root.findall("object"): name = obj.find("name").text.strip() if name not in CLASS_MAP: continue bbox = obj.find("bndbox") xmin = float(bbox.find("xmin").text) ymin = float(bbox.find("ymin").text) xmax = float(bbox.find("xmax").text) ymax = float(bbox.find("ymax").text) xc = (xmin + xmax) / 2 / w yc = (ymin + ymax) / 2 / h bw = (xmax - xmin) / w bh = (ymax - ymin) / h lines.append(f"{CLASS_MAP[name]} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}") with open(out_path, "w") as f: f.write("\n".join(lines)) for xml_file in Path("./dataset/annotations/xml").glob("*.xml"): stem = xml_file.stem img_file = Path("./dataset/images") / f"{stem}.jpg" if not img_file.exists(): img_file = Path("./dataset/images") / f"{stem}.png" if img_file.exists(): voc_to_yolo(xml_file, img_file, Path("./dataset/annotations/txt_new") / f"{stem}.txt")用PIL读真实尺寸而不是xml里的size,能规避尺寸写错的问题。CLASS_MAP里的中文类别名要和xml里完全一致,包括空格,建议先打印几个xml的name字段确认。
4. 用YOLOv8训练钢丝绳缺陷检测:从data.yaml到第一个baseline
4.1 数据集划分与data.yaml写法
1300张按8:1:1划分,训练1040、验证130、测试130。划分时要保证两类缺陷在三个子集里比例接近,否则验证集指标会失真。我一般用sklearn.model_selection.train_test_split做分层抽样,按主类别分层。
import random from pathlib import Path import shutil random.seed(42) all_imgs = list(Path("./dataset/images").glob("*.*")) random.shuffle(all_imgs) n = len(all_imgs) train_end = int(n * 0.8) val_end = int(n * 0.9) splits = { "train": all_imgs[:train_end], "val": all_imgs[train_end:val_end], "test": all_imgs[val_end:] } for split, files in splits.items(): img_out = Path(f"./yolo_dataset/images/{split}") lbl_out = Path(f"./yolo_dataset/labels/{split}") img_out.mkdir(parents=True, exist_ok=True) lbl_out.mkdir(parents=True, exist_ok=True) for img in files: shutil.copy(img, img_out / img.name) txt = Path("./dataset/annotations/txt") / f"{img.stem}.txt" if txt.exists(): shutil.copy(txt, lbl_out / f"{img.stem}.txt")data.yaml里path写绝对路径最稳,train、val、test写相对path的子目录。names的顺序必须和txt里的class_id一致,写反了模型会把破损认成雷击。
path: /home/user/yolo_dataset train: images/train val: images/val test: images/test nc: 2 names: 0: 破损 1: 雷击4.2 训练命令与关键参数
yolo detect train \ data=./data.yaml \ model=yolov8s.pt \ epochs=150 \ imgsz=640 \ batch=16 \ lr0=0.01 \ lrf=0.01 \ patience=30 \ augment=True \ mosaic=1.0 \ mixup=0.1 \ project=./runs \ name=steel_defect_v1yolov8s在1300张上比yolov8n更稳,比yolov8m不容易过拟合。imgsz=640是默认值,如果原图分辨率远大于640,比如4000×3000,建议先缩放到1280再训练,否则小目标雷击缺陷缩到640后只剩几个像素。patience=30表示30轮验证指标不升就早停,小数据集上很有用。mosaic=1.0和mixup=0.1是强增强,能缓解样本不足,但如果雷击缺陷本身边界模糊,mixup可能让模型更困惑,可以先关掉对比。
4.3 训练过程看什么指标
重点看metrics/mAP50-95和每一类的mAP50。如果破损类mAP正常但雷击类一直低于0.3,大概率是雷击样本太少或标注框太松。用yolo detect val跑验证集,加save_json=True导出预测结果,再用脚本统计漏检和误检。
yolo detect val \ model=./runs/steel_defect_v1/weights/best.pt \ data=./data.yaml \ split=test \ save_json=True \ project=./runs \ name=val_v1导出的predictions.json里每条记录包含image_id、category_id、bbox、score。和COCO格式的instances_test.json对比,就能算出每一类的AP。如果雷击类AP低,先看是不是验证集里雷击样本少于10张,是的话指标本身不可信。
5. 避坑与排查:钢丝绳缺陷检测数据集最常见的5个翻车点
5.1 图片和标注文件名大小写不一致
现象:训练时报「No labels found」,但明明txt文件存在。原因:Windows下文件名不区分大小写,Steel_0001.jpg和steel_0001.txt能配对,传到Linux后大小写敏感,匹配失败。解决:统一转小写,或者用脚本按stem.lower()重新配对。
5.2 xml里类别名带空格或不可见字符
现象:CLASS_MAP里写「破损」,但xml里实际是「破损 」(尾部有空格),导致该类样本全部被跳过,训练时只有雷击类。原因:标注工具导出时带了空格。解决:解析时用name.strip(),并先打印所有唯一类别名确认。
5.3 图片尺寸和xml的size字段不一致
现象:训练后框整体偏移,可视化时框跑到目标旁边。原因:xml里的width、height是标注时的尺寸,图片后来被裁剪或缩放但xml没更新。解决:用PIL读真实尺寸重新生成txt,丢弃尺寸差异超过5%的样本。
5.4 txt里class_id从1开始
现象:训练不报错,但推理时所有框都标成「雷击」,破损类完全消失。原因:标注人员按1、2编号,而YOLO要求0、1。解决:统计txt里所有class_id的唯一值,如果是1和2,统一减1。
5.5 验证集和训练集图片重复
现象:验证集mAP高得离谱,测试集一塌糊涂。原因:随机划分时同一张图的增强版本或近似帧同时进了训练和验证。解决:按图片文件名前缀分组划分,比如steel_0001和steel_0001_aug必须进同一个子集。
6. 小样本下的进阶技巧:用切片推理和类别权重把雷击缺陷召回拉上来
1300张里雷击缺陷往往只有两三百张,直接训练召回率上不去。我一般做两件事:一是训练时给雷击类加类别权重,二是推理时用切片推理(SAHI)处理高分辨率原图。类别权重在YOLOv8里没有直接参数,但可以通过复制雷击样本的txt和图片来过采样,复制2到3倍,同时保持验证集不变。切片推理则是把大图切成640×640的重叠子图分别检测,再合并框,对小目标雷击烧蚀坑效果明显。
from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction model = AutoDetectionModel.from_pretrained( model_type="yolov8", model_path="./runs/steel_defect_v1/weights/best.pt", confidence_threshold=0.25, device="cuda:0" ) result = get_sliced_prediction( "test_highres.jpg", model, slice_height=640, slice_width=640, overlap_height_ratio=0.2, overlap_width_ratio=0.2 ) result.export_visuals(export_dir="./sahi_out")overlap_height_ratio=0.2表示相邻切片重叠20%,防止目标被切一半。confidence_threshold先设0.25,切片推理会产生大量低分框,合并时用NMS去重。如果显存够,slice_height设成1280效果更好,但速度会慢。验证切片推理是否有效,就看雷击类的召回率有没有提升,同时误检不能增加太多。我自己的习惯是每次改完推理参数,固定跑同一批50张测试图,人工数一遍漏检和误检,记在表格里,比只看mAP靠谱。希望帮到你。
本文还有配套的精品资源,点击获取