尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

光伏板积灰检测数据集:VOC+YOLO双格式与YOLOv8训练实战

发布时间:2026/9/28 20:10:12

资讯中心
01
ARTICLE

光伏板积灰检测数据集:VOC+YOLO双格式与YOLOv8训练实战

光伏板积灰检测数据集:VOC+YOLO双格式与YOLOv8训练实战
简介面向光伏电站运维与目标检测实践的数据集资源。内容聚焦太阳能光伏板积灰/灰尘检测基于1463张现场图像构建统一采用Pascal VOC与YOLO双格式标注覆盖单一类别“Dirt”共包含6822个矩形标注框可支撑YOLO系列模型在积灰检测、清洁度判断等场景下的训练与验证。数据集由labelImg工具完成标注标注规则明确适合已有基础深度学习知识的目标检测入门者及需要真实光伏场景数据的研究者。资源共2000个文件以图像、XML标注文件、TXT标注文件为主压缩包大小75.98MB目录结构清晰便于直接划分训练集与验证集。目前已有536人学习下载。需要注意图片重复度较高数据集虽保证标注准确但模型精度需自行验证。1. 太阳能光伏板积灰检测数据集VOCYOLO 双格式 1463 张图下不下先看三个点做光伏巡检的人都知道灰尘板子表面会发灰机器视觉识别时最难平衡的是“框住整个积灰区”还是“只框灰团”。这个数据集给的是已经被 labelImg 画好的 1463 张积灰检测样本VOC xml 和 YOLO txt 双格式单类别 Dirt共 6822 个框。它解决的是光伏板表面灰尘目标检测的起步问题不需要从零标注直接拆训练集、改 data.yaml、上 YOLOv8 就能跑通一条完整检测流程。适合想跑通目标检测全流程的入门者也适合做光伏运维算法预研的工程师。作者在说明里明确写了“图片重复度很高、低价出售、请谨慎下载”这不是谦虚而是下载前必须看清的提示后面我会展开讲重复样本对训练划分和验证精度的影响。2. 目录结构与双格式标注XML 和 TXT 对齐之后训练框架才不打架2.1 1463 张图对应 1463 个 XML 和 TXT数量齐整但别高兴太早压缩包解开后图片是.jpg标注同时存在.xml和.txt文件名前缀是firc_solarpanel_xxxx。三者的命名一一对应比如firc_solarpanel_1345.jpg搭配firc_solarpanel_1345.xml和firc_solarpanel_1345.txt。文件类型数量作用jpg 图像1463光伏板表面状态原图VOC xml1463保存类别名和 xmin/ymin/xmax/ymaxYOLO txt1463归一化后的中心点坐标与宽高这种一份标注双格式的情况对工程落地很友好PyTorch 系的检测框架大多认 YOLO txt而调试可视化时读 XML 更直观。数量齐整说明没有缺漏文件但图片内容重复度很高文件名后面那串数字并不代表 1463 个完全不同的组件很多是同一块板子的不同角度或连续帧。这个点先记住它直接影响后面的训练集划分和验证集评估。2.2 用 Python 解析 XML先看文件名、图像尺寸和 Dirt 框拿到 XML 后我习惯写一段小脚本把标注统计出来而不是直接扔给训练脚本。常见做法是用xml.etree.ElementTree读树结构import xml.etree.ElementTree as ET tree ET.parse(firc_solarpanel_1345.xml) root tree.getroot() filename root.find(filename).text size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) print(文件名:, filename, 分辨率:, img_w, img_h) for obj in root.findall(object): name obj.find(name).text bnd obj.find(bndbox) xmin int(bnd.find(xmin).text) ymin int(bnd.find(ymin).text) xmax int(bnd.find(xmax).text) ymax int(bnd.find(ymax).text) print(name, 框:, (xmin, ymin, xmax, ymax))这段代码做的事很直接先读size拿宽高再遍历object拿类别名和边界框坐标。输出会看到Dirt类别和一堆像素坐标。为什么强调先跑这段因为数据集里的框并不都紧贴灰尘团有些框把一片灰斑区域整体包起来这种宽松标注对检测模型来说会让预测框偏向大而松后面评估精确率时影响很大。先统计心里有数后面才好决定用多大的置信度阈值。2.3 YOLO txt 的五行字段中心点、宽高和归一化YOLO 格式的 TXT 不像 XML 那么直观它每行代表一个目标框。用文本方式打开firc_solarpanel_1349.txt你会看到类似0 0.5231 0.4872 0.1289 0.2031的结构。head -3 firc_solarpanel_1349.txt解释一下字段第 1 位0是类别 id单类别 Dirt 固定为 0第 2 位0.5231是框中心点 x 在图像宽度上的比例第 3 位0.4872是框中心点 y 在图像高度上的比例第 4 位0.1289是框宽占图像宽的比例第 5 位0.2031是框高占图像高的比例。这个坐标系统的好处是无论原图是 640×480 还是 1024×768训练时都能直接缩放。但要注意灰尘目标在很多图上非常小宽高比可能只有 0.01 到 0.03人眼在 640 像素的图上几乎看不见。如果直接用小分辨率训练这些小框很容易在特征图下采样时被丢掉。从 VOC 的 xmin/ymin/xmax/ymax 转成 YOLO 格式公式也很固定def voc2yolo(xmin, ymin, xmax, ymax, img_w, img_h): x_center ((xmin xmax) / 2) / img_w y_center ((ymin ymax) / 2) / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h return f0 {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}核心是先把像素坐标换算成相对比例再输出成六位小数的固定格式。常见翻车点有两个一是x_center写成了xmin / img_w忘记加框宽的一半二是 class id 没有从 0 开始。转换完最好拿一张图回读 txt把归一化坐标乘回宽高再在原图上画框做可视化确认没有偏移。这一章的结论是双格式让数据集适配面广但 Dirt 框偏松、目标偏小这两个特点决定了后续训练时不能无脑上来就跑。3. 划分训练集和验证集按文件名前缀分组避免重复图串集3.1 随机 shuffle 是数据泄漏的常见来源之前我拿到这类数据集第一反应是random.shuffle然后按 8:2 直接切。后来做真实场景测试时发现验证集 mAP 很高换到现场新图掉得厉害。事后分析根因就是数据重复度高同一块光伏板的连续帧一部分进了训练集另一部分进了验证集模型已经在训练时“见过”验证图分数自然虚高。这也是作者在说明里反复提示重复度高的原因。要解决这个问题不能只看文件多而是看这张图与训练集里哪些图是同源的。最简单可靠的方式是拿文件名里的编号做分组把同一来源的所有图片放到同一个集合里再按组划分。3.2 分组划分脚本保证同一编号的图片只进 train 或 val 其中一边下面是我的划分脚本核心是按firc_solarpanel_1345里的1345这组编号聚合。import os import random from collections import defaultdict img_files [f for f in os.listdir(images) if f.endswith(.jpg)] grouped defaultdict(list) for f in img_files: # 例如 firc_solarpanel_1345.jpg - 1345 seq_id f.split(_)[2] grouped[seq_id].append(f) groups list(grouped.keys()) random.seed(42) random.shuffle(groups) split_idx int(len(groups) * 0.8) train_groups set(groups[:split_idx]) val_groups set(groups[split_idx:]) train_files [] val_files [] for g in train_groups: train_files.extend(grouped[g]) for g in val_groups: val_files.extend(grouped[g]) print(ftrain images: {len(train_files)}, val images: {len(val_files)})要关注的参数就这么几个split_idx int(len(groups) * 0.8)80% 的编号组进训练集20% 进验证集。如果样本量小可以把比例改成 0.7 或多留 5% 做测试。random.seed(42)固定随机种子复现结果时不会每次跑出来不一样。用集合set去重避免同一个编号出现在两个集合中。这段脚本只输出了图片列表真正使用时要把对应图片和标注一起复制到images/train、labels/train这样的目录结构里YOLOv8 训练时会自动按data.yaml里的路径找同名的 txt 标注。import shutil from pathlib import Path base Path(solar_dataset) for f in train_files: shutil.copy(fimages/{f}, base / images/train / f) shutil.copy(flabels_yolo/{f.replace(.jpg, .txt)}, base / labels/train / f.replace(.jpg, .txt)) for f in val_files: shutil.copy(fimages/{f}, base / images/val / f) shutil.copy(flabels_yolo/{f.replace(.jpg, .txt)}, base / labels/val / f.replace(.jpg, .txt))复制完检查一下目录数量train 和 val 的图片数相加要等于 1463labels 对应 txt 也要相等。少了说明文件名对不上通常是.jpg和.JPG后缀大小写不一致导致的。3.3 标注分布检查单类 6822 框在划分后是否均衡划分完还要确认一件事灰尘框有没有集中出现在训练集而验证集一张带框的都没有。这种情况在重复度高的数据集里经常发生因为同一组图片的框数极度相似。def count_boxes(file_list): total 0 for f in file_list: txt_path os.path.join(labels_yolo, f.replace(.jpg, .txt)) with open(txt_path) as fp: total len(fp.readlines()) return total print(train 框数:, count_boxes(train_files)) print(val 框数:, count_boxes(val_files))这段逻辑是逐行读 YOLO txt每行代表一个框。Dirt 类全数据集总共 6822 个框平均每张 4.66 个框。如果 val 的框数明显偏低说明验证集偏向于“干净板子”模型只需要学会输出零框就能拿到不错的表现评估没有意义。这时要回到分组划分按框数重新均衡两个集合。把验证集质量搞扎实后续判断模型是否过拟合才有参考价值。这一章值得多花十分钟自查。4. 用 YOLOv8 训练积灰检测模型data.yaml、训练命令和五组关键参数4.1 按 YOLOv8 标准目录整理数据YOLOv8 的默认数据组织方式是 images 和 labels 两大目录里面再分 train/val。刚才划分阶段生成的train_files和val_files已经用shutil.copy复制到solar_dataset下了。结构如下solar_dataset/ images/train images/val labels/train labels/val注意 labels 里只放 YOLO 的 txt 文件XML 不用放进来因为 Ultralytics 训练时读的是 txt。如果你的项目同时需要 VOC 格式调试可以把 XML 放在另一个目录但 data.yaml 一定指向 txt 所在目录。这个布局是整个流程的骨架后面换数据集、换机器都是这套规矩。4.2 data.yaml 配置单类也要把类别名写对下面是一份可用的data.yamlpath: solar_dataset train: images/train val: images/val nc: 1 names: 0: Dirt重点解释几个字段path写数据集根目录相对路径和绝对路径都可以推荐相对路径方便换机器训练。train和val是在path下的相对路径YOLOv8 支持单字符串或列表。nc类别数这个数据集是单类必须写1写多会导致类别维度不匹配。names用字典格式键从 0 开始类名要和训练输出对应。YOLO txt 里的第一个数字0就对应这里的Dirt。很多人把names: {Dirt: 0}写反了虽然 Ultralytics 偶尔能自动修正但最好按规范写。单类数据集最容易出的问题不是类别名而是背景样本太多导致模型学成“什么框都不出”。4.3 训练命令与关键参数imgsz、batch、lr0、patience在终端里执行训练最省事的方式是用命令行yolo detect train \ datasolar_dataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ device0参数怎么选我的经验如下modelyolov8n.pt用官方预训练权重初始化会先从本地缓存找权重没有就自动下载。如果离线环境下载失败就把权重文件放到固定缓存目录里再写绝对路径。网络正常时不用管。imgsz640默认值。但灰尘目标偏小如果显卡显存允许建议改成960或1280。目标越小输入分辨率越影响召回率。batch16取决于显卡显存。8G 显存跑yolov8n可以上 3216G 可以尝试 batch 64。显存不够先降 batch不要直接降 imgsz。lr00.01默认。数据量只有 1463 张且重复高时学习率再低一点比如0.005不容易震荡。patience20连续 20 个 epoch 验证集没有提升就早停。这个值用来防过拟合非常有效。训练完成后runs/detect/train/weights/下会生成best.pt和last.pt。接下来要做的是看曲线不是急着跑推理。4.4 从 results.csv 判断过拟合不要只看 mAP训练日志里的 mAP50 和 mAP50-95 容易让人产生错觉。重复度高的数据集常出现 mAP50 高但泛化差的情况。我的习惯是训练结束后立刻读runs/detect/train/results.csv对比训练 loss 和验证 loss 的间距。import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/detect/train/results.csv) plt.plot(df[epoch], df[train/box_loss], labeltrain_box_loss) plt.plot(df[epoch], df[val/box_loss], labelval_box_loss) plt.legend() plt.show()正常的趋势是两条线一起下降并靠近如果 val_box_loss 在某个 epoch 后开始掉头往上而 train_box_loss 还在降就是过拟合信号。此时该做的是回第 3 章去重而不是堆 epoch。另一个检查点是confusion_matrix.png单类看 background 误报是否居高不下背景误报高说明图片里灰尘区域太小模型找不到目标这时候优先提高 imgsz而不是调训练轮数。5. 常见问题与避坑拿到数据集后最容易踩的五个坑5.1 重复图让验证分数虚高现象训练时 mAP50 冲到 90% 以上一到现场新图就漏检。原因文件名前缀相同的图片在随机划分时被同时分进 train 和 val模型记住了场景而不是学会“灰尘长什么样”。作者已在说明中提示图片重复度很高这个坑几乎是必然踩到。解决严格按 3.2 的分组脚本划分同一个编号的图只允许出现在一侧。如果条件允许更狠的做法是把重复帧完全去重只保留每个编号下差异最大的一到两张再用去重后的子集训练。5.2 Dirt 标签框太松框住整个灰斑而非单个灰尘团现象模型预测出来的框很大把干净区域也包进去视觉上像“圈地”。原因labelImg 标注时对一片密密麻麻的灰尘区直接画一个外接矩形框住整体而不是每个灰团一个框。这种宽标注在评估时因为 IoU 较大mAP 不会被惩罚但实际定位精度差。解决训练时把置信度阈值调高到 0.35 甚至 0.5滤掉边缘模糊的大框推理后按宽高比筛掉面积异常的框如果要做精细检测需要自己补一批更紧的框数据。5.3 VOC 转 YOLO 时中心坐标计算错位现象训练 loss 不降打开 txt 一看坐标值大于 1 或者全是 0.5。原因转写脚本时把x_center直接写成(xmin xmax) / 2 / img_w手一滑就漏了括号或者把归一化的宽高又做了一次除以 2。解决用 2.3 的voc2yolo函数并做回读校验。取一张图把 txt 里的值乘回宽高画框叠加在用 OpenCV 读出的原图上肉眼确认框的位置和灰尘区域匹配再批量转换。5.4 验证集框数分布严重不均衡现象val 的 loss 很低但 val 里大多数图根本没有框。原因重复度高的数据里同组图片标注稀疏分组划分后恰好把“干净组”整组分到了验证集。解决每次划分后都要跑一遍 3.3 的框统计。如果 val 框数占比和图片占比相差超过 10%重新调随机种子或按分组手动均衡保证验证集至少有一半以上图像带框。5.5 把数据集当全部生产数据用现象训练完拿去做实际光伏电站巡检遇到倾斜角度、阴天、背板反光就抓瞎。原因这只是一个标注好、价格低的起步数据集不覆盖所有光伏板材质、光照和灰尘形态。作者也特别声明不对模型精度作任何保证。解决把这份数据当成流程验证和基准测试不要当成最终生产数据。真正落地前至少要补拍本电站的 500 张以上现场图沿用同样的 VOC/YOLO 双格式做增量微调。6. 进阶把 Dirt 框转成积灰覆盖率用面积占比验证模型效果6.1 批量推理并输出检测框坐标模型训练到够用之后最有价值的输出不是“图上有灰尘”而是“这块光伏板积灰面积大概占多少”。在运维场景中这个面积占比直接对应清洗决策。我一般用下面的脚本做推理统计import cv2 from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) img cv2.imread(test_solar.jpg) results model.predict(img, conf0.35, iou0.5)[0] boxes results.boxes.xyxy.cpu().numpy() img_area img.shape[0] * img.shape[1] dirt_area 0 for x1, y1, x2, y2 in boxes: dirt_area (x2 - x1) * (y2 - y1) print(f预测框总面积占比: {dirt_area / img_area:.1%})这里conf0.35是为了过滤宽松标签造成的大而模糊的框iou0.5用于去重叠。如果检测到的框非常多且密集直接按框面积求和会高估覆盖率因为灰尘其实是稀疏分布的。遇到这种情况我会在求和前先按单框面积过滤把像素面积小于图像总面积 0.2% 的框视为噪声。6.2 用覆盖率趋势做模型验证这个方法比单纯看 mAP 更贴近业务选一块积灰程度中等的板子人工目测给出一个粗略的积灰等级再和模型算出的覆盖率对照。如果外观上有明显灰尘但模型输出趋近于零说明召回不够需要回去提高 imgsz 或补充小目标样本。如果模型输出覆盖率明显高于目测说明框太松应该调高置信度或重新标一批紧框。从那以后我每次拿到这种“重复度高、标签偏松”的下载数据集都会强制走一遍全集去重、分组划分、框分布统计、裸测真实图这四条流程再决定用不用它。可以这么说这个数据集本身不完美但用它能完整演练一遍“VOCYOLO 双格式转训练、评估、误判排查、面积量化”的工程链路对刚接触目标检测的人很值得。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。