简介:本资源是一套基于Python开发的无人机光伏面板故障检测系统,面向计算机、人工智能、自动化及通信等专业的学生与教师,适用于毕业设计、课程大作业及工程实践场景。项目完整实现图像采集、缺陷识别(如热斑、裂纹、遮挡)、定位标注与结果可视化全流程,代码经实机调试验证,答辩获98分高分评价,兼具教学示范性与工程可拓展性。压缩包共409个文件,含289个核心Python源码(含CNN模型训练与推理模块)、52个DLL动态库及22个PYD加速模块,辅以EXE可执行程序、CFG配置文件、PTH模型权重与TF事件日志等,整体106.71MB,结构清晰便于学习与二次开发。目前已有59人下载学习,配套文档详述环境配置、数据预处理、模型训练与部署流程,并提供bat脚本、checkpoint断点续训支持及完整目录说明,特别适合零基础入门者系统掌握CV+嵌入式视觉检测技术栈。
1. 这不是“无人机+光伏”的PPT摆拍项目:它真能跑通从航拍图到故障热斑定位的完整链路,且所有代码在Win10/Ubuntu双环境实测可复现
你见过太多毕业设计标题党——“基于XXX的智能系统”,点开全是调用API、贴几张示意图、模型参数全靠手填。但这个项目不一样:它用真实无人机采集的光伏板航拍图像(含红外与可见光双模),在Python环境下完成端到端故障检测,输出带坐标框的热斑/裂纹/遮挡标注图,并生成Excel故障报告。答辩98分不是因为PPT炫酷,而是评审老师当场用自己U盘拷走代码,在实验室笔记本上5分钟跑通了demo——连TensorFlow GPU版兼容性问题都提前打了补丁。适合三类人:零基础想交差的大四学生(有详细step-by-step运行指南)、课程设计卡在数据预处理环节的自动化专业同学(提供已标注的237张光伏板样本图+YOLOv5格式转换脚本)、以及需要快速验证算法落地可行性的光伏运维工程师(支持导出ONNX模型供边缘设备部署)。它不讲大道理,只解决一个具体问题:怎么让一台消费级无人机飞一趟,回来就能告诉你哪块板子该换、哪片区域要清洗。
2. 从航拍图到故障坐标:核心流程拆解与模块选型依据
2.1 为什么选YOLOv5s而非ResNet+FCN?——轻量、快、适配无人机小目标
光伏面板故障(尤其是微米级隐裂、0.5cm热斑)在航拍图中占比极小(平均仅占图像面积0.3%),且存在严重尺度变化(同一架无人机在不同高度拍摄,单块板子像素尺寸从80×160到320×640不等)。我们对比了4种主流方案:
- Mask R-CNN:精度高但推理速度<3fps(GTX1060),无法满足实时巡检需求;
- U-Net:分割效果好,但需逐块裁剪+拼接,后处理复杂度高,易产生边界伪影;
- YOLOv8m:mAP@0.5达82.3%,但模型体积186MB,嵌入式部署困难;
- YOLOv5s:mAP@0.5为76.1%,但推理耗时仅17ms/帧(GTX1060),模型仅14.2MB,且作者已针对光伏小目标重设anchor(聚类得到3组尺寸:[12,18], [24,36], [48,72]),比默认COCO anchor提升召回率11.7%。
提示:项目中
models/yolov5s_pv.yaml文件已固化这些anchor,勿直接替换为官方yaml,否则训练会发散。
2.2 数据预处理:如何把无人机拍的歪斜图变成模型能吃的“标准输入”
无人机航拍必然存在俯仰角偏差、镜头畸变、光照不均。项目未采用OpenCV常规校正(易引入插值噪声),而是构建三级流水线:
- 几何校正层:用
cv2.findHomography匹配4个角点(需人工标定1张参考图),生成单应性矩阵; - 辐射校正层:基于灰度世界假设(Gray World Assumption),对RGB三通道分别做白平衡(代码见
preprocess/white_balance.py); - 动态裁切层:根据GPS坐标与光伏阵列CAD图纸,自动识别有效板区(非阴影/非杂草区),裁掉无信息边框。
# preprocess/geo_correct.py 核心逻辑 def correct_image(img_path: str, ref_corners: np.ndarray) -> np.ndarray: """ ref_corners: shape=(4,2), 顺时针顺序的参考图四角像素坐标 返回校正后图像(已去畸变+透视变换) """ img = cv2.imread(img_path) h, w = img.shape[:2] # 获取当前图四角GPS投影坐标(需提前用QGIS导出CSV) curr_corners = get_gps_corners(img_path) # 此函数读取exif中的GPS+姿态角 H, _ = cv2.findHomography(curr_corners, ref_corners) # 计算单应性矩阵 corrected = cv2.warpPerspective(img, H, (w, h), flags=cv2.INTER_CUBIC) return corrected参数说明:ref_corners必须是同一坐标系下的参考图四角(建议用厂区正射影像图),get_gps_corners函数依赖exifread库解析无人机照片EXIF中的经纬度与俯仰角,若你的DJI无人机关闭了GPS写入,请手动在data/gps_coords.csv中补全坐标。
2.3 模型训练:为什么用迁移学习+冻结前3层?——避免小数据集过拟合
项目仅提供237张标注图(含12类故障),远低于YOLOv5常规训练要求(≥1000张)。直接训练会导致loss震荡剧烈(实测val_loss在0.8~2.3间跳变)。解决方案:
- 加载COCO预训练权重(
yolov5s.pt); - 冻结Backbone前3个CSP结构(对应
model.model[0:10]); - 仅训练Head层与最后两个CSP(共12层),学习率设为1e-4(默认1e-2会崩溃);
- 使用Mosaic增强(概率0.5)+ HSV色彩扰动(saturation=0.7, exposure=0.4)。
训练命令(train.sh):
python train.py \ --img 640 \ --batch 16 \ --epochs 150 \ --data data/pv_fault.yaml \ --weights yolov5s.pt \ --cfg models/yolov5s_pv.yaml \ --name pv_fault_v1 \ --freeze 10 \ --lr 0.0001关键参数解释:--freeze 10表示冻结模型前10层(即Backbone全部冻结),--lr 0.0001是血泪经验——试过1e-3,第3轮就nan;--img 640是平衡精度与速度的临界值(小于640则小目标漏检率升至23%,大于640显存溢出)。
3. 部署与推理:从训练完的模型到无人机巡检报告生成
3.1 模型导出:ONNX格式为何比PyTorch原生模型更适合现场部署
毕业答辩演示用PyTorch没问题,但实际部署到无人机机载Jetson Nano或地面巡检平板时,PyTorch推理延迟高达120ms/帧(实测),而ONNX Runtime在相同硬件下仅需38ms。项目提供export_onnx.py脚本,关键配置如下:
# export_onnx.py import torch from models.experimental import attempt_load model = attempt_load('runs/train/pv_fault_v1/weights/best.pt', map_location='cpu') model.eval() dummy_input = torch.randn(1, 3, 640, 640) # 必须与训练时--img一致 torch.onnx.export( model, dummy_input, 'yolov5s_pv.onnx', opset_version=12, input_names=['input'], output_names=['output'], dynamic_axes={'input': {0: 'batch'}, 'output': {0: 'batch'}} # 支持batch size动态 )注意:opset_version=12是Jetson系列固件兼容的最高版本,若用opset_version=13导出,JetPack 4.6会报错Unsupported operator Resize。
3.2 推理脚本:如何让一张无人机照片5秒内输出带坐标的故障报告
detect.py是核心推理入口,支持三种输入模式:单图、视频流、文件夹批量。最常用的是文件夹模式(对应无人机一次飞行拍的127张图):
python detect.py \ --weights yolov5s_pv.onnx \ --source data/drone_flight_20230815/ \ --img-size 640 \ --conf 0.45 \ --iou 0.5 \ --save-txt \ --save-conf \ --project runs/detect \ --name flight_report_20230815参数详解:
--conf 0.45:置信度阈值,低于此值的检测框被过滤(经测试,0.45时漏检率6.2%,误检率2.1%,平衡最优);--iou 0.5:NMS阈值,防止同一故障被重复框出;--save-txt:生成每张图对应的*.txt文件(YOLO格式:class x_center y_center width height conf);--save-conf:在输出图上显示置信度数值(便于人工复核);- 输出目录
runs/detect/flight_report_20230815/下会生成:images/(带框图)、labels/(txt坐标)、report.xlsx(汇总表)。
report.xlsx包含5列:ImageName,FaultType,Xmin,Ymin,Confidence,其中Xmin/Ymin已自动转换为原始图像像素坐标(非归一化值),可直接导入GIS软件。
3.3 报告生成:Excel自动合并+故障分级逻辑
generate_report.py负责将labels/下所有txt整合为Excel,并按故障严重性分级:
- 一级故障(立即停运):热斑(class=0)且Confidence≥0.85,或裂纹(class=1)长度>5cm(通过像素距离换算);
- 二级故障(两周内检修):遮挡(class=2)面积占比>15%(基于bounding box面积/整图面积);
- 三级故障(季度巡检):其余所有检测结果。
# generate_report.py 关键计算 def calc_fault_level(conf: float, cls_id: int, bbox_area: float, img_area: float) -> str: if cls_id == 0 and conf >= 0.85: # 热斑高置信 return "一级" elif cls_id == 1: # 裂纹 length_px = max(bbox[2], bbox[3]) # 取宽高中较大者为长度 length_cm = length_px * 0.023 # 像素转厘米(实测:640px对应14.7cm) return "一级" if length_cm > 5 else "二级" elif cls_id == 2 and (bbox_area / img_area) > 0.15: # 遮挡超15% return "二级" else: return "三级"注意:0.023是像素-厘米换算系数,需根据你的无人机型号和飞行高度重新标定(方法见文档calibration_guide.md)。
4. 避坑:我在调试过程中踩过的7个真实坑,现在帮你绕开
4.1 现象:训练时val_loss突然飙升至10+,且持续不下降
原因:data/pv_fault.yaml中nc: 12(类别数)与models/yolov5s_pv.yaml中nc: 80不一致,导致分类头维度错配。YOLOv5在加载权重时不会校验nc,但训练时会用错误维度计算loss。
解决:严格检查两个yaml文件的nc值必须完全相同,修改后删除runs/train/pv_fault_v1/weights目录重训。
4.2 现象:推理时CPU占用100%,GPU利用率却为0
原因:detect.py默认使用CPU推理,即使你传入.pt权重。YOLOv5的--device参数必须显式指定0(GPU)或cpu。
解决:添加--device 0参数,或在代码中强制设置device = select_device('0')。
4.3 现象:导出的ONNX模型在Jetson上运行报错Segmentation fault (core dumped)
原因:Jetson Nano的CUDA版本(10.2)与PyTorch 1.10编译环境不匹配,且ONNX Runtime需安装onnxruntime-gpu而非onnxruntime。
解决:
pip uninstall onnxruntime pip install onnxruntime-gpu==1.10.0 # 必须与PyTorch版本一致4.4 现象:generate_report.py生成的Excel中坐标全为0
原因:--save-txt生成的txt文件是归一化坐标(x,y,w,h ∈ [0,1]),但脚本误当成像素坐标直接写入Excel。
解决:在generate_report.py中增加反归一化逻辑:
# 假设原始图尺寸为640x480 x_pixel = int(x_norm * 640) y_pixel = int(y_norm * 480) w_pixel = int(w_norm * 640) h_pixel = int(h_norm * 480) xmin = x_pixel - w_pixel//2 ymin = y_pixel - h_pixel//24.5 现象:无人机照片EXIF中无GPS信息,get_gps_corners函数报KeyError
原因:DJI Mavic Air 2默认关闭GPS写入,需在DJI Fly App中开启「记录GPS信息」。
解决:
- 打开DJI Fly → 设置 → 相机设置 → 开启「记录GPS信息」;
- 若已拍完,用
exiftool -GPSLatitude=31.2345 -GPSLongitude=121.4567 *.JPG批量注入坐标(需提前用RTK测绘获取精确坐标)。
5. 故障定位精度验证:用真实光伏电站数据做AB测试,误差<3.2cm
5.1 测试方法:双盲交叉验证协议
我们在华东某20MW渔光互补电站实测:
- A组:人工巡检(5名持证电工,每人独立标注100块板子,取交集作为Ground Truth);
- B组:本项目模型自动检测(同一套图像,同一台无人机拍摄);
- 评估指标:
- 定位误差:检测框中心点与人工标注中心点的欧氏距离(单位:cm);
- 分类准确率:故障类型匹配率(热斑/裂纹/遮挡等12类);
- 漏检率:人工标出但模型未检出的比例。
测试结果(n=1200块板子):
| 指标 | 数值 | 说明 |
|---|---|---|
| 平均定位误差 | 2.8cm | 在飞行高度80m时,对应图像像素误差≤12px |
| 分类准确率 | 91.3% | 热斑识别率最高(96.7%),鸟粪遮挡最低(83.2%,因形态多变) |
| 漏检率 | 4.1% | 主要发生在板子边缘(因Mosaic增强导致边缘信息丢失) |
注意:误差<3.2cm是行业验收红线(国标GB/T 37409-2019要求热斑定位误差≤5cm),本项目达标。
5.2 提升定位精度的实战技巧:两步微调法
单纯提高模型分辨率(如--img 1280)会加剧显存压力且收益递减。我摸索出更有效的组合技:
- 第一阶段:粗定位
用--img 640快速生成初始检测框(耗时17ms); - 第二阶段:精修裁切
对每个初始框,向外扩展20%像素,截取子图,用--img 1280在子图上二次检测(耗时42ms,但只处理10~15个框,总耗时<1s/图)。
# refine_detect.py 示例逻辑 for i, det in enumerate(detections): # det = [x,y,w,h,conf,cls] x1, y1, x2, y2 = int(det[0]-det[2]/2), int(det[1]-det[3]/2), int(det[0]+det[2]/2), int(det[1]+det[3]/2) # 向外扩展20% h, w = y2-y1, x2-x1 x1_pad = max(0, x1 - int(w*0.2)) y1_pad = max(0, y1 - int(h*0.2)) x2_pad = min(orig_w, x2 + int(w*0.2)) y2_pad = min(orig_h, y2 + int(h*0.2)) patch = orig_img[y1_pad:y2_pad, x1_pad:x2_pad] # 在patch上用1280模型二次检测 refined_det = model_1280(patch) # 将refined_det坐标映射回原图 final_x = refined_det[0] + x1_pad final_y = refined_det[1] + y1_pad实测此法将平均误差从2.8cm降至1.9cm,且总推理时间仅增加0.3s/图(GTX1060)。
5.3 从毕设到工程落地:我给学弟学妹的三个硬核建议
- 别迷信“高分=可用”:我的98分答辩演示用的是实验室打光棚里的标准板,但真实电站有反光、积水、灰尘。务必用你学校附近的真实光伏电站拍10张图跑一遍
detect.py,如果漏检率>15%,立刻检查--conf阈值和--iou参数; - 文档比代码重要十倍:答辩时老师问“你这个模型在阴天能用吗?”,我翻出
docs/weather_test_report.pdf里阴天/晴天/多云的mAP对比表(阴天mAP降3.2%,但仍在72.1%),这比背100行代码管用; - 留好后悔药:
sysconfig.cfg里固化了所有环境变量(CUDA路径、ONNX Runtime版本),pyvenv.cfg明确写了Python 3.8.10——每次重装系统,我只执行python -m venv env && source env/bin/activate && pip install -r requirements.txt,5分钟恢复全部功能。
从那以后我每次交接项目,都强制走一遍python test_env.py(检查CUDA、ONNX、OpenCV版本是否匹配),再跑python test_data.py(验证237张图能否全加载无报错)。这套动作成了我的肌肉记忆。希望帮到你。
本文还有配套的精品资源,点击获取