简介面向风力发电机组叶片巡检与缺陷识别场景数据集包含5113张真实叶片图像并以COCO JSON格式完成标注覆盖排水孔受损、雷击、污垢、漏油、PU胶带、表面裂纹、侵蚀等多类缺陷。资源包共2000个文件主体为1997张jpg图片可直接用于训练目标检测或实例分割模型另含3个json文件作为标注信息可匹配YOLO、MMDetection等主流框架的数据接口。压缩包整体约174.49MB结构清晰便于分类整理与快速加载。目前已有948人学习下载适合风机运维、缺陷检测算法开发的研究者、学生与工程人员。借助该数据集用户无需从零采集与标注即可构建叶片缺陷识别基线模型并可针对排水孔受损、雷击等典型失效形式进行专项调优。1. 风力叶片缺陷检测数据集最容易被低估的一点是它把“看图”和“可训练”之间的距离缩短了无人机巡检一天能带回上万帧叶片影像但真正卡住落地进度的往往是标注雷击点长什么样、裂纹和污垢的边界怎么划每个标注员理解都不同。这份 5113 张图、COCO JSON 格式标注的风力叶片缺陷检测数据集把排水孔受损、雷击、污垢、漏油、PU 胶带、表面裂纹、侵蚀 7 类缺陷统一成了一套可解析的标注规范可以直接喂给 YOLO 做基线训练也可以拿来对齐团队的标注口径。想做风力叶片巡检的算法工程师、工业缺陷检测的选型团队以及想搞懂 COCO JSON 怎么落地的人都会用到它。我一般会把它当成冷启动数据先跑通检测链路再逐步用现场图片扩充。下面只围绕读格式、转格式、训练、评估这条主线展开所有命令和脚本都给了具体参数拿到手改路径就能用。2. 拆开 COCO JSON 标注结构7 类缺陷的字段约定与统计脚本拿到数据集我建议先别急着转格式或训练。第一步是把 JSON 拆开看一遍确认 categories 的 id 和 name 对不对、annotations 里的 image_id 能不能对上、bbox 有没有负数。COCO JSON 虽然叫通用格式但不同标注工具导出时字段略有差异直接跳去训练很容易在中间某一步报错排查起来反而更慢。2.1 images、annotations、categories 三张“表”怎么对应COCO JSON 顶层是一个字典包含 info、licenses、images、annotations、categories 等字段。检测任务里真正要关心的是后三个。images 数组是图片清单每项记录 id、file_name、width、heightannotations 数组是标注实例通过 image_id 指向某张图片并记录 category_id、bbox、segmentation、areacategories 数组则是 id 到类别名的映射。三者关系可以看成三张关联表annotations 同时关联 images 和 categories。这种设计与 VOC XML 那种“图片和标注绑在同一个目录”的做法不一样XML 要遍历所有文件才能拿到统计信息COCO JSON 则把所有标注集中在一个文件里用 id 关联。好处是一次加载全部标注类别统计、样本筛选、格式转换都在内存里完成代价是解析代码稍绕image_id 或 category_id 写错一个整个训练集就会错位。提示常见误用是把 COCO 的 bbox 当成 [x1, y1, x2, y2]实际是 [x, y, width, height]。写可视化脚本和格式转换前先确认这一点。2.2 标题里的 7 类缺陷如何映射到 categories标题里列的 7 类缺陷在 COCO JSON 里会以 categories 数组的形式出现。工程上建议把 name 字段用英文小写标识因为 YOLO 的 data.yaml、训练日志以及 CVAT 导入对非 ASCII 字段的支持层次不齐。下面这张表是我维护类别映射时的习惯写法id 从 1 开始0 预留给背景。category_id对外标识中文名称常见呈现1drain_hole_damage排水孔受损叶片根部排水孔周围开裂或变形2lightning_strike雷击黑色烧蚀斑块边缘不规则3dirt污垢大范围灰黑色附着物边界模糊4oil_leak漏油深色油渍沿缝隙或孔洞渗出5pu_tapePU胶带规则条状胶带边缘清晰6surface_crack表面裂纹细长线性纹理有时带分支7erosion侵蚀表面材料剥落呈坑洼状这张表的顺序不一定和你拿到的 JSON 一致。拿到文件后第一件事是打印 categories 的原始内容而不是用记忆里的 ID 去写脚本。雷击可能是类别 2也可能是类别 1排序取决于标注工具的导出逻辑只有 categories 数组与后续转换脚本完全一致训练出来的模型才对得上号。2.3 用 Python 统计 5113 张图的类别分布拿到 JSON 后的第一个动作我会跑一遍统计脚本确认图片数、实例数和各类别数量是否符合预期。这能提前暴露类别映射写反、漏标等低级错误。import json from collections import Counter with open(annotations/instances_wind_blade.json, r, encodingutf-8) as f: coco json.load(f) cat_id2name {cat[id]: cat[name] for cat in coco[categories]} ann_per_cat Counter() image_has_cat {} for ann in coco[annotations]: cat_name cat_id2name.get(ann[category_id], unknown) ann_per_cat[cat_name] 1 image_has_cat.setdefault(ann[image_id], set()).add(cat_name) print(图片数量:, len(coco[images])) print(标注实例数:, len(coco[annotations])) print(类别实例分布:) for name, cnt in ann_per_cat.most_common(): print(f{name}: {cnt})逻辑说明先建立 category_id 到类别名的映射然后遍历所有 annotation按类别累加实例数同时把每张图涉及到的类别汇总到 image_has_cat。第三步的 image_has_cat 可以看出一张图同时出现多少类缺陷这对判断标注质量很重要。参数说明coco_path 换成实际文件名如果 JSON 里 categories 的 id 不是从 1 开始编号要跟着调整。运行后应看到len(coco[images])等于 5113如果少了多半是下载时丢图导致标注和图片不同步。实例数远大于图片数是正常的说明不少图里同时标了多个缺陷框。3. 从 COCO JSON 到 YOLO 训练转换脚本与批次划分COCO JSON 更适合存档和评估但真要跑 yolov8 训练自己的数据集多数工程师会先把它转成 YOLO txt。这一步不复杂却集中了最多低级错误类别偏移一位、坐标没有归一化、txt 和图片不同名每一条都会让训练结果莫名变差。3.1 为什么很多缺陷检测流程都要先转成 YOLO txtYOLO 的训练链路要求每张图片对应一个同名 .txt 文件每一行是class cx cy w h坐标全部是相对值。COCO 的 bbox 是像素坐标[x, y, width, height]需要先转换成中心点坐标再归一化。这个转换套路和 kitti 标注转 yolo 是同一种操作逻辑差别只在于读取格式KITTI 的 txt 每行是type truncated occluded alpha bboxCOCO 是 JSON 对象但最终得到的 YOLO 行格式一样。踩坑最多的地方有两个。一是类别 idCOCO 里 category_id 通常从 1 开始YOLO 的 class 编号必须从 0 开始连续排列转换脚本漏了减一会导致所有类别整体错位。二是中心点换算cx x bw/2而不是x bw公式写错时损失函数照样能收敛但预测框整体偏向一侧。3.2 coco2yolo.py最小可用转换脚本import json from pathlib import Path def coco_to_yolo(coco_path: str, out_dir: str) - None: with open(coco_path, r, encodingutf-8) as f: coco json.load(f) out Path(out_dir) out.mkdir(parentsTrue, exist_okTrue) # COCO 类别 id 不连续时重新映射为 0 到 N-1 cat_map {cat[id]: i for i, cat in enumerate(coco[categories])} img_map {img[id]: img for img in coco[images]} # 先为每张图创建空的 txt 文件 for img in coco[images]: txt_path out / (Path(img[file_name]).stem .txt) txt_path.touch() for ann in coco[annotations]: img img_map[ann[image_id]] w, h img[width], img[height] x, y, bw, bh ann[bbox] # 像素 bbox 转归一化的中心点坐标和宽高 cx min(max((x bw / 2) / w, 0.0), 1.0) cy min(max((y bh / 2) / h, 0.0), 1.0) nw min(max(bw / w, 0.0), 1.0) nh min(max(bh / h, 0.0), 1.0) line f{cat_map[ann[category_id]]} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f} with open(out / (Path(img[file_name]).stem .txt), a) as f: f.write(line \n) if __name__ __main__: coco_to_yolo(annotations/instances_wind_blade.json, labels)逻辑说明脚本先建立两个映射字典cat_map 把非连续的 COCO category_id 映射成 0 到 N-1img_map 负责从 image_id 快速取 width 和 height。写入 txt 时用追加模式因为同一张图可能有多个标注框。clamp 操作把归一化结果限制在 0 到 1 之间防止缺陷贴边时坐标越界。参数说明如果只检测“表面裂纹”和“雷击”两个类别可以在遍历处加一行if ann[category_id] not in {2, 6}: continueout_dir 建议放在图片目录的外层方便后续做数据切分。转换前先备份原 COCO JSON不要在转换产物上反复修改。注意这个脚本不会检查 bbox 自身是否越界。叶片图中缺陷有时贴边归一化后接近 0 或 1 是正常的但如果出现负数或大于 1就需要回原始 JSON 复核。3.3 训练、验证集怎么切分更合理风力叶片巡检数据通常有强序列相关性同一叶片连续拍摄的几帧如果被随机分到训练集和验证集相当于给验证集透了题。我一般按拍摄任务或文件前缀分组再对组做 8:1:1 切分。最省事的做法是在 images 的每个元素里加一个 task_id 字段然后按这个字段分组。切分后的目录结构建议是 images/train、images/val、labels/train、labels/val 四个文件夹。移动图片时必须把同名 txt 一起移动否则训练时找不到标注的图会被静默跳过。建议写一个校验脚本检查两边 jpg 与 txt 的集合是否一致能省掉一晚上调参时间。3.4 第一轮训练命令与关键参数yolo detect train \ datawind_blade.yaml \ modelyolov8m.pt \ epochs100 \ imgsz1280 \ batch16参数推荐值说明imgsz1280 或 960叶片缺陷是小目标分辨率太低会丢失细节epochs100先跑通流程后续按验证集曲线做早停batch16取决于显存8GB 以下建议降到 8optimizerAdamW 或 SGD5000 张图量级两者差异不大ampTrue混合精度能加速训练发现 loss 异常时先关掉data.yaml 里的 path、train、val、names 四个字段要和上面的目录结构对应。names 的顺序必须与第 3.2 节脚本里的 cat_map 一致而不是与 COCO 原始 category id 一致。第一次训练建议不叠加任何额外 trick先拿一个能复现的基线。4. 缺陷类别不平衡排查与数据增强策略第一轮基线跑完后回头打开第 2 章的统计输出大概率会发现类别分布并不友好。污垢和侵蚀往往占大头漏油、PU 胶带这类偶发缺陷数量有限。如果不做任何处理整体 mAP 会被大样本类别拉高小样本类别几乎不参与收敛。下一阶段的工作对象不是网络结构而是数据集本身。4.1 先看类别分布再决定增强方案运行第 2 章的统计脚本后你大概率会看到某几类实例很多、某几类偏少。如果最少的类别只有最多的十分之一直接训练时最小类的 mAP 会明显偏低。我的经验阈值是低于总量 5% 的类别先按少样本类处理。这里要区分图片数少和实例数少。有的图里同时出现十几处表面裂纹实例数不少但场景单一有的图只有一处雷击重复采集多次才构成几十个实例。前者侧重数据增强后者要侧重收集不同背景的图片。用第 2 章脚本同时打印 image_has_cat就是在做这个区分。4.2 拷贝粘贴缺陷区域基于 segmentation 的增强普通几何增强对类别不平衡帮助有限因为翻转变换只是改变框的位置不增加新实例。工业缺陷检测更常用的是拷贝粘贴增强把某个类的 segmentation 区域裁剪下来旋转缩放到合适大小贴到另一张图的随机位置同时写回一个新增的 bbox 标注。import cv2 import numpy as np def copy_paste_from_coco(src_img, src_ann, dst_img, dst_ann_list): # 用 segmentation 多边形生成掩码 poly np.array(src_ann[segmentation][0], dtypenp.int32).reshape(-1, 2) mask np.zeros(src_img.shape[:2], dtypenp.uint8) cv2.fillPoly(mask, [poly], 255) x, y, w, h [int(v) for v in src_ann[bbox]] if w 0 or h 0: return patch cv2.bitwise_and(src_img, src_img, maskmask) patch patch[y:yh, x:xw] # 随机缩放模拟无人机拍摄距离波动 scale 0.8 0.4 * np.random.rand() patch cv2.resize(patch, None, fxscale, fyscale) dst_h, dst_w dst_img.shape[:2] ph, pw patch.shape[:2] if ph dst_h or pw dst_w: return new_x np.random.randint(0, dst_w - pw) new_y np.random.randint(0, dst_h - ph) dst_img[new_y:new_yph, new_x:new_xpw] patch # 记录新增标注后续再转成 YOLO 格式 dst_ann_list.append([src_ann[category_id], new_x, new_y, pw, ph])逻辑说明先根据 segmentation 生成掩码用 bitwise_and 把缺陷区域从原图抠出来再随机缩放后贴到目标图同时记录新 bbox。注意这是简化版本直接贴图会带上黑色边缘实际项目中要把掩码作为 alpha 通道做融合效果更自然。参数说明scale 范围 0.8 到 1.2 是模拟无人机巡检的高度差雷击这类小目标上限不建议超过 1.5否则缺陷形态会失真。目标图选择上不要把污垢贴到雷击图上尽量选同背景的图片否则模型学到的可能是伪影而非缺陷特征。4.3 用 CVAT 复核错标和类间边界数据增强解决数量解决不了标签质量。实际项目里最影响缺陷检测上限的是“污垢 vs 侵蚀”“表面裂纹 vs 雷击”这类类间边界。CVAT 这类数据标注工具可以直接导入 COCO JSON创建任务、上传图片、在导入配置里选 COCO JSON 1.0标签列表会自动对应 categories复核时逐张看框、改标签再导出 COCO JSON 覆盖原文件即可。复核时建议两个人背靠背过同一批图遇到分歧单独建一个争议任务最后统一口径。这个流程比多标几千张图更值钱因为模型学的是多数标注员的共识而不是某个人的主观判断。5. 用混淆矩阵逐类验收 7 类缺陷的检测结果第一轮训练跑完后不要只看整体 mAP。风力叶片缺陷检测里平均指标很容易被污垢这类大样本类别拉高漏油、PU 胶带这些小样本类别可能表现很差。我会单独对验证集跑一次评估再逐类看数字。5.1 一条命令拿到混淆矩阵yolo detect val modelruns/detect/train/weights/best.pt datawind_blade.yamlval 命令会在训练输出目录里生成 confusion_matrix.png 和 results.csv。混淆矩阵横坐标是预测类别纵坐标是真实类别对角线越亮越好results.csv 里有每一类的 precision、recall 和 mAP可以直接按列排序。5.2 找误检对而不是只看分数混淆矩阵最有价值的地方是告诉你模型把哪两类缺陷搞混。风力叶片场景里最常看到的三组误检是污垢被判成侵蚀因为两者都是大范围暗色区域细长裂纹被判成雷击的边框PU 胶带的边缘部分被判成表面裂纹。如果某个类别 recall 低于 0.6先别急着调阈值回第 2 章统计里看这个类别到底有多少实例。import pandas as pd cm pd.read_csv(runs/detect/train/confusion_matrix.csv, index_col0) for true_label in cm.index: if true_label background: continue row cm.loc[true_label].drop(labels[true_label]) top row.sort_values(ascendingFalse).head(3) top top[top 0] if len(top): print(f真实类别 {true_label} 被误判为: {dict(top)})逻辑说明读入混淆矩阵后跳过 background 行逐行把当前真实类别误判最多的预测项打印出来去掉对角线后剩下的就是主要误判方向。输出结果决定下一步是补样本还是细化标注规则。5.3 把争议样本回灌给标注流程这是最值得固定下来的迭代动作。从验证集中把被误判的图片抽出来连同模型预测框转成 COCO JSON重新开一个 CVAT 复核任务让标注员回答“是 a 类、b 类、还是无效预测”。复核结果并入训练集后重新训练一轮通常比盲目增加 epoch 提升更快。我一般会在第一次迭代后把验证集固定下来后续只改训练集保证每次对比的验收口径不变。本文还有配套的精品资源点击获取