多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

钢丝绳破损雷击缺陷检测数据集:VOC与YOLO双格式标注解析与实战

钢丝绳破损雷击缺陷检测数据集:VOC与YOLO双格式标注解析与实战 简介这份钢丝绳破损雷击缺陷检测数据集面向工业质检与电力巡检方向的算法工程师、高校研究者及深度学习学习者用于训练和验证钢丝绳表面破损与雷击损伤的目标检测模型。数据集共含1318张jpg图片每张均配有Pascal VOC格式xml与YOLO格式txt标注标注类别为leiji雷击与posun破损对应框数分别为691和822总框数1513采用labelImg矩形框标注可直接用于YOLO或VOC系列检测网络训练。压缩包为7z格式内含2000个文件以1318个xml与682个txt为主整体约100.94MB目录结构清晰便于按标注格式快速筛选与转换。目前已有458人学习下载适合需要真实工业缺陷样本、快速搭建检测基线或做数据增强实验的读者参考使用。1. 钢丝绳破损雷击缺陷检测数据集1318 张图、1513 个框这份资源到底能干什么拿到一份工业缺陷数据集第一反应往往不是「能不能训」而是「标注到底靠不靠谱」。这份钢丝绳破损雷击缺陷检测数据集图片 1318 张xml 和 txt 标注各 1318 个类别只有两个leiji雷击和posun破损总框数 1513其中雷击 691 框、破损 822 框。标注工具是 labelImg规则就是最朴素的矩形框。它解决的是钢丝绳这类长条状工业构件在巡检场景下的缺陷定位问题——你想做缺陷检测、想验证某个检测头在细长目标上的表现、想补一份工业缺陷的验证集这份资源可以直接进流程。适合做工业质检、电力巡检、缺陷检测方向的从业者也适合刚接触 Pascal VOC 和 YOLO 双格式、想拿真实标注练手的人。需要先说明数据集不对训练精度作任何保证它提供的是准确且合理的标注模型效果取决于你的训练策略和场景匹配度。2. 双格式标注拆解VOC xml 与 YOLO txt 到底怎么对应2.1 为什么同一份数据要同时给 xml 和 txtPascal VOC 的 xml 是「绝对坐标 图像尺寸」的描述方式YOLO 的 txt 是「归一化中心点 宽高」的描述方式。两者描述的是同一个框但消费方完全不同xml 适合直接读结构、做可视化校验、转 COCO 或做数据审计txt 适合直接喂给 YOLO 系列训练脚本省掉转换步骤。这份资源同时给了两套意味着你不需要自己写转换脚本但也带来一个隐患——两套标注如果不一致训练和验证会对不上。常见做法是先用 xml 做一次可视化抽检确认框的位置和类别没问题再信任 txt。xml 的结构长这样字段含义直接决定你后面解析时取哪个节点annotation folderimages/folder filenamefirc_gss_943.jpg/filename size width1920/width height1080/height depth3/depth /size object nameleiji/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin512/xmin ymin233/ymin xmax704/xmax ymax318/ymax /bndbox /object /annotationsize里的宽高是原图尺寸bndbox是左上角和右下角的绝对像素坐标。解析时最容易翻车的地方是有些 xml 的filename和实际 jpg 文件名不一致或者size写错导致归一化算错。我一般会先跑一遍校验脚本把xmax width、xmin 0、xmax xmin这类异常框全部筛出来。2.2 用 Python 批量校验 xml 与 txt 的一致性下面这段脚本做三件事遍历所有 xml检查坐标合法性读取同名 txt把归一化坐标还原成绝对坐标对比两者是否在容差范围内一致。容差设 1 像素因为归一化再乘回去会有浮点误差。import os import xml.etree.ElementTree as ET def parse_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) 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) boxes.append((name, xmin, ymin, xmax, ymax)) return w, h, boxes def parse_txt(txt_path, w, h): boxes [] with open(txt_path, r) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue cls_id int(parts[0]) cx, cy, bw, bh map(float, parts[1:]) # 还原成绝对坐标 xmin (cx - bw / 2) * w ymin (cy - bh / 2) * h xmax (cx bw / 2) * w ymax (cy bh / 2) * h boxes.append((cls_id, xmin, ymin, xmax, ymax)) return boxes def check_pair(xml_path, txt_path, tol1.0): w, h, xml_boxes parse_xml(xml_path) txt_boxes parse_txt(txt_path, w, h) if len(xml_boxes) ! len(txt_boxes): return f数量不一致: xml{len(xml_boxes)} txt{len(txt_boxes)} for i, (xb, tb) in enumerate(zip(xml_boxes, txt_boxes)): if abs(xb[1] - tb[1]) tol or abs(xb[2] - tb[2]) tol: return f第{i}个框坐标偏差过大 return None if __name__ __main__: img_dir ./images xml_dir ./annotations_xml txt_dir ./labels_txt errors [] for fname in os.listdir(xml_dir): if not fname.endswith(.xml): continue stem fname[:-4] xml_path os.path.join(xml_dir, fname) txt_path os.path.join(txt_dir, stem .txt) if not os.path.exists(txt_path): errors.append(f{stem}: 缺少txt) continue msg check_pair(xml_path, txt_path) if msg: errors.append(f{stem}: {msg}) print(f共检查 {len(os.listdir(xml_dir))} 对异常 {len(errors)} 条) for e in errors[:20]: print(e)逻辑说明parse_xml取原图宽高和每个 object 的绝对坐标parse_txt把 YOLO 的归一化中心点还原成绝对坐标check_pair先比数量再比坐标容差 1 像素。参数上tol可以按你的标注精度调工业缺陷框通常允许 2 到 3 像素误差但这份数据标注质量较整齐1 像素足够。跑完如果异常条数为 0说明两套标注一致可以放心用 txt 训练、用 xml 做审计。2.3 类别映射与框数分布说明了什么类别只有两个leiji691 框、posun822 框比例接近 1:1.19不算严重失衡。但要注意框数不等于图片数一张图可能同时有雷击和破损也可能只有一种。实际训练时如果某类在图片层面的出现频率远低于框数占比仍然需要做重采样或类别加权。常见做法是先统计每张图的类别分布再决定是否用WeightedRandomSampler或 focal loss。这份数据的类别名是拼音训练配置文件里的names要写成[leiji, posun]顺序不能反否则类别 id 会错位。3. 从 7z 到可训练目录解压、划分与配置文件落地3.1 Linux 与 Windows 下解压 7z 的正确姿势资源是.7z格式Windows 上常见做法是用 7-Zip 或 Bandizip 右键解压但如果你在 Linux 服务器上跑训练unzip是不认 7z 的会直接报cannot find zipfile directory。需要先装p7zip# Ubuntu / Debian sudo apt-get install p7zip-full # CentOS / RHEL sudo yum install p7zip p7zip-plugins # 解压到指定目录 7z x 钢丝绳破损雷击缺陷检测数据集1300张xml和txt标注文件.7z -o./dataset_rawx表示保留完整路径解压-o后面跟输出目录中间没有空格。解压后先ls看一眼结构通常会有images、xml、txt三个文件夹或者全部混在一起。如果混在一起用下面的命令按扩展名分拣mkdir -p images xml txt find ./dataset_raw -name *.jpg -exec mv {} images/ \; find ./dataset_raw -name *.xml -exec mv {} xml/ \; find ./dataset_raw -name *.txt -exec mv {} txt/ \;注意find的-exec mv在文件量大时可能触发参数过长1318 个文件问题不大但如果以后处理上万张建议用-exec mv {} images/ 或者xargs。3.2 按 8:1:1 划分训练集、验证集、测试集YOLO 训练需要images/train、images/val、labels/train、labels/val这样的目录结构。下面脚本按 8:1:1 随机划分固定随机种子保证可复现import os import random import shutil random.seed(42) img_dir ./images txt_dir ./txt out_root ./yolo_dataset stems [f[:-4] for f in os.listdir(img_dir) if f.endswith(.jpg)] random.shuffle(stems) n len(stems) n_train int(n * 0.8) n_val int(n * 0.1) splits { train: stems[:n_train], val: stems[n_train:n_train n_val], test: stems[n_train n_val:] } for split, names in splits.items(): img_out os.path.join(out_root, images, split) lbl_out os.path.join(out_root, labels, split) os.makedirs(img_out, exist_okTrue) os.makedirs(lbl_out, exist_okTrue) for stem in names: shutil.copy(os.path.join(img_dir, stem .jpg), os.path.join(img_out, stem .jpg)) shutil.copy(os.path.join(txt_dir, stem .txt), os.path.join(lbl_out, stem .txt)) print(f{split}: {len(names)} 张)逻辑说明random.seed(42)保证每次划分结果一致方便复现实验n_train、n_val按比例取整剩下的给 test。参数上8:1:1 适合 1318 张这个量级如果后面做交叉验证可以改成 5 折。划分完检查一下labels/train里有没有空 txt——空 txt 表示该图无目标YOLO 会把它当负样本如果负样本太多会拉低召回需要确认这些空文件是不是标注遗漏。3.3 data.yaml 与训练入口的最小配置YOLO 系列的data.yaml只需要四行核心信息path: ./yolo_dataset train: images/train val: images/val test: images/test nc: 2 names: [leiji, posun]path是数据集根目录train、val、test是相对路径。nc是类别数必须和names长度一致。常见翻车点是names顺序和 txt 里的类别 id 对不上——这份数据的 txt 里 0 对应leiji、1 对应posun如果你写成[posun, leiji]训练不会报错但推理时类别全反。训练命令以 YOLOv8 为例yolo detect train data./data.yaml modelyolov8n.pt epochs100 imgsz640 batch16imgsz640是常见起点但钢丝绳缺陷框通常偏细长640 可能让框在特征图上只剩几个像素建议先跑一轮看instances分布如果小框占比高把imgsz提到 960 或 1280同时把batch降下来防显存溢出。4. 避坑与排查这份数据集最容易翻车的五个地方4.1 现象训练 loss 正常下降但验证集 mAP 一直是 0原因data.yaml里的val路径写错或者labels/val目录为空。YOLO 在验证时找不到标注会把所有预测都判为误检mAP 自然为 0。解决训练前先ls yolo_dataset/labels/val | wc -l确认数量与images/val一致再检查data.yaml里val是相对path的路径不是绝对路径。4.2 现象报错Label class 2 is not in the data.yaml原因txt 里出现了类别 id 2但nc设的是 2合法 id 只有 0 和 1。这种情况通常是标注时误建了第三个类别或者转换脚本把类别名映射错了。解决用awk {print $1} labels/*.txt | sort -u统计所有出现的类别 id如果有超出范围的回到 xml 里查对应的name字段确认是标注错误还是映射遗漏。4.3 现象解压后文件名乱码图片和标注对不上原因7z 在 Windows 下打包时用了 GBK 编码Linux 解压默认按 UTF-8 解析中文文件名会变成乱码。这份数据的文件名是firc_gss_943这种英文加数字一般不会乱码但如果你的解压工具把目录名也带进来可能出现路径层级错位。解决解压时加-mcp936指定代码页或者直接在 Windows 下解压后再传到 Linux。更稳妥的做法是解压后先find . -name *.jpg | head看文件名是否正常。4.4 现象同一张图在 xml 里有 3 个框txt 里只有 2 个原因xml 和 txt 不是同一次标注生成的或者转换时漏了difficult为 1 的框。这份数据声明是 labelImg 标注labelImg 导出 YOLO 格式时会跳过difficult1的 object但 xml 里仍然保留。解决用第 2 章的校验脚本跑一遍如果数量不一致检查 xml 里是否有difficult为 1 的框决定是保留还是剔除。工业缺陷检测一般不建议跳过 difficult 框因为难样本对模型更有价值。4.5 现象训练到一半显存爆了报CUDA out of memory原因imgsz调大后没有同步降batch或者workers开太多导致内存泄漏。解决先把batch降到 8 或 4再跑nvidia-smi看显存占用如果还是爆把imgsz从 1280 降到 960。另外YOLO 的cacheTrue会把所有图片缓存到内存1318 张 1920x1080 的图大约占 8GB 内存内存不够就设cacheFalse。5. 进阶用法用 xml 做难例挖掘与标注质量复核训练完一轮后别急着调参先做两件事用 xml 做一次全量可视化抽检再用模型预测结果反查标注遗漏。可视化脚本如下把 xml 里的框画到图上随机抽 50 张拼成网格import os import random import xml.etree.ElementTree as ET import cv2 import numpy as np def draw_xml(img_path, xml_path): img cv2.imread(img_path) tree ET.parse(xml_path) root tree.getroot() for obj in root.findall(object): name obj.find(name).text bnd obj.find(bndbox) xmin int(float(bnd.find(xmin).text)) ymin int(float(bnd.find(ymin).text)) xmax int(float(bnd.find(xmax).text)) ymax int(float(bnd.find(ymax).text)) color (0, 255, 0) if name leiji else (0, 0, 255) cv2.rectangle(img, (xmin, ymin), (xmax, ymax), color, 2) cv2.putText(img, name, (xmin, ymin - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2) return img img_dir ./images xml_dir ./xml stems [f[:-4] for f in os.listdir(xml_dir) if f.endswith(.xml)] random.seed(0) sample random.sample(stems, 50) grid [] for stem in sample: img draw_xml(os.path.join(img_dir, stem .jpg), os.path.join(xml_dir, stem .xml)) img cv2.resize(img, (320, 180)) grid.append(img) rows [] for i in range(0, 50, 5): rows.append(np.hstack(grid[i:i5])) canvas np.vstack(rows) cv2.imwrite(check_grid.jpg, canvas)逻辑说明draw_xml按类别给框上色leiji绿色、posun红色方便一眼区分random.sample固定种子抽 50 张拼成 10x5 网格。参数上cv2.resize到 320x180 是为了拼图后还能看清框的大致位置如果要细看某个框单独打开原图。跑完打开check_grid.jpg重点看三类问题框是否把缺陷完整包住、有没有明显漏标、类别是否标反。我一般会把这个网格图过一遍发现可疑的记下文件名再单独放大核对。第二件事是用训练好的模型跑一遍验证集把预测框和 xml 标注叠在一起找「模型检出但标注没有」的区域。这些区域往往是漏标尤其是雷击痕迹这种边界模糊的缺陷。具体做法是用 YOLO 的predict输出 txt再写脚本对比预测框和标注框的 IoU低于 0.3 且置信度高于 0.5 的预测框单独列出来人工复核。这一步做完你手里就有一份「标注质量报告」比盲目调参有用得多。从那以后我每次拿到新数据集都强制先跑一遍 xml 与 txt 一致性校验再抽 50 张可视化最后用模型反查漏标。这三步走完才敢把数据丢进训练脚本。希望帮到你。本文还有配套的精品资源点击获取
返回列表