简介面向太阳能电池板缺陷检测研究的图像数据集涵盖44个不同太阳能模块提取的2624张300×300像素8位灰度图像样本包括功能正常及多种退化程度缺陷。缺陷分为内在与外在两类涵盖电池片裂纹、断栅、划痕、污染、紫外线照射与湿气侵蚀导致的性能退化等可作为图像分类、目标检测与分割任务的训练基准。所有图像已完成尺寸与视角归一化并消除EL成像时的镜头失真数据一致性较好。压缩包内共2000个文件以PNG图像为主体另含CSV标签文件、Python脚本、Markdown说明与预览图整体大小89.65MB可配合常见深度学习框架直接开展实验。已有392人学习下载适合算法工程师、科研人员及高年级学生用于模型验证、课题研究或产线质检原型开发。附带标签列表与说明文档能帮助快速理解样本组织方式节省数据清洗时间。1. 太阳能电池板缺陷检测数据集别急着训模型先搞懂这批数据是怎么来的太阳能电池板缺陷检测数据集说到底是给机器视觉缺陷检测场景准备的一批带标注图像核心是电致发光EL图像里面既有正常电池片样本也有隐裂、断栅、碎片这类缺陷样本。它解决的是光伏产线上“靠人眼在暗室里看 EL 图找缺陷”这个环节的自动化问题——你把训练脚本和数据路径配好就能用 YOLOv5/YOLOv8 这类检测模型把隐裂、断栅的位置框出来。适合谁用做光伏组件质检算法、搞工业缺陷检测、或者刚开始拿真实工业数据练 YOLO 的工程师都合适。我拆完这份资源之后最大的感受是缺陷检测数据集的价值不在“有多少张图”而在标注规范和样本均衡能不能撑起训练这两点直接决定你后面少走多少弯路。2. 数据集的目录与标注格式动手训练前先搞懂这批数据的组织方式2.1 EL 图像为什么是太阳能电池板缺陷检测的主力光伏行业做电池片内部缺陷检测几乎不用普通可见光照片而是用电致发光成像。原理是给电池片通正向偏压让载流子复合发光发出的近红外光波长在 1150nm 附近缺陷区域复合效率低发光强度就弱在图像上表现为暗色的线条或块状区域。隐裂、断栅、碎片、黑心这些缺陷在 EL 图像下非常清楚尤其是隐裂那种细微的暗纹在可见光下基本看不见但在 EL 下就是一条明显的暗线。这份数据集里的图像就是典型的 EL 灰度图。注意是灰度图不是三通道彩色图。这带来两个直接影响第一你后面做数据增强时不能用颜色抖动、色相变换这类操作那是给自然图像准备的第二模型输入用单通道或复制成三通道都行但灰度本质意味着对比度才是缺陷能否被检出的关键。我一般会把输入统一转成三通道再送进 YOLO不是为了颜色信息而是为了沿用现成的预训练权重。2.2 目录结构images 和 labels 如何一一对应拿到数据集后别急着开训练先花五分钟把目录结构看清楚。常见组织方式是按 YOLO 惯例图像和标注文件分成两个根目录solar_panel_dataset/ ├── images/ │ ├── train/ │ │ ├── SP_0001.jpg │ │ ├── SP_0002.jpg │ │ └── ... │ ├── val/ │ │ └── ... │ └── test/ │ └── ... ├── labels/ │ ├── train/ │ │ ├── SP_0001.txt │ │ ├── SP_0002.txt │ │ └── ... │ ├── val/ │ │ └── ... │ └── test/ │ └── ... └── classes.txt这套结构里最关键的是文件名一一对应SP_0001.jpg对应SP_0001.txt前缀完全相同只是扩展名不同。训练时脚本就是靠这个对应关系去加载标注的。classes.txt里是类别名列表每行一个类别顺序就是训练时类别 ID 的顺序不要随意改。如果这份资源里 train/val/test 已经划分好直接用没划分的话按 8:1:1 自己拆但要保证同一块电池片的图像不要同时出现在训练集和验证集里后面避坑章我会专门说这个。2.3 标注文件里的五个字段class_id、中心点坐标和宽高打开任意一个 txt 标注文件你会看到每行五个数字这是 YOLO 格式的标准写法0 0.523437 0.612500 0.084375 0.135417 1 0.321875 0.381250 0.046875 0.058333 0 0.764062 0.243750 0.093750 0.120833每一行的含义是类别 ID、目标中心点的 x 坐标、目标中心点的 y 坐标、目标宽度、目标高度。注意后四个值全部做了归一化处理用像素坐标除以图像的宽和高所以取值范围是 0 到 1。这样做的好处是图像分辨率变了标注不用跟着改坏处是你用肉眼从 txt 里看不出缺陷在图像的哪个位置必须还原回像素坐标才能理解。字段含义取值说明第 1 个类别 ID从 0 开始对应 classes.txt 的行号第 2 个中心点 X 坐标归一化像素 X / 图像宽度第 3 个中心点 Y 坐标归一化像素 Y / 图像高度第 4 个框宽度归一化框宽像素 / 图像宽度第 5 个框高度归一化框高像素 / 图像高度我在实际项目里见过不少翻车现场有人把 VOC 格式的左上角右下角坐标直接当成中心点填进 YOLO 训练loss 降不下去画出来的框全偏到一边。所以这里值得踩一脚如果你的标注是从 LabelImg 的 XML 或者 Roboflow 的 JSON 转过来的转换脚本里一定要把(xmin, ymin, xmax, ymax)换成((xminxmax)/2, (yminymax)/2, xmax-xmin, ymax-ymin)再归一化。2.4 用一段 Python 脚本快速统计类别分布与标注质量拿到数据集先别跑训练先跑一段统计脚本搞清楚每个类别的样本数、框数量、框的宽高分布这一步能帮你提前发现标注文件里的低级错误比如空标注、坐标越界、框太小。import os from collections import defaultdict label_dir solar_panel_dataset/labels/train class_names [crack, finger_interruption, fragment, normal] stats defaultdict(lambda: {samples: set(), boxes: 0}) error_files [] for fname in os.listdir(label_dir): if not fname.endswith(.txt): continue fpath os.path.join(label_dir, fname) with open(fpath, r) as f: lines [line.strip() for line in f if line.strip()] if not lines: error_files.append((fname, empty)) continue for line in lines: parts line.split() if len(parts) ! 5: error_files.append((fname, field_count)) continue cls_id int(parts[0]) x, y, w, h map(float, parts[1:]) # 越界检查归一化坐标应当在 [0, 1] 范围内 if not all(0 v 1 for v in (x, y, w, h)): error_files.append((fname, out_of_range)) continue if w 0.01 or h 0.01: error_files.append((fname, too_small)) continue stats[cls_id][samples].add(fname.replace(.txt, )) stats[cls_id][boxes] 1 total_images len(os.listdir(label_dir)) print(flabel 文件总数: {total_images}) for cls_id in range(len(class_names)): print(f{class_names[cls_id]}: 图像数{len(stats[cls_id][samples])}, 框数{stats[cls_id][boxes]}) if error_files: print(f异常文件: {error_files[:10]})逻辑说明这段脚本先把每个 txt 的行数、字段数、坐标范围、框大小逐一检查再用 defaultdict 按类别累计“出现过该类的图像数”和“框总数”。之所以要分别统计图像数和框数是因为一张图上可能有多处缺陷图像数代表样本覆盖度框数代表目标密度。如果某个类别的图像数很少但框数很多说明数据高度集中在少数图上训练时容易过拟合。参数说明框宽高小于 0.01 的判断阈值对应到 640×640 输入下就是小于 6.4 像素这类小目标基本没法训练要么删掉要么单独处理。3. 把数据集喂给 YOLOv8从数据加载到训练配置3.1 准备工作安装环境与编写数据集 yaml训练环境我直接用 Ultralytics 的 YOLOv8这套框架对工业缺陷检测足够友好训练、验证、导出一条龙。安装很简单pip 装一个包就够pip install ultralytics然后写一个数据集描述文件solar_panel.yamlYOLO 训练脚本靠它找到图像路径和类别名# solar_panel.yaml path: /path/to/solar_panel_dataset train: images/train val: images/val test: images/test names: 0: crack 1: finger_interruption 2: fragment 3: normal这里的path是数据集根目录的绝对路径建议写死绝对路径别用相对路径——训练脚本的工作目录一变相对路径经常出幺蛾子。train和val填的是相对于path的子路径。注意names的 ID 顺序必须和 labels 里 txt 的类别 ID 一致我前面特意在统计脚本里用了这个顺序就是为了提前验证一致性。3.2 启动训练命令里的每个参数分别管什么训练命令本身不复杂但每个参数都要知道是干什么的别照抄cd /path/to/solar_panel_dataset yolo detect train \ modelyolov8m.pt \ datasolar_panel.yaml \ epochs100 \ imgsz640 \ batch16 \ device0 \ workers4 \ cacheTrue \ projectruns/solar_panel \ nameexp1参数建议值作用与调整思路modelyolov8m.pt预训练权重。缺陷目标不太大用 m 比 s 精度稳比 l 省显存显存紧张先用 sepochs100工业缺陷数据集通常 100 轮内收敛看 loss 再决定续跑还是提前停imgsz640经典输入尺寸。如果断栅这类小目标多后面可以试 960 或 1280batch16受显存限制。RTX 3060 级别 16 起步A100 可以到 32device0GPU 编号。没有 GPU 就填 cpu但训练会慢非常多cacheTrue把图像提前缓存到显存省去每轮 IO 等待这里我想多聊两句modelyolov8m.pt。它是在 COCO 上预训练过的权重虽然 COCO 是自然图像和 EL 灰度图差距很大但骨干网络提取边缘、纹理特征的能力是通用的。你完全可以用yolov8m.yaml从零训练但收敛会慢不少mAP 也往往更低。我一般直接用预训练权重然后在光伏数据上微调这是工业小规模数据集最稳的路线。3.3 训练过程中的两个关键监控点loss 曲线与 PR 曲线训练跑起来之后在runs/solar_panel/exp1/下会生成results.png这个图里包含了 box_loss、cls_loss、mAP50、mAP50-95 等曲线的变化。我每次训练都会盯着两个关键点看。第一是 box_loss 和 cls_loss 是否在前 20 轮内稳定下降。如果 loss 在震荡甚至上升先别急着加数据检查标注文件里有没有坐标越界、框错位的问题。第二是 mAP50 曲线的走向缺陷检测场景下 mAP50 比 mAP50-95 更贴近实际需求——产线上“框到了”和“没框到”是一票否决框得有多精细是次要的。正常节奏是前 10 轮 mAP50 快速爬升30 轮左右增速放缓60 到 80 轮进入平台期。如果到 100 轮还在明显上升说明没收敛完用yolo detect train ... resumeTrue接着跑。如果你发现 mAP50 在 90 轮突然掉了一截那大概率是学习率调到了低位后过拟合开始占上风可以回滚到平台期那轮的权重用YOLO 会自动保存best.pt它就是验证集上 mAP 最高的那轮。4. 数据增强与样本均衡别让正常样本把缺陷淹没了4.1 光伏场景特有的增强策略太阳能电池板 EL 图像和自然图像有明显差异直接用 YOLO 默认的增强策略会出问题。默认增强里有色彩类操作但对灰度 EL 图来说色相、饱和度变换毫无意义还白耗算力。更关键的是EL 图像的缺陷是低对比度暗纹光照、电流波动导致的整体亮度不均才是真实场景里最常见的干扰。所以我在这类数据集上常用的增强组合是水平翻转、垂直翻转、小角度旋转±15 度以内、轻微缩放外加亮度对比度微调。# hyp_solar.yaml 覆盖默认超参数 fliplr: 0.5 flipud: 0.3 hsv_h: 0.0 hsv_s: 0.0 hsv_v: 0.2 degrees: 15.0 translate: 0.1 scale: 0.4参数说明hsv_h和hsv_s直接置零因为灰度图没有色相和饱和度概念hsv_v只给 0.2模拟的是 EL 成像时电流波动导致的亮度变化这个值太大会把隐裂的暗纹直接埋进背景里。degrees给 15 度是因为电池片本身有栅线结构旋转角度太大模型可能会学到“栅线方向错了”这种不存在的变化模式。4.2 缺陷粘贴与正常样本的平衡处理我拆过不少缺陷检测数据集一个几乎必然存在的问题是正常样本数量碾压缺陷样本。太阳能电池板产线上绝大多数电池片是好的缺陷是少数所以这份数据集里 normal 类别的图像很可能占了一半以上。如果直接训练模型会学歪把所有图都预测成 normal 就能拿到很高的准确率但产线上要的就是把稀有的缺陷捞出来。两个常用解法第一是训练时限制 normal 类别的采样权重YOLO 里可以不用额外脚本直接在训练前把 normal 图像复制几份到数据集里或者在增强阶段对 normal 图做随机裁切、亮度扰动来“凑数”第二是缺陷粘贴把标注好的缺陷区域裁出来贴到 normal 电池片的随机位置上生成新的合成缺陷样本。import cv2 import numpy as np def paste_defect(normal_img, defect_img, defect_bbox, times3): 将缺陷区域粘贴到正常电池片图像上, 返回新图像和标注 h, w normal_img.shape[:2] dh, dw defect_img.shape[:2] labels_new [] for _ in range(times): # 随机生成粘贴位置, 留出边缘余量 x np.random.randint(0, w - dw) y np.random.randint(0, h - dh) roi normal_img[y:ydh, x:xdw] # 按缺陷区域的亮度做简单融合: 缺陷区域像素值乘以 0.8 blended cv2.addWeighted(roi, 0.2, defect_img, 0.8, 0) normal_img[y:ydh, x:xdw] blended cx (x dw / 2) / w cy (y dh / 2) / h bw dw / w bh dh / h labels_new.append([0, cx, cy, bw, bh]) return normal_img, labels_new逻辑说明这段脚本把缺陷区域按 80% 的权重叠加到正常图上避免生硬边界穿帮。粘贴位置完全随机但留出了边缘余量防止框越界。合成样本的标注直接在粘贴坐标上算出来。参数说明times3表示一张正常图上贴 3 个缺陷适合缺陷密度低的场景权重 0.8 是经验值太大会让缺陷区域突兀得像贴纸太小模型学不到特征。4.3 从增强到训练如何使用这些配置增强配置写进 hyp 文件后训练时用hyp参数指过去就行yolo detect train \ modelyolov8m.pt \ datasolar_panel.yaml \ hyphyp_solar.yaml \ epochs100 \ imgsz640 \ batch16Mosaic 增强我一般会关掉或者调低因为 EL 图像的电池片边界是完整结构mosaic 把四张图硬拼在一起会产生大量跨图拼接的假边缘模型容易学到“接缝就是缺陷”。用mosaic0.3这样的低比例让它偶尔出现但不成主导。另一个技巧是开启close_mosaic10让最后 10 轮关闭 mosaic用真实分布做收尾验证集表现会更稳定。5. 复现中的常见问题与避坑记录这些坑我踩过你直接绕开5.1 坑一图像与标签文件名不匹配mAP 全程为 0现象训练能正常启动loss 也降但 val 的 mAP50 一直是 0每张图都预测不出框。原因images 和 labels 目录里部分文件名的前缀不一致比如图像叫SP_0001.jpg标注叫SP_0001_crop.txt。YOLO 加载标签时按图像名去匹配后缀对不上就默认这个图没有标注于是验证集里所有图都变成了“负样本”模型学到的是“什么都不框”最优。解决训练前用脚本对两边文件名取集合求差集把不一致的列出来统一重命名。别只看前几个文件上千张图里混几十张不匹配的mAP 能直接从 0.9 掉到 0.3。5.2 坑二正常样本比例过高模型输出全预测为背景现象loss 曲线正常mAP50 到了 0.8 以上但单独拿 50 张只有缺陷的图去测召回率不到一半。原因训练集里 normal 占了七成以上模型学到“大多数时候不框框”是最优策略。验证集又是同分布的数据所以 mAP 虚高一到实际场景就现原形。解决按 4.2 节的做法做缺陷粘贴和负样本降采样让训练时缺陷样本和正常样本比例接近 1:1或者缺陷略多一点。用验证脚本单独统计有缺陷图像上的召回率这个指标比总 mAP 更能反映产线可用性。5.3 坑三低对比度隐裂被当成噪声处理现象隐裂类别的 AP 只有 0.1 左右但人工看标注图确实有框。训练集的标注框也没有错误。原因EL 图像上隐裂就是几条暗线灰度值只比背景低 3 到 5 个灰阶。模型对低对比度目标天然不敏感加上为了降噪做的中值滤波和归一化增强很容易把暗纹直接抹平。解决标注阶段要求框一定要贴合裂纹走向别用大包围盒把整片暗区框成一个框增强阶段把亮度抖动幅度调小加一个轻微锐化操作。更激进的做法是输入图先做 CLAHE对比度受限自适应直方图均衡把暗纹拉伸出来再喂给模型。5.4 坑四小目标缺陷在 640 尺度下难以召回现象断栅、碎片这类小缺陷框的像素宽度经常在 10 个像素以下训练完的模型能检出大隐裂但小缺陷一个都找不到。原因YOLO 在 640×640 输入下下采样到 P3 层是 80×80一个 10 像素的缺陷在特征图上只占 1 到 2 个像素特征响应太弱。解决两个方向。一是把imgsz调到 960 或 1280每张图的细节信息变多小目标在特征图上的占比变大二是做滑窗切图把 2000×2000 的原始 EL 图切成 640×640 的子图再训练缺点是要重新切验证集和测试集工作量不小。模型侧可以开smallTrue试 P2 层输出但显存占用会明显上升。5.5 坑五训练集和验证集同源指标虚高得吓人现象训练时 mAP50 已经到 0.95 以上觉得模型很完美但把模型拿到另一批现场数据上测mAP 直接掉到 0.5。原因这份数据集里同一块电池片的 EL 图往往会拍多张如果不做去重直接随机划分训练集和验证集里可能出现同一块电池片的不同图像模型记忆了这块电池片的特征验证时当然检得准。解决划分数据前先看文件名如果文件名前缀代表电池片编号按前缀分组再划分。比如用SP_0001这个前缀作为 group id保证同一组只进一个集合。这是工业缺陷检测里最容易被忽略的一个坑比调模型参数的影响大得多。6. 用独立测试集做一次真实缺陷检出验证从 mAP 到现场可用性的最后一公里训练完的模型最终是要拿到产线上用的mAP 只是中间指标我习惯在交付前用一套独立测试集做一次完整的可视化验证。这套测试集的标准是里面的图像既不来自训练集也不来自验证集最好是从产线新拍的 EL 图里抽的。没有新数据的话至少保证按电池片分组切出来。验证脚本要做的事有两件跑出每张图的预测结果再把预测框画回原图逐张看效果。from ultralytics import YOLO model YOLO(runs/solar_panel/exp1/weights/best.pt) results model.predict( sourcesolar_panel_dataset/images/test, conf0.25, iou0.45, saveTrue, projectruns/solar_panel, nametest_vis, )参数说明conf0.25是置信度阈值低于这个值的预测会被丢弃产线上误报代价高时我一般调到 0.4漏检代价高时调到 0.15。iou0.45是 NMS 的 IoU 阈值同一目标多个框重叠时合并这个值一般不动。saveTrue会把结果图存到runs/solar_panel/test_vis/每张图上画着预测框和类别、置信度。看完可视化图我会再单独算两个指标缺陷样本上的召回率以及正常样本上的误报率。召回率用“检出的缺陷数 / 标注的缺陷总数”误报率用“正常图上被框出来的框数 / 正常图总数”。这两个指标才是产线上真正关心的数——产线宁可漏检率低一点也不能让误报把良品打成缺陷。这段验证跑完之后我还会调一次置信度阈值用上面的命令把conf改成 0.15 跑一遍对比两张结果图。如果 0.15 下缺陷多检出来很多但正常图上误报也变多说明模型能力边界就在这需要回头补数据而不是调阈值。我最早做光伏缺陷检测项目时就是没跑这一步直接用了默认阈值上线结果现场误报率翻了一倍挨了产线老大好一顿数落。从那以后我每训完一版模型都强制自己走一遍固定阈值的数据集验证把召回率和误报率打印出来贴在看板上再谈上线。这套流程看起来笨但能拦住大部分自我感觉良好的翻车希望帮到你。本文还有配套的精品资源点击获取