简介:本资源为面向YOLO系列目标检测算法的航空卫星图像数据集,适用于遥感场景下的地物识别与模型训练验证,覆盖森林、公路、作物、河流、住宅、工业、果园、牧场及贫瘠土地等九类典型目标,适合从事遥感图像分析、无人机巡检或地理信息研究的开发者与学习者使用。压缩包共2000个文件,包含1230个xml标注文件与770个txt标注文件,分别对应VOC与YOLO两种标签格式,并已划分好训练与验证集,附带data.yaml配置文件,可直接适配yolov5、yolov8、yolov9、yolov7、yolov10及yolo11等主流算法。包体整体约60.51MB,目录结构清晰,便于按格式快速检索与调用。目前已有42人学习下载,读者可借助该数据集完成从数据加载、格式转换到模型训练与测试的完整流程,快速验证算法在遥感地物检测任务中的表现,节省自行标注与整理数据的时间成本。
1. 航空卫星图像目标检测数据集:1366 张带标签图像能直接跑 YOLO 吗
拿到一份标注好的航空卫星图像数据集,第一反应往往不是兴奋,而是怀疑——标签格式对不对、类别分布偏不偏、能不能直接喂给 YOLOv8 或 YOLO11 训练。这份资源包含 1366 张航空卫星图像,覆盖森林、公路、作物、河流、住宅、工业、果园、牧场、贫瘠土地九类地物,同时提供 YOLO 格式(txt)和 VOC 格式(xml)两套标签,已经划分好训练集与验证集,附带 data.yaml 配置文件。换句话说,它省掉了最耗时的标注环节,拿到手就能接上 YOLOv5 到 YOLO11 的训练流程。适合做遥感地物分类检测的从业者、需要快速验证模型改进效果的研究者,以及想跑通完整训练链路但缺数据的新手。下面从目录结构、标签格式、训练配置到踩坑排查,把这份数据集拆开讲清楚。
2. 数据集结构与标签格式:txt 和 xml 到底怎么对应
2.1 目录组织与文件命名规律
这份数据集的目录结构是典型的 YOLO 训练工程布局,常见做法是根目录下分 images 和 labels 两个大文件夹,各自再分 train 和 val。图像文件以 img_ 开头加编号命名,比如 img_091_1074.jpg 对应的标签文件就是 img_091_1074.txt 或 img_091_1074.xml。项目正文里列出的那串文件名——img_091_1074.txt、img_091_1078.txt、img_091_632.txt 等——就是 labels 目录下的标注文件片段,编号与图像一一对应。
这里有个细节值得注意:文件名末尾带部分类别名称。这意味着你拿到标签文件时,光看文件名就能大致判断这张图里标注了什么地物,排查数据时不用逐张打开图像。比如文件名里带 forest 或 road 的,说明该图至少包含对应类别。这个设计在人工抽检时非常省事。
VOC 格式的 xml 文件和 YOLO 格式的 txt 文件分别放在两个文件夹里,内容描述的是同一批图像的同一批标注框,只是坐标系表达方式不同。你不需要同时用两套,选一套即可——用 YOLO 系列训练就取 txt,用其他框架或做数据转换就取 xml。
2.2 YOLO 格式的坐标含义与换算
YOLO 格式每行代表一个目标框,结构是:
<class> <x_center> <y_center> <width> <height>五个字段用空格分隔。<class>是类别索引,从 0 开始,对应 data.yaml 里 names 列表的顺序。后面四个都是归一化后的比例值,范围 0 到 1,分别表示框中心点的 x 坐标、中心点的 y 坐标、框的宽度、框的高度,全部相对于图像宽度和高度。
举个例子,假设图像尺寸是 640×640,某行标注为3 0.512 0.438 0.120 0.085,那么:
- 类别索引 3,对应 data.yaml 中 names 列表第 4 个类别
- 中心点像素坐标:x = 0.512 × 640 ≈ 328,y = 0.438 × 640 ≈ 280
- 框的像素宽:0.120 × 640 ≈ 77,高:0.085 × 640 ≈ 54
- 左上角坐标:x1 = 328 - 77/2 ≈ 289,y1 = 280 - 54/2 ≈ 253
- 右下角坐标:x2 = 328 + 77/2 ≈ 367,y2 = 280 + 54/2 ≈ 307
这个换算在排查标签是否越界、框是否合理时必用。我一般会写个小脚本随机抽几十张图把框画出来目检,比盯着数字靠谱得多。
2.3 VOC 格式与 YOLO 格式的差异
VOC 格式的 xml 文件用的是绝对像素坐标,结构大致如下:
<annotation> <filename>img_091_1074.jpg</filename> <size> <width>640</width> <height>640</height> <depth>3</depth> </size> <object> <name>forest</name> <bndbox> <xmin>289</xmin> <ymin>253</ymin> <xmax>367</xmax> <ymax>307</ymax> </bndbox> </object> </annotation>对比可以看出,VOC 用 xmin/ymin/xmax/ymax 四个绝对坐标描述框,类别用字符串名称而非索引。YOLO 格式则把坐标归一化并压缩成一行五个数字。两者转换的核心公式是:
- x_center = (xmin + xmax) / 2 / width
- y_center = (ymin + ymax) / 2 / height
- w = (xmax - xmin) / width
- h = (ymax - ymin) / height
如果你拿到的是 xml 但想用 YOLO 训练,转换脚本必须处理边界情况:xmax 等于图像宽度时归一化后是 1.0,某些版本的 YOLO 对 1.0 边界容忍度不同,稳妥做法是截断到 0.999。这个坑后面还会细说。
2.4 data.yaml 配置文件的写法
data.yaml 是 YOLO 训练时指定数据路径和类别名称的配置文件。这份数据集已经附带,典型内容如下:
path: ./dataset train: images/train val: images/val nc: 9 names: 0: forest 1: road 2: crop 3: river 4: residential 5: industrial 6: orchard 7: pasture 8: barrenpath是数据集根目录,train和val是相对路径。nc是类别数量,必须和 names 列表长度一致。names 的顺序决定了标签里类别索引的含义——如果索引 0 在标签里代表森林,names 第 0 项就必须是 forest,顺序错了模型学出来的类别全是乱的。
提示:不同 YOLO 版本对 data.yaml 的字段名有细微差异。YOLOv5 用
nc和names,YOLOv8 及以后也兼容这两个字段,但部分版本推荐用names字典形式。如果训练时报类别数不匹配,先检查这里。
3. 用这份数据集训练 YOLOv8/YOLO11:从环境到首轮推理
3.1 环境准备与依赖安装
训练前先把环境搭好。我一般用 conda 建独立环境,避免和系统里的包打架:
conda create -n yolo_sat python=3.10 -y conda activate yolo_sat pip install ultralyticsultralytics这个包同时覆盖 YOLOv8 和 YOLO11 的训练、验证、导出接口,装一个就够。如果你要用 YOLOv5,得单独 clone 它的仓库装 requirements,两套环境的依赖版本不完全兼容,别混在一个环境里。
装完后验证一下:
yolo checks这条命令会打印 PyTorch 版本、CUDA 是否可用、GPU 型号等信息。如果 CUDA 显示不可用但你确实有显卡,大概率是 PyTorch 装成了 CPU 版,需要按官网命令重装对应 CUDA 版本的 torch。
3.2 用命令行启动首轮训练
环境就绪后,最简训练命令如下:
yolo detect train \ data=./dataset/data.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ device=0 \ project=runs/sat \ name=exp1逐项说明:data指向 data.yaml;model指定预训练权重,yolov8n 是最小的 nano 版本,适合先跑通流程,确认无误再换 s/m/l;epochs是训练轮数,1366 张图的数据量下 100 轮通常够收敛;imgsz是输入分辨率,640 是默认值,航空图像目标偏小的话可以提到 1024,但显存占用会明显上升;batch是批大小,16 在 8GB 显存上比较稳;device=0指定第一块 GPU;project和name控制输出目录。
训练过程中终端会打印每轮的 box_loss、cls_loss、mAP50 等指标。重点看 mAP50 是否稳步上升、验证集 loss 是否在后期反弹。如果训练集 loss 降但验证集 loss 涨,说明过拟合了,要么减 epochs,要么加数据增强。
3.3 用 Python 脚本做更细的控制
命令行适合快速跑通,但要做自定义增强、回调或者批量实验,用 Python 脚本更灵活:
from ultralytics import YOLO # 加载预训练模型 model = YOLO("yolov8n.pt") # 开始训练 results = model.train( data="./dataset/data.yaml", epochs=100, imgsz=640, batch=16, device=0, patience=20, # 20轮无提升则早停 augment=True, # 开启默认数据增强 mosaic=1.0, # mosaic增强概率 mixup=0.1, # mixup增强概率 project="runs/sat", name="exp1_py" ) # 训练结束后在验证集上评估 metrics = model.val() print(f"mAP50: {metrics.box.map50:.4f}") print(f"mAP50-95: {metrics.box.map:.4f}")patience=20是早停机制,连续 20 轮验证指标不提升就停,省时间。mosaic和mixup是两种增强策略,mosaic 把四张图拼成一张,对小目标检测帮助大;mixup 做图像混合,比例别设太高否则标签会糊。航空图像里河流、公路这类细长目标,mosaic 增强效果通常比随机裁剪好。
3.4 推理验证与结果查看
训练完成后,用训练出的权重跑推理:
yolo detect predict \ model=runs/sat/exp1/weights/best.pt \ source=./dataset/images/val \ save=True \ conf=0.25 \ iou=0.45conf=0.25是置信度阈值,低于这个值的框不输出;iou=0.45是 NMS 的 IoU 阈值,控制重叠框的合并程度。航空图像里住宅区和工业区容易混淆,如果发现这两类互相误检,可以适当提高 conf 到 0.35 再观察。
结果默认存在 runs/detect/predict 下,图像上会画出检测框和类别标签。我习惯随机抽 20 张目检,重点看三类问题:漏检的小目标、类别标错的框、框位置偏移明显的。这三类问题分别对应数据标注质量、类别定义模糊、坐标转换误差,排查方向不同。
4. 避坑与排查:标签、类别和训练配置里的常见翻车点
4.1 标签坐标越界导致训练报错
现象:训练启动后报Label class x is invalid或normalized coordinates out of range,进程直接退出。
原因:YOLO 格式要求所有坐标在 0 到 1 之间。VOC 转 YOLO 时,如果目标框正好贴到图像边缘,xmax 等于图像宽度,归一化后得到 1.0。部分 YOLO 版本对 1.0 的容忍度不同,会判定越界。另外标注时手误把坐标写成负数或大于图像尺寸也会触发。
解决:写个校验脚本遍历所有 txt,把越界坐标截断到 [0.001, 0.999] 区间:
import os def clamp_labels(label_dir): for fname in os.listdir(label_dir): if not fname.endswith(".txt"): continue path = os.path.join(label_dir, fname) fixed_lines = [] with open(path, "r") as f: for line in f: parts = line.strip().split() if len(parts) != 5: continue cls = parts[0] coords = [min(max(float(v), 0.001), 0.999) for v in parts[1:]] fixed_lines.append(f"{cls} " + " ".join(f"{c:.6f}" for c in coords)) with open(path, "w") as f: f.write("\n".join(fixed_lines)) clamp_labels("./dataset/labels/train") clamp_labels("./dataset/labels/val")跑完再启动训练就不会报越界了。这个脚本我每次拿到新数据集都会先跑一遍,属于后悔药级别的操作。
4.2 类别索引与 names 顺序不匹配
现象:训练能跑,loss 也在降,但推理时所有框的类别都是错的,比如河流被标成公路。
原因:标签里的类别索引和 data.yaml 里 names 的顺序对不上。比如标签里 0 代表森林,但 names 第 0 项写的是 road。这种情况 loss 照样降,因为模型学的是「索引 0 对应的视觉特征」,它不知道你心里想的是森林还是公路。
解决:先统计标签里出现的所有类别索引,再和 names 逐项核对:
import os from collections import Counter def count_classes(label_dir): counter = Counter() for fname in os.listdir(label_dir): if not fname.endswith(".txt"): continue with open(os.path.join(label_dir, fname)) as f: for line in f: if line.strip(): counter[line.split()[0]] += 1 return counter print(count_classes("./dataset/labels/train"))输出会告诉你每个索引出现了多少次。如果某个索引出现次数为 0,说明 names 里多写了类别或者标签漏标了。如果索引分布和预期严重不符,就得回去查标注定义。
4.3 训练集与验证集图像重叠
现象:验证集 mAP 高得离谱,接近 0.95 以上,但换一批新图推理效果断崖式下跌。
原因:数据划分时训练集和验证集混入了相同或高度相似的图像。航空图像如果来自同一区域连续拍摄,相邻帧之间差异极小,随机划分很容易把近似图分到两边,导致验证集「泄题」。
解决:按图像来源或拍摄区域划分,而不是随机打乱。如果数据集已经划分好,抽检一下训练集和验证集里有没有文件名高度相似的图像:
import os train_imgs = set(os.listdir("./dataset/images/train")) val_imgs = set(os.listdir("./dataset/images/val")) # 提取编号前缀做粗匹配 def prefix(name): return "_".join(name.split("_")[:2]) train_prefixes = {prefix(n) for n in train_imgs} val_prefixes = {prefix(n) for n in val_imgs} overlap = train_prefixes & val_prefixes print(f"重叠前缀数量: {len(overlap)}")如果重叠很多,说明划分有问题,需要重新按区域分。这个坑在遥感数据集里特别常见,血泪经验。
4.4 显存不足导致训练中断
现象:训练跑了几十轮突然报 CUDA out of memory,或者一开始就起不来。
原因:imgsz 或 batch 设太大,或者开了 mosaic 增强后单张图实际占用显存翻倍。航空图像本身分辨率高,640 的 imgsz 可能已经是缩放过后的结果。
解决:优先降 batch,从 16 降到 8 或 4;其次降 imgsz,从 640 降到 512;还可以开梯度累积模拟大 batch:
yolo detect train \ data=./dataset/data.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=512 \ batch=8 \ device=0如果显存实在紧张,用 YOLOv8n 或 YOLO11n 这种轻量模型先跑通,确认流程无误再换大模型。别一上来就上 YOLOv8x,1366 张图的数据量也撑不起大模型的参数量,过拟合风险很高。
4.5 验证集指标虚高但实际推理差
现象:训练日志里 mAP50 到了 0.9,但拿真实航拍图推理,漏检和误检都很严重。
原因:除了上面说的数据泄漏,还有一种情况是验证集和训练集来自同一分布,但实际应用场景差异大。比如数据集里的图像都是晴天正射影像,实际推理用的是有云层遮挡或大角度倾斜的图像,域偏移导致性能下降。
解决:在训练时加入更强的数据增强模拟域偏移,比如随机亮度对比度调整、随机旋转、随机缩放。YOLO 默认增强里已经有部分,可以手动加强:
model.train( data="./dataset/data.yaml", epochs=100, imgsz=640, hsv_h=0.015, # 色调抖动 hsv_s=0.7, # 饱和度抖动 hsv_v=0.4, # 亮度抖动 degrees=10.0, # 随机旋转角度 translate=0.1, # 随机平移 scale=0.5, # 随机缩放 )这些参数增大后训练集上的指标会降,但泛化能力会好一些。别指望一份数据集能覆盖所有场景,实际部署前一定要用目标场景的图做验证。
5. 进阶技巧:用这份数据集验证模型改进与导出部署
5.1 用同一份数据做改进对比实验
这份数据集类别清晰、标注完整,很适合做模型改进的对照实验。比如你想验证一个新的注意力模块或损失函数是否有效,固定数据划分和训练超参,只改模型结构,跑两组对比 mAP50 和 mAP50-95 就行。关键是控制变量:同样的 epochs、imgsz、batch、增强参数,甚至随机种子也固定。
from ultralytics import YOLO def run_experiment(model_cfg, name): model = YOLO(model_cfg) model.train( data="./dataset/data.yaml", epochs=100, imgsz=640, batch=16, device=0, seed=42, project="runs/ablation", name=name, exist_ok=True, ) metrics = model.val() return metrics.box.map50, metrics.box.map baseline_map50, baseline_map = run_experiment("yolov8n.pt", "baseline") improved_map50, improved_map = run_experiment("yolov8n_custom.yaml", "improved") print(f"baseline mAP50: {baseline_map50:.4f}, mAP50-95: {baseline_map:.4f}") print(f"improved mAP50: {improved_map50:.4f}, mAP50-95: {improved_map:.4f}")seed=42固定随机种子,减少随机性带来的波动。但要注意,即使固定种子,不同硬件和 CUDA 版本下结果也可能有微小差异,对比时看趋势不看小数点后三位。
5.2 导出 ONNX 做部署验证
训练完的权重如果要部署到非 Python 环境,导出 ONNX 是常见做法:
yolo export \ model=runs/sat/exp1/weights/best.pt \ format=onnx \ imgsz=640 \ opset=12 \ simplify=Trueopset=12是 ONNX 算子集版本,兼容性较好;simplify=True会做图优化,去掉冗余节点。导出后用 onnxruntime 验证一下推理结果和 PyTorch 是否一致:
import onnxruntime as ort import numpy as np session = ort.InferenceSession("best.onnx") input_name = session.get_inputs()[0].name # 构造一个随机输入 dummy = np.random.randn(1, 3, 640, 640).astype(np.float32) outputs = session.run(None, {input_name: dummy}) print(f"输出张量形状: {outputs[0].shape}")输出形状通常是 [1, 4+nc, 8400],8400 是候选框数量,4+nc 是框坐标加类别分数。如果形状不对,检查导出时的 imgsz 和 nc 是否匹配。
5.3 一个容易忽略的细节:图像尺寸一致性
这份数据集里的图像尺寸未必完全一致。YOLO 训练时会统一缩放到 imgsz 指定的大小,但标签坐标是归一化的,缩放不影响。问题出在推理阶段:如果你用原始尺寸推理再映射回原图,框位置会有偏差。稳妥做法是推理时也统一缩放到训练时的 imgsz,拿到结果后再按比例映射回原图坐标。
我一般会在推理脚本里加一段尺寸检查:
from PIL import Image import os def check_sizes(img_dir): sizes = {} for fname in os.listdir(img_dir): if fname.lower().endswith((".jpg", ".png")): with Image.open(os.path.join(img_dir, fname)) as im: sizes[im.size] = sizes.get(im.size, 0) + 1 return sizes print(check_sizes("./dataset/images/val"))如果输出显示多种尺寸,说明数据集本身不统一,训练时 YOLO 会处理,但你自己写推理代码时得注意。从那以后我每次拿到新数据集,第一件事就是跑一遍尺寸统计和标签校验,这两个检查能挡掉后面八成的玄学问题。希望帮到你。
本文还有配套的精品资源,点击获取