光伏板缺陷检测数据集与YOLO目标检测实战:从标注到切片推理
简介本资源为面向深度学习目标检测的光伏板缺陷检测数据集适用于YOLO系列、Faster R-CNN、SSD等模型的训练与验证主要服务于从事工业视觉检测、新能源运维及算法实践的研究者与开发者。数据集包含Crack、Grid、Spot三类缺陷标注共240张图片提供YOLO与VOC两种格式并附有指定类别信息的yaml文件图片与txt标签已按训练集、验证集和测试集划分可直接投入YOLO算法训练。压缩包为zip格式内含2000个文件其中1999个txt标签文件与1个yaml配置文件整体大小约629MB标签文件与图片一一对应便于快速构建数据加载流程。目前已有1915人学习下载适合需要快速验证缺陷检测模型、对比不同检测框架性能或开展课程实验的读者能有效节省数据采集与标注成本直接聚焦模型调优与效果评估。1. 光伏板缺陷检测数据集与目标检测从航拍到落地的第一道坎光伏电站的巡检方式正在经历一次静默的替换。三年前大多数运维团队还在用人工拿着手持红外仪逐排扫一个 50MW 的电站要跑整整两天现在越来越多的人把无人机航拍图丢进目标检测模型让算法去框出热斑、隐裂、二极管故障和玻璃破损。这个转变的核心卡点不在模型结构而在数据集——光伏板缺陷检测数据集配合目标检测才是让整套流程跑通的第一块砖。这篇文章面向的是手里已经有一批航拍图、或者正准备采集数据、想用 YOLO 系列做缺陷检测的工程师。我会把数据集的构成、标注规范、格式转换、训练参数和踩坑记录按可复现的顺序讲清楚。不聊空洞的算法演进史只讲你打开标注工具之后每一步该做什么、参数为什么这么设、模型不收敛时先看哪里。光伏板缺陷检测数据集在公开领域并不算丰富多数时候你得自己攒所以标注质量和类别定义比模型选型更决定最终效果。2. 光伏板缺陷检测数据集类别定义、采集条件与标注规范2.1 缺陷类别怎么定从运维需求反推标签体系很多人拿到航拍图第一反应是「把所有异常都标出来」结果标了二十几个类训练完 mAP 惨不忍睹。光伏板缺陷检测数据集的类别设计要从运维能处理的粒度出发而不是从图像上能看到的粒度出发。常见做法是收敛到 5 到 7 类类别名英文标签视觉特征运维含义热斑hotspot红外图中局部高亮电池片局部短路或遮挡隐裂crack可见光下细线状暗纹电池片微裂功率衰减二极管故障diode_fault红外图中整串异常旁路二极管失效玻璃破损glass_break可见光下不规则碎裂物理损伤需更换污渍遮挡soiling可见光下片状暗区清洗可解决蜗牛纹snail_trail可见光下银灰色线纹封装材料老化类别定义有三个原则。第一类间视觉边界要清晰热斑和污渍在红外图里容易混那就只在红外图上标热斑污渍放到可见光数据集里。第二类别数量控制在 10 以内超过之后每类样本量很难均衡。第三留一个 other 类兜底把不确定的异常丢进去避免标注员硬归类导致标签噪声。提示如果电站同时有红外和可见光两种航拍图建议做成两个独立数据集分别训练不要试图用一个模型同时吃两种模态除非你明确要做多模态目标检测融合。2.2 采集条件高度、角度、光照与分辨率数据集的质量在采集阶段就决定了。光伏板缺陷检测对采集条件比通用目标检测敏感得多因为缺陷本身在图像里占的像素很少。我一般会控制这几个参数飞行高度相对地面 8 到 15 米。低于 8 米单张图覆盖组件太少效率低高于 15 米隐裂和蜗牛纹基本糊掉。拍摄角度尽量垂直向下偏角不超过 15 度。角度太大会让组件边框产生透视变形标注框和实际缺陷区域对不上。光照条件可见光采集选上午 10 点到下午 2 点之间的晴天阴影最少。红外采集选日出前或日落后避免太阳辐射干扰热斑判断。分辨率单张图不低于 4000×3000。如果无人机只能出 2000 万像素以下的图宁可降低飞行高度。重叠率航向重叠 70%旁向重叠 50%方便后续拼接和去重。采集完之后先做一轮粗筛。模糊的、过曝的、组件占比低于 30% 的图直接删掉。这一步偷懒后面标注和训练会加倍还回来。2.3 标注规范框怎么画、边界怎么定、一致性怎么保标注是光伏板缺陷检测数据集里最耗人力的环节。用 LabelImg 或 CVAT 都可以关键是规范要统一。框的边界定义热斑框到高亮区域的边缘隐裂框到暗纹的起止点玻璃破损框到碎裂区域的外接矩形。不要框到组件边框上也不要把相邻组件的缺陷框在一起。一致性保障靠三件事。第一写一份标注手册每个类配 5 张正例和 3 张反例。第二每 200 张图做一次交叉复核两个人标同一批图IoU 低于 0.7 的框拿出来讨论。第三用标注工具的快捷键和预设标签减少手输错误。# 标注目录结构建议 dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── classes.txtclasses.txt 里每行一个类名顺序和标注时生成的 class_id 一一对应。这个文件后面转 YOLO 格式时要用别弄丢。3. 从原始标注到 YOLO 格式转换脚本与四个边界坑3.1 为什么必须转成 YOLO 格式LabelImg 默认输出 Pascal VOC 的 XML每个文件里存的是绝对坐标 xmin、ymin、xmax、ymax。YOLO 系列要的是归一化后的中心点坐标和宽高每行格式是class_id cx cy w h数值都在 0 到 1 之间。不转行不行不行。YOLOv5 之后的版本虽然支持多种输入格式但 VOC 转 YOLO 这一步在数据加载阶段做会拖慢训练速度而且容易在增强时出坐标越界的问题。提前转好训练时直接用是最稳的做法。3.2 转换脚本VOC XML 到 YOLO TXTimport xml.etree.ElementTree as ET import os # 类别映射顺序必须和 classes.txt 一致 CLASS_MAP { hotspot: 0, crack: 1, diode_fault: 2, glass_break: 3, soiling: 4, snail_trail: 5, } def voc_to_yolo(xml_path, img_w, img_h, out_path): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): name obj.find(name).text.strip() if name not in CLASS_MAP: continue cls_id CLASS_MAP[name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 边界裁剪防止标注框超出图像范围 xmin max(0, min(xmin, img_w)) xmax max(0, min(xmax, img_w)) ymin max(0, min(ymin, img_h)) ymax max(0, min(ymax, img_h)) # 转中心点归一化坐标 cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h # 过滤掉宽高为 0 的无效框 if w 0 or h 0: continue lines.append(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) with open(out_path, w) as f: f.write(\n.join(lines))逻辑说明脚本先解析 XML拿到每个 object 的类名和绝对坐标。边界裁剪这一步很关键标注员手抖把框拖出图像边界是常事不裁的话归一化后会出现负数或大于 1 的值训练时直接报错。宽高为 0 的框也要过滤通常是误操作产生的。参数说明img_w 和 img_h 必须和实际图像尺寸一致不能写死。如果你的图像尺寸不统一建议先统一 resize 到 640×640 再标注或者转换时逐张读取图像尺寸。3.3 四个边界坑坑一图像尺寸和标注尺寸不一致。有些无人机出图是 4000×3000但导出时被压缩成 1920×1440XML 里存的还是原始坐标。转换前用 PIL 读一下实际尺寸对不上就按比例缩放坐标。坑二类别名大小写和空格。XML 里写的是 HotspotCLASS_MAP 里写的是 hotspot匹配不上直接跳过标注就丢了。转换完统计一下每类框的数量和标注时对不上就查这里。坑三中文类名。有些团队标注时用中文类名转 YOLO 时编码出问题。建议标注阶段就用英文classes.txt 也用英文省掉编码麻烦。坑四空标注文件。没有缺陷的图也会生成一个空 XML转换后是空 TXT。YOLO 训练时空文件是合法的负样本但如果你不想要负样本转换后检查一下文件大小0 字节的直接删。# 转换后快速校验统计每类框数量 cat labels/train/*.txt | awk {print $1} | sort | uniq -c这条命令输出每个 class_id 的框数量。如果某个类数量为 0说明转换时类名没匹配上回去查 CLASS_MAP。4. 训练参数怎么设YOLO 光伏缺陷检测的调参清单4.1 模型选型v5、v8 还是 v11光伏板缺陷检测的图分辨率高、目标小模型选型要看你的算力和数据量。模型适合场景输入尺寸备注YOLOv5s数据量 2000 张快速验证640轻量收敛快YOLOv8m数据量 2000-5000 张640 或 1024精度和速度平衡YOLOv11m数据量 5000 张1024小目标召回更好我一般先用 YOLOv5s 跑一轮 baseline确认数据管道没问题再换大模型调精度。直接上大模型数据有问题时排查成本太高。4.2 关键参数学习率、锚框和输入尺寸# data.yaml path: ./dataset train: images/train val: images/val test: images/test nc: 6 names: [hotspot, crack, diode_fault, glass_break, soiling, snail_trail]# 训练命令 python train.py \ --data data.yaml \ --weights yolov5s.pt \ --img 1024 \ --batch 8 \ --epochs 200 \ --lr0 0.01 \ --lrf 0.01 \ --patience 30 \ --device 0参数说明img 设 1024 是因为缺陷目标小640 下隐裂可能只剩几个像素。batch 根据显存调8GB 显存跑 1024 尺寸大概只能到 8。lr0 是初始学习率0.01 是 YOLO 的默认值数据量小的时候可以降到 0.001。patience 是早停轮数30 轮验证集不提升就停省时间。锚框方面YOLOv5 之后的版本默认用自适应锚框不需要手动改。但如果你的缺陷框普遍偏小可以在训练前用 k-means 重新聚类一遍锚框脚本在 utils/autoanchor.py 里。4.3 数据增强哪些该开、哪些该关光伏板缺陷检测的数据增强有特殊性。翻转和旋转可以开因为组件方向不固定。但颜色抖动要慎开热斑和污渍的区分依赖颜色信息抖动太猛会让模型学偏。Mosaic 增强可以开但 close_mosaic 设 10 到 20最后几轮关掉让模型在真实分布上收敛。# 增强参数追加 --flipud 0.5 --fliplr 0.5 --degrees 90 --mosaic 1.0 --close_mosaic 15degrees 设 90 是因为航拍图旋转后组件仍然是矩形不会产生不合理的场景。如果你做的是地面拍摄旋转角度要限制在 15 度以内。5. 避坑与排查光伏缺陷检测训练中最容易翻车的五件事5.1 现象mAP 从第一轮就不涨loss 在 0.7 附近震荡原因类别标签和 data.yaml 里的 names 顺序对不上。YOLO 按 class_id 索引 names如果 classes.txt 里 hotspot 是 0data.yaml 里 hotspot 排第二位模型学到的就是错位的类别。解决转换脚本里的 CLASS_MAP 和 data.yaml 的 names 列表逐项核对。写个脚本读 labels 里的 class_id 最大值确认不超过 nc-1。5.2 现象验证集 mAP 很高但测试集一塌糊涂原因训练集和验证集来自同一个电站的同一批航拍分布太接近。测试集换了电站或换了拍摄时间光照和背景变了模型泛化不了。解决划分数据集时按电站或按拍摄批次分不要随机分。如果只有一个电站的数据至少按上午/下午、晴天/多云分。光伏板缺陷检测数据集的泛化能力比通用数据集更依赖采集多样性。5.3 现象小目标漏检严重隐裂和蜗牛纹基本检不出来原因输入尺寸太小或者锚框尺寸不匹配。1024 输入下一个 4000 像素宽的图里隐裂可能只占 20 个像素缩到 1024 后只剩 5 个像素。解决把输入尺寸提到 1280 或 1536同时用切片推理。训练时把大图裁成 640×640 的小块每块里缺陷占比更大。推理时也切片再合并结果。5.4 现象训练到 50 轮左右 loss 突然变成 nan原因学习率太大或者数据里有脏标注。脏标注包括坐标超出 0-1 范围、宽高为负、class_id 超出 nc。解决训练前跑一遍数据校验脚本检查所有 label 文件。学习率降到 0.001 重跑如果还 nan就是数据问题。# 数据校验检查坐标范围和 class_id import os for f in os.listdir(labels/train): with open(os.path.join(labels/train, f)) as fp: for line in fp: parts line.strip().split() cls_id int(parts[0]) coords [float(x) for x in parts[1:]] if cls_id 6 or any(c 0 or c 1 for c in coords): print(f异常: {f} - {line.strip()})5.5 现象推理时框重叠严重同一个缺陷出好几个框原因NMS 的 IoU 阈值设太高或者模型在缺陷附近产生了多个候选框。光伏板缺陷检测里热斑区域往往是一片渐变的高亮模型容易在边缘产生多个框。解决推理时把 NMS 的 IoU 阈值从默认的 0.45 降到 0.3同时开 agnostic NMS。如果还重叠检查训练数据里同一个缺陷是不是被标了多个框。6. 进阶技巧用切片推理把隐裂召回率拉上去隐裂和蜗牛纹是光伏板缺陷检测里最难的两类。它们在 4000 像素的原图里可能只占 30 到 50 个像素直接缩到 1024 训练信息损失太大。我试过几种方案最稳的是切片推理加多尺度融合。具体做法分三步。第一步训练时把原图裁成 640×640 的切片步长 320保证 50% 重叠。每个切片单独标注缺陷在切片里的像素占比从 1% 提到 5% 以上。第二步推理时对整张图做同样的切片每个切片跑一次模型记录所有检测框。第三步把所有切片的框映射回原图坐标用 NMS 合并。def slice_inference(model, image, slice_size640, stride320, conf0.25): h, w image.shape[:2] all_boxes [] for y in range(0, h, stride): for x in range(0, w, stride): # 边界处理最后一块切片对齐到图像边缘 x1 min(x, w - slice_size) y1 min(y, h - slice_size) x2 x1 slice_size y2 y1 slice_size patch image[y1:y2, x1:x2] results model(patch, confconf) for box in results.xyxy[0]: # 映射回原图坐标 bx1 box[0] x1 by1 box[1] y1 bx2 box[2] x1 by2 box[3] y1 all_boxes.append([bx1, by1, bx2, by2, box[4], box[5]]) # 全局 NMS 合并 return global_nms(all_boxes, iou_thres0.3)参数说明slice_size 和训练时的切片尺寸一致stride 设 slice_size 的一半保证重叠。conf 可以设低一点0.2 到 0.25因为切片后缺陷更清晰低阈值能捞回更多漏检后面靠 NMS 去重。这套方案在我经手的一个 30MW 电站数据集上隐裂召回率从 0.42 提到 0.71蜗牛纹从 0.38 提到 0.65。代价是推理时间变成原来的 4 到 6 倍但巡检场景对实时性要求不高离线跑批完全能接受。还有一个细节切片训练时如果某个切片里没有缺陷不要直接丢掉保留作为负样本。光伏板背景里有很多纹理容易被误检负样本能压住这部分误报。我一般保留 10% 到 15% 的纯背景切片。最后说一个我踩过的坑。切片推理合并时如果两张相邻切片都检到了同一个缺陷NMS 的 IoU 阈值设 0.3 可能合不掉因为切片边界处的框可能只有部分重叠。解决办法是在切片时保证 stride 不超过 slice_size 的 0.6让重叠区域足够大同一个缺陷至少完整出现在一个切片里。这个参数我调了三次才找到合适的值希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →