资讯动态

无人机电力巡检线树检测数据集详解:VOC/YOLO格式与YOLOv8训练实践

发布时间:2026/10/22 9:18:41 来源:尧图企业网站定制
1. 无人机电力巡检为什么要做“线树检测”应用场景与数据价值1.1 “线树矛盾”是巡检现场最头痛的老大难做无人机电力巡检的朋友应该都有同感航拍这关其实不难难的是拍回来的图怎么看、怎么用。线路走廊大部分穿过山区和林区植被在春夏两季疯长树枝、竹子一旦逼近导线遇到潮湿天气就可能放电、跳闸甚至引发山火。这类隐患有个近乎行话的说法叫“线树矛盾”几乎是外线班组每天都在盯的事情。人工巡检的效率瓶颈很明显一条线路几十公里光靠人开车、走路逐基杆塔看一天跑不了多少。无人机飞一遍虽然快但导出的航拍图少则几千张、多则上万张回放筛查全靠肉眼看久了不仅眼睛疲劳漏判也难免。真正有用的方案是把目标检测模型搬过来让算法自己去框出“电缆”和“植被”这两类目标再结合可见光图像中的位置关系判断侵限风险。这也是无人机航拍电缆植被检测这类项目越来越受关注的核心原因。1.2 6187张的数据集到底解决了什么问题我这两天整理了一套无人机航拍电缆植被检测数据集共 6187 张图片VOC 和 YOLO 两种标注格式都齐了。数量看起来不算夸张但在航拍电力场景里这已经是相当可用的规模。要知道航拍数据获取本身就有门槛要联系线路、等天气、飞航线、拍完还要一帧帧筛图然后人工框几百张图就够熬夜的。6187张图意味着你可以走比较标准的训练流程分出训练集验证集、做数据增强、用预训练权重微调而不必担心数据量太少导致模型完全训不动。这套数据适合谁首先是做电力巡检智能化项目的开发者你要训练一个线路走廊隐患识别模型手里最缺的就是带标注的现场数据其次是做目标检测方向研究的学生想拿一份真实航拍场景练手VOC和YOLO双格式免去了到处找转换工具的麻烦再就是做无人机方案集成的工程师想快速验证“能不能在机载设备上实时识别植被和电缆”。不管是哪种用途你先要弄清楚格式怎么组织、类别怎么定义、坐标怎么换算然后才能稳稳当当地把训练跑起来。2. 数据集实拆VOC和YOLO格式目录、标注类别与图像特征2.1 VOC和YOLO两种格式到底长什么样VOC格式沿用的是 Pascal VOC 的那套目录习惯核心是每张图对应一个XML文件。XML里写清楚了图片宽度、高度以及每个目标的类别名和 bndbox 坐标也就是左上角和右下角的像素坐标。目录大致长这样dataset/ ├── JPEGImages/ # 所有jpg图片 │ ├── 000001.jpg │ └── ... ├── Annotations/ # 对应的XML标注 │ ├── 000001.xml │ └── ... └── ImageSets/Main/ # 可选的训练/验证划分列表YOLO格式就简单粗暴了每张图对应一个同名的txt文件每一行表示一个目标类别ID、归一化后的中心点x、中心点y、宽度w、高度h。所有数值都除以了图片宽高落在0到1之间所以换不同训练分辨率也不用重新算坐标。dataset/ ├── images/ │ ├── 000001.jpg │ └── ... └── labels/ ├── 000001.txt └── ...两种格式各有用处。VOC信息更完整适合手工查看、二次编辑YOLO格式是各个YOLO版本直接吃的格式训练前基本不用额外处理。2.2 先别急着训练把标注类别搞清楚很多新手拿到数据集就套模板开训结果类别名对不上模型输出的类别跟自己的预期完全是两回事。最稳妥的做法是写个脚本把XML里的 name 标签扫一遍统计都有哪些类。基于这类项目的常见实践标注里一般会包含两个核心类别电缆cable和植被/树木tree。有些同类型数据集还会额外标注杆塔pylon因为杆塔既是线路结构的参照物也是无人机巡检经常入镜的强目标。我建议你拿到数据后先执行下面这段扫描import xml.etree.ElementTree as ET from pathlib import Path annot_dir Path(Annotations) class_set {} for xml_file in sorted(annot_dir.glob(*.xml)): tree ET.parse(xml_file) root tree.getroot() for obj in root.iter(object): name obj.find(name).text.strip() class_set[name] class_set.get(name, 0) 1 print(类别统计, class_set)扫描完你会看到每一类的样本数量。如果某一类比另一类少很多后面训练时就得留意类别不平衡问题。另外要确认标注文件的类别名跟你的任务定义一致你的业务如果只关心“树离导线多近”那类别就是 tree 和 cable如果还要识别线路上的其他部件就按需增删类别ID。YOLO格式里类别顺序和名字不是固定的它只认ID所以你在配置文件中怎么设置模型就怎么输出。2.3 图像内容和标注尺度有什么特点这套数据因为是无人机视角图像特征和普通目标检测数据集有明显的区别。首先是视角特殊大部分图是俯拍或斜俯拍目标不像行车记录仪拍出的物体那样正立清晰姿态变化很大其次是光照不统一同一条线路可能上午飞一边顺光、下午飞另一边逆光图里反差很大再有就是目标尺度悬殊杆塔在画面里可能占几百个像素而远处的电缆往往只有几个像素宽横穿整张图。标注方面也要多留个心眼。有的标注框贴着目标严丝合缝有的则宽松一些把周边的浅色光晕也算进去了。这两种风格各有取舍框得紧模型回归目标位置时更精确但容易漏掉边缘框得宽训练更容易收敛但测试时预测框往往偏大。实际操作中不用纠结哪种更好保持训练集和验证集标注风格一致就行。3. 数据预处理与格式转换实操3.1 第一步先做数据体检不要拿到数据直接开训先做一遍体检。航拍数据常见这几个坑下载解压后图片损坏、标注XML缺失、图片跟XML名字对不上、某些XML的 bndbox 里有负数或者宽高为0。这些问题不会报错只会悄悄拉低训练效果。我习惯的检查顺序是先统计 JPEGImages 和 Annotations 的数量是否一致再抽样解析XML看看是否有空标注和越界坐标。写个简单脚本from pathlib import Path import xml.etree.ElementTree as ET from PIL import Image img_files {p.stem for p in Path(JPEGImages).glob(*.jpg)} xml_files {p.stem for p in Path(Annotations).glob(*.xml)} print(图片数, len(img_files)) print(标注数, len(xml_files)) print(有图无标注, len(img_files - xml_files)) print(有标注无图, len(xml_files - img_files)) # 检查图片是否损坏 for p in Path(JPEGImages).glob(*.jpg): try: img Image.open(p) img.verify() except Exception: print(损坏图片, p.name)这套检查跑完基本能保证后续转换不会因为文件缺失中途报错。3.2 VOC转YOLO的Python脚本与坐标细节把VOC转成YOLO核心就是读XML里的 bndbox再换算成归一化坐标。细节决定成败下面这几个点最容易出错第一VOC里 xmin/ymin/xmax/ymax 是像素坐标YOLO要求的是中心点加宽高第二转换后数值要除以图片的真实宽高不是XML里记录的宽高再相信一次最好以实际读取的图片尺寸为准第三个别标注框可能超出了图像边界直接写入txt会导致训练时解析报错要裁剪到0到1的范围并过滤宽高为负的无效框。以下是一个通用转换脚本类名到ID的映射你自己定义import xml.etree.ElementTree as ET from pathlib import Path from PIL import Image annot_dir Path(Annotations) save_dir Path(labels) save_dir.mkdir(exist_okTrue) class_dict {tree: 0, cable: 1} # 按实际情况调整 for xml_file in sorted(annot_dir.glob(*.xml)): tree ET.parse(xml_file) root tree.getroot() # 以实际图片尺寸为准 img_path Path(JPEGImages) / (xml_file.stem .jpg) with Image.open(img_path) as img: width, height img.size txt_path save_dir / (xml_file.stem .txt) lines [] for obj in root.iter(object): name obj.find(name).text.strip() if name not in class_dict: continue box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) # 防止坐标越界约束在有效像素范围内 x1 max(0, min(x1, width - 1)) y1 max(0, min(y1, height - 1)) x2 max(0, min(x2, width - 1)) y2 max(0, min(y2, height - 1)) # 过滤掉宽或高为0的无效目标 if x2 x1 or y2 y1: continue x_center (x1 x2) / 2 / width y_center (y1 y2) / 2 / height box_w (x2 - x1) / width box_h (y2 - y1) / height lines.append(f{class_dict[name]} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) txt_path.write_text(\n.join(lines), encodingutf-8) print(转换完成)转换后建议随机挑几张图把txt里的坐标画回图上对比确认没有框错位。3.3 训练集和验证集怎么划分才靠谱划分数据看起来一句话的事实际上坑不少。最忌讳的是直接按文件名顺序前80%训练、后20%验证因为航拍数据往往是一条航线连续拍的相邻帧内容高度相似这样划分会导致训练集和验证集之间存在大量重复场景验证指标虚高。我实际操作时通常按“航线或拍摄批次”划分没有额外元信息时就按文件名排序后做间隔抽样或者用分层抽样让每类目标在训练和验证里的比例接近。分层抽样可以直接用 sklearnfrom pathlib import Path from sklearn.model_selection import train_test_split # 假设已经有 images 目录和 labels 目录 images sorted(Path(images).glob(*.jpg)) # stratify需要每张图的类别信息这里简化为按文件名序列分层 # 也可以用每张图标签中的类别ID作为分层依据 train_imgs, val_imgs train_test_split( images, test_size0.2, random_state42 )如果你想要每张图的类别信息做真正的分层可以解析对应txt的第一列按其作为 stratify 参数。验证集保持在 15%~20% 就差不多再大反而浪费训练样本。4. 基于YOLOv8的模型训练实操从配置文件到调参4.1 环境准备和数据配置文件YOLOv8是目前我跑这类场景用得最顺的框架安装直接一条命令pip install ultralytics训练前要写一个数据配置文件告诉模型图片路径、验证路径和类别名。格式如下path: /data/cable_vege train: images/train val: images/val names: 0: tree 1: cable注意 path 是数据集根目录train和val是相对路径。如果目录里没有单独的 train/val 子目录只有 images 和 labels可以先把 images 按比例拆成 train 和 val 两个目录labels 也要对应拆成两份保证图片和标签相对路径完全一致。我习惯用一个小脚本同步拆分避免手工移动导致某个验证图片找不到标签。4.2 训练参数选择模型大小、分辨率、批次和轮次跑这类检测任务模型大小选择很直接。机载设备或边缘盒子算力有限优先用 yolov8n 或 yolov8s服务器训练可以做实验出效果用 yolov8m。分辨率方面无人机拍摄的电缆在原始图里往往很细如果用默认的 640x640 输入小目标会被降采样到几个像素很难学出特征。这套数据我建议训练和推理都开 imgsz1280 或至少 1024代价是显存占用涨好几倍。批次大小取决于显存做一张参数对照表会更清楚配置项推荐值说明imgsz1024~1280太高容易OOM太低小目标漏检batch4~1624G显存可跑8起步小显存配合 accumulateepochs100~200有早停兜底够用patience20连续20轮验证指标不升就停pretrainedyolov8m.pt迁移学习效果远好于随机初始化训练命令很简单yolo train modelyolov8m.pt datacable_vege.yaml epochs150 imgsz1280 batch8 patience20如果显存不够可以先把 batch 调小到4再加 accumulate8 模拟更大的批大小效果类似但训练时间会拉长。4.3 训练指标怎么看什么时候该停训练过程中重点看两个曲线一个是训练集和验证集的 loss 有没有同步下降另一个是验证集的 mAP50 和 mAP50-95 是否还在上升。电力场景下我更关心 recall召回率因为漏掉一棵贴近导线的树比误报几棵树严重得多。mAP50-95 在航拍小目标场景通常会比 mAP50 低不少这是正常现象不必慌。训练结束后去看 per-class 的 AP。如果 tree 类 AP 很高而 cable 类 AP 明显低说明电缆这种细长小目标没学好解决办法通常是提高输入分辨率、增强训练数据里的尺度变化或者单独采样一些含电缆的图像做重训。另外一定拿出几十张验证图看一眼模型可视化输出指标再漂亮框得偏不偏、有没有把山间小路当电缆还是肉眼看得准。5. 实测踩坑记录漏检、误检、数据泄漏与标注问题排查5.1 小目标漏检分辨率不够和Mosaic增强的取舍无人机航拍里电缆是最容易漏的一类。电缆在画面里往往只有几个像素宽前景背景对比度又低模型很容易把它忽略。我实测下来最有效的手段就是抬 inference 分辨率其次是在训练后期关闭Mosaic增强。Mosaic增强对小目标其实有点坑四张图拼在一起目标再被缩小一次本来就细的电缆变得更细反而帮倒忙。如果你用的是较新版Ultralytics可以在训练命令里加 close_mosaic10意思是最后10轮关闭Mosaic。老版本没有这个参数也不用纠结手动改成常规训练即可。推理阶段还可以考虑把大图切成若干小图分块检测再合并结果对极小目标效果提升非常明显代价是推理时间变长。5.2 误检怎么压背景干扰、置信度阈值和后处理误检同样让人头疼。最常见的是把道路、栅栏、输电线杆附近的拉线等线性结构识别成电缆。这类误检单看模型输出很难根除因为形态上确实像。我的经验是三个方向一起使劲。第一数据层面尽量补充“难负样本”也就是不含电缆但有很多线性结构的航拍图标注为空即可让模型学会在这些背景上闭嘴。第二调高推理置信度阈值从默认的0.25调到0.3或0.35误检会明显变少前提是漏检没有明显增加。第三加后处理规则比如按检测框的长宽比过滤真正电缆的框通常是长条形的ratio明显偏离的框直接丢掉。排查误检还有一个笨但有效的办法把预测结果导出成图片按类别分别归档花十分钟快速翻一遍就能看到误检集中在哪类背景上然后针对性处理。5.3 数据泄漏与标注质量一个值得反复自查的动作数据泄漏在航拍数据里很容易踩。同一航线相邻帧往往很相似如果随意随机划分模型可能在验证集上表现得异常好一上真实新数据就垮掉。判断方法很简单看验证集的mAP是不是高得离谱而loss又一直降不下来两者不匹配就要怀疑泄漏。解决办法是重新按航线或时间间隔划分数据。标注质量方面最常见的问题是类别名不统一比如有人标“tree”有人标“vegetation”脚本按名称映射时漏掉了一类模型训练时类别数就对不上。另外如果转换YOLO格式后发现训练时提示 labels 越界十有八九是原始标注框坐标超出了图片范围脚本里一定得做 clip 和过滤。我每次开始训练前都会做一次可视化检查把几十张图的标注框画出来用眼睛过一遍虽然费点时间但比训了半天才发现数据错了强得多。我把这几种常见问题整理成一个速查表方便对照现象大概率原因排查方向验证mAP极高但测试效果差数据泄漏检查训练/验证划分是否同航线相邻帧loss降不下去标签越界、类别错乱检查txt坐标是否在0~1、类别ID是否匹配cable类AP低目标过小、样本少提高imgsz、补充数据、关闭Mosaic大量线性结构误检背景干扰、无负样本补充负样本、调高conf阈值、加长宽比过滤训练时OOM显存不足降batch、降imgsz、开accumulate6. 一些实际操作后的体会关于这套数据我最想多说一句的是别小看数据整理这一步。很多人拿到6187张图第一反应是赶紧把训练跑起来但实际上花半天做体检、转格式、划数据后面能省好几天返工的时间。我自己踩过连续帧泄漏的坑也踩过类别名不统一的坑都是看着不起眼、影响却很大的问题。另外如果后续要落地到实际巡检项目我建议你在检测完目标之后加上一个简单的距离判断逻辑知道相机分辨率和飞行高度时可以把图像像素距离估算成实际距离再按线路电压等级对应的安全距离配置告警阈值。这样从“检测出树和电缆”推进到“判断是否侵限”整套方案的价值会上升一个台阶。数据是死的怎么用才是活功夫。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑