ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

航拍滑坡数据集VOC+YOLO格式实战:遥感目标检测训练与避坑指南

航拍滑坡数据集VOC+YOLO格式实战:遥感目标检测训练与避坑指南 简介面向遥感地质灾害监测与计算机视觉目标检测的航拍滑坡检测数据集适合研究人员、算法工程师和深度学习者用于滑坡识别模型训练、数据格式切换与检测精度验证。资源包为ZIP压缩格式大小约200.98MB共2000个文件其中以xml标注文件为主并附带说明txt覆盖4315张512×512分辨率的航拍滑坡图像提供Pascal VOC和YOLO两种标注格式滑坡目标框总计11315个类别为单一的landslide标注工具为labelImg。数据集经过增强处理但未预设训练、验证、测试划分用户可按需自行切分有利于练习数据拆分与模型调优。当前已有34人学习浏览可作为滑坡识别、遥感图像理解等方向的实验数据帮助快速搭建目标检测流程并验证算法在不同场景下的泛化能力。1. 航拍滑坡数据集是干嘛的一个行业痛点与这份数据的解法搞地质灾害遥感的人大概都有这个体验网上公开的滑坡数据不是 DEM 栅格就是灾害点坐标真正能直接喂进 YOLO 训练管线、带框标注的航拍影像集少得可怜。这个「航拍滑坡数据集 4315 张 VOCYOLO 格式.zip」正好补上这块短板——4315 张航拍影像每张都有对应的目标框标注VOC 和 YOLO 两种格式给你打包好解压就能用。它适合三类人想跑通「用自己的数据训 YOLO」全流程的初学者做应急巡检或地质灾害监测方案预研的一线工程师以及需要一份非公开风格样本做对比实验的研究生。数据本身不神秘但围绕它展开的解压、格式核对、转换、训练、避坑、验证是一条值得完整走一遍的技术链路。顺着这个标题我把每一步怎么落地和会在哪里翻车讲清楚。2. 先弄清包里装了什么VOC 与 YOLO 两种标注格式的分工2.1 VOC 侧的三件套JPEGImages、Annotations、ImageSetsPASCAL VOC 格式是这个 zip 里最直观的一半。解压后你会看到典型的 VOC 目录骨架JPEGImages放航拍原图Annotations放同名 XML 标注文件ImageSets/Main里是 train.txt、val.txt 这类划分列表。VOC 标注用像素坐标记录目标位置XML 里size给出图像宽高每个object里有name表示类别bndbox给出左上角和右下角的像素坐标。annotation folderJPEGImages/folder filenamelandslide_001.jpg/filename size width1920/width height1080/height depth3/depth /size object namelandslide/name difficult0/difficult bndbox xmin320/xmin ymin240/ymin xmax1280/xmax ymax860/ymax /bndbox /object /annotation像素坐标的好处是直观用 labelImg 或 CVAT 标注完导出就是这个结构人眼能直接和影像对得上。VOC 格式除了喂检测模型还被很多语义分割工具兼容——你拿同一份 XML 做滑坡影响范围分析也能把bndbox当成裁剪范围用。这类航拍数据集常见的一个特征是目标占画面比例偏大像上面这种从 320 到 1280 的框说明滑坡体本身就铺了一大片这会影响后续选 imgsz 的策略。2.2 YOLO 侧的具体形态images/ 与 labels/ 下的 txt 对应关系YOLO 侧就好认多了一个images目录放图片一个labels目录放同名 TXT。每行格式固定为class cx cy w h其中 cx、cy 是目标中心点坐标w、h 是目标宽高全部做了归一化取值 0 到 1。比如同一张landslide_001.jpg对应landslide_001.txt内容是0 0.4167 0.5093 0.5000 0.5741这行数字的意思是类别 ID 是 0目标中心在图像 41.67% 宽度、50.93% 高度处占宽 50%、高 57.4%。YOLO 训练时直接读这种 TXT不再需要边训练边解析 XML路径匹配靠的是同名前缀。两种格式同时下发不是脱裤子放屁。最实际的用途是交叉校验训练前写三行脚本把 YOLO 的归一化坐标乘回图像宽高和 VOC 的 bndbox 对比误差超过一个像素就说明标注有损。VOC 到 YOLO 的转换是常规操作但反过来从 YOLO 转 VOC 经常有人少了四舍五入导致框偏了几个像素在滑坡这种边界模糊的目标上无伤大雅在小裂缝目标上可能直接让 IoU 从 0.75 掉到 0.68。所以我的习惯是收到数据包先做一次一致性校验确认两个格式是同一批标注导出的而不是各自标了一遍。2.3 为什么同时发两种格式降低交接成本与两轮踩坑铺垫从工程交接的角度看发双格式的核心收益是让不同工位的同事不用等转换。做检测的拿 YOLO 版直接进训练做前处理的拿 VOC 版做裁剪和可视化做语义分割的拿 XML 做掩码生成。省掉一次全量转换也就省掉了转换脚本维护和坐标丢失排查的时间。尤其是团队里有人用老版本 detectron2、有人用 YOLOv5、还有人用自家框架统一成双格式是最省事的交接形态。这类「XX 数据集 VOCYOLO 格式.zip」的发布方式在红外电力巡检、烟草病虫害这些垂直领域已经成了事实标准因为发布者清楚下游消费方用什么工具不可控。你拿到手要做的不是质疑为什么给两份而是先确认两份标注数据对不对得上再做自己的训练计划。3. 从 VOC 转到 YOLO自写转换脚本与三个必调的坑3.1 开工前的检查先数文件再动手标题写着 4315 张解压后第一步不是写脚本而是核对数量。我一般先跑一个命令确认三个数字图像数量、XML 数量、TXT 数量。ls JPEGImages | wc -l ls Annotations | wc -l ls labels | wc -l正常情况三个数都是 4315。如果 Annotations 少了十几份多半是标注员漏存如果 labels 比 JPEGImages 多说明存在无对象标注的空文件这两个情况在训练前必须处理。空 TXT 在 YOLO 训练里不会报错但会让这张图永远没有正样本白白浪费训练时间还会在验证时拉低召回率。检查完数量再看一眼类别名不同数据包可能叫landslide、slump、crack或者干脆全部归成一类。标题没写类别数那就在Annotations里抓一次全量name字段grep -rh name Annotations | sort | uniq -c这一步输出的类别名和数量就是后续配置 YAML 的依据不要自己猜。3.2 转换脚本xml 解析到 txt 的完整套路确认没问题后按需写转换脚本。虽然包里已经给了 YOLO 格式但如果你后面自己补充标注、合并别的数据集这步躲不掉。我用 Python 的标准库写不引额外依赖跑起来最省事import os import xml.etree.ElementTree as ET from pathlib import Path class_names [landslide] # 以实际类别名为准 def voc_to_yolo(xml_file, out_txt, class_names): tree ET.parse(xml_file) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_names: continue # 过滤掉不需要的类 cls_id class_names.index(name) # 兼容没有 difficult 字段的标注 diff obj.find(difficult) difficult int(diff.text) if diff is not None else 0 if difficult 1: continue # 难样本要不要保留看任务检测大滑坡体时可跳过 box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # 像素坐标 - 归一化中心点与宽高 cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h bw (xmax - xmin) / img_w bh (ymax - ymin) / img_h # 越界裁剪后面细讲 cx min(max(cx, 0.0), 1.0) cy min(max(cy, 0.0), 1.0) bw min(bw, 1.0) bh min(bh, 1.0) lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) with open(out_txt, w, encodingutf-8) as f: f.write(\n.join(lines)) xml_dir Path(Annotations) out_dir Path(labels) out_dir.mkdir(exist_okTrue) for xml_path in xml_dir.glob(*.xml): out_path out_dir / (xml_path.stem .txt) voc_to_yolo(str(xml_path), str(out_path), class_names)这段转换最基本的输入输出XML 解析出宽高和每个目标框归一化后填六个小数精度逐行写 TXT。精度取六位已经足够因为 1920 宽的图像一像素对应 0.0005 左右六位小数远小于一个像素误差。3.3 三个必调参数越界框、difficult 与类别起始序号第一个必调是越界框。航拍影像尤其是无人机拼接图边缘经常出现目标被截断XML 里 xmax 可能写成图像宽度加几十像素。直接转会产生大于 1 的归一化值YOLO 训练时 loss 出现 NaN 是很常见的翻车现场。解决方式就是代码里的 clip 操作把 cx、cy、w、h 全部限制在 0 到 1 之间。第二个必调是 difficult 字段。VOC 规范里 difficult1 代表难样本通常指目标极小或严重遮挡。检测常规目标时可以跳过但滑坡检测里难样本往往是最需要学习的那一批——滑坡初期的小裂缝、被植被遮挡一半的滑体。我的实际建议是训练集把 difficult 也包含进去但分配更低的样本权重或者干脆单列一个困难样本验证集来观察模型尾部表现。要不要过滤取决于你的业务对「漏报」的容忍度。第三个必调是类别起始序号。VOC 里类名是字符串YOLO 里类别必须从 0 开始编号很多人转换后从 1 开始训练时模型输出的 class_id 和标注错位一位mAP 曲线看起来正常但实际推理时全部类别漂移。转换脚本里用class_names.index(name)来编号能保证始终从 0 开始对应。加新类时记得只改 class_names 列表的顺序不要自己在循环里维护编号变量那是在制造问题。每转完一批随机挑三张图把 TXT 里的坐标可视化画回原图检查一遍这一步能挡住九成低级错误。4. 拿这份数据跑通 YOLOv8最小训练命令与必调参数4.1 一张表列好先决条件到哪一步才算环境就绪常见做法是用 ultralytics 的 YOLOv8 跑这份数据Python 生态最省事。先对照这张表自查环境避免训练到一半发现算力不够项目建议配置说明操作系统Windows 10/11 或 Ubuntu 20.04Windows 下注意路径全英文Python3.8 到 3.113.12 某些 CUDA 版本适配有问题显卡NVIDIA 显卡显存 8G 起8G 跑 v8s 的默认 batch 刚够CUDA11.8 或 12.1与 PyTorch 版本对应PyTorch2.0 以上低版本兼容性差新功能缺失存储至少 10G 空闲原图加训练日志加权重环境配置是这门手艺里玄学最多的一环CUDA 版本不匹配导致的报错能占初学者排错时间的一半。我的做法是直接创建独立 conda 环境装好 ultralytics 和对应 torch 版本不碰系统全局 Python。先跑一个yolo detect predict拿官方权重做验证能出图说明环境闭环了再上这份数据集。4.2 配置数据集 yaml路径、类别数、train/val 划分YOLOv8 的训练入口是数据集 YAML它告诉框架去哪找图片和标签以及类别信息。这份数据包按上一章检查完类别名假设为landslide那 YAML 这样写path: D:/datasets/landslide # 数据集根目录绝对路径不要用相对路径 train: images/train # 训练图片目录相对于 path val: images/val # 验证图片目录相对于 path nc: 1 names: 0: landslide这里先手动把 labels 和 images 按比例切成train、val两个子目录。切分时要额外注意一个隐藏点航拍影像常来自同一个大场景的滑窗切片相邻切片的标注高度相关如果随机分验证集会混入大量与训练图几乎相同的场景验证 mAP 虚高。正确的划分是按影像来源分桶同一个原始场景的全部切片只能进 train 或 val 一边。标题没给出每个切片来源稳妥做法是先看文件名前缀按前缀分组再划分。import os import shutil import random from collections import defaultdict random.seed(42) src_img images src_lbl labels train_img, val_img images/train, images/val train_lbl, val_lbl labels/train, labels/val # 按文件名前缀分组模拟按场景划分 files [f for f in os.listdir(src_img) if f.endswith(.jpg)] groups defaultdict(list) for f in files: prefix f.split(_)[0] # 例如 scene1_001.jpg - scene1 groups[prefix].append(f) train_files, val_files [], [] for prefix, flist in groups.items(): random.shuffle(flist) split int(len(flist) * 0.8) train_files flist[:split] val_files flist[split:] def copy_set(files, img_src, lbl_src, img_dst, lbl_dst): for f in files: shutil.copy(os.path.join(img_src, f), os.path.join(img_dst, f)) lbl f.replace(.jpg, .txt) shutil.copy(os.path.join(lbl_src, lbl), os.path.join(lbl_dst, lbl)) os.makedirs(train_img, exist_okTrue) os.makedirs(train_lbl, exist_okTrue) os.makedirs(val_img, exist_okTrue) os.makedirs(val_lbl, exist_okTrue) copy_set(train_files, src_img, src_lbl, train_img, train_lbl) copy_set(val_files, src_img, src_lbl, val_img, val_lbl) print(ftrain {len(train_files)} val {len(val_files)})场景前缀分组的意义在于防止数据串扰。如果全随机分同一滑坡场景的两个相邻切片一个进训练一个进验证模型其实已经见过验证图的内容了测试分数根本没有参考价值。4.3 训练命令与关键超参imgsz、batch、epochs、预训练权重YAML 就位后训练命令本身很短yolo detect train \ datalandslide.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ workers4modelyolov8s.pt是官方预训练权重框架会自动下载。预训练模型下载这一步很多人卡住内网环境建议提前手动下载放到项目目录下再通过model./yolov8s.pt指定本地路径。预训练权重对这个航拍滑坡数据集的价值是让特征提取器从自然图像域起步FG 收敛比随机初始化快得多最终 mAP 也普遍高出几个点。显存只有 8G 的机器把 batch 降到 8workers在 Windows 上建议保持 4太高容易踩 DataLoader 的坑。imgsz640不是拍脑袋定的。滑坡体目标通常比行人、车辆大得多很多框占图像宽高的 30% 以上640 的分辨率不会把目标压没。但如果你的任务里还有细小的裂缝、碎屑坡脚这类小目标建议单独跑一组imgsz1280对比代价是训练时间约为 4 倍、显存占用大幅上升可以用后续的滑窗推理来缓解。这里有一个关键信号要看训练时的box_loss曲线如果 loss 降不下去但cls_loss正常普遍是目标框大小分布太宽模型对小框回归能力不足优先调 imgsz 而不是盲目加层。遥感影像的数据增强有个特殊坑HSV 颜色增强默认开启但航拍滑坡影像的颜色分布和地物纹理高度相关植被、裸土、水体的色调被大幅扰动后模型很容易学到错误的颜色特征。常见做法是训练时把hsv_h、hsv_s、hsv_v显式调低或者直接设为 0。yolo detect train \ datalandslide.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ hsv_h0.01 \ hsv_s0.2 \ hsv_v0.1 \ mosaic1.0 \ fliplr0.5 \ flipud0.0fliud0.0是航拍数据处理里常被忽略的一条。航拍图方向通常和飞行航向强相关上下翻转会制造出大量现实中不存在的排列且滑坡的光照阴影方向会被破坏。左右翻转则相对安全mosaic 拼接保留 1.0 是因为它能让模型在小目标上积累更多上下文。这几个参数比学习率和优化器选择更能决定这份数据集的最终表现。5. 避坑清单这份滑坡数据集最容易翻车的五个现场5.1 解压路径的隐形炸弹中文目录、多级嵌套、伪加密现象数据集解压到本地后训练时提示AssertionError或图片路径不存在但明明目录里能看到文件。原因zip 包内如果带着套一层的顶层目录解压后实际图片在航拍滑坡数据集/images下一层YAML 里的路径就会指错更隐蔽的是 Windows 中文路径下部分 OpenCV 版本读取文件会直接失败报错还不是「找不到文件」而是莫名其妙的cv2.error。另一个我遇到过的情况是 zip 设置了伪加密——压缩包把每个文件标记成需要密码但实际上不输入密码也能解压有些解压工具会弹窗卡住让人误以为文件坏了。解决目录一律改名为纯英文短路径如D:\data\landslide先打开压缩包看第一层目录结构确认没有多余嵌套用 7-Zip 打开后直接拖出文件而不是双击解压能绕过大多数伪加密弹窗。解压完成后跑一遍图片数量校验再继续往下做。5.2 标注框越界导致训练 loss 异常现象训练前几个 epoch 的box_loss在正常下降突然某个 epoch 跳出断崖式峰值甚至出现 NaN之后 mAP 波动巨大。原因上一章提到过XML 里标注框超出图像边界转换后的归一化坐标大于 1 或小于 0YOLO 在计算 IoU 和损失时遇到非法的框坐标反向传播就会炸。很多标注工具允许标注时把框拖到画布外航拍大图被裁剪成切片时尤其容易产生这类数据。解决训练前写个脚本扫描全部 TXT统计超出 0 到 1 范围的坐标值一旦发现就检查对应原图裁剪逻辑。修复是个体力活——正确的做法是重新执行带 clip 的转换脚本而不是手工改 TXT因为 clip 之后框的面积和中心点可能受影响的手工逐个改容易漏。批量 clip 后再跑一次训练loss 曲线就正常了。5.3 类别不均衡滑坡主体多、裂缝少现象训练曲线看起来收敛了但验证集上裂缝类别的召回率只有 20%滑坡主体却有 85%整体 mAP 被平均分拉得还行一拆类目就露馅。原因4315 张影像里滑坡主体框可能占了九成裂缝、碎屑流等附属类别只有零星几百个框模型被大类别主导小类别几乎学不到。标题没列出类别清单拿到数据后先看uniq -c的结果如果符合这个分布就是典型的长尾问题。解决先按类别统计框数量对样本量少的类别做复制粘贴增强或者对包含该类别的图片提高采样权重。Ultralytics 框架里可以用weights参数指定每类的损失权重我把少数类权重调到 3 到 5 倍之后召回率通常能拉回 55% 以上。注意权重不要一次拉太高否则模型会出现大量把大目标误判成小类别的过拟合式输出反而不利于整体 mAP。5.4 随机划分数据导致验证虚高部署后现原形现象训练时验证 mAP 高达 0.9部署到一段新的航拍视频上识别效果惨不忍睹漏检一大堆。原因这是航拍类数据集最容易踩的坑我在 4.2 节已经说到了场景串扰。如果划分训练集和验证集时是纯随机抽的同一场景的相邻切片会同时出现在两边。模型在训练时已经见过验证切片的内容分数自然漂亮但遇到没见过的场景就失去泛化能力。滑坡检测的应用场景几乎都是新地区、新地形验证集若不能反映这一点训练就是自欺欺人。解决严格按文件名前缀或日期进行分组划分保证同一个原始场景的所有切片只落在训练集或验证集一侧。把划分前后两组实验的 mAP 对比一下你往往会看到同一个模型从 0.9 掉到 0.7 左右这个 0.7 才是真实水平。把这次血泪经验记录下来以后做任何遥感数据集划分代码里第一件事就是按场景分桶。5.5 显存不足和训练中断小卡救急三板斧现象12G 显存跑imgsz640, batch16中途CUDA out of memory训练了几个小时直接白干或者训练中断后一切重来费时费力。原因YOLOv8 默认的 batch 对显存不友好航拍影像纹理丰富即使分辨率不高特征图的内存占用也比普通数据集更大。初学者往往直接照抄别人的训练命令没考虑自己的显卡实际余量。解决第一板斧把 batch 降到 8workers降到 2第二板斧把imgsz降到 480代价是损失部分小目标精度适合先跑通流程第三板斧开启梯度累积Ultralytics 框架可以通过设置batch8搭配增大训练迭代来达到等效大 batch 的效果。另外养成训练前先跑 5 个 epoch 试水的好习惯确认不爆显存、loss 能降再跑正式的长训练。YOLO 训练中断后没有内置保存「后悔药」——只有设好save_period定期保存 checkpoint万一中断了也能从断点续跑。所有超参数实验前都先问自己一句如果这个模型明天要部署在新航线上还能不能有现在的效果。6. 从 mAP 到能用的决策阈值用验证集反向压出你真正要的模型训练收敛只是第一步航拍滑坡检测落地时核心不是 mAP 而是「在固定的误报预算下能抓到多少真滑坡」。我常用的一个方法是把验证集当成压测集用训练好的best.pt跑推理扫描置信度门限从 0.1 到 0.9 的 F1 分数找到业务最舒服的那个点。from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) best_thresh, best_f1 0.5, 0.0 for thresh in [x / 10 for x in range(1, 10)]: metrics model.val(confthresh, iou0.5, verboseFalse) f1 metrics.box.f1[0] # 取第一类的 F1 if f1 best_f1: best_f1, best_thresh f1, thresh print(fbest threshold {best_thresh}, f1 {best_f1})这事说起来像玄学但实际效果很直接有些模型在默认 0.25 置信度下误报一堆裸土和道路把门限抬到 0.5 后误报减半、召回只掉一点反过来如果业务要求漏报率极低门限降到 0.15 多抓几个假阳性也能接受。适应这个环节的唯一办法是把验证集的错误预测框全部可视化看一眼归类一下哪些是地形阴影、哪些是道路路基你就知道这个模型真正在什么条件下会翻车。另一个更贴近航拍场景的技巧是大图滑窗推理。航拍原始分辨率往往不止 640直接把整张图喂给模型会把小目标压没我的做法是切成 50% 重叠的 640 切片逐块推理后再按坐标合并结果。合并时同一个目标会被多个切片重复检测到用 NMS 的 IoU 阈值收敛一下即可。配合同样的滑窗做训练数据裁剪模型对小裂缝的召回率有明显提升。我自己养成的习惯是每次训练结束固定验证集把所有 FP 样本打印出来当图册翻一遍。滑坡检测真正的落地瓶颈通常不是网络结构而是「阴影被当滑坡」「道路被当裂缝」这类相似地物的区分度。先看模型错在哪再决定是加数据还是调阈值比盲目堆参数省时间得多。希望这份航拍滑坡数据集的完整折腾路径能帮到你也祝你训出来的模型第一次上真实航线就不掉链子。本文还有配套的精品资源点击获取
返回列表