
简介面向风力发电运维与计算机视觉研究场景这套风力叶片缺陷检测数据集提供5113张真实采集图像采用COCO JSON格式标注可识别排水孔受损、雷击、污垢、漏油、PU胶带、表面裂纹、侵蚀等多种典型缺陷。数据覆盖多机组不同部位表现适合用于目标检测、实例分割模型训练也可支撑无人机/机器人巡检场景下的算法验证与阈值调优。压缩包共2000个文件其中1997个为jpg原图3个为json标注文件资源包整体约174.49MB图像与标注一一对应目录结构清晰可方便地接入MMDetection、Detectron2或YOLO等主流框架进行训练与评估。对初学者而言这是一套可直接上手的带标签数据集省去自行采集和标注的时间成本对算法工程师而言多类别缺陷标注支持细粒度分类与定位研究。目前已有952人学习下载尤其适合风电运维智能化、工业视觉检测方向的学生和从业者。1. 风力叶片缺陷检测数据集5113张标注图能直接拿来训练吗风电场的叶片缺陷巡检这几年基本都从人肉登高看换成了无人机拍照回来筛。照片一多肉眼识别就成了瓶颈雷击痕和裂纹混在一起污垢和PU胶带破损有时看着像同一种东西。手头这个风力叶片缺陷检测数据集给了5113张现场图统一用COCO JSON格式标注覆盖排水孔受损、雷击、污垢、漏油、PU胶带、表面裂纹、侵蚀这几类高频缺陷。对算法工程师来说最大的价值是省掉了最费时的标注环节让检测任务从“找数据标数据”直接跳到“调模型”。这篇我按自己做目标检测的流程把数据解析、格式转换、训练调参到避坑一次讲完。2. 数据集的打开方式先吃透COCO JSON格式再谈训练拿到一份标注数据集我习惯不急着写训练脚本先把文件结构看清楚。风电叶片缺陷数据集的常见组织方式是把图片放在按拍摄时间或叶片编号命名的目录里标注文件集中在annotations目录下COCO JSON格式的标注一般拆成 train、val、test 三个文件也有只给一个总标注文件、由使用者自行划分的情况。先做数据摸底后面训练遇到指标异常时能提前排除数据源问题。2.1 读COCO JSON时重点看哪几个字段COCO标注是嵌套的JSON最外层通常是三个数组images、annotations、categories。images记录图片路径和宽高annotations记录每个缺陷框的坐标、类别、面积和所属图片idcategories是类别字典。落在风电检测场景里还需要额外确认一点annotations里给的是单纯的bbox还是带segmentation因为叶片缺陷很多是细长形有分割标注的话后期转实例分割会省很多事。import json ann_path annotations/instances_train.json with open(ann_path, r, encodingutf-8) as f: data json.load(f) # 查看最外层结构 print(list(data.keys())) # 常见输出: [images, annotations, categories] # 查看有哪些缺陷类别 for c in data[categories]: print(c[id], c[name])这段代码先确认数据集确实按COCO JSON格式组织同时把类别id和名称一次性打出来。后续的转换脚本要以这份id映射为准如果训练出来的类别名和业务口径对不上先回到这里核对。注意categories里的 id 不一定连续YOLO 这类框架要求类别从 0 开始连续编号后面转换时要另建一张映射表。再统计一下类别分布和单图标注密度from collections import Counter ann_count Counter() per_image_count Counter() for ann in data[annotations]: ann_count[ann[category_id]] 1 per_image_count[ann[image_id]] 1 # 打印每个类别的缺陷数量 for cat in data[categories]: print(cat[name], ann_count.get(cat[id], 0)) # 统计一张图上平均有几个缺陷框 total_imgs len(data[images]) total_anns len(data[annotations]) print(平均每张图标注数:, total_anns / total_imgs) # 空图数量指没有标注框的图片 empty_imgs total_imgs - len(per_image_count) print(空图数量:, empty_imgs)ann_count能直接暴露类别不均衡比如雷击样本很多、排水孔受损只有几百条后续训练就要考虑样本均衡。per_image_count帮我判断有没有大量空图空图比例高时评估阶段需要调整置信度阈值否则误检会被一起算进去。2.2 bbox雪上加霜的“边界政治”刚接触COCO JSON格式的人容易把bbox当成两个坐标点去解析。实际COCO的bbox是[x, y, width, height]左上角坐标加宽高单位是像素。area对矩形框来说就是width * height但有些标注工具导出的标注里area填的是0或不准确转格式时自己重算一份不要直接依赖area字段。上面说的是单框。叶片缺陷还有另一个麻烦同一处损伤可能被标注成两个重叠框一个按长条形状标、一个按整体区域标。如果annotations里出现大量IoU超过0.5、类别相同的框训练时 loss 会被重复梯度带偏。我会对 bbox 做个粗筛重叠过高的同类框直接去掉一个。读取单个样本看bbox和segmentation的实际内容ann data[annotations][0] print(category_id:, ann[category_id]) print(bbox:, ann[bbox]) print(area:, ann[area]) print(segmentation keys:, list(ann.keys()))打印结果里如果segmentation是一个多边形点列表说明这份数据将来可以支持分割模型如果是空列表则只有框标注。当前这个数据集能用的是框级别的缺陷检测先按目标检测来做后续要分割时再补标注。2.3 划分训练集别一股脑随机切只有一份总JSON时很多人的做法是随机按8:1:1划分。这个做法在叶片检测里容易翻车同一只叶片的多张照片往往前后帧高度相似如果随机切训练集和验证集里会出现同一叶片、同一缺陷的重复画面评估指标虚高真上线时换一批叶片就掉点。随手划分的代码看起来没错实际上是把“同一场景”泄露到了两个集合里。常用做法按叶片编号分组比如文件名里出现blade_03这类前缀就以叶片为单位划分。没有编号时退一步按图片的拍摄时间戳聚类后再切分至少保证验证集不是同一批无人机航线拍回来的连拍帧。划分之后再做一次类别分布对比train 和 val 里排水孔受损的占比不能差太多。3. 把COCO JSON喂进检测模型格式转换到首轮训练3.1 用YOLO还是MMDetection先想好再转YOLO系列因为部署方便很多人默认选它。但YOLO的原生训练格式不是COCO JSON它的标签文件是每个txt存一行“类别id cx cy w h”其中cx、cy、w、h是相对图宽高的归一化值。MMDetection则原生支持COCO格式如果是跑Mask R-CNN这类实例分割模型直接改配置就能训不用转格式。我一般这样选想快速验证召回率转YOLO格式用YOLOv8跑一个baseline后面要做分割或多尺度精细检测再切回MMDetection。风力叶片缺陷前景往往细长比如裂纹和雷击路径在YOLO的水平框里跟背景混在一起所以建议先跑目标检测拿到基线再判断是否需要像素级分割。3.2 把COCO JSON格式转成YOLO标签的脚本核心步骤是按image_id反查图片、把bbox的x,y,w,h转成相对坐标、再除以图宽高归一化。需要提前建图片id到文件名的映射因为annotations里不直接存图片路径只有image_id。import json import os def coco_to_yolo(coco_json, out_dir): with open(coco_json, r, encodingutf-8) as f: data json.load(f) # 建立image_id到文件名的映射 img_id_to_file {img[id]: img[file_name] for img in data[images]} img_id_to_size {img[id]: (img[width], img[height]) for img in data[images]} # 建立category_id到连续id的映射YOLO要求0开始连续 cat_id_to_idx {cat[id]: idx for idx, cat in enumerate(data[categories])} # 按图片聚合标注避免重复打开文件 annotations_by_img {} for ann in data[annotations]: annotations_by_img.setdefault(ann[image_id], []).append(ann) for img_id, anns in annotations_by_img.items(): file_name img_id_to_file[img_id] width, height img_id_to_size[img_id] label_name os.path.splitext(file_name)[0] .txt with open(os.path.join(out_dir, label_name), w) as f: for ann in anns: cat_idx cat_id_to_idx[ann[category_id]] x, y, w, h ann[bbox] # 边界保护防止标注框越界导致训练报错 x max(0, x) y max(0, y) w min(w, width - x) h min(h, height - y) if w 0 or h 0: continue cx (x w / 2) / width cy (y h / 2) / height f.write(f{cat_idx} {cx:.6f} {cy:.6f} {w / width:.6f} {h / height:.6f}\n)这段代码里有两个关键点一是类别id必须重新映射COCO的category_id可能从1开始或带着断号YOLO不认二是bbox要重新clip无人机照片拼接或手工标注时经常出现细微越界边界保护过后再跳过无效框可以让训练时不出现负坐标报错。转完后把图片文件放好目录结构建议这样wind_blade_dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yaml对应的data.yaml按类别名填。这里要确认YOLO只识别数字id和names列表的对应顺序names列表必须和转换时的cat_id_to_idx顺序一致否则模型推出来类别对不上。3.3 首次训练的参数推荐跑baseline时不要一开始就堆增强。我在YOLOv8里这样配置# data.yaml path: ./wind_blade_dataset train: images/train val: images/val nc: 7 names: [drain_hole_damage, lightning_strike, dirt, oil_leak, pu_tape, surface_crack, erosion]yolo detect train datadata.yaml modelyolov8m.pt epochs100 imgsz1280 batch8imgsz是这类细长缺陷的关键参数。叶片原图通常很高清细裂纹只有几十像素宽如果设成640小目标细节会被压没。我推荐1280起步显存不够降到960。batch受显存限制一张卡从4开始配合optimizerAdamW和余弦退火学习率多卡时8到16都行但要注意第一轮先跑20个epoch看loss是否下降别直接100个epoch跑到底。另外这个数据集的标注框平均面积如果偏小YOLO 会自动做马赛克增强但马赛克会把叶片拼接成不自然的场景训练后期容易出现“假背景”误检。我会在cacheTrue的前提下把mosaic在最后20个epoch关掉改用close_mosaic20参数让模型在真实分布上收敛这一招在缺陷检测里比通用训练稳定不少。4. 训练这批数据我踩过的4个坑风电缺陷数据集和公共数据集不一样缺陷形态高度相似、类别边界模糊、样本不均衡扎堆出现。下面这几条都是我实际跑过之后比较典型的翻车点现象、原因、解决一次讲清楚。4.1 雷击和表面裂纹互相串我在验证集上看到模型把雷击区域标成表面裂纹而且雷击召回率很低。原因在于雷击在叶片上留下的是细长树枝状轨迹表面裂纹同样细长两者都以线性纹理为主在一张高清图上人工都容易看混模型更难分开。解决方法是先确认标注边界如果两类缺陷经常在同位置同时出现先按业务需求判断。维修动作只提示“此处有损伤”就把雷击和裂纹合并成一个大类训练如果必须细分把裁剪图单独抽出来做一个二分类小模型比直接在一个检测模型里硬分更稳。4.2 排水孔受损样本太少训练完几乎不预测排水孔受损通常只在固定位置出现而且远拍时目标小样本量可能是其他类别的十分之一。我一开始没做处理训练后该类几乎为零。解决分两个层面训练层面用cls损失权重给这个小类加权让模型在分类头里偏向它数据层面把包含排水孔的图复制几份做随机旋转、亮度扰动或者用小目标复制粘贴增强把排水孔框贴到其他叶片图的对应结构位置。贴的时候注意不要贴在无规则的背景上否则模型学到的上下文是错的。4.3 PU胶带和污垢混成一个类PU胶带本身颜色和部分污渍相近远看都是深色长条不放大很难判断。我回看标注后发现问题在标注规范上数据集里 PU 胶带这一类把“正常完好的胶带”也标了进来标注人员对“缺陷”的理解不一致类别内部矛盾大。解决方法是清洗按标注框裁剪所有该类区域人眼过一遍把不满足条件的框删掉或改成正常背景。清洗之后这个类的精确率一般能提升8到10个点代价是花一两个小时看图。4.4 大图推理慢细目标漏检叶片原图常见是 4000×3000 级别直接喂进模型不现实。中间做法是切块但切块时如果不带重叠裂纹被切成两段模型只识别出其中一段最终框会不稳定。解决切块时让相邻块重叠20%到30%推理后按坐标还原到原图再做NMS。这个对线状缺陷几乎是必须的代价是推理时间变长但召回率提升明显。具体实现时重叠比例、切块大小和模型输入尺寸要联动调比如模型输入1280切块设成1536重叠256这样小目标至少在一个块里是完整的。5. 不急着上线先评估COCO训练效果再说5.1 评估指标看哪几个数不要只看mAP50。风电叶片这样的细长小目标数据集mAP50-95更能反映定位精度。训练完我会看三行数mAP50、mAP50-95、per-class recall。mAP50高而mAP50-95低说明框位置大方向对但贴不紧两者都低说明特征没学到。另外要单独看每个类别的召回率因为这个业务里漏检的代价远大于误检漏一次排水孔受损可能让风机带病运行到下一次定检。5.2 可视化验证比指标更可靠把预测结果画回原图叠加 ground truth 和预测框重点看三类图多缺陷密集的图、细裂纹特写的图、排水孔那种远拍小目标。pycocotools 自带可视化方法直接读COCO JSON格式就能画import cv2 from pycocotools.coco import COCO ann_file annotations/instances_val.json coco COCO(ann_file) image_ids coco.getImgIds()[:20] for img_id in image_ids: img_info coco.loadImgs(img_id)[0] img cv2.imread(img_info[file_name]) anns coco.loadAnns(coco.getAnnIds(imgIdsimg_id)) coco.showAnns(anns)这段代码用 pycocotools 把 COCO JSON 格式的标注渲染出来省去自己画框的麻烦。如果没装 pycocotools执行pip install pycocotools即可。注意coco.showAnns只是在坐标系上画出标注要真正叠加到图上需要用cv2把img显示出来或直接把标注框坐标画到图像副本上。随机抽前20张如果看到的都是空图改成按类别筛选抽样。5.3 置信度阈值怎么设风电巡检的漏报一次可能让缺陷带病运行到下一个检修周期误报一次顶多多派一趟人工确认。所以上线时的置信度阈值应保守。我一般从0.25往下探到0.15观察误报数量变化。同时分析误报区域集中在叶片边缘还是高光处如果是高光加一个光照mask在预处理时压掉高光区域如果是叶片结构边缘考虑在NMS后加一个边缘距离过滤把离叶片边缘过远的孤立框去掉。5.4 看混淆矩阵定位“打不开”的类别除了指标我还会导出一张混淆矩阵看具体是哪些类别互相混。雷击被误判成表面裂纹、PU胶带被误判成污垢这是风电数据集的典型组合。混淆矩阵里如果这两个类互相串说明它们在大尺度特征上重叠度高光调阈值没用得从类别合并、多尺度裁剪或数据清洗入手回到第4章去看具体原因。6. 进阶让模型在你自己叶片场景里更准拿到这份数据集跑通第一版后真正落地时你还需要回到自己的风机叶片样本上做适配。第一件事是重审类别合并。业务按维修动作分类时雷击和裂纹外形相似但维修方式不同可以用两级结构第一级检测“有无损伤”第二级对裁剪图做细分类把雷击和裂纹分开。两级结构在风电缺陷检测里很常见效果往往好过单模型直接输出所有类别。数据集原生是COCO JSON格式转两级结构时只需要保留第一级的大类标注第二级用crop出来的图重新训练一个分类器即可。另一个值得做的方向是利用叶片分割结果。很多检测模型会把背景里的泥土路面误检成污垢若先用一个叶片分割模型把叶片区域抠出来再把缺陷检测限制在这块区域里误检率会显著下降。叶片分割标注可以自己做小批量甚至用这份数据集的矩形框生成弱监督mask够用即可。数据增强上风电不同季节光照差异很大建议训练时加随机亮度、对比度扰动以及水平翻转。叶片左右镜像后缺陷形态不变水平翻转是安全增强垂直翻转不太合适因为叶片朝向固定会引入不真实的形变。小目标增强对排水孔这类缺陷尤其有用把原图裁成多个512到640大小的块每个块独立训练后再集成比直接在大图上检测稳定得多。我最后的迁移学习习惯是先用这份5113张COCO JSON格式的数据、加一个预训练权重训练出第一版等收集到自己风机叶片的新样本后用新样本继续训练同时保留一部分旧数据防止灾难性遗忘。想省事时用第一版模型给新照片做伪标注把高置信度的预测框当候选标注人工只修正错漏能少标不少框。这套流程我用了很多次关键点在于旧数据保留比例不要低于新样本的1/2且训练时新旧样本要混着打乱。最后讲一个教训不要在第一轮就上复杂模型和重型增强。先在1280分辨率下用中等模型跑一个干净基线记录每类缺陷的召回率再用标注分布去查漏在哪里。模型的瓶颈通常不在网络结构而在目标太小、类别重叠和训练样本不均衡。把这三件事搞清楚再决定要不要分割或加大输入方向就不会偏。希望这篇笔记对你有用。本文还有配套的精品资源点击获取