简介:本资源为基于YOLOv8的光伏电池缺陷检测项目源码包,面向具备一定深度学习基础的目标检测学习者与工业质检开发者,用于解决划痕、污渍、裂纹等光伏电池表面缺陷的自动识别问题。压缩包共1111个文件,约31.97MB,以159个Python脚本、68个YAML配置、220个TXT说明及267张PNG效果图为主,另含少量权重文件、Dockerfile与Jupyter笔记,覆盖训练、推理与部署环节。项目核心提供train.py与predict.py两个脚本,分别负责数据集加载、参数配置、训练与权重保存,以及在测试图像上输出边界框和类别,并涉及数据增强、学习率调度等策略。目前已有557人学习下载,读者可借此掌握YOLOv8单阶段检测流程、缺陷数据集标注思路与GPU环境部署细节,并理解模型迭代优化方向。
1. 光伏电池缺陷检测为什么值得用 YOLOv8 重做一遍
光伏组件出厂前的 EL 和电致发光成像检测,长期依赖人工目检和传统视觉算法。人工看片一天几千张,漏检率随疲劳度飙升;传统 OpenCV 方案靠阈值和形态学,遇到隐裂、断栅、黑斑这类低对比度缺陷就频繁翻车。YOLOv8 把检测框回归和分类头解耦,配合 CSPDarknet 主干和 PAN-FPN 颈部,在小目标密集排列的电池片场景里天然占优。这个项目要解决的核心问题是:把光伏电池片图像里的隐裂、断栅、黑斑、混片、缺角等缺陷自动框出来并分类,替代人工复检。适合有 Python 基础、想跑通工业缺陷检测全流程的工程师,也适合手里有产线图像但不知道怎么标注和训练的人。读完你能拿到一套从数据标注、训练调参到推理部署的完整路径,以及几个我踩过的坑。
2. 光伏电池缺陷检测的数据集怎么建才不白干
2.1 缺陷类别定义与标注粒度
光伏电池缺陷检测的类别定义直接决定模型上限。我一般把类别控制在 5 到 7 类,太细会导致类间样本极度不平衡,太粗又失去分拣价值。常见做法是分成:隐裂(micro-crack)、断栅(finger break)、黑斑(black spot)、混片(mixed cell)、缺角(edge chip)、焊带偏移(ribbon shift)。标注粒度上有个血泪经验:隐裂在 EL 图像里往往是一条细线,用矩形框标注时框会很大但目标像素极少,建议隐裂单独用分割标注或者放大框后做后处理裁剪,否则 YOLOv8 的检测头学到的特征被背景稀释。
标注工具用 LabelImg 或 X-AnyLabeling 都行,导出 YOLO 格式的 txt。每张图对应一个 txt,每行格式是class_id x_center y_center width height,全部归一化到 0 到 1。这里有个容易忽略的点:光伏电池片图像通常是高分辨率整版图,直接缩放到 640 会让隐裂消失。我的做法是先切图,把整版按电池片网格切成单片的图,再送标注。
import cv2 import os # 将整版 EL 图像按 6x10 网格切成单片电池片 img = cv2.imread("panel_el.png") h, w = img.shape[:2] rows, cols = 6, 10 cell_h, cell_w = h // rows, w // cols os.makedirs("cells", exist_ok=True) for r in range(rows): for c in range(cols): cell = img[r*cell_h:(r+1)*cell_h, c*cell_w:(c+1)*cell_w] cv2.imwrite(f"cells/cell_{r}_{c}.png", cell)这段代码把整版图按行列切分。rows和cols要根据你的组件版型改,常见 60 片版型是 6×10,72 片是 6×12。切完后每张单片图分辨率大概 300 到 500 像素,隐裂至少占几个像素,缩放后还能保留。切图时注意边缘留 2 到 3 像素重叠,避免缺陷正好落在切割线上被切碎。
2.2 数据增强与类别不平衡处理
光伏缺陷检测的类别不平衡非常严重,正常片远多于缺陷片,隐裂又远少于黑斑。YOLOv8 自带 mosaic、mixup、随机翻转等增强,但默认配置对工业图像不够。我一般会做三件事:第一,对缺陷样本做离线过采样,把隐裂样本复制 3 到 5 倍;第二,在data.yaml里不设fraction,让全部数据参与;第三,训练时用copy_paste增强,把缺陷区域抠出来贴到正常片上,这个对隐裂特别有效。
# data.yaml path: ./pv_dataset train: images/train val: images/val nc: 6 names: 0: micro_crack 1: finger_break 2: black_spot 3: mixed_cell 4: edge_chip 5: ribbon_shiftnc是类别数,必须和 names 数量一致。path用相对路径时是相对于 ultralytics 的运行目录,建议写绝对路径避免找不到。train 和 val 分别指向图像目录,YOLOv8 会自动找同名的 labels 目录下的 txt。如果验证集里某些类别样本太少,mAP 会剧烈波动,建议每类至少留 50 个验证样本。
提示:切图后一定要检查有没有把缺陷切到两张图各一半的情况,这种样本标注框会跨图,训练时直接报错或者学出奇怪特征。
3. YOLOv8 训练光伏缺陷模型的参数怎么设
3.1 环境配置与预训练权重选择
环境配置是新手第一道坎。我一般用 conda 建一个干净环境,Python 3.9 到 3.10 都稳,3.11 在某些 CUDA 版本上会出玄学问题。装 ultralytics 直接用 pip,不要手动装 torch 再装 ultralytics,让它自己解析依赖。
conda create -n pv_yolo python=3.10 -y conda activate pv_yolo pip install ultralytics # 验证 GPU 是否可用 python -c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))"如果输出True和你的显卡型号,说明环境通了。GTX 1660 Ti 跑 YOLOv8n 或 YOLOv8s 完全够用,6GB 显存把batch设到 8 到 12,imgsz设 640。预训练权重选yolov8s.pt比较平衡,n 版精度对隐裂偏低,m 版在 1660 Ti 上训练慢到怀疑人生。下载权重时注意放在项目根目录,训练命令里直接写文件名。
3.2 训练命令与关键参数含义
训练命令看起来简单,但参数设错就是几小时白跑。我常用的命令如下:
yolo detect train \ model=yolov8s.pt \ data=./data.yaml \ epochs=200 \ imgsz=640 \ batch=8 \ lr0=0.01 \ lrf=0.01 \ patience=30 \ workers=4 \ device=0 \ project=pv_runs \ name=exp1epochs=200是上限,实际靠patience=30早停,30 轮验证 mAP 不升就停。lr0=0.01是初始学习率,光伏数据量小的时候可以降到 0.005,否则前期 loss 震荡。lrf=0.01是最终学习率因子,余弦退火到初始的 1%。workers=4是数据加载线程,Windows 上设太高会卡死,Linux 可以到 8。device=0指定第一块 GPU,CPU 训练把 device 设成cpu但速度没法看。
训练过程中重点看三个指标:box_loss和cls_loss是否稳定下降,mAP50是否在涨。如果cls_loss不降反升,大概率是类别标注有错或者学习率太大。如果mAP50卡在 0.5 左右不动,检查验证集里是不是有大量未标注缺陷。
3.3 损失曲线与训练过程可视化
YOLOv8 训练完会在project/name下生成results.csv,里面记录了每轮的 loss 和 mAP。画损失函数曲线图是排查训练问题的基本手段。
import pandas as pd import matplotlib.pyplot as plt df = pd.read_csv("pv_runs/exp1/results.csv") df.columns = df.columns.str.strip() # 列名可能带空格 fig, axes = plt.subplots(1, 2, figsize=(12, 4)) axes[0].plot(df["epoch"], df["train/box_loss"], label="box_loss") axes[0].plot(df["epoch"], df["train/cls_loss"], label="cls_loss") axes[0].set_xlabel("epoch"); axes[0].set_ylabel("loss"); axes[0].legend() axes[1].plot(df["epoch"], df["metrics/mAP50(B)"], label="mAP50") axes[1].plot(df["epoch"], df["metrics/mAP50-95(B)"], label="mAP50-95") axes[1].set_xlabel("epoch"); axes[1].set_ylabel("mAP"); axes[1].legend() plt.tight_layout(); plt.savefig("train_curve.png", dpi=150)results.csv的列名在不同 ultralytics 版本里可能略有差异,用strip()去空格是保险做法。左图看 loss 是否收敛,右图看 mAP 是否过拟合。如果训练 loss 一直降但验证 mAP 早早就平了,说明过拟合,加增强或者减模型容量。如果两条 loss 都剧烈震荡,把lr0减半再跑。
4. 光伏缺陷检测的避坑与排查记录
4.1 隐裂漏检严重,mAP 只有 0.3
现象:训练完黑斑和断栅 mAP 都在 0.8 以上,隐裂只有 0.3 左右。原因:隐裂在 640 输入下像素太少,YOLOv8 的 P3 特征图 stride 是 8,隐裂特征在浅层就被池化掉了。解决:把imgsz提到 1024,或者改用yolov8s-seg做分割,再或者把隐裂样本单独放大裁剪后训练。我最后是把 imgsz 设 1024 加隐裂过采样,mAP 拉到 0.65。
4.2 验证集 mAP 很高但实际推理全是误检
现象:验证集 mAP50 到 0.9,拿产线新图推理,正常片被框出一堆缺陷。原因:训练集和验证集来自同一批图像,分布太像,模型学到了批次相关的特征比如光照和背景纹理。解决:按时间或产线批次划分训练验证集,验证集必须来自不同批次。另外推理时把conf从默认 0.25 提到 0.5,iou设 0.5 做 NMS,能压掉大部分低置信误检。
4.3 训练到一半 loss 变成 nan
现象:前 50 轮正常,突然 loss 变 nan,训练中断。原因:光伏图像里有些样本标注框宽高为 0,或者归一化后超出 0 到 1 范围,计算 loss 时除零。解决:训练前跑一遍标注检查脚本,过滤掉宽高小于 2 像素的框,把坐标 clip 到 0 到 1。另外把amp关掉(amp=False)能避免混合精度下的数值溢出,代价是显存多占一点。
4.4 推理速度在产线上跟不上
现象:模型 mAP 达标,但单张推理 200ms,产线节拍要求 50ms。原因:默认 PyTorch 推理没做优化,而且 imgsz 设了 1024。解决:导出 ONNX 或 TensorRT,用yolo export model=best.pt format=engine half=True生成 FP16 引擎,1660 Ti 上能压到 30ms 以内。如果还要更快,考虑 RK3588 部署,用 RKNN 工具链量化成 INT8,但要注意量化后隐裂精度会掉,需要拿几百张图做量化校准。
4.5 热力图可视化发现模型看错地方
现象:用 Grad-CAM 画热力图,发现模型关注的是电池片边缘而不是缺陷区域。原因:数据集中缺陷大多在边缘,模型学到了位置先验而不是缺陷特征。解决:做随机裁剪增强,把缺陷位置打乱,或者用 copy_paste 把缺陷贴到图像中心区域。这个坑很隐蔽,mAP 看不出来,但换一批布局不同的组件就崩。
5. 从训练到部署:光伏缺陷检测的进阶技巧
模型训完只是开始,真正落地要考虑推理封装和持续迭代。我一般会把推理封装成一个带后处理的类,把检测框映射回整版图坐标,再按电池片网格聚合结果。这样输出的是「第几行第几列哪片电池有什么缺陷」,而不是一堆散框,产线分拣系统直接能用。
from ultralytics import YOLO import numpy as np class PVPredictor: def __init__(self, weights, conf=0.5, iou=0.5, imgsz=1024): self.model = YOLO(weights) self.conf, self.iou, self.imgsz = conf, iou, imgsz def predict_cell(self, cell_img): # 单片电池推理,返回缺陷列表 results = self.model.predict(cell_img, conf=self.conf, iou=self.iou, imgsz=self.imgsz, verbose=False) defects = [] for box in results[0].boxes: cls_id = int(box.cls[0]) defects.append({ "class": self.model.names[cls_id], "conf": float(box.conf[0]), "xyxy": box.xyxy[0].tolist() }) return defects def predict_panel(self, panel_img, rows=6, cols=10): # 整版切分后逐片推理,返回带网格坐标的结果 h, w = panel_img.shape[:2] ch, cw = h // rows, w // cols panel_result = [] for r in range(rows): for c in range(cols): cell = panel_img[r*ch:(r+1)*ch, c*cw:(c+1)*cw] defects = self.predict_cell(cell) if defects: panel_result.append({"row": r, "col": c, "defects": defects}) return panel_resultconf和iou是推理时最该调的两个参数,产线宁可漏检不可误检时把 conf 提到 0.6 以上。predict_panel里的 rows 和 cols 要和切图时一致,否则网格对不上。这个封装的好处是推理逻辑和业务逻辑分离,换模型只改 weights 路径。
验证模型有没有真正学到缺陷特征,除了看 mAP,我还会做两个测试:一是拿正常片推理,看误检数量,正常片误检超过 5% 就不能上线;二是拿缺陷片做遮挡测试,把缺陷区域遮住再推理,如果模型还能框出来,说明它看的是背景不是缺陷。这两个测试比 mAP 更能反映真实能力。
最后说个习惯:每次训练完把data.yaml、训练命令、results.csv和best.pt一起归档到带日期的目录,产线出问题要回溯时能快速复现。我吃过亏,半年前的模型效果掉了,结果找不到当时用的哪版数据,只能重训。光伏缺陷检测这个方向,数据质量比模型结构重要得多,把标注和切图做扎实,YOLOv8 默认参数就能出可用的结果。希望帮到你。
本文还有配套的精品资源,点击获取