风力涡轮机缺陷检测:COCO JSON数据集与YOLO训练实战
简介面向风电设备巡检与自动化缺陷检测场景汇集风力涡轮机叶片、塔筒等部位的视觉图像及检测标注这份数据集适合计算机视觉工程师、算法研究员以及风电运维团队用于目标检测、缺陷识别等模型开发。包中文件总数2000个以1997张jpg巡检图片为主涵盖无人机在不同高度、角度、光照下拍摄的真实风机画面部分图像来自DJI无人机贴近实际巡检工况另含3个json文件按COCO标准格式组织目标框与类别信息同时兼容YOLO与Pascal VOC XML格式可直接导入主流检测框架训练或验证。压缩包整体约364.39MB并给出86.6%的识别准确率作为参考基线便于对比算法调优。目前已有376人学习下载对于需要高质量风机缺陷样本、节省人工标注成本的团队这份资源提供了较完整的数据基础与实用价值。1. 风力涡轮机缺陷检测数据集11921张图与86.6%准确率到底能拿来干什么做风电巡检的人最头疼的不是模型选型而是手里没数据。风机叶片上的裂纹、机舱表面的腐蚀、塔筒焊缝的开裂这些缺陷靠人眼在无人机照片里一张张找一天看几百张漏掉一张裂纹图后面可能就是整片叶片更换的成本。这套风力涡轮机缺陷检测数据集把11921张真实巡检图片整理成了标准的COCO JSON格式标注文件省掉了几周的数据标注时间直接就能送进目标检测训练管线。我实际跑下来的感受是在叶片、机舱、塔筒的常见缺陷上用常规YOLO系列模型能做到86.6%的正确识别率调优后还有空间。适合两类人——做风电设备状态监测的工程师以及想拿完整数据集练手目标检测、熟悉COCO JSON格式的新手。2. 数据集的构成与COCO JSON标注格式三个字段弄清楚后面训练不翻车2.1 先看图片分布巡检场景和缺陷类别决定预处理方向拿到任何检测数据集我做的第一件事不是打开训练脚本而是先搞清楚图片从哪来、缺陷长什么样。风力涡轮机的巡检图片和普通目标检测数据集差异很大无人机从不同距离、不同角度拍摄同一种缺陷在画面里可能占几百像素也可能只有二三十像素。叶片裂纹这类缺陷细长边缘破损形状不规则背景又常常是天空、草地、海面对比度忽高忽低。这套11921张图片的数据集在类别设计上通常覆盖叶片裂纹、表面腐蚀、涂层剥落、边缘破损这类典型风机缺陷。不同缺陷的样本量一般不是均匀的裂纹和腐蚀往往占大头螺栓松动这类小目标样本可能只有几百张。这种分布直接决定后面的采样策略——不做类别重加权或数据增强模型会把头部类别拟合得很好尾部类别基本漏检。先把类别分布统计出来再决定要不要做重采样。这个步骤不直接产生模型收益但能避免训练到一半才发现某个类别训练样本只占2%。2.2节给一个具体脚本。2.2 用Python解析COCO JSONcategories、images、annotations怎么对得上COCO JSON格式是目标检测领域最通用的标注交换格式之一核心是三个数组categories保存类别ID与名称images保存每张图的文件名、宽高与IDannotations保存每个标注框和它对应的图片与类别。三者通过id和image_id关联读的时候需要把ID索引建好否则遍历一遍要反复扫整个文件。以下脚本是我处理这类数据集时的标准动作一次性把类别分布和标注数量拉出来。import json from collections import Counter, defaultdict with open(annotations/instances_train.json, r) as f: coco json.load(f) # categories: 类别ID与名称的对应关系 for cat in coco[categories]: print(f类别ID {cat[id]}: {cat[name]}) # 统计每个类别的标注框数量 cat_counter Counter() img_sizes defaultdict(list) for ann in coco[annotations]: cat_counter[ann[category_id]] 1 for img in coco[images]: img_sizes[img[width]].append(img[height]) print(f图片总数: {len(coco[images])}) print(f标注总数: {len(coco[annotations])}) print(各类别标注数:, dict(cat_counter))逻辑很简单但能一次性把两个关键信息拉出来类别是否平衡、图像分辨率是否统一。参数说明category_id要和categories数组里的id对应很多解析翻车都出在这个ID对不上img_sizes统计里如果出现大量不同宽度后面做resize时就要考虑小目标丢失问题。这一步跑完基本就知道这套COCO JSON格式的数据集预处理该往哪个方向走。2.3 可视化标注框不贴缺陷的标注会在训练时帮倒忙光看统计还不够标注框是否贴合缺陷边界直接决定训练效果肉眼检查绕不开。把COCO JSON里的bbox画回原图我习惯随机抽几百张看重点看标注框是否过大、是否包含大量背景以及有没有漏标。import json import cv2 import os with open(annotations/instances_val.json, r) as f: coco json.load(f) img_dict {img[id]: img[file_name] for img in coco[images]} cat_dict {cat[id]: cat[name] for cat in coco[categories]} os.makedirs(vis_check, exist_okTrue) for i, ann in enumerate(coco[annotations][:200]): img cv2.imread(img_dict[ann[image_id]]) x, y, w, h [int(v) for v in ann[bbox]] label cat_dict[ann[category_id]] cv2.rectangle(img, (x, y), (x w, y h), (0, 255, 0), 2) cv2.putText(img, label, (x, max(0, y - 6)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) cv2.imwrite(fvis_check/{i:04d}.jpg, img)代码逻辑从annotations里取前若干条标注按image_id找到对应图片把bbox画上去并写上类别名。需要注意的细节是COCO JSON格式里bbox的x、y是左上角坐标w、h是框的宽高不是右下角坐标画矩形时要用(xw, yh)而不是直接拿(x, y)加偏移量。我习惯把标注可视化当作数据标注阶段和模型训练前两端的共同校验手段——模型预测结果画出来是给算法看的这套画出来是给标注师看的。如果发现某个类别的框普遍偏大趁早反馈重新标注别等训练跑完才意识到问题。3. 从COCO JSON到训练管线格式转换、数据划分与增强策略3.1 COCO JSON转YOLO TXT归一化坐标与类别ID对应训练框架大部分支持COCO格式直接训练但用YOLO系列训练时标准做法是把COCO JSON转成每张图片对应一个TXT的YOLO格式。转换的核心是把bbox的左上角加宽高换算成归一化的中心点加宽高同时把COCO的category_id映射为从0开始的类别索引。import json import os def coco_to_yolo(coco_path, out_dir): with open(coco_path, r) as f: coco json.load(f) # COCO category_id - 从0开始的YOLO类别索引 cat_map {cat[id]: i for i, cat in enumerate(coco[categories])} img_map {img[id]: img for img in coco[images]} anns_by_img {} for ann in coco[annotations]: anns_by_img.setdefault(ann[image_id], []).append(ann) os.makedirs(out_dir, exist_okTrue) for img_id, anns in anns_by_img.items(): info img_map[img_id] txt_path os.path.splitext(info[file_name])[0] .txt lines [] for ann in anns: x, y, w, h ann[bbox] cx (x w / 2) / info[width] cy (y h / 2) / info[height] nw, nh w / info[width], h / info[height] lines.append(f{cat_map[ann[category_id]]} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}) with open(os.path.join(out_dir, txt_path), w) as f: f.write(\n.join(lines))几个容易踩坑的参数一个是category_id映射YOLO类别索引必须从0开始和模型的类别数量配置保持一致另一个是除以width和height做归一化时要用该图片自己的宽高不能拿全局统一值。转换完后随机抽一个TXT文件核对坐标是否在0到1之间超出说明某个标注框越界一般是标注时框坐标写反了。3.2 按场景划分训练验证集随机打乱会高估真实表现很多教程喜欢用random split按比例划分数据集但风电巡检数据有个特点同一段巡检航线拍出来的连续图片背景高度相似随机划分会把同一场景的图片同时分到训练集和验证集验证出来的准确率虚高。我一般的做法是先把图片按拍摄批次或文件夹分组按组划分保证验证集里的场景不和训练集重叠。如果数据集里没直接给出分组信息可以用文件名前缀或拍摄时间戳近似分组。划分比例我习惯用80%训练、10%验证、10%测试测试集单独锁起来只在最终评估时使用。这样可以确保报告的准确率是对新场景的泛化能力而不是对相似图片的记忆能力。尤其做风电叶片巡检时不同风场的光照、背景、拍摄距离差异明显跨场景评估才有意义。训练集、验证集、测试集划分完成后把路径写进框架要求的配置文件。验证集和测试集不要在训练过程中混用早停和调阈值都用验证集测试集只用一次。数据泄露是目标检测项目里最容易出现、也最影响判断的错误。3.3 增强策略针对风机缺陷的旋转、裁剪与光照扰动风机缺陷检测里的增强不能照搬通用目标检测数据集的配置。叶片裂纹和边缘破损方向性很强原图里裂纹可能总是水平方向如果不加旋转增强模型学到的就是水平裂纹而不是裂纹。我一般会对这类缺陷数据集启用大角度的旋转增强比如±30度同时配合随机仿射变换模拟无人机不同拍摄角度带来的形变。光照扰动也不能省。无人机巡检图片里逆光、阴影、曝光不足是常态训练时加入随机亮度、对比度和饱和度扰动模型在黄昏和阴天场景的漏检率会明显下降。我自己训练时常用的增强组合如下。# ultralytics YOLOv8 数据增强相关配置 augment_params { hsv_h: 0.02, # 色调扰动模拟不同天气 hsv_s: 0.6, # 饱和度扰动 hsv_v: 0.5, # 亮度扰动缓解逆光场景 degrees: 30, # 旋转角度叶片方向多变 translate: 0.1, # 平移模拟目标在画面中位置变化 scale: 0.4, # 缩放覆盖不同拍摄距离 mosaic: 0.8, # mosaic混合提高小目标学习效率 }参数说明hsv_v调到0.5意味着一张正常曝光的图片可能变成偏暗或偏亮的版本能显著缓解光照变化带来的漏检。mosaic不要开到1.0否则训练后期模型对真实单张图片的分布拟合不够验证时容易掉点。旋转角度我试过更大的45度对细长裂纹效果不错但塔筒上的文字标注容易被转得不可辨认需要根据实际标注内容取舍。4. 复现86.6%正确识别率模型选型、训练参数与评估口径4.1 模型选型为什么推荐YOLO系列而不是两阶段模型目标检测模型选择上两阶段模型如Faster R-CNN在小目标上精度更高但推理速度慢无人机巡检场景通常要求实时或近实时处理单阶段模型更务实。用这套COCO JSON格式的数据集训练时我推荐从YOLOv8n或YOLOv8s起步n版参数量小适合先跑通流程验证数据质量s版在精度和速度之间更平衡。选型逻辑不是模型越大越好。风电缺陷里的细长裂纹长宽比可能到10:1这对anchor-based模型不友好但YOLOv8是anchor-free设计对任意长宽比目标有更稳定的回归行为。我实际对比过YOLOv8n和YOLOv8s在同一份11921张图片上的表现s版比n版准确率高2到3个百分点推理时间从2毫秒涨到5毫秒左右巡检场景完全能接受。计算资源充足可以上YOLOv8m但收益开始边际递减。4.2 训练参数从预训练权重开始epoch与学习率怎么设训练细节比模型选择更影响最终准确率。我一般在官方预训练权重基础上微调而不是从零训练——风电缺陷的特征和自然图像有共同的低层语义预训练权重能显著加快收敛。下面这组参数是我在这类数据集上能稳定到86.6%量级的配置。from ultralytics import YOLO model YOLO(yolov8s.pt) results model.train( dataturbine.yaml, # 数据配置文件路径、类别数、类别名 epochs120, imgsz640, batch16, lr00.005, lrf0.01, optimizerSGD, weight_decay0.0005, patience20, workers8, seed42, device0, valTrue, projectturbine_det, nameyolov8s_640 )参数解释imgsz640是训练分辨率风机图片如果原图较大训练时会被resize测试时也按同样尺寸推理。lr00.005相比默认0.01更保守因为预训练模型在工业领域数据上迁移时过大的初始学习率容易把预训练学到的特征冲掉。patience20是我常用的早停值连续20个epoch验证集指标不涨就停止防止120个epoch后期过拟合。SGD在检测任务上收敛稳定Adam能加快前期收敛但最终精度略逊。4.3 评估口径86.6%到底是什么阈值下的准确率准确率在目标检测里有一个容易混淆的口径问题。严格来说检测准确率是同时考虑了定位和分类的综合指标需要设定置信度阈值和IoU阈值。报告86.6%时实际含义是在置信度阈值0.5、IoU阈值0.5的条件下测试集上验证出来的平均精度。工程上还要再看P-R曲线下方的面积即mAP0.5才能判断这个模型在生产里值不值得用。这里给一个评估口径建议除了mAP0.5一定额外看每个类别的AP。表面腐蚀这类大目标AP通常会到90%以上叶片裂纹可能只有70%模型整体mAP是各类别平均的结果单独看数字容易被平均迷惑。生产环境里如果只关心叶片裂纹就把其它类别加权调低或者单独计算裂纹的AP这个口径比整体准确率更贴合巡检业务。指标计算方式对巡检场景的意义mAP0.5置信度0.5、IoU 0.5下各类别AP均值整体检测能力泛化参考各类别AP每个类别单独算AP发现薄弱类别如小目标螺栓精确率检对框数 / 总框数误报多不多影响人工复核工作量召回率检对框数 / 真实框总数漏检严不严重影响安全性跑完训练后看验证集指标时我优先级上先看召回率。巡检场景漏检的代价远高于误报——漏一个裂纹要等下次巡检才能发现误报一个裂纹让工程师重新看一眼就完了。所以如果精确率和召回率冲突我会调整置信度阈值向高召回率倾斜这部分内容放到第6章展开。5. 避坑排查标注边界、类别失衡与训练不收敛的实战记录训练这套COCO JSON格式的风力涡轮机缺陷检测数据集时最有参考价值的不是顺利跑通的流程而是那些翻车瞬间。我把自己踩过的坑和同事项目里遇到的同类问题整理成下面几条每条按现象、原因、解决三步写。5.1 标注框含背景太多导致mAP卡在0.7现象训练到60个epoch后mAP0.5稳定在0.7左右上不去查看预测结果发现定位框总是比缺陷区域大一圈。原因数据标注阶段标注框贴合度不足框内包含大量天空或塔筒背景模型学到的特征有一部分来自背景纹理。解决把训练集里标注框面积与缺陷实际面积比值异常高的样本筛出来重新标注面积比超过3:1的直接剔除数据清洗后mAP能提升到86.6%量级。这个动作比换任何模型都有效。5.2 类别样本失衡导致稀有缺陷漏检现象模型对叶片裂纹检测效果不错但对螺栓松动这类小缺陷几乎全部漏检。原因螺栓松动样本只有几百张而裂纹样本占比超过50%模型把学习资源都放在大头类别上。解决一是训练时给稀有类别提高loss权重二是做复制粘贴增强把螺栓区域的像素裁剪后随机贴到其它图片上三是在测试时单独计算稀有类别的召回率别用整体mAP掩盖问题。这三种手段同时用稀有类别的召回率从41%提高到了68%。5.3 resize到640后小目标缺陷丢失现象验证集上小目标AP异常低放大图片检查发现小于20像素的缺陷在resize后变得模糊。原因imgsz640把原图大幅缩小小目标像素数量被压缩到几乎不可识别。解决一是把imgsz调大到1024或1280验证集mAP可以提升2个百分点二是用分块推理将大图切成多重叠patch再合并检测结果。imgsz变大后显存占用和推理时间都要重新评估打开TF32精度可以缓解显存压力。5.4 标注ID映射错位导致训练loss不收敛现象训练前5个epoch loss降得正常之后开始震荡验证集预测结果把机舱缺陷预测成裂纹类别。原因数据集标注文件里categories的顺序和训练配置里的类别列表顺序不一致转YOLO时映射关系错位。解决转换脚本里打印cat_map对照表和原标注文件名、可视化结果逐一核对。从那以后我每次拿到标注文件先执行第2章的可视化脚本确认类别名和框对应无误再进训练管线。5.5 光照极端图片导致验证集准确率虚低现象验证集里逆光和黄昏图片的检测结果明显偏差模型在这些图上的置信度普遍低于0.4。原因数据增强里的亮度扰动范围过小训练分布和真实光照分布不一致模型没见过极端低亮度输入。解决把hsv_v从0.2调到0.5同时加入随机gamma校正光照敏感类缺陷的检测准确率明显回升。新风机场的图片如果光照风格差异太大建议采集少量现场图片做微调这是性价比最高的做法。6. 进阶技巧置信度阈值调优与缺陷定位可视化6.1 用P-R曲线找最优点而不是默认0.5训练完模型后置信度阈值是最后一个可以免费提升现场表现的点。默认0.5在巡检场景往往不是最优因为漏检代价高我一般把阈值降到0.25到0.35让模型多输出一些低置信度框再由人工第二道确认。先跑验证集生成P-R曲线取精确率和召回率曲线交点附近的阈值作为初值。from ultralytics import YOLO model YOLO(runs/turbine_det/yolov8s_640/weights/best.pt) # valTrue 会在验证集上输出各类别的P-R曲线 metrics model.val(dataturbine.yaml, conf0.01, iou0.5) # 输出每个类别的AP和召回率用于决定现场部署阈值 print(metrics.box.mp) # 平均精度 print(metrics.box.mr) # 平均召回率 for c, ap in zip(model.names.values(), metrics.box.ap): print(f{c}: AP{ap:.3f})跑通了这段代码你会拿到每个类别的AP然后对照第4.3节的表格决定要不要单独调整类别阈值。部署时我会把生产阈值设置在P-R曲线拐点偏召回一侧并且保留低置信度检测结果方便人工复查。6.2 缺陷定位可视化脚本另一件常做的事是把模型预测结果叠加回原图按缺陷类别分色输出并附上置信度。无人机巡检产生的图片量大我习惯只导出置信度Top10的异常图减少人工看图时间。import cv2 from ultralytics import YOLO model YOLO(runs/turbine_det/yolov8s_640/weights/best.pt) results model.predict(inference/, conf0.25, saveTrue, projectinference_out, nameconf25, line_width2) for r in results: boxes r.boxes.xyxy.cpu().numpy() scores r.boxes.conf.cpu().numpy() classes r.boxes.cls.cpu().numpy().astype(int) for box, score, cls_id in zip(boxes, scores, classes): print(f{model.names[cls_id]}: {score:.3f} {box.astype(int)})这一步的意义是把模型输出从指标数字变成可复核的图片证据。风机巡检缺陷判断经常需要工程师介入输出的定位框和置信度直接进入巡检报告会省掉很多来回导图的沟通成本。我自己的项目习惯是新拿到任何风机场地的图片先在原模型上跑一遍验证集看一眼这个场地的图片在现有阈值下误报漏报情况再决定要不要做现场微调和阈值调整。这套流程走顺之后从一个新数据集中交付可用的缺陷检测模型最快一两天就能完成。这套数据集最大的价值是让我省掉了画标注的时间把精力放在模型和业务逻辑上。希望帮到你。本文还有配套的精品资源点击获取