☰
风力机缺陷检测数据集3687张图:VOC+YOLO双格式与YOLOv8训练实践
2026/9/27 23:34:08 网站建设 项目流程

简介:面向风力机叶片缺陷检测任务,这份VOC+YOLO双格式数据集适合计算机视觉入门者、风机巡检算法研发工程师及目标检测方向研究生使用。数据集说明包含3687张风机图片,每张均配套Pascal VOC格式xml与YOLO格式txt标注,统一为defect单一类别,矩形框总数为12220个;标注工具为labelImg,按类别画矩形框,规则明确,可直接用于YOLO、Faster R-CNN等模型训练与评估。压缩包文件列表统计共2000个文件,以xml标注文件为主(1999个xml),另含1个txt说明,整体90.46MB,解压使用方便;未提供分割路径,可按需自行划分训练集与验证集。已有581人学习浏览,尤其适合需要风机缺陷数据集快速搭建实验、进行数据格式转换或复现检测流程的开发者。需要说明的是,资料提供准确合理的标注,但对训练所得模型权重精度不作保证。

1. 风力机缺陷检测数据集:3687张图、1个类别,为什么双格式是关键

风力机缺陷检测损伤检测数据集VOC+YOLO格式3687张1类别,听起来是个普通的物资包,但真正在无人机巡检、叶片外观检测里做过落地的人会明白,这个组合是风电场视觉检测最缺的东西:现场真实图、一致的标注框、开箱即用的双格式标签。它不是一堆图片,而是一份能让检测模型从零起步的训练资产。

风机缺陷图像和通用目标检测数据的最大区别是背景乱、目标小、缺陷稀疏。叶片可能占满整图,一道裂纹只有几十个像素;塔筒锈蚀和背景锈斑混在一起,人眼都要贴近看。所以3687张只配1个类别,比7个类别每类500张更实用——模型只需要区分“损伤区域”和“正常表面”,边界清晰,收敛也快。适合刚开始做工业缺陷检测的学生和工程师,也适合用少量数据快速验证YOLO流程的团队。

2. 把7z包变成可用训练集:解压、目录检查与数据体检

2.1 Linux 下解压 7z 的标准姿势

拿到“风力机缺陷检测损伤检测数据集VOC+YOLO格式3687张1类别.7z”这种压缩包,第一步不是急着看图片,而是把它解到一个结构干净的目录里。常见做法是建一个wind_turbine_defect/工作目录,压缩包放进去,然后统一解压。这里先要确认系统装了 p7zip,因为很多轻量 Linux 环境默认只带unzip,遇到 7z 会直接懵。

先确认系统有没有装 p7zip:

# Debian/Ubuntu 系安装 7z 工具 sudo apt update && sudo apt install -y p7zip-full # CentOS/RHEL 系安装 # sudo yum install -y p7zip p7zip-plugins

安装后验证:

7z --help | head -10

输出里有7-Zip [64]或类似版本信息就说明可用。注意p7zip(不带 full)只支持解压 7z,不支持创建和部分加密特性,务必装p7zip-full,后续如果要把数据集重新压缩成 7z 发给队友,也要靠它。装好后执行解压:

7z x wind_turbine_defect_3687.7z -o./wind_turbine_defect # -o 后不要写空格

逻辑说明:x是解压并保留目录结构,-o指定输出目录。为什么强调-o和参数之间不能有空格?很多新手在这里把目录名写进了选项,导致 7z 把压缩包解到当前目录,文件散落一地。如果作者在发布页单独给了解压密码,用-p传入;没有密码就正常解压,不需要理会“7z 必须加密码”的说法。解压完成后先别急着删压缩包,留着它做完整性比对,后文避坑章节会细说原因。

2.2 解压后的目录体检:VOC 和 YOLO 文件夹长什么样

解压完成后,先看顶层目录结构:

cd wind_turbine_defect find . -maxdepth 2 -type d | sort

一个合理的双格式数据集,通常会同时存在VOC系列目录和YOLO系列目录。VOC 一侧是JPEGImages(图片)、Annotations(XML 标注)、ImageSets/Main(train/val/test 划分文件);YOLO 一侧是images、labels以及可选的train.txt、val.txt。如果只有图片加一个标注 CSV,那就是单格式,需要按后面一章的脚本自行转换。

接着做两项体检。一是图片与标注数量对齐:

echo "图片总数: $(ls JPEGImages/*.jpg | wc -l)" echo "标注总数: $(ls Annotations/*.xml | wc -l)" echo "YOLO标注总数: $(ls labels/*.txt | wc -l)"

二是检查 YOLO 格式里有没有空标注文件。空文件代表“这张图里没有目标”,如果几十张图都是空的,会影响训练时正负样本平衡。工业数据里负样本图有它的价值,但数量要心里有数:

find labels -name "*.txt" -size 0 | wc -l

逻辑说明:这两步能提前揪出“图片有但标签丢”“标注框全废”这类问题。工业数据集经常是反复拷贝转存后漏文件,全部对齐后再进行下一步格式处理最稳妥。数据没有经过这一步检查就进训练,后面 loss 曲线异常时你会分不清是数据问题还是网络问题。如果发现ImageSets/Main里的train.txt数量和解压目录下的图片总数对不上,还要继续查是不是划分文件写的是旧文件名。

2.3 可视化抽查标注质量

结构体检通过后,推荐用 OpenCV 把标注框画回图上人工抽查 50 张。这一步能发现缩放比例错、框外溢出、类别标错这三类标注问题。训练一个目标检测模型的成本很高,但 50 张可视化检查只要几分钟,这是性价比最高的质量门。

import cv2, glob, os for img_path in glob.glob("JPEGImages/*.jpg"): xml_path = img_path.replace("JPEGImages", "Annotations").replace(".jpg", ".xml") # 跳过没有对应 XML 的图 if not os.path.exists(xml_path): continue img = cv2.imread(img_path) from lxml import etree root = etree.parse(xml_path).getroot() for obj in root.findall("object"): bnd = obj.find("bndbox") xmin = int(float(bnd.find("xmin").text)) ymin = int(float(bnd.find("ymin").text)) w = int(float(bnd.find("xmax").text)) - xmin h = int(float(bnd.find("ymax").text)) - ymin cv2.rectangle(img, (xmin, ymin), (xmin + w, ymin + h), (0, 0, 255), 2) out = "check/" + os.path.basename(img_path) os.makedirs("check", exist_ok=True) cv2.imwrite(out, img)

这段代码把每个 VOC 标注框画到原图上输出到check/目录。参数说明:(0, 0, 255)是 BGR 颜色,笔宽 2 像素;如果图片分辨率大,可以cv2.resize后再画,否则 4K 图肉眼看不清楚。抽查标准是:框是否紧贴缺陷区域、有没有框到背景大面积区域、有没有把叶片前缘腐蚀框成整片叶片。实际项目里我就遇到过把整个叶片根部框进去的标注,模型训练出来预测框全是半片叶片,这就是标注噪声的典型后果。

提示:如果画出的大量框都偏大,说明原始标注用的多边形被转换成了外接矩形,这在 1 类别缺陷检测里是可接受的,但如果后续要做分割任务就得回到原始标注。

3. VOC 与 YOLO 格式转换:3687 张图的脚本与四个边界坑

3.1 为什么双格式值得保留

标题里“VOC+YOLO格式”不是多余信息。VOC 用 XML 记录目标框,人和机器都读得懂;YOLO 用归一化坐标的 TXT,训练时逐行读取。很多算法库只认其中一种,比如 YOLOv8 的ultralytics原生吃 YOLO TXT,而老牌检测框架和部分公开评测脚本只认 VOC XML。双格式的意义就是让你免掉“换个框架重标一遍”的重复劳动,一份 7z 包内两种格式并存,是做数据集的人给使用者留的后悔药。

VOC 和 YOLO 坐标差异只在一点:VOC 存的是绝对像素坐标(xmin, ymin, xmax, ymax),YOLO 存的是归一化相对坐标(center_x, center_y, width, height,四个值都在 0~1 之间)。转换公式就是简单的四则运算,但真正让转换脚本翻车的,是下面四个边界坑。

3.2 完整的 VOC→YOLO 转换脚本

import os from lxml import etree def voc2yolo(xml_path, img_dir, out_dir, class_list): root = etree.parse(xml_path).getroot() # 图片宽高从 xml 的 size 节点读取,不要自己去 cv2.imread size = root.find("size") img_w, img_h = int(size.find("width").text), int(size.find("height").text) img_name = root.find("filename").text # 处理文件名带中文或带空格的情况 base = os.path.splitext(img_name)[0] lines = [] for obj in root.findall("object"): name = obj.find("name").text # 类别不在 class_list 时宁可跳过,不写 unknown if name not in class_list: continue bnd = obj.find("bndbox") xmin = max(0, float(bnd.find("xmin").text)) ymin = max(0, float(bnd.find("ymin").text)) xmax = min(img_w, float(bnd.find("xmax").text)) ymax = min(img_h, float(bnd.find("ymax").text)) # 框退化检查:面积为零直接丢弃 if xmax <= xmin or ymax <= ymin: continue x_center = (xmin + xmax) / 2.0 / img_w y_center = (ymin + ymax) / 2.0 / img_h w = (xmax - xmin) / img_w h = (ymax - ymin) / img_h lines.append(f"{class_list.index(name)} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}") out_path = os.path.join(out_dir, base + ".txt") with open(out_path, "w") as f: f.write("\n".join(lines))

逻辑说明:脚本里最关键的一行是宽高读取走 XML 的size节点,而不是自己重新读图。为什么?因为数据集作者给图做过缩放、剪切时如果只更新了 JPEG 没同步 XML,XML 里的宽高是最接近原始标注状态的;反之亦然,统一走一个源头才不会出现坐标和图片尺寸比例错位。max/min裁剪是为了避免极端情况下的框越界,xmax <= xmin的丢弃条件是防守“退化框”。

参数说明:class_list传["defect"]这种单类别列表即可;输出 TXT 的每行格式是类别id 归一化中心x 归一化中心y 归一化宽 归一化高。六个小数的精度够用,模型训练时不会因为精度不足产生漂移;不要写%.8f导致文件体积翻倍,也不要只写%.2f把小目标框精度损失掉。上面的脚本省略了目录遍历逻辑,实际使用时在main里import glob对Annotations/*.xml逐个调用即可。

转换完检查输出行数的总和:

wc -l labels/*.txt | tail -1

如果总行数和 XML 里object总数相差很大,参考 3.3 的边界场景排查。这一步的数字也能反过来校验原数据集标注质量,如果单张图平均框数低于 0.5,说明很多图是负样本,训练时要考虑正负样本比例。

3.3 四个边界坑:坐标来源、空文件、类别名、尺寸不一致

第一坑:XML 里size的宽高和实际图片不一致。原因大多是数据处理阶段 resize 之后 XML 没重新写。解决:转换前用脚本统一比对PIL.Image.open的size和 XML 的size,不一致先修 XML 或先重出图。我一般会写一个循环把所有不一致的文件名打印出来,先看一眼有多少,少于 20 个就手动修,多于 50 个就重新导出图片。

第二坑:YOLO TXT 空文件。VOC 里一张图如果没有目标,转换脚本会写出空 TXT。有些用户把空 TXT 当异常清掉了,导致负样本图失去“无目标”语义,在验证时被误判为漏检。解决:空 TXT 保留,并单独统计数量。负样本图在缺陷检测里非常值钱,它能教会模型“叶片干净时不要输出框”,这比任何误报抑制策略都直接。

第三坑:类别大小写不一致。一个数据集里可能同时出现Defect和defect,在class_list匹配时直接pass了。解决:转换前把所有 XML 的类别名统一小写化,或读取时split后统一strip()。这类问题在多人协作标注的数据集里极常见,标注工具的默认类别名没对齐,每个人按自己的习惯填。

第四坑:VOC→YOLO 和 YOLO→VOC 互转时坐标回推精度。把归一化坐标乘回img_w后要记得四舍五入,不然回推的xmax可能差半个像素,在评测 mAP 时出现 1~2 个框对不准。解决:回推时用round()并做一次越界裁剪。另外注意 7z 包里的 VOC 标注和 YOLO 标注可能来自同一份标注的真值,但坐标不完全一致,互转后要抽几个文件人工比对,别默认两者可以互相覆盖。

注意:这一类数据集常被拿去跑旋转框检测,但标题写的是 VOC+YOLO 水平矩形框,转旋转框需要额外角度信息,原包没有的话不必强行转换。

4. 用 YOLOv8 在 3687 张图上训练损伤检测:配置文件、超参与曲线判断

4.1 数据集配置文件的写法

假设你已经把 YOLO 格式的images/和labels/准备好了,还差最后一份数据集 YAML。YOLOv8 训练自己的数据集,第一步就是把这份 YAML 写对。注意,这里的train和val可以写目录路径,也可以写 TXT 索引文件路径,两种风格ultralytics都能识别,新手最容易在相对路径和绝对路径之间踩坑。

# defect.yaml path: /data/wind_turbine_defect/yolo # 数据集根目录,绝对路径最稳 train: images/train val: images/val nc: 1 names: 0: defect

逻辑说明:path的根目录下只要存在train和val子目录,ultralytics会自动找对应的labels/train和labels/val,也就是兄弟目录下的 TXT 文件。如果你的文件分布是train.txt、val.txt这种索引文件风格,也可以写train: train.txt,此时每行写图片绝对路径。参数说明:nc必须和names的键数量一致,0 开头的类别 id 决定 TXT 首列数值。把path写成相对路径容易出“找不到文件”的错,尤其在不同容器间拷贝项目时,我一般固定用绝对路径,并在训练前cd到项目根目录确认一次。

4.2 训练命令与关键超参

yolo train data=defect.yaml model=yolov8m.pt epochs=120 imgsz=640 batch=16 lr0=0.01 mosaic=0.5 close_mosaic=10 patience=20

逐项拆开讲。model=yolov8m.pt是选择预训练权重,中等模型适合 3687 张这种规模,v8s更快但特征表达弱,v8l在小数据集上更容易过拟合。imgsz=640是训练和推理的统一分辨率,如果原图多在 2000 像素以上且缺陷很小,可以试imgsz=960,代价是显存占用几乎翻倍。batch=16在单张 V100 或 RTX 3090 上足够,显存小于 24G 就降到 8,batch 太小 BN 层统计量不稳,这是训练后期 loss 震荡的常见来源。

lr0=0.01是初始学习率,单类缺陷任务不需要用更大的 0.05,因为类别少、任务简单,学习率过大容易在早期就把 loss 推到 nan。mosaic=0.5表示只有一半 epoch 启用 mosaic 增强,因为叶片缺陷目标小,mosaic 拼图会把小目标进一步缩小;close_mosaic=10表示最后 10 个 epoch 关闭 mosaic,让模型在正常的单图分布上微调,这是防止小目标检测在最后阶段失稳的关键操作。patience=20是早停,验证集 mAP 连续 20 轮不涨就提前结束,防止后段过拟合浪费时间。

训练过程中注意看两类指标:一是train/box_loss和train/cls_loss是否同步下降;二是val/dfl_loss不能反弹太早。风电损伤检测里常见的 BN 崩溃现象,表面是 loss 变成 nan,实际原因是训练后期 BN 统计量在 mosaic 和正常图的分布切换下失稳。遇到这个情况,先把batch调小到 8,再关掉 mosaic 重新训练最后 20 轮。还要注意把cache=True加上,数据量不大但图很大时,缓存到内存能让每个 epoch 的时间缩短一半,这是最容易忽略的提速参数。

4.3 用混淆矩阵和损失函数判断 1 类别任务的真实水平

训练结束后的runs/detect/trainX/confusion_matrix.png里 1 类别会显示成 2×2 加一个 background,很多新手觉得混淆矩阵总和不是 1,像个 bug,其实这里每行是独立归一化的,总和不唯一是正常的。你要盯的是 background 那列:如果大量缺陷框被模型分到 background,说明置信度阈值或者正负样本比有问题;反过来如果背景被大量分到 defect,说明模型过拟合了纹理噪声。

针对 3687 张 1 类别的场景,验证阶段建议直接把conf=0.25压到0.05再看一遍检测结果。缺陷框小且边缘对比度低时,默认阈值会把一堆“及格框”砍掉,导致视觉效果很差但 mAP 并不低。用yolo predict model=best.pt source=val_images conf=0.05输出可视化结果后,再去决定后续报警阈值该定多少。损失函数曲线的判断同理:box_loss 和 cls_loss 下降曲线应该是平滑递减,如果出现周期性的锯齿,多半是数据加载顺序里混入了噪声样本,回去查标注。

5. 风力机缺陷检测数据集的五个常见坑:从 7z 解压报错到训练不收敛

5.1 7z 解压时报“Cannot open encrypted archive”但密码明明正确

现象:解压命令输完,报错提示无法打开加密压缩包,密码复制粘贴检查过却依然失败。

原因:大多数情况是压缩包文件名或压缩内文件名带了非 UTF-8 编码,7z 在读取时把文件名解码成了乱码,你看到报错发生在读取文件列表阶段,根本还没到校验密码那一步。另一种可能是压缩包在网盘传输中断,文件尾部分块缺失,7z 检查 CRC 失败后误报加密错误。这种情况和密码正确与否无关,属于最典型的“7z 压缩文件密码是正确的但一直报错”。

解决:先用7z t 包名.7z跑一次性完整性测试,确认包体没问题;再用7z l 包名.7z查看内部文件列表,如果出现乱码,用7z x -mcp936或设置终端为 UTF-8 以正确解码。若传输损坏只能重新下载,别在解压软件里反复试密码,浪费时间。

5.2 VOC 里一张图对应多张 XML 或漏 XML

现象:图片总数是 3687,但 XML 有 3720 个,多出来的几十个找不到对应图。

原因:数据集的标注阶段可能有重复标注文件被保留到打包目录,或 XML 命名和图片名不完全一致,比如图片叫img_001.jpg、XML 叫IMG_001.xml。差别只在大小写,Windows 下发现不了,Linux 下一秒变两个文件。还有一种可能是标注工具生成了.xml的临时备份文件,文件名带~后缀。

解决:写脚本按统一规则重命名,优先把图片名作为基准,XML 文件名转成和图片一致后再比对。转换前先按 basename 取差集,把多余文件移出目录,避免训练时yolo因为找不到配对文件直接跳过图片。这里有一个实际经验:不要直接删除多余 XML,先移到quarantine/目录,等确认训练正常后再清,毕竟数据集的原始标注很珍贵。

5.3 YOLO 训练时 image 和 label 数量对不上但没报错

现象:训练能启动,但日志里每轮的图片数明显少于 3687,跑到一半才发现 val 集数量不对。

原因:yolo train data=...的验证集图片没有对应 TXT,ultralytics会把这部分图片静默过滤掉。这比 5.2 更隐蔽,因为不是报错而是少数据。很多人在训练完看 mAP 时才发现验证集只有 300 张,而自己明明划了 400 张,这就是静默过滤的翻车现场。

解决:训练前用下面的脚本核对每一张图是否有同名 TXT:

for img in $(cat val.txt); do lbl="${img%.jpg}.txt" [ -f "$lbl" ] || echo "missing: $img" done

缺的按需补空 TXT 或移出验证集;这一步做完再训练。我一般还会写一个 Python 脚本统计labels/val和images/val的文件数差值,并打印具体缺失文件名,双保险。

5.4 缺陷目标太小,默认输入尺寸导致大量漏检

现象:训练时用imgsz=640,验证 mAP 有 0.72,但无人机实拍场景里叶片裂纹框不出来。

原因:风机叶片缺陷在整张画面中的像素占比常在 1% 以下,imgsz=640相当于把目标缩小到几个像素,特征没了。模型学到的是“整片叶片”而非“裂纹”。这是小目标检测的血泪经验,imgsz 设置不当,mAP 再高也是假的。

解决:分两部分调。一是推理侧把imgsz提到 960 或 1280,二是训练侧配合mosaic=0和scale=0.3这种更保守的增强参数,让模型不要老看到被拉大缩小后的畸形目标。如果显存不够,用Rect训练或切块推理,把大图切成 1280 的 patch 再检测,这是风电巡检里更常见的做法。切块时要注意 patch 之间留 10% 重叠,防止缺陷正好被切在边缘。

5.5 7z 重压缩后数据集给队友无法解压

现象:把 VOC 和 YOLO 目录整理好重新打 7z 包发出去,队友在 Windows 上解压到一半报“头部错误”或者文件夹内路径变空。

原因:打包时用了7z a -mhe=on对文件头加密,而队友的 7-Zip 版本太老不支持;或者打包时写了绝对路径,解压后生成一连串嵌套目录。还有一种可能是打包时把符号链接也打进去了,Windows 解压时无法处理。

解决:打包时把工作目录切到数据集根目录的上一级,用相对路径加包名:

cd /data 7z a -t7z wind_turbine_defect_3687.7z wind_turbine_defect/ -mx=5

-mx=5是压缩等级,默认级别并不比极限档差多少,但极限档会让压缩和解压都慢一倍。要做好“发给别人能直接跑”的数据包,打包前把解压后的相对路径测一遍,别用绝对路径。我通常在打包前先解压到一个临时目录跑一遍校验,确认没问题再发出去。

6. 把 3687 张数据用到极致:数据增强、badcase 回灌与置信度阈值校准

数据增强对 1 类别小缺陷数据集比调网络结构更值得投资。YOLOv8 自带增强之外,我建议做三类“物理层面”的增强:随机亮度扰动模拟不同光照下的叶片表面;随机高斯噪声模拟雨雾天气;以及对叶片缺陷做局部裁剪放大后重新粘贴回原图背景。后者对本数据集尤其有效,因为一张图里的缺陷往往只有一处,直接用 Copy-Paste 可以把缺陷密度翻倍。实现时注意粘贴的缺陷框不要和原缺陷重叠,PIL 合成后重新计算 YOLO 归一化坐标再写进 TXT,跑一轮增强再跑一轮训练,往往比单纯把 epochs 从 120 加到 300 更有效。

badcase 回灌是另一个冷门但高收益的操作。把 val 集里模型预测错的图单独抽出来,如果错误原因是目标过曝或模糊,不要简单加进训练集,而是对这些图做一次轻微的cv2.GaussianBlur和光照归一化,作为“困难样本”放进 train 集。这样做的意义不是增加数量,而是让模型在训练阶段就见过和它推理时最像的低质量输入,而不是只在验证时才看到。

最后是置信度阈值校准。别只盯着 mAP,工业缺陷检测追求的是误报率可控。对 3687 张数据训练出的模型,先在 50 张完全没有缺陷的负样本图上跑一遍,统计误检框的置信度分布;再在 100 张有缺陷图上统计召回框的置信度,用这两条分布的交点去定最终报警阈值,通常结果在 0.15~0.35 之间。把阈值写小会漏报,写大全是误报,这个交点方案比拍脑袋定conf=0.25可靠得多。我的习惯是每次迭代后保留三件套:训练曲线截图、验证集 badcase 汇总、阈值校准表,这样任何一次改参数都有据可查。整个过程走一遍后你会发现,3687 张 1 类别的数据集能支撑起一条足够可信的缺陷检测闭环,剩下的就是你自己的数据收集节奏了,希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询