简介:这份太阳能电池板缺陷检测数据集,包含两千余张统一尺寸的八位灰度图像,图像来自四十四个不同太阳能模块,同时涵盖正常样本与内在外在缺陷样本,可供机器学习、深度学习研究者及光伏质量检测人员用于缺陷分类、目标检测和图像分割等场景。压缩包共两千个文件,主力为图像文件,另含标注表、处理脚本、说明文档与预览图,整体体积不到一百兆。图像已完成尺寸与视角归一化,并消除电致发光成像时的镜头畸变,标注信息完整,能够直接用于模型训练、算法对比与效果验证。目前已有三百九十余人学习浏览,既适合初学者理解光伏缺陷形态,也能支撑工业质检模型的迭代优化,是开展太阳能电池板自动缺陷识别的实用基础数据。
1. 太阳能电池板缺陷检测数据集:从“电致发光拼图”到可用的训练集
光伏电站运维里最耗时的不是爬屋顶换板,而是每天面对上百块组件分辨“这块是正常老化还是隐裂扩散”。太阳能电池板缺陷检测数据集就是专门解决这个问题的——把电致发光图、可见光航拍和红外热成像里的电池片缺陷(隐裂、断栅、PID、热斑、碎片)标注出来,做成目标检测模型能直接吃进去的训练素材。和从网上下载的通用物体检测数据集不同,这类数据集有强烈的工业属性:缺陷目标小、细长、类间差异大、背景纹理干扰多,所以做起来比想象中麻烦。这篇适合负责光伏电站智能巡检、组件产线质检,以及想用目标检测数据集入门工业视觉的算法工程师和测试工程师。数据怎么采、怎么标、怎么转成训练格式、怎么调参和踩坑,我按自己的实操路径一次讲清楚。
2. 三类数据来源与采集方案:EL图像、可见光和红外热成像怎么选
采集之前得先明白一件事:太阳能电池板的缺陷在不同成像模态下“长相”完全不同。电致发光像是缺陷检测的黄金标准,但环境要求苛刻;可见光适合表面脏污和破损,对隐裂基本无能为力;红外热成像擅长发热类缺陷,但分辨率低。三者的选择直接决定了数据集的天花板,所以这一章先讲清楚每种模态的来龙去脉,再给采集流程和标注规范。
2.1 EL电致发光图像:为什么它是缺陷检测的黄金标准
EL检测的原理不复杂:给太阳能电池板两端加正向偏压,让电池片内部产生电致发光,完整的电池会均匀发光,而隐裂、断栅、PID等缺陷区域的复合电流增大,导致局部发光强度下降,在图像上表现为暗纹、暗区或发丝状的黑色线条。常见的采集设备是一台EL测试仪加上工业相机和暗室,组件被夹紧通电后,相机在暗室里拍摄,曝光时间通常设在1到5秒,电流密度控制在10到30A/m²这个量级。参数怎么调有自己的玄学:电流太大会让背景整体过曝,细小的隐裂反而被淹没;曝光太长则整块组件发白的区域过多,后期归一化困难。我一般会先拍三张不同电流的样本,目测暗纹对比度最好的那组作为基准。
EL图的标注是数据集的基石。缺陷类别里最常见的包括:隐裂(发丝状暗线,可能横跨多个电池片)、断栅(电池片表面的细栅线断裂,呈现规律性的暗细条)、黑片/暗片(整片电池亮度明显偏低)、PID(电势诱导衰减,整片发灰或边缘发暗)以及碎片和栅线短路。类别定义表要提前定好,否则标注员会把“断栅”和“隐裂”混淆——两者在EL图上都是暗线,区别在于断栅通常平行且等间距,隐裂则是不规则分叉。标注时建议把整片电池作为单位,框要贴着缺陷轮廓,但不能切掉缺陷延伸到图外的部分,这个后面格式转换时会有坐标越界的坑。
2.2 无人机可见光与红外热成像:数据采集流程与参数
可见光和红外热成像主要服务于电站巡检场景。无人机搭载可见光相机在组件上方飞行,飞行高度控制在30到50米,云台角度尽量正对组件平面,否则透视畸变会影响标注框的准确度。航线规划要保证前后和左右的图像重叠率不低于60%,因为可见光缺陷(脏污、玻璃碎、表面裂纹)的尺寸小,重叠率高一点才能防止漏拍。红外热成像则要在白天午间或组件发热稳定的时段拍摄,热斑、旁路二极管故障会在热像图上呈现明显的高温团块,但红外相机分辨率普遍偏低,缺陷边界模糊,所以标注时要保守一点,只框温度异常区域的外圈,别把整串组件都框进去。
可见光图像里电池片之间的间距、组件边框、玻璃反光都是强烈的背景干扰。采集回来后最好做一次人工初筛,把曝光过度、严重反光、运动模糊的帧直接删掉——这些坏样本喂给模型,只会让训练损失在epoch后期来回震荡。任何公开的太阳能电池板缺陷检测数据集都不可能覆盖你现场的光照角度和组件型号,所以最稳妥的做法还是自己采集一批本场站数据,再和公开数据集混合训练。
2.3 标注工具选择与缺陷标注的三条硬规矩
标注工具我推荐用X-AnyLabeling或者CVAT,前者本地跑方便,后者多人协作时能配置审校流程。别用LabelImg硬扛批量任务,它没有辅助标注功能,对动辄几千张的EL图来说太费人力。X-AnyLabeling支持加载预训练的SAM模型做半自动分割,对“像素级缺陷”能省不少力气,但注意缺陷是细长线条时SAM容易欠拟合,最终还是要人工微调框。
标注规范就三条硬规矩。第一,一个缺陷一个框,不许把相邻两片电池的缺陷并成一个框,除非缺陷真的横跨边界;第二,框必须紧贴缺陷,EL图像里暗纹边缘模糊,宁小勿大——框大了会让IoU虚高,模型学不到缺陷的真实边界;第三,模糊存疑的样本要么删掉要么标成“待确认”,绝不能凭感觉硬分到某一类。这一条在多人协作时尤其重要,否则写标签的人中途离职,后面的人接手的都是“标注风格不一致”的混沌数据集。
3. 数据集格式转换:从VOC到YOLO的脚本与四个边界坑
标注工具导出时默认给的往往是PASCAL VOC格式(每张图对应一个xml文件),但训练目标检测模型普遍要的是YOLO格式(每张图对应一个txt文件)或COCO格式(所有标注汇总到一个json)。第一次做转换的人最容易在这步翻车:不是找不到标签映射,就是看着txt里的“0 0.5 0.5 0.3 0.2”不知道是什么意思。这章先讲结构,再贴脚本,最后把四个边界坑说透。
3.1 三种主流格式的结构差异与适用场景
VOC格式的xml里记录的是每个目标的类别名和两个角点的绝对像素坐标(xmin, ymin, xmax, ymax),人类可读性好,适合人工检查,但解析速度慢。YOLO格式则是一行一个目标,五列分别是“类别编号 中心点x 中心点y 宽度 高度”,其中坐标全部归一化到0到1之间,和图像分辨率无关,推理时更直接。COCO格式是json,包含images、annotations、categories三个数组,做数据蒸馏、模型评估时最通用。三种格式本身没有优劣,但训练时得按框架的要求来。YOLOv8的训练器接受YOLO格式的txt,同时也支持COCO格式;如果你用的是mmrotate这类旋转检测框架,训练DOTA格式的数据集又是另一套坐标定义,旋转框会多一个角度参数,所以先确认框架再决定转成什么格式,别一上来就全转成YOLO。
3.2 VOC转YOLO:一份可以改的Python脚本
下面这份脚本就是我在本地做转换时的基础版本,它做三件事:读xml、归一化、写txt。类名映射表需要你自己改成实际标注的类别,注意类名顺序就是训练时类别编号的顺序,这个顺序定下来之后不能乱动。
import os import xml.etree.ElementTree as ET from pathlib import Path from PIL import Image # 类名映射:顺序即类别编号,定好就别改 CLASS_MAP = { "crack": 0, # 隐裂 "broken_grid": 1, # 断栅 "pid": 2, # PID 暗片 "hot_spot": 3, # 热斑 "dirt": 4, # 脏污 } def convert_voc_to_yolo(xml_path, output_txt_path, width_orig, height_orig): tree = ET.parse(xml_path) root = tree.getroot() lines = [] for obj in root.findall("object"): name = obj.find("name").text if name not in CLASS_MAP: # 未在映射表中的类别直接跳过,避免训练时类别编号错位 continue cls_id = CLASS_MAP[name] box = obj.find("bndbox") # xml里存的是字符串,取出来要转成float xmin = float(box.find("xmin").text) ymin = float(box.find("ymin").text) xmax = float(box.find("xmax").text) ymax = float(box.find("ymax").text) # 归一化:中心点坐标 + 宽高,全部除以原图宽高 x_center = (xmin + xmax) / 2.0 / width_orig y_center = (ymin + ymax) / 2.0 / height_orig w = (xmax - xmin) / width_orig h = (ymax - ymin) / height_orig # 边界保护:把越界值钳制到 [0, 1] 内,避免训练崩溃 x_center = min(max(x_center, 0.0), 1.0) y_center = min(max(y_center, 0.0), 1.0) w = min(max(w, 0.0), 1.0) h = min(max(h, 0.0), 1.0) lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}") with open(output_txt_path, "w", encoding="utf-8") as f: f.write("\n".join(lines)) def batch_convert(annotation_dir, image_dir, output_dir): # 遍历所有xml,逐个转换 for xml_file in Path(annotation_dir).glob("*.xml"): # 读取对应图片的真实宽高,xml里的size标签有时不准 img_file = Path(image_dir) / (xml_file.stem + ".jpg") with Image.open(img_file) as img: w, h = img.size txt_path = Path(output_dir) / (xml_file.stem + ".txt") convert_voc_to_yolo(xml_file, txt_path, w, h) if __name__ == "__main__": batch_convert("annotations", "images", "labels")脚本逻辑先说清楚:转换的核心是坐标系的换算,从“左上右下两点”变成“中心点加宽高”,同时把像素值除以原图宽高。为什么除以宽高而不是固定某个缩放值?因为模型训练时输入尺寸会resize到640或1280,绝对像素坐标在不同分辨率下没有可比性,归一化之后才能适配任意输入尺寸。PIL读取宽高的那一步是为了防止xml里的size标签和实际图不一致——有些标注工具导出时会把size写错,这个坑我踩过好几次,后来一律以实际图像为准。
3.3 格式转换中的四个边界坑
第一个坑是类别编号错位。xml里的name是字符串,而YOLO格式只认数字。如果CLASS_MAP里某个类被漏掉,或者顺序调整过,之前训练的模型权重就全部作废,所以类别顺序必须从数据集的“宪法”地位来对待,哪怕只加一个类也应该从头重训。
第二个坑是归一化精度。YOLO标签文件里的坐标精度如果只写到4位小数,原本在1280分辨率下的1像素误差在归一化后大约是0.0008,看起来很小,但对细长隐裂这类目标来说,宽度可能只有2到3个像素,一位小数误差就会丢掉一半的宽度信息。所以txt输出格式建议至少写6位小数,上面脚本里的f"{...:.6f}"就是为此而设。
第三个坑是空标注文件。如果某个xml里没有有效类别(比如全部在CLASS_MAP之外),脚本会写一个空txt。空txt在YOLO训练里是合法的(表示图中无目标),但如果你后续用albumentations或自定义Dataset做增强,空文件可能触发除零异常。我的习惯是转换后统计一下txt行数,再和xml目标数对一遍,不齐就查。
第四个坑是坐标越界。缺陷在EL图上经常被标注到电池片边缘,归一化后x_center + w/2可能大于1.0。训练时某些框架会对越界标注报IndexError或直接丢出边界外的anchor,导致正样本变少。脚本里的钳制操作是最后一道防线,但更根本的解法是在标注环节就不要把框画到图外。你可以写一个小脚本扫描所有txt,检查数值是否都在(0,1)区间,遇到越界就把对应的xml调出来人工修一遍。
4. 用YOLOv8训练自己的太阳能电池板缺陷检测数据集:配置与关键参数
数据集准备好之后,接下来的问题是怎么样把它跑起来。这个方向下的检索词里“yolov8训练自己的数据集”“目标检测数据集”出现频率最高,说明大部分人是带着开源模型直接上手的。YOLOv8是当前工业缺陷检测里最常见的起点,它开箱即用,训练命令短,并且对小目标也有独立检测头。但“开箱即用”不等于“参数不用改”,太阳能电池板缺陷和COCO那些自然图像的分布差别太大,四个关键参数动了之后效果完全不同。
4.1 数据集目录结构与data.yaml配置
先把目录结构按照YOLO的约定摆好。train和val文件夹下各建images和labels,images里放jpg或png,labels里放转换好的txt,文件名要严格对应(不包括扩展名)。验证集建议从每个缺陷类别里分别抽一部分,而不是简单随机抽,否则某个类别样本本来就少,又都抽到train里,val就看不到这一类了。
# data.yaml path: /path/to/solar_panel_dataset train: images/train val: images/val nc: 5 names: 0: crack 1: broken_grid 2: pid 3: hot_spot 4: dirtyaml里最关键的三个字段是path、train/val路径和names列表。path建议写绝对路径,相对路径在换机器训练时经常出问题。names的顺序必须和第3章CLASS_MAP里的顺序保持一致,这一点绑定的是txt里每行开头的数字,不是name字符串,所以光看标签文件看不出错,只有训练日志里类别分布对不上才能发现。nc是类别总数,如果写成4而实际标签里有第5类,训练时会直接报“class id out of range”。
4.2 训练命令与四个必调参数
训练命令本身很短,核心是模型权重和四个参数:
yolo detect train \ model=yolov8s.pt \ data=/path/to/solar_panel_dataset/data.yaml \ imgsz=1280 \ batch=8 \ epochs=200 \ patience=30 \ device=0参数说明都是血泪经验型的,不是照抄文档。imgsz是第一个要动的参数。COCO预训练默认是640,但太阳能电池板缺陷(尤其隐裂)的像素宽度常常只有几个像素,640下采样后特征几乎消失。我一般从1280起跳,显存不够就降到960,代价是训练时间变长,但对于小缺陷检测这是最值得投入的一项。batch的大小受单卡显存约束,8到16之间都可以,如果训练初期loss出现剧烈震荡,优先调低batch或学习率,不要硬扛。epochs设200是为了配合早停,太阳能板数据集如果只有几百张图,其实100个epoch基本就收敛了,但多给一些余量没坏处。patience是早停容忍度,设30表示连续30个epoch验证指标不上升就停止,避免过拟合,这个值在数据量小的工业数据集上特别有用。
提示:cache=True可以把数据提前缓存到内存,几百张图的话训练速度快很多,第一次会花几十秒构建缓存,后面每次启动都是秒级。optimizer默认是auto,数据量小时换成SGD往往更稳,AdamW在小数据集上收敛快但容易遗忘早期学到的特征,具体效果最好在自己数据集上对比。
多GPU并行时要注意device="0,1"和batch的含义,YOLO的batch是“每卡batch”,总batch是单卡batch乘以卡数。
4.3 验证指标怎么看:mAP、precision、recall与缺陷检测的取舍
训练结束后,val目录下的结果会打印出mAP50、mAP50-95、precision、recall这几个指标。它们的关系不是“越高越好”这么简单。mAP50=0.9听起来很好,但如果你按0.5的IoU阈值评估,隐裂这种细长目标很容易因为框稍微歪一点就IoU大跌,所以我会额外关注mAP50-95——它用多个IoU阈值平均,能反映框的贴合度,对缺陷检测更有参考意义。
precision和recall的取舍要看你的应用场景。电站巡检宁可多报缺陷后人工复核,所以recall优先,把置信度阈值调低;产线质检则要求precision优先,把阈值调高,减少误杀导致的产能损失。这里有个常被忽略的点:验证指标的置信度阈值默认是0.25,如果你在推理阶段把阈值调到0.5,mAP会下降一大截,这并不代表模型退化了,而是你人为提升了检出门槛。最后再看PR曲线的形状,如果曲线陡降,说明模型对大部分样本信心不足,这时候调阈值没用,要回到imgsz和数据量上想办法。
5. 太阳能电池板缺陷数据集常见问题排查:五个踩坑记录
任何工业数据集都不会一次就训练成功,尤其是这种目标细长、类别不平衡、现场环境多变的数据集。这里挑五个我见过最高频的问题,每条按“现象→原因→解决”写,覆盖从数据到训练再到推理的完整链路。
5.1 漏检严重但mAP却很高?数据分布不均
现象:验证集mAP50超过0.9,但新拍的EL图像里隐裂漏检一大半。 原因:训练集里隐裂标注太集中在一个组件批次,背景纹理单一,模型实际上记住了“这类纹理的组件上才有隐裂”,而不是学“隐裂的特征”。验证集也来自同一批次,所以指标虚高。 解决:按组件型号或拍摄批次划分train和val,而不是按图片随机切分。最简单的方法是给每张图打一个批次编号(像是用文件名前缀),划分时保证val包含所有批次的样本,并且每个类别在val里的比例和train尽量一致。这和4.1里“按类别抽样”是同一件事的两个侧面,目的都是让验证集能真实反映模型的泛化能力。
5.2 微裂纹类别训练loss不降?标注间距不一致
现象:总loss下降很快,但微裂纹类别的单独指标几乎不降,F1偏低。 原因:不同标注员对微裂纹的标注框差异很大——有人框细线,有人连周围渐变暗区一起框。同一类目标在监督信号里的“真值形状”不一致,模型无法收敛到统一表征。 解决:返工标注,统一规则为“框住可见暗纹,不框渐变阴影”。返工后如果数据量不够,可以考虑把微裂纹与普通裂纹合并成一个“crack”类,先保证类别内的标注一致性,再考虑细分。与其有一个质量差的细分类别,不如一个质量好的合并类别,这个教训我在多个工业数据项目里都验证过。
5.3 换一个电站后模型泛化崩了?图像风格迁移与归一化
现象:在A电站训练好的模型拿到B电站,同一块组件在不同光照姿态下出现大量误报,甚至把正常的栅线当断栅。 原因:EL图的对比度、亮度和噪声水平随设备批次漂移;可见光图随日照角度、组件反光变化。模型学到的是“图像的统计风格”而不是“缺陷的结构特征”。 解决:训练阶段增加Mosaic、仿射变换、HSV扰动(对灰度EL图也可以用对比度扰动),把图像风格抖开;推理阶段对输入做一次CLAHE自适应直方图均衡化,减少亮度漂移的影响。数据层面,把B电站少量图像(哪怕100到200张)混入训练集重训,泛化都会有很大改善。
5.4 小目标隐裂永远检不准?切片策略
现象:隐裂宽度只有2到3px,imgsz提到1280还是漏检,或者mAP低得离谱。 原因:原图分辨率可能是2000×1500,缺陷在特征金字塔最深层对应的特征图尺寸只有输入图像的1/32,隐裂在这种尺度上已经退化成单像素点。 解决:切片训练和切片推理。训练时把原图切成若干个无重叠或小重叠的patch,每个patch单独标注单独训练;推理时同样切片再汇总。切片的边长通常取原图的1/2或1/4(如512×512到768×768),切得过小会把缺陷切成两半,过大则回到原点。合并patch时要带一些重叠(比如10%),避免恰好落在切缝上的缺陷被截断。
import cv2 from pathlib import Path def slice_image(img_path, patch_size=768, overlap=0.1): img = cv2.imread(str(img_path)) h, w = img.shape[:2] step = int(patch_size * (1 - overlap)) patches = [] for y in range(0, h, step): for x in range(0, w, step): # 边界处最后一张要裁到图片边缘 y2 = min(y + patch_size, h) x2 = min(x + patch_size, w) patch = img[y:y2, x:x2] # 太小的边缘patch直接丢弃,避免送入模型的是黑边 if patch.shape[0] >= patch_size // 2 and patch.shape[1] >= patch_size // 2: patches.append((x, y, patch)) return patches这段脚本的核心参数是patch_size和overlap。patch_size控制切片尺寸,也决定了送入模型的输入分辨率;overlap让相邻patch有公共区域,防止缺陷正好卡在切缝上被拦腰截断。返回的(x, y)是patch左上角在原图中的坐标,推理时要把检测框加上这个偏移量还原到整图坐标系。
5.5 类别不平衡导致模型“偏科”?重采样与损失权重
现象:pid类别整批数据只有30个标注框,隐裂有8000个,训练后一切正常但pid的recall几乎是0。 原因:类别数量差了几百倍,梯度被多数类别主导,少数类别学习信号微弱。这在工业故障检测数据集里是通病,轴承故障样本和光伏缺陷样本都容易这样,不是模型独有的问题。 解决:先做重采样,让训练时每个batch里各类别按比例出现,类别少的图重复采样。然后调整损失权重,YOLOv8的cls_loss可以在超参里单独提高(例如从默认0.5提到1.0),让分类分支更关注少数类。最极端的办法是合并或裁掉过少类别,因为少到几十个框的类别即使硬训出来,也几乎没有泛化能力,生产环境里不如不检测。
6. 切片推理、尺度校准与置信度阈值:缺陷检测落地的最后一公里
训练完模型只是开始,把模型部署到EL检测仪或无人机后端才算落地。这里分享一个我反复验证过最值的技巧:切片推理加尺度校准。我在项目里把单张2000×1500的EL图切成6个768×768的patch(重叠10%),隐裂的mAP50直接涨了8个点,而推理时间只多了30%,因为小图让模型的计算负载更均衡,GPU利用率反而更高。切片后在合并阶段要按缺陷的中心点去重,两个patch重叠区检到同一个框时,取置信度高的那个,否则会出现“一个缺陷报两次”。
置信度阈值不要定死,要根据现场反馈调整。推理时可以先用默认的0.25跑一遍,把预测框的可信度分布导出,找到recall曲线拐点——拐点之前是宁可误报也不要漏掉的区间,拐点之后才是误报激增区间。还是那句话,巡检场景往左调,产线场景往右调。我最初做产线质检时把阈值定在0.5,被误杀率投诉了几次才明白,盲目套预设值等于没调参。
最后记录一段自己的教训:我曾经为了追求mAP把模型做到板块,换了新批次组件后直接失准,后来才意识到问题根本在数据集里没有涵盖那个批次的纹理风格。从那以后我坚持给每个数据集写一个说明文档,记录采集设备、光照条件、组件型号、标注人员名单和缺陷判定规则,这比调任何超参都管用。希望这份笔记能帮你少走一段同样的弯路,祝你的太阳能电池板缺陷检测数据集早日跑出可用的模型。
本文还有配套的精品资源,点击获取