☰
山体滑坡检测数据集823张YOLO+VOC双格式实战:从数据体检到YOLOv8/v11训练全链路
2026/10/12 0:03:58 网站建设 项目流程

简介:本资源为面向地质灾害识别与计算机视觉学习者的山体滑坡目标检测数据集,适用于深度学习入门、目标检测模型训练及滑坡智能识别研究。压缩包共2000个文件,约63.01MB,包含823张jpg图片、823个VOC格式xml标注文件、825个txt文件,其中txt为YOLO格式标签,xml与txt一一对应,方便在VOC与YOLO两种主流框架间直接切换使用。数据集仅含landslide一个类别,共标注950个矩形框,图片清晰且未做数据增强,标注准确合理,可直接用于训练与验证。目前已有484人学习下载,适合需要快速搭建滑坡检测实验、验证算法效果或补充地质灾害样本的读者,能省去自行采集与标注的成本,为模型训练提供规范的数据基础。

1. 山体滑坡检测数据集:823 张 YOLO+VOC 双格式到底能干什么

山体滑坡这类地质灾害的目标检测,和常规的车辆、行人检测完全不是一个难度量级。滑坡体没有固定形状,边界模糊,颜色和纹理跟周围裸露岩土高度相似,同一张图里可能既有滑坡区又有塌方堆积区,标注尺度差异极大。823 张这个量级,说多不多,说少不少——它刚好卡在「能训出一个可用 baseline,但必须靠增强和迁移学习才能上生产」的区间。YOLO+VOC 双格式意味着你拿到手就能直接喂给 Ultralytics 系的 YOLOv8/v11,也能用 VOC 的 XML 走 SSD、Faster R-CNN 那条老路,省掉格式转换的折腾。这篇笔记面向两类人:一是手里有滑坡监测需求、想快速验证模型可行性的工程同学;二是刚入门目标检测、想找一个真实非标准数据集练手的开发者。我会把从数据检查、格式转换、训练配置到推理验证的完整链路拆开讲,参数怎么设、哪里容易翻车,都按我实际踩过的坑来说。

2. 拿到 823 张滑坡数据先别急着训:数据体检与格式拆解

2.1 为什么滑坡数据集必须先做分布体检

很多人拿到 zip 解压完,看一眼图片数量就开始写 train.py,这是滑坡检测翻车率最高的起手式。滑坡数据和 COCO 那种均衡数据集不同,它的类别分布、目标尺度、背景占比都极度偏斜。823 张里可能有 600 张是远景航拍、200 张是近景边坡、剩下 20 多张是雨后泥流的特殊场景。如果你不先摸清这些,直接按 8:1:1 随机切分,很可能验证集里全是远景,模型在近景上直接崩。

我一般会先跑一个统计脚本,把每张图的宽高、标注框数量、框的宽高比、类别分布全部拉出来。这一步花不了十分钟,但能帮你决定后面增强策略怎么配、输入分辨率设多少、要不要做分层采样。

import os import xml.etree.ElementTree as ET from collections import Counter import matplotlib.pyplot as plt # 指向 VOC 格式的 Annotations 目录 anno_dir = "./dataset/VOC/Annotations" img_dir = "./dataset/VOC/JPEGImages" box_counts = [] aspect_ratios = [] class_counter = Counter() sizes = [] for xml_file in os.listdir(anno_dir): if not xml_file.endswith(".xml"): continue tree = ET.parse(os.path.join(anno_dir, xml_file)) root = tree.getroot() # 读取图像尺寸 w = int(root.find("size/width").text) h = int(root.find("size/height").text) sizes.append((w, h)) objs = root.findall("object") box_counts.append(len(objs)) for obj in objs: name = obj.find("name").text class_counter[name] += 1 bnd = obj.find("bndbox") bw = float(bnd.find("xmax").text) - float(bnd.find("xmin").text) bh = float(bnd.find("ymax").text) - float(bnd.find("ymin").text) if bh > 0: aspect_ratios.append(bw / bh) print("图片总数:", len(box_counts)) print("每图平均框数:", sum(box_counts) / len(box_counts)) print("类别分布:", class_counter) print("宽高比中位数:", sorted(aspect_ratios)[len(aspect_ratios)//2]) print("分辨率样本:", sizes[:5])

这段脚本做四件事:统计每张图的标注框数量、类别频次、框的宽高比分布、图像分辨率。逻辑很直白,但输出信息量很大。如果类别分布里某一类占比超过 80%,你就得考虑类别重加权或者对少样本类做定向增强。如果宽高比中位数偏离 1 太远,说明滑坡体多为长条形,anchor 或者 YOLO 的自动 anchor 要留意。分辨率样本则决定你训练时 imgsz 设 640 还是 1024——滑坡小目标多的话,640 会丢细节。

2.2 VOC 与 YOLO 格式的字段对应关系

这个数据集同时给了 VOC 和 YOLO 两种格式,很多人只用一个,另一个直接删。我的建议是留着 VOC,因为它的 XML 里保留了图像尺寸、标注难度等元信息,排查标注错误时比 YOLO 的 txt 好用得多。两者的核心差异在于坐标表达:VOC 用绝对像素坐标 (xmin, ymin, xmax, ymax),YOLO 用归一化中心点加宽高 (cx, cy, w, h),且都除以图像宽高。

字段VOC XMLYOLO txt换算关系
类别<name>文本行首整数索引需维护类别映射表
中心 x无cx(xmin+xmax)/2/width
中心 y无cy(ymin+ymax)/2/height
宽xmax-xminw(xmax-xmin)/width
高ymax-yminh(ymax-ymin)/height
图像尺寸<size>节点不存储转换时从 XML 读取

理解这张表很关键,因为后面无论你是 VOC 转 YOLO 还是反向验证,都是围绕这几个字段做算术。特别注意 YOLO 的坐标必须裁剪到 [0,1],标注越界是滑坡数据集里最常见的脏数据——标注员在拉框时手一抖超出图像边界,转换后 cx 可能大于 1,训练时直接报错或者静默产生错误梯度。

2.3 用脚本把 VOC 转成 YOLO 并做越界裁剪

虽然数据集号称双格式,但实际拿到的 YOLO 标签未必和 VOC 完全对齐,我习惯以 VOC 为准重新生成一遍 YOLO 标签,顺便做越界裁剪和空标注过滤。

import os import xml.etree.ElementTree as ET classes = ["landslide"] # 按你的实际类别改,滑坡数据集常见就一类 anno_dir = "./dataset/VOC/Annotations" out_dir = "./dataset/YOLO/labels" os.makedirs(out_dir, exist_ok=True) for xml_file in os.listdir(anno_dir): if not xml_file.endswith(".xml"): continue tree = ET.parse(os.path.join(anno_dir, xml_file)) root = tree.getroot() w = int(root.find("size/width").text) h = int(root.find("size/height").text) lines = [] for obj in root.findall("object"): name = obj.find("name").text if name not in classes: continue cls_id = classes.index(name) bnd = obj.find("bndbox") xmin = max(0, float(bnd.find("xmin").text)) ymin = max(0, float(bnd.find("ymin").text)) xmax = min(w, float(bnd.find("xmax").text)) ymax = min(h, float(bnd.find("ymax").text)) # 裁剪后如果框太小直接丢弃,避免噪声 if xmax - xmin < 2 or ymax - ymin < 2: continue cx = (xmin + xmax) / 2 / w cy = (ymin + ymax) / 2 / h bw = (xmax - xmin) / w bh = (ymax - ymin) / h lines.append(f"{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}") # 没有有效标注的图写空文件,训练时用配置过滤 with open(os.path.join(out_dir, xml_file.replace(".xml", ".txt")), "w") as f: f.write("\n".join(lines))

关键点在裁剪逻辑:xmin 和 ymin 用 max(0, ...) 兜底,xmax 和 ymax 用 min(w, ...) 兜底,这样即使原始标注越界也能拉回合法范围。裁剪后宽高小于 2 像素的框直接丢弃,因为这种框在训练中只会贡献噪声梯度。空标注文件保留但内容为空,Ultralytics 训练时可以通过配置忽略,但如果你用其他框架,可能需要显式删除。

3. 用 YOLOv8/v11 训练滑坡检测模型:配置与参数

3.1 数据集 YAML 怎么写才不出错

Ultralytics 系的数据集配置文件看着简单,但滑坡数据集有几个容易写错的地方。路径要用绝对路径或者相对于训练启动目录的路径,train 和 val 指向的是图片目录而不是标签目录,标签目录由框架自动按同名规则去找。

# landslide.yaml path: /data/landslide # 数据集根目录 train: images/train # 训练图片相对路径 val: images/val test: images/test nc: 1 # 类别数,滑坡数据集通常就一类 names: 0: landslide

这里最容易翻车的是 path 和 train 的拼接关系。Ultralytics 会把 path 和 train 拼起来找图片,然后自动把路径里的images替换成labels去找标签。所以你的目录结构必须是images/train和labels/train平行。如果你把标签放在别的地方,训练时会报「No labels found」,这个报错我见过太多次了。

3.2 训练命令与关键参数逐个说

滑坡数据集 823 张,属于小数据集,训练策略和大数据集完全不同。下面是我常用的启动命令:

yolo detect train \ data=landslide.yaml \ model=yolov8s.pt \ epochs=200 \ imgsz=640 \ batch=16 \ lr0=0.001 \ lrf=0.01 \ warmup_epochs=5 \ mosaic=1.0 \ mixup=0.1 \ copy_paste=0.1 \ degrees=15 \ translate=0.1 \ scale=0.5 \ fliplr=0.5 \ patience=50 \ device=0 \ project=runs/landslide \ name=exp1

逐个说参数。model 选 yolov8s 而不是 n 版本,是因为滑坡特征复杂,n 版容量太小容易欠拟合,s 版在 823 张上刚好平衡。epochs 设 200 配合 patience=50,小数据集收敛快,通常 80 到 120 轮就触发早停。lr0=0.001 比默认的 0.01 小一个量级,小数据集用大学习率容易震荡。warmup_epochs=5 让前几轮慢慢升温,避免一开始就破坏预训练权重。

增强参数是重点。mosaic=1.0 开启马赛克增强,对滑坡这种目标尺度差异大的场景特别有用,能让模型见到更多尺度组合。mixup=0.1 轻度混合,再高会模糊滑坡边界。copy_paste=0.1 对少样本类有帮助,但滑坡只有一类时作用有限。degrees=15 做小角度旋转,滑坡方向不固定,适度旋转合理,但别超过 30 度,否则会出现不真实的坡面朝向。scale=0.5 允许 0.5 到 1.5 倍缩放,覆盖远近景。

提示:如果你发现训练 loss 正常下降但 mAP 一直上不去,先把 mosaic 关掉再训一轮对比。mosaic 在小数据集上有时会让模型学到拼接边界的伪特征,滑坡这种纹理连续的场景尤其敏感。

3.3 训练过程该盯哪些指标

训练启动后,控制台会输出 box_loss、cls_loss、dfl_loss 和 mAP50、mAP50-95。滑坡检测最该关注的是 mAP50-95 而不是 mAP50,因为滑坡边界模糊,IoU 阈值高的时候才能反映模型是否真的定位准了。如果 mAP50 很高但 mAP50-95 很低,说明模型能找到滑坡大概位置但框不准,这时候要检查标注质量而不是调模型。

另一个信号是 cls_loss。滑坡只有一类时,cls_loss 应该很快降到接近 0。如果它一直不降,大概率是标签文件里有类别索引错误,比如写成了 1 但你的 nc 是 1(合法索引只有 0)。这种错误不会报错,但模型永远学不会。

4. 滑坡检测的避坑与排查:5 个血泪教训

4.1 验证集 mAP 虚高但实际推理全错

现象:训练日志里 mAP50 到了 0.85,但拿真实滑坡照片推理,模型要么不框要么框到云层上。

原因:823 张数据如果随机切分,验证集和训练集可能来自同一批航拍序列,图像高度相似。模型记住了背景特征而不是滑坡特征。滑坡数据集经常是连续拍摄的,相邻帧差异极小,随机切分等于变相泄漏。

解决:按拍摄区域或时间做分组切分,同一区域或同一批次的图只能进训练集或验证集其中之一。如果数据里没有区域标签,至少按图像相似度做聚类后再切分。我一般会用感知哈希做一遍去重,相似度超过阈值的图归到同一组。

4.2 推理时小滑坡全部漏检

现象:大块滑坡能检出,但面积小于图像 1% 的滑坡全部漏掉。

原因:imgsz=640 时,下采样 32 倍后小目标在特征图上只剩几个像素。滑坡数据集里小目标占比往往不低,尤其是远景航拍。

解决:把 imgsz 提到 1024 或 1280,同时 batch 相应调小避免显存爆掉。另一个办法是在数据增强里加小目标复制粘贴,把少数的滑坡区域裁剪出来贴到不同背景上。如果显存实在不够,用切片推理,把大图切成重叠的小块分别检测再合并。

4.3 标注框大量越界导致训练报错

现象:训练启动时报「normalized coordinates out of range」或者 loss 直接变 NaN。

原因:VOC 转 YOLO 时没做裁剪,标注员拉框超出图像边界,cx 或 cy 大于 1。

解决:用 2.3 节的转换脚本重新生成标签,裁剪逻辑必须加。转换完再跑一遍校验,扫描所有 txt 文件确认坐标都在 [0,1] 内。这个校验脚本很简单但能省掉几小时的排查。

4.4 模型把裸露岩土误判为滑坡

现象:推理结果里大量非滑坡的裸地被框出来,误报率高。

原因:滑坡和裸露岩土在 RGB 图像里颜色纹理接近,模型学到的判别特征不够。823 张数据里如果负样本(有裸地但无滑坡)太少,模型没见过足够的困难负样本。

解决:收集一批纯裸地、无滑坡的负样本图加入训练集,标签为空文件。负样本比例控制在 10% 到 20%。另外可以在增强里加颜色抖动,让模型不过度依赖颜色特征。如果条件允许,引入高程数据或 SAR 影像做多模态,但这超出纯 RGB 数据集的范围了。

4.5 训练完模型文件很大推理很慢

现象:yolov8s 训完在边缘设备上跑不动,单帧推理超过 200ms。

原因:没做模型导出优化,直接用的 PyTorch 权重。

解决:导出成 ONNX 或 TensorRT。滑坡检测如果部署在无人机或边缘盒子上,TensorRT 的 FP16 量化通常能提速 2 到 3 倍,精度损失在 1 个点以内。导出命令是yolo export model=best.pt format=engine half=True。注意导出时的 imgsz 要和训练一致,否则精度会掉。

5. 把 823 张用到极致:分层采样与推理后处理技巧

823 张要训出能用的滑坡检测模型,核心思路是让每一张图发挥最大价值。我一般会做两件事:分层采样和推理后处理。

分层采样是按场景难度把数据分成几层。具体做法是用 2.1 节的统计脚本输出每张图的框数量和平均框面积,然后按框面积分成小目标、中目标、大目标三层,每层按比例抽验证集。这样验证集能覆盖各种尺度,mAP 才有参考意义。代码上就是在切分前给每张图打上分层标签,用 sklearn 的 StratifiedShuffleSplit 按层抽样。

import numpy as np from sklearn.model_selection import StratifiedShuffleSplit # strata 是每张图的分层标签,0=小目标为主,1=中,2=大 strata = np.array(strata_labels) indices = np.arange(len(strata)) sss = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42) for train_idx, val_idx in sss.split(indices, strata): train_files = [files[i] for i in train_idx] val_files = [files[i] for i in val_idx]

推理后处理这块,滑坡检测有个特殊之处:滑坡区域通常是连通的,不会像行人那样分散。所以可以用连通域分析做后处理,把 IoU 重叠高且空间相邻的检测框合并成一个。具体做法是取出所有置信度高于阈值的框,按空间距离聚类,同一簇内取置信度最高的框或者做加权框融合。这个后处理能把碎片化的检测结果整合成完整的滑坡区域,对面积统计类应用特别有用。

另一个技巧是测试时增强(TTA)。Ultralytics 推理时加augment=True会做多尺度加翻转的 TTA,mAP 通常能涨 1 到 2 个点,代价是推理时间翻几倍。如果做离线分析不在乎速度,这个开关值得开。但部署到实时系统就别用了。

最后说一个我自己的习惯:每次训完模型,我都会挑 20 张验证集里 mAP 最低的图,逐张看推理结果和标注的差异。这 20 张图里藏着模型真正的短板——可能是某种光照、某个角度、某类边界情况。看多了你会发现,滑坡检测的瓶颈往往不在模型结构,而在数据本身覆盖的场景够不够全。823 张能不能撑起你的业务,取决于这 823 张里有多少是真正多样化的。如果发现某类场景完全缺失,与其调参,不如先去补数据。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询