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

风力叶片缺陷检测实战:COCO数据集转YOLO格式与训练全流程

发布时间:2026/9/24 19:18:30

资讯中心
01
ARTICLE

风力叶片缺陷检测实战:COCO数据集转YOLO格式与训练全流程

风力叶片缺陷检测实战:COCO数据集转YOLO格式与训练全流程
简介面向风力叶片缺陷检测的数据集资源图片样本总量2249张采用COCO JSON格式进行标注覆盖排水孔受损、雷击、污垢、漏油、PU胶带、表面裂纹、侵蚀等典型缺陷类别适合风电运维、工业质检及目标检测算法研究人员用于模型训练与效果验证也可作为高校人工智能课程的实训案例。压缩包文件总数2000个其中1997张JPEG原图与3个JSON标注文件整体大小约74.32MB标注内容按COCO标准组织类别信息与目标框坐标齐备解压后按目录检索即可使用文件命名体现叶片型号与采集批次便于按需筛选与扩展样本。资源目前已有818人学习下载数据组织清晰、格式通用读者拿到后可直接解析标注并接入YOLO、MMDetection等常见检测框架也可结合叶片部位信息进一步开展缺陷分类与定位分析是练习工业视觉检测流程的实用数据基础。1. 风力叶片缺陷检测数据集2249 张图能否撑起一个能用的检测模型做风电运维或者工业视觉的同行应该都有体会叶片缺陷数据比模型本身难搞得多。雷击、污垢、漏油、表面裂纹、排水孔受损、侵蚀、PU 胶带脱落这些缺陷种类杂、外观差异大而且叶片图像动辄几千万像素标注成本极高。这套数据集一共 2249 张图全部用 COCO JSON 格式标注覆盖 7 类典型叶片缺陷对于想快速验证检测方案、跑通训练流程、或者做算法预研的人来说是一个很实在的起点。它适合的目标很明确手里暂时没有真实叶片数据、想先用公开数据把 YOLO 或 RT-DETR 流程跑通的人以及需要一批带精细分割或框标注的样本做数据增强、模型微调或论文实验对比的从业者。别指望 2249 张图能直接训练出一个直接上机的工业级模型但用它做基准验证、评估标注格式、测试数据管线完全够用。2. 缺陷类型与标注格式COCO JSON 不只是“框”更是后续一切操作的基石2.1 七类缺陷的视觉特征与检测难点数据集的缺陷类别设计贴合真实巡检场景不像很多公开数据集那样只放“正常/异常”二分类。这 7 类缺陷分别是排水孔受损、雷击、污垢、漏油、PU 胶带、表面裂纹、侵蚀。每一类在视觉上都有明显的差异化特征但也有不少误检陷阱。排水孔受损通常出现在叶片根部或特定气动附件附近形状不规则容易与污垢混淆雷击损伤表现为黑色烧蚀点或碳化痕迹但部分轻度雷击只有细微变色污垢是分布最广的类别从泥点到大面积覆盖都有边界模糊漏油常伴随深色液体痕迹但叶片表面本身有阴影容易误判PU 胶带是人为附加物边缘清晰但颜色可能与背景接近表面裂纹是最细碎的缺陷细线状、对比度低对标注框的紧密度要求很高框大了会把背景噪声带进来侵蚀是表面材料脱落呈片状与污垢、裂纹可能同时出现在同一区域。从检测角度看这张数据集的主要难点是小目标多、背景复杂、类间相似度高。裂纹和侵蚀在低分辨率缩略图上几乎无法分辨所以训练时图片尺寸、增强策略都要针对这一点调整。2.2 COCO JSON 格式结构速览COCO 格式的核心是标注文件里同时包含 images、annotations、categories 三段结构。先看一个典型的 JSON 片段了解字段含义{ images: [ { id: 1, file_name: ASP22BladeA1704103741_jpg.rf.aff8a02936abb81f6aabeceda26df399.jpg, width: 1280, height: 720 } ], categories: [ {id: 0, name: 排水孔受损}, {id: 1, name: 雷击}, {id: 2, name: 污垢}, {id: 3, name: 漏油}, {id: 4, name: PU胶带}, {id: 5, name: 表面裂纹}, {id: 6, name: 侵蚀} ], annotations: [ { id: 1, image_id: 1, category_id: 5, bbox: [356, 201, 88, 57], area: 5016, iscrowd: 0 } ] }这里的 bbox 是 [x, y, width, height] 格式以图像左上角为原点。area 是框面积有些框架在过滤小目标时会用到iscrowd 为 0表示这是普通实例框不是密集人群那种群体标注。category_id 从 0 开始还是从 1 开始不同框架要求不同YOLO 系列通常希望类别从 0 开始但 Detectron2 默认从 1 开始。拿到数据集后第一件事就是确认类别 id 的起始值否则训练时会直接报类别数不匹配的错误。2.3 为什么要用 COCO 而不是 YOLO 的 txt 格式很多从 YOLOv5 入门的人会觉得 COCO JSON 很绕明明 txt 一行一个框多省事。但 COCO 格式是工业界和学术界的“通用语”——MMDetection、Detectron2、Ultralytics 都原生支持而且它天然携带 image_id、area、iscrowd 这些字段方便做按类别统计、去重、质量筛选。更重要的是COCO 格式可以无损转换回 YOLO、VOC、LabelMe 等格式反之则不行。因为 COCO 的 bbox 是绝对像素坐标而 YOLO 是中心点相对坐标转换过程中如果图像宽高信息丢失相对坐标就错了。所以原始数据保留 COCO JSON 是最稳的。我一般拿到这个数据集后会先用脚本统计每张图的标注数量、每类缺陷的实例数、bbox 的大小分布确认数据质量后再决定是直接用还是做过滤。统计脚本不长但能避免后面训练时蓝屏式崩溃import json from collections import Counter with open(annotations.json, r, encodingutf-8) as f: coco json.load(f) cat_name {c[id]: c[name] for c in coco[categories]} per_image Counter() per_cat Counter() box_areas [] for ann in coco[annotations]: per_image[ann[image_id]] 1 per_cat[cat_name[ann[category_id]]] 1 w, h ann[bbox][2], ann[bbox][3] box_areas.append(w * h) print(图片数:, len(coco[images])) print(标注数:, len(coco[annotations])) print(每类数量:, dict(per_cat)) print(平均每图标注:, sum(per_image.values()) / len(per_image)) print(最小框面积:, min(box_areas), 中位数:, sorted(box_areas)[len(box_areas)//2])参数说明per_image 统计每张图上的标注数量如果某张图有几十个框而多数图只有一两个就要留意那张图是不是拼接图或特殊工况per_cat 统计每类缺陷的实例数量如果裂纹只有几十个而污垢有几百个训练时就要给裂纹类别提高权重否则模型会偏向多数类box_areas 列表用来观察目标尺度如果大量框的面积低于整图面积的 1%那就需要在训练时打开高分辨率输入或使用多尺度训练。3. COCO 转 YOLO 格式训练 YOLOv8 前必须做对的一步3.1 转换脚本核心逻辑与边界条件Ultralytics YOLOv8 可以直接读 COCO 格式但通常我们还是会转成 YOLO 的 txt 格式可以防止后续版本升级导致原生 COCO 加载逻辑变动。转换的核心逻辑并不复杂把 COCO 的 bbox 从 [x, y, w, h] 转成 YOLO 的 [cx, cy, w, h]并全部用图像的宽高归一化到 0~1 之间。下面是完整的转换脚本import json import os from pathlib import Path def coco_to_yolo(coco_path, img_dir, out_dir): with open(coco_path, r, encodingutf-8) as f: coco json.load(f) Path(out_dir).mkdir(parentsTrue, exist_okTrue) img_info {img[id]: img for img in coco[images]} cat_id_map {c[id]: idx for idx, c in enumerate(coco[categories])} labels {} for ann in coco[annotations]: img img_info[ann[image_id]] w, h img[width], img[height] x, y, bw, bh ann[bbox] # 边界检查有些标注框可能超出图像范围 x2 min(x bw, w) y2 min(y bh, h) bw max(x2 - x, 1) bh max(y2 - y, 1) cx (x bw / 2) / w cy (y bh / 2) / h nw bw / w nh bh / h # 过滤掉过小的框 if nw 0.001 or nh 0.001: continue cat_id cat_id_map[ann[category_id]] line f{cat_id} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}\n labels.setdefault(ann[image_id], []).append(line) for image_id, lines in labels.items(): img img_info[image_id] stem Path(img[file_name]).stem with open(os.path.join(out_dir, f{stem}.txt), w) as f: f.writelines(lines) print(f转换完成共 {len(labels)} 个标签文件)这段代码里最容易被忽略的是边界检查和最小尺寸过滤。标注工具或数据导出过程中偶尔会出现 bbox 的 x w 超过图像宽度的情况如果不裁剪归一化之后坐标会大于 1YOLO 训练时 grad 会直接爆掉。最小尺寸过滤主要针对那些面积只有几个像素的噪声标注这类框对训练没有正向帮助反而会让模型去拟合无效特征。还有一个细节cat_id_map 的生成方式。COCO 原始类别 id 可能不是从 0 开始可能是 0、1、2、3 这样的连续值也可能是 1、3、5 这样的离散值。转换脚本中必须显式地做一个映射把原始 id 按出现顺序映射到 0~N-1 的连续索引否则 YOLO 训练时会报类别数不匹配。3.2 转换后的数据目录结构YOLOv8 要求数据目录按 train 和 val 分好每个子目录下包含 images 和 labels 两个兄弟目录。建议按下面的结构组织wind_turbine_blade/ ├── train/ │ ├── images/ │ │ ├── ASP22BladeA1704103741_jpg.rf....jpg │ │ └── ... │ └── labels/ │ ├── ASP22BladeA1704103741_jpg.rf....txt │ └── ... ├── val/ │ ├── images/ │ └── labels/ └── data.yamldata.yaml 的内容也很关键类别顺序必须和转换后的 txt 类别 id 完全对应path: /path/to/wind_turbine_blade train: train/images val: val/images names: 0: 排水孔受损 1: 雷击 2: 污垢 3: 漏油 4: PU胶带 5: 表面裂纹 6: 侵蚀如果训练的机器不在本地路径要改成绝对路径或相对路径注意 Ultralytics 对 path 字段的解析方式是拼接 train 相对路径很容易因为路径写错而报 FileNotFoundError。我习惯把 path 改成绝对路径省得在不同机器之间切换时反复踩坑。3.3 训练前验证转换结果转换完了不是直接开训先做一次可视化验证。用 OpenCV 或 PIL 把标注框画回原图随机挑 30 张看看框的位置对不对这是成本最低的回归测试。import cv2 import random from pathlib import Path img_dir Path(train/images) label_dir Path(train/labels) imgs list(img_dir.glob(*.jpg))[:30] for img_path in imgs: img cv2.imread(str(img_path)) h, w img.shape[:2] label_path label_dir / (img_path.stem .txt) with open(label_path) as f: lines f.readlines() for line in lines: parts line.strip().split() cls, cx, cy, bw, bh int(parts[0]), *map(float, parts[1:]) x int((cx - bw/2) * w) y int((cy - bh/2) * h) x2 int((cx bw/2) * w) y2 int((cy bh/2) * h) cv2.rectangle(img, (x, y), (x2, y2), (0, 255, 0), 2) cv2.putText(img, str(cls), (x, y-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) cv2.imwrite(fcheck_{img_path.name}, img)这段脚本会输出带框的图片检查时重点看两类问题一是框是否贴着缺陷边缘如果偏移超过 5 个像素说明标注本身有问题或 bbox 读取错位二是类别 id 是否对应上如果表面裂纹的框里画的全是污垢说明类别映射表写错了。可视化检查只需几分钟但能省下后面几小时的无效训练时间。4. 用 Ultralytics YOLOv8 训练参数配置与训练过程要点4.1 数据集划分与验证集选择2249 张图不算大但也不是小到不能拆分。按照 8:1:1 或 8:2 的比例拆训练集和验证集都可以。但如果数据集中存在同一个叶片的多张连续拍摄图直接随机拆分会导致训练集和验证集之间出现数据泄漏比如同一叶片缺陷的不同角度照片一张在训练集、一张在验证集验证指标虚高。我一般先按叶片编号分组同一叶片的图片全部放进同一份然后再拆分。这个数据集的文件名里其实带了叶片编号比如 ASP22BladeA、MAN320BladeB可以通过正则提取前缀来做分组。如果嫌麻烦也可以直接用 sklearn 的 GroupShuffleSplitfrom sklearn.model_selection import GroupShuffleSplit groups [f.split(_)[0] for f in all_images] gss GroupShuffleSplit(n_splits1, test_size0.2, random_state42) train_idx, val_idx next(gss.split(all_images, groupsgroups))参数说明test_size 设为 0.220% 的数据用来做验证集。random_state 固定为 42保证每次划分结果一致方便对比实验。这里不设置 test 集的原因是这个数据集主要用于训练和验证真正做测试用的是另一批在现场采集的数据避免测试集被反复调参污染。4.2 训练命令与关键超参数用 YOLOv8 训练很简单但超参数不能全用默认值。针对叶片缺陷这种小目标和类别不均衡的数据集建议在默认基础上做几处调整yolo detect train \ datadata.yaml \ modelyolov8m.pt \ epochs100 \ imgsz1280 \ batch16 \ lr00.001 \ mosaic0.5 \ close_mosaic10 \ box7.5 \ cls1.0 \ device0imgsz 设置到 1280 是这次训练的关键。叶片缺陷中的裂纹和侵蚀在原始图像里往往只占几十像素如果用默认的 640 训练这些目标会被压缩到十几个像素甚至消失模型根本学不到特征。即使原始图像是 1280 或更高分辨率训练时也要保持较大的输入尺寸代价是显存占用上升、训练速度变慢但对小目标检测来说值得。mosaic0.5 表示开启 50% 概率的马赛克增强YOLOv8 默认是 1.0但叶片缺陷的上下文很重要马赛克会把不同叶片拼接在一起生成大量跨图背景噪声。特别是污垢和漏油本身依赖局部纹理和颜色上下文被马赛克截断后特征完全失效。我一般会在迁移学习阶段用 0.5到后面微调阶段直接把 mosaic 关掉配合 close_mosaic10 让最后 10 个 epoch 自动关闭马赛克。box 和 cls 是损失函数权重。box 控制定位损失的贡献叶片缺陷里有大量细长裂纹对定位精度要求高所以我更倾向于把 bbox 损失权重调高到 7.5。默认的 7.5 其实已经是这个值但如果你发现检测结果中框的位置偏大或偏小可以适当微调。4.3 显存不足时的应对策略batch16 在 1280 分辨率下单卡 24G 显存正好能放得下。如果你的卡只有 12G不用急着降 imgsz先把 batch 降到 8再看显存占用。如果还是不够可以开启梯度累积yolo detect train \ datadata.yaml \ modelyolov8m.pt \ epochs100 \ imgsz1280 \ batch8 \ accumulate2 \ device0accumulate2 表示每 2 个 batch 做一次参数更新等效于 batch16 的优化效果训练速度会慢一些但显存占用不变。注意 accumulate 值不一定要写成 2它取决于你的目标 batch size 和实际 batch size 的比值。如果 batch8 但想要 24 的等效 batch那 accumulate 应该设 3。如果降 batch 后显存还是不够那就是这种方案跑不了可以考虑用 RT-DETR 或 YOLOv8n 这种轻量模型但检测精度会明显下降。4.4 训练过程的监控指标训练日志里最值得关注的是 val_cls_loss 和 val_box_loss 有没有在最后 20 个 epoch 里仍然持续下降以及 mAP50 和 mAP50-95 的差距。叶片缺陷这种场景类别间相似度高mAP50-95 通常不会太高如果 mAP50 已经到 0.85 而 mAP50-95 只有 0.4说明框的定位和分类阈值设置还有优化空间可以先做 NMS 后处理调整而不是继续加训练轮次。另外一定要保存 best.pt 和 last.ptUltralytics 默认会做。best.pt 是基于验证集 mAP50-95 的最优权重last.pt 是最后一个 epoch 的权重。如果训练后期出现验证指标下降但训练指标还在上升那大概率是过拟合可以回退到 best.pt或考虑增加数据增强强度。5. 避坑与常见问题训练叶片缺陷检测时最容易翻车的五个点5.1 类别 id 错位导致模型完全学不到目标现象训练正常跑完验证集 mAP 很低预测出来的类别全是乱的比如把雷击全识别成污垢。原因COCO 原始 JSON 里的 category_id 可能不是从 0 开始而转换脚本里用的 enumerate(coco[categories]) 是按 categories 数组的顺序重新编号的。如果原始类别 id 是 1~7且 categories 数组顺序恰好也是 1~7那看起来没问题。但如果原始 id 和数组顺序不一致映射就错了。解决转换前先打印 coco[categories] 的 id 和 name确认映射关系。更稳妥的做法是直接用 cat_id_map {c[id]: idx for idx, c in enumerate(coco[categories])} 并打印出来检查一遍列表顺序与 data.yaml 中的 names 顺序完全一致。5.2 原图分辨率过高导致训练时内存爆炸现象加载某几张图时 OOM或训练刚开始就报 CUDA out of memory但数据集本身只有 2249 张看起来不该爆显存。原因叶片巡检照片有的原始分辨率达到 4000x3000直接送到模型里会算不出特征图GPU 显存被瞬间吃满。ultralytics 会在训练时按 imgsz 做缩放但在数据加载和预处理阶段如果原始图像过大解码本身就会占用大量内存。解决训练前先用脚本批量把图像缩放到 1920x1080 或 1600x1200保存为 JPEG 质量 90然后再做划分和训练。注意缩放要同步修改标注框坐标不能只改图不改标签。实际上用上面提到的 COCO 到 YOLO 转换脚本如果先统一缩放图片再读取新的宽高做归一化风险更小。更推荐的做法是图像尺寸保持原图不变让 Ultralytics 在管道内部按 imgsz 做 letterbox 缩放这样能避免标注坐标被二次换算。5.3 val 阶段出现大量空标注图片导致指标虚高现象验证时 mAP 很高但实际部署到新图片上效果很差。原因数据划分时如果随机拆分某些小而干净的图片大量出现在验证集里这些图本身没有标注或标注很少模型只要输出空结果就能获得低错误的假象。叶片数据里常有只包含背景的正常叶片照片这些照片如果进验证集会拉高验证指标。解决划分前先剔除没有标注的图片或确保验证集里每张图至少有一个标注。更严格的做法是按叶片编号分组并把正常叶片样本单独抽出来做背景测试集专门用来测试误检率。5.4 类别不均衡导致少数类完全学不出来现象训练后排水孔受损和裂纹的 recall 很低但污垢和漏油的 mAP 很高。原因2249 张图里污垢、漏油这类常见缺陷可能占了一半以上的标注实例而排水孔受损可能只有几十个实例。YOLO 默认按类别均匀采样但如果一个类别只有几十个正样本模型很难学到稳定特征。解决最简单的方法是调整每个类别的 loss 权重Ultralytics 可以通过 cls 参数给不同类别加权重但操作比较繁琐。更常用的是先统计每类实例数对样本量少的类别做过采样即在训练时按概率多加载包含该类别的图片。常见做法是写一个自定义 Dataset在 getitem 时优先返回包含少数类别的样本。5.5 标注框过于紧贴裂纹导致定位不稳定现象训练出的模型对裂纹的检测框抖动特别大同一张图多次推理结果差异明显有时框得住有时只框住一半。原因表面裂纹是细长形目标原始标注框如果是紧贴裂纹的外接矩形长宽比可能达到 1:10 甚至更窄。YOLO 系列的 anchor 机制对这种极端长宽比的目标不够友好虽然 YOLOv8 是 anchor-free但回归目标的宽高比仍然会影响损失计算稳定性。解决训练时使用更大的输入尺寸让细长目标在特征图上占更多像素同时将标注框做 1.05~1.1 倍的轻微外扩让模型有更充足的空间回归。外扩操作可以用脚本统一对 bbox 做 paddingx, y, w, h ann[bbox] pad 0.05 x x - w * pad y y - h * pad w w * (1 2 * pad) h h * (1 2 * pad)参数说明pad 取 0.05表示每个方向向外扩原宽高的 5%合计宽高扩大 10%。对于裂纹这种目标5% 的外扩不会引入过多背景噪声但对模型回归的帮助非常明显。6. 验证与进阶用自己的数据微调时哪些工作值得做拿到这套数据集最简单直接的路子是直接训练一个 YOLOv8 模型然后对单张图片做推理。但如果你的场景和风电叶片有些出入比如用的是无人机拍摄的图或叶片表面材质不同那建议把它当作预训练基础再注入你自己的少量标注数据做微调。微调前先做一件重要的事用训练好的模型跑你自己的未标注图片把高置信度的检测结果导出为 COCO 格式的伪标注人工检查后再加入训练集。这个流程叫半自动标注能极大减少人工标注时间。比如对于污垢和漏油这种外观相对固定的类别模型自动标注的准确率可以到 90% 以上你只需要修正少数误检。具体做法是写个推理脚本把检测结果保存为 COCO JSONfrom ultralytics import YOLO model YOLO(best.pt) results model.predict(unlabeled/, imgsz1280, conf0.5, save_jsonTrue)save_json 会让每个结果生成一个同名 JSON 文件里面是 detected 的 bbox 和类别。把这些文件合并成 COCO 格式需要写几行代码但值得做因为合并后的文件可以直接用 labelimg 或 labelme 打开微调不用在多个格式之间来回倒。验证方面除了看 mAP还要关注误检率。叶片缺陷检测的一个现实问题是现场作业人员对漏检的容忍度很低但误检太多会影响巡检效率。如果你的模型把每一道阴影或污渍都标成裂纹那实际使用价值很低。这时候可以调高 conf 阈值比如从 0.25 提到 0.45同时调整 NMS 的 iou 阈值从默认的 0.7 调整到 0.5减少重叠框的保留。最后说一个我自己的习惯每次训练前无论数据多小我都会检查一遍验证集的标注分布是否和训练集一致。那次在风电叶片项目上因为数据划分没有按叶片分组验证集里混入了同一叶片连续帧的相似图导致 mAP 虚高模型交付到现场后才发现对真实场景的泛化远不如预期。从那以后我每次都强制走一遍 GroupShuffleSplit并在训练脚本里打印每类实例数的训练/验证比例确保比例偏差不超过 20%。这个检查只需要一分钟但能省掉好几天的无效优化希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

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

03
WHY YAOTU

想打造同款高转化官网?

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

场景化定制

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

营销型架构

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

全周期服务

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

免费获取你的建站方案

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