ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

遥感公开数据集选型指南:语义分割、目标检测、场景分类与变化检测实战避坑

遥感公开数据集选型指南:语义分割、目标检测、场景分类与变化检测实战避坑

1. 从一堆散乱的文件夹说起:遥感数据集到底该怎么选

刚入行做遥感深度学习那会儿,我最头疼的不是模型调参,也不是显卡不够用,而是面对搜索引擎里几十个G的“数据集大全”压缩包,完全不知道从哪下手。下载了三个号称“语义分割通用”的数据集,解压一看,一个标注格式是单通道灰度图,一个是三通道彩色图,还有一个干脆是COCO格式的JSON——光写数据加载器就耗掉了一周。后来带新人,发现大家踩的坑几乎一模一样:要么被“公开数据集”四个字迷惑,以为下载即用;要么盲目追求体量,拿一个几十万张图的场景分类集去训分割模型,结果类别体系完全对不上。

这篇东西就是把我这些年整理、清洗、踩坑、复现过的遥感公开数据集做一次系统梳理。核心围绕四个任务方向:语义分割、目标检测、场景分类、变化检测。每个方向我会说清楚三件事:这个数据集到底解决什么问题、它的标注体系有什么坑、以及在实际项目里怎么用才不翻车。适合正在做遥感相关课题的研究生、刚转行进入遥感AI的算法工程师,以及需要快速选型做原型验证的开发者。读完你至少能省下两周的无效下载和格式转换时间。

提示:遥感数据集和自然图像数据集最大的区别在于成像视角、分辨率跨度、标注粒度。自然图像里一只猫就是一只猫,遥感图像里一栋楼可能被标成“建筑物”“屋顶”“不透水面”三种类别,取决于标注规范。选型第一步永远是确认你的任务定义和数据集标注规范是否对齐。

2. 语义分割数据集:像素级标注背后的类别体系陷阱

2.1 为什么语义分割数据集最容易被误用

语义分割在遥感里的典型应用是土地覆盖分类、建筑物提取、道路提取、水体提取。看起来任务很明确,但实际拿到数据集就会发现,每个数据集的类别体系都是“自定义”的。有的把“草地”和“林地”合并成“植被”,有的把“裸地”细分成“沙地”“砾石地”“裸土”。你拿A数据集训的模型去B数据集测试,mIoU直接掉二十个点,不是模型不行,是类别定义根本对不上。

我见过最离谱的情况是,某数据集把“道路”标注为“不透水面”的子类,另一个数据集把“道路”和“停车场”合并成“交通用地”。如果你的下游任务需要区分道路和停车场,用后者训出来的模型永远做不到。所以选语义分割数据集,第一件事不是看有多少张图,而是把类别定义表打印出来,逐条对照你的业务需求。

2.2 几个主流语义分割数据集的实战点评

某大型土地覆盖分类数据集:这个数据集在圈内知名度很高,覆盖范围广,标注类别从水体、植被到建设用地都有。优点是空间分辨率统一,标注质量稳定;缺点是类别体系偏粗,适合做宏观土地覆盖制图,不适合精细建筑物提取。我试过用它训建筑物分割,结果模型把“建设用地”里的所有东西都当成建筑物,连广场都标出来了。后来老老实实换了一个专门做建筑物提取的数据集。

某高分辨率建筑物提取数据集:这个数据集的特点是标注精细,建筑物边界清晰,适合做实例级或语义级建筑物提取。但要注意它的成像区域集中在特定城市,模型泛化到其他城市时性能下降明显。我的经验是,用这个数据集做预训练,然后用目标区域的少量标注做微调,效果比直接拿它训完就部署好得多。

某多光谱语义分割数据集:包含可见光和近红外波段,适合做植被指数相关的分割任务。坑在于多光谱数据的通道顺序和位深跟普通RGB图像不一样,直接套用ImageNet预训练权重会出问题。我一般会先把多光谱数据归一化到0-255,然后只取RGB三通道做预训练,再逐步解冻多光谱分支。

数据集类型典型类别数标注粒度适用场景主要坑点
土地覆盖类5-15粗宏观制图类别合并导致细类丢失
建筑物提取类1-2细城市建模区域集中,泛化差
多光谱类8-20中植被监测通道顺序和位深不统一
道路提取类1-3细交通规划拓扑连通性标注不一致

2.3 语义分割数据加载的实操细节

拿到数据集后,第一件事是写一个可视化脚本,把图像和标注叠加显示。这一步能帮你发现很多问题:标注是否偏移、类别ID是否从0开始、是否有未标注区域(通常用255或0表示忽略)。我习惯用以下流程做快速检查:

import numpy as np from PIL import Image def check_dataset(img_path, mask_path): img = np.array(Image.open(img_path)) mask = np.array(Image.open(mask_path)) print(f"图像尺寸: {img.shape}, 标注尺寸: {mask.shape}") print(f"图像数据类型: {img.dtype}, 标注数据类型: {mask.dtype}") print(f"标注唯一值: {np.unique(mask)}") # 检查尺寸是否对齐 if img.shape[:2] != mask.shape[:2]: print("警告:图像和标注尺寸不一致,需要resize或crop") # 检查是否有忽略区域 if 255 in np.unique(mask): print("存在忽略区域,损失函数需设置ignore_index=255")

这个脚本我每次拿到新数据集都会跑一遍,能省掉后面调试时的很多困惑。特别是标注唯一值,如果发现类别ID不连续(比如只有0、1、3、7),说明中间有类别被合并或删除,需要对照类别定义表确认。

注意:遥感图像的标注经常存在“未标注区域”,这些区域在训练时应该被忽略,而不是当成背景类。我见过有人直接把未标注区域当背景训,结果模型把大片未标注的农田都预测成背景,mIoU虚高但实际不可用。

3. 目标检测数据集:小目标、旋转框与标注一致性

3.1 遥感目标检测和自然图像检测的本质差异

自然图像目标检测里,COCO数据集的目标尺寸分布相对均匀,大中小目标都有。遥感图像不一样,飞机、车辆、船只这些目标在整幅图里可能只占几十个像素。更麻烦的是,遥感图像的目标有方向性——一架飞机斜着停和正着停,水平框标注会包含大量背景,旋转框标注才能准确描述。这就导致遥感目标检测数据集分两大阵营:水平框(HBB)和旋转框(OBB)。

我刚开始做遥感检测时,拿水平框数据集训了一个车辆检测模型,结果密集停车场里的车辆框大量重叠,NMS一压就漏检。后来换旋转框数据集,同样的模型结构,召回率直接涨了十几个点。所以选检测数据集,先确认你的应用场景是否需要旋转框。如果只是做粗略计数,水平框够用;如果要精确定位和方向估计,必须上旋转框。

3.2 主流检测数据集的标注格式与转换

遥感检测数据集的标注格式五花八门:PASCAL VOC XML、COCO JSON、YOLO TXT、DOTA TXT。最让人头疼的是DOTA格式,它的标注是四点多边形,需要转换成旋转框或水平框才能用于常见检测框架。我整理了一个转换对照表:

数据集标注格式框类型类别数转换难点
某航拍检测集PASCAL VOC水平框20类别名不统一
某旋转框检测集DOTA TXT旋转框15需转COCO或YOLO
某车辆检测集COCO JSON水平框1图像尺寸极大
某船只检测集YOLO TXT水平框1标注密度不均

转换DOTA格式到YOLO旋转框时,最容易出错的是角度定义。DOTA的角度是顺时针从x轴正方向开始,而某些框架用的是逆时针。我一般会写一个可视化验证脚本,把转换后的框画回原图,肉眼确认无误后再开始训练。这一步千万别省,我见过有人转换完直接训,训了一周发现框全歪了。

3.3 小目标检测的数据增强策略

遥感小目标检测的核心矛盾是:目标太小,下采样几次就没了。我试过几种方案,最有效的是切图训练。把大图切成512x512或1024x1024的小图,保证目标在切图后仍有足够像素。切图时要注意重叠率,一般设20%-30%,避免目标被切碎。

def slice_image(img, annotations, slice_size=1024, overlap=0.2): stride = int(slice_size * (1 - overlap)) h, w = img.shape[:2] slices = [] for y in range(0, h, stride): for x in range(0, w, stride): y2 = min(y + slice_size, h) x2 = min(x + slice_size, w) # 确保切片不小于slice_size if y2 - y < slice_size: y = max(0, y2 - slice_size) if x2 - x < slice_size: x = max(0, x2 - slice_size) slice_img = img[y:y2, x:x2] # 筛选落在切片内的标注 slice_anns = filter_annotations(annotations, x, y, x2, y2) slices.append((slice_img, slice_anns)) return slices

切图之后,小目标的像素占比从0.1%提升到2%-5%,检测效果提升非常明显。但要注意,切图会导致同一目标出现在多个切片中,训练时需要做去重处理,推理时需要用NMS合并跨切片的检测结果。

提示:遥感检测数据集的标注一致性是个大问题。同一个数据集里,有的标注员把“大型车辆”和“小型车辆”分得很清楚,有的就统一标“车辆”。用之前最好抽样检查几百张图,确认标注标准是否统一。如果发现不一致,要么重新标注,要么把类别合并到统一粒度。

4. 场景分类数据集:从“这张图是什么”到“这个区域是什么”

4.1 场景分类在遥感里的特殊定义

自然图像场景分类是判断整张图是“海滩”还是“森林”。遥感场景分类不太一样,它通常是判断一个图像块(patch)对应的地物类型,比如“密集住宅区”“工业区”“农田”“机场”。这个任务看起来简单,但实际做起来有几个坑:一是图像块尺寸选择,太小了看不出场景,太大了类别混杂;二是类别边界模糊,“低密度住宅”和“中密度住宅”的区分标准因人而异。

我做过一个实验,用同一个数据集训场景分类模型,分别用64x64、128x128、256x256的图像块。结果128x128的验证准确率最高,64x64因为信息不足,256x256因为类别混杂,都差一些。所以选场景分类数据集时,要关注它的图像块尺寸和采样方式。

4.2 场景分类数据集的类别体系与采样偏差

某知名遥感场景分类数据集包含几十个类别,从“棒球场”到“停车场”都有。但仔细看类别分布,会发现严重的长尾问题:某些类别有上千张图,某些类别只有几十张。直接训练会导致模型偏向头部类别。我的做法是:先统计类别分布,对尾部类别做过采样或数据增强,同时用类别平衡的损失函数(如Focal Loss或Class-Balanced Loss)。

另一个问题是采样偏差。很多场景分类数据集是从特定区域采样的,比如某数据集主要覆盖欧洲城市,模型学到的是欧洲建筑风格。用到亚洲城市时,准确率下降明显。解决办法是用目标区域的少量标注做微调,或者用域适应方法。

数据集类别数图像块尺寸采样区域主要偏差
某大型场景集45256x256全球欧美区域偏多
某土地利用集21128x128特定国家类别不平衡
某细粒度场景集3064x64城市区域边界模糊

4.3 场景分类的预训练与迁移策略

场景分类数据集通常规模不大,从头训容易过拟合。我一般用ImageNet预训练权重做初始化,然后冻结前几层,只训后面的分类头。如果目标数据集和ImageNet差异太大(比如多光谱图像),就先在大型遥感场景分类数据集上做预训练,再迁移到小数据集。

import torchvision.models as models import torch.nn as nn def build_scene_classifier(num_classes, pretrained=True): model = models.resnet50(pretrained=pretrained) # 冻结前几层 for name, param in model.named_parameters(): if 'layer1' in name or 'layer2' in name: param.requires_grad = False # 替换分类头 model.fc = nn.Sequential( nn.Dropout(0.5), nn.Linear(model.fc.in_features, num_classes) ) return model

这个策略我在多个场景分类项目里用过,比从头训的准确率高5-10个点。注意冻结层数要根据目标数据集大小调整,数据集越小,冻结越多。

5. 变化检测数据集:双时相标注的配准与语义对齐

5.1 变化检测任务的特殊性

变化检测是遥感里最“娇贵”的任务。它需要同一区域两个时相的图像,以及像素级的変化标注。难点在于:两期图像必须精确配准,光照和季节差异要尽量小,标注要区分“真实变化”和“伪变化”(如季节导致的植被颜色变化)。我见过很多变化检测数据集,两期图像配准误差超过2个像素,训出来的模型把配准误差当成变化,完全不可用。

选变化检测数据集,第一件事是检查配准质量。我一般会取几对图像,手动叠加显示,看道路、建筑物边缘是否对齐。如果边缘有重影,说明配准有问题,要么自己重新配准,要么换数据集。

5.2 变化检测数据集的标注类型

变化检测的标注分几种:二值变化(变化/未变化)、多类变化(建筑物新增、道路扩建、植被减少等)、实例级变化(具体哪个建筑物变了)。二值变化数据集最多,但实际应用价值有限,因为用户通常想知道“变成了什么”。多类变化数据集更实用,但标注成本高,数量少。

某经典变化检测数据集提供二值标注,适合做算法原型验证。某多类变化检测数据集提供建筑物新增和拆除的区分,适合做城市扩张监测。我的建议是:先用二值数据集验证模型架构,再用多类数据集做实际应用。

5.3 变化检测的数据增强与训练技巧

变化检测的数据增强和普通任务不一样,两期图像必须做相同的几何变换,否则变化区域会错位。颜色变换可以不同,因为要模拟光照差异。我通常这样组织增强:

import albumentations as A # 几何变换:两期图像同步应用 geometric_transform = A.Compose([ A.RandomRotate90(), A.HorizontalFlip(), A.VerticalFlip(), ], additional_targets={'image2': 'image'}) # 颜色变换:分别应用 color_transform = A.Compose([ A.RandomBrightnessContrast(), A.HueSaturationValue(), ]) def augment_pair(img1, img2, mask): # 同步几何变换 transformed = geometric_transform(image=img1, image2=img2, mask=mask) img1, img2, mask = transformed['image'], transformed['image2'], transformed['mask'] # 分别颜色变换 img1 = color_transform(image=img1)['image'] img2 = color_transform(image=img2)['image'] return img1, img2, mask

这个流程我用了很久,能有效提升模型对光照变化的鲁棒性。注意颜色变换的强度不要太大,否则会引入不真实的颜色偏移。

注意:变化检测的评估指标要小心。有些数据集变化区域占比很小(比如不到1%),如果用像素准确率评估,模型全预测“未变化”也能拿99%的准确率。这时候要用F1分数或IoU来评估,才能反映真实性能。

6. 数据集选型的通用检查清单与踩坑复盘

6.1 下载之前必须确认的五件事

我整理了一个检查清单,每次选数据集之前过一遍,能避免80%的返工:

  1. 任务定义是否匹配:你的任务是分割、检测、分类还是变化检测?数据集的标注类型是否支持?
  2. 类别体系是否对齐:数据集的类别定义和你的业务需求是否一致?不一致的话,能否合并或映射?
  3. 标注质量是否可靠:抽样检查标注边界是否准确,是否有漏标、错标?
  4. 数据规模是否足够:训练集、验证集、测试集划分是否合理?类别分布是否平衡?
  5. 许可协议是否允许:数据集是否允许商业使用?是否需要引用?

这五条里,最容易忽略的是第三条和第五条。我见过有人用了一个标注质量很差的数据集,训出来的模型在测试集上表现很好,一上真实数据就崩了。也见过有人做完项目才发现数据集不允许商业使用,只能推倒重来。

6.2 几个我踩过的真实坑

坑一:图像和标注尺寸不一致。某数据集的部分图像是5000x5000,标注是10000x10000,直接加载会报错。后来发现是标注在保存时被上采样了,需要手动下采样对齐。这个坑让我写了一个通用的尺寸检查脚本,每次加载数据前先跑一遍。

坑二:类别ID不连续。某分割数据集的类别ID是0、1、2、4、5,跳过了3。我一开始没注意,模型输出5个类别,但实际只有4个有效类别,导致训练时loss计算错误。后来养成习惯,先打印np.unique(mask)确认类别ID。

坑三:坐标系不一致。某检测数据集的标注用的是地理坐标系,图像用的是像素坐标系,转换时没注意,框全偏了。这个坑最隐蔽,因为可视化的时候如果不叠加底图,根本看不出来。后来我每次转换完都叠加原图检查。

坑四:训练集和测试集有重叠区域。某数据集划分时没有按区域划分,而是随机划分,导致同一区域的图像同时出现在训练集和测试集。模型在测试集上表现很好,但实际部署时性能下降。后来我改用按地理区域划分,确保训练集和测试集没有空间重叠。

6.3 数据集组合使用的策略

实际项目中,单一数据集往往不够用。我通常组合多个数据集:用一个大规模数据集做预训练,用目标区域的小数据集做微调。组合时要注意类别体系对齐,把不同数据集的类别映射到统一体系。比如数据集A的“建筑”和数据集B的“建筑物”合并成“建筑”,数据集A的“道路”和数据集B的“公路”合并成“道路”。

组合训练的另一个技巧是采样权重。大数据集采样权重低,小数据集采样权重高,避免模型被大数据集主导。我一般用WeightedRandomSampler,权重和数据集大小的平方根成反比。

from torch.utils.data import WeightedRandomSampler import numpy as np def build_sampler(dataset_sizes): weights = [] for size in dataset_sizes: w = 1.0 / np.sqrt(size) weights.extend([w] * size) weights = np.array(weights) weights = weights / weights.sum() sampler = WeightedRandomSampler(weights, num_samples=len(weights), replacement=True) return sampler

这个策略我在多数据集联合训练时经常用,能有效平衡不同数据集的影响。注意权重不要设得太极端,否则小数据集会被过采样,导致过拟合。

6.4 数据清洗的自动化脚本

最后分享一个我常用的数据清洗脚本框架,能自动检查常见问题:

import os import numpy as np from PIL import Image def audit_dataset(root_dir): issues = [] for subdir in ['images', 'masks']: path = os.path.join(root_dir, subdir) if not os.path.exists(path): issues.append(f"缺失目录: {path}") continue files = os.listdir(path) print(f"{subdir}: {len(files)} 个文件") for f in files[:10]: # 抽样检查 filepath = os.path.join(path, f) try: img = Image.open(filepath) arr = np.array(img) if arr.ndim == 2: unique = np.unique(arr) if len(unique) > 50: issues.append(f"{f}: 标注类别过多({len(unique)}),可能是灰度图误用") if arr.shape[0] < 64 or arr.shape[1] < 64: issues.append(f"{f}: 尺寸过小({arr.shape})") except Exception as e: issues.append(f"{f}: 无法读取 - {str(e)}") return issues

这个脚本跑一遍,能快速发现格式错误、尺寸异常、标注类别异常等问题。我每次拿到新数据集都会先跑这个,比手动检查快得多。

遥感公开数据集这个领域,信息更新很快,新的数据集不断出现,旧的也在迭代。但核心的选型逻辑和踩坑经验是通用的:先对齐任务定义,再检查标注质量,最后考虑数据规模和组合策略。把这几点做好,后面模型训练和调参才有意义。否则再好的模型,喂进去脏数据,出来的也是垃圾。

返回列表