资讯动态

高分二号遥感影像语义分割数据集制作全流程:从预处理到Labelme标注

发布时间:2026/8/24 7:43:06 来源:尧图企业网站定制
1. 项目概述为什么从零开始制作遥感数据集如果你正在研究遥感图像的语义分割比如用深度学习模型去识别高分二号影像里的建筑、道路、水体那你肯定遇到过最头疼的问题找不到现成的、完全符合你研究区或任务需求的数据集。网上的公开数据集要么区域不对要么类别定义和你想要的不一样要么标注质量参差不齐。这时候自己动手从原始的高分二号GF-2影像开始制作一套量身定制的数据集就成了必经之路也是最能保证后续模型效果的关键一步。这个过程听起来有点吓人尤其是对刚入门的朋友。它涉及到数据获取、预处理、标注工具选择、标注规范制定、格式转换等一系列环节。但别担心这其实是一个标准化流程一旦跑通你就会发现它并没有想象中那么复杂而且能给你带来巨大的灵活性和控制力。我自己在多个城市建筑物提取、农田地块分割的项目里都是这么一步步走过来的。今天我就以国产的高分二号卫星影像为例带你完整走一遍这个流程把每个环节的“坑”和技巧都讲清楚。简单来说我们要做的是拿到原始的GF-2多光谱或全色影像 - 进行必要的预处理如辐射定标、大气校正、图像融合、裁剪- 使用标注工具比如我们这里会用labelme人工勾绘出我们感兴趣的地物类别 - 将标注结果转换成模型训练所需的格式如PNG掩码图- 最后整理成标准的数据集目录。核心关键词就是遥感图像、语义分割、数据集制作、高分二号、labelme。2. 高分二号遥感影像的获取与预处理2.1 理解高分二号数据源高分二号GF-2是我们国家高分辨率对地观测系统的重要一员它的数据在国土资源调查、城市规划、环境监测等领域应用非常广泛。选择它作为例子一是因为数据相对容易获取通过官方渠道或合作单位二是因为其参数具有代表性。GF-2搭载了两台高分辨率1米全色、4米多光谱相机。这里有几个关键参数你需要心里有数全色波段1米分辨率只有一个波段图像细节非常丰富但缺乏色彩信息。多光谱波段4米分辨率包含蓝、绿、红、近红外四个波段。多光谱信息对于区分地物类型比如植被、水体至关重要。幅宽约45公里一次能拍挺大一块区域。我们拿到的原始数据通常是分发的“原始数据包”里面包含全色和多光谱的单独文件以及一堆描述成像参数的元数据文件.xml或 .rpb。你不可能直接把这一大包数据扔给标注软件必须经过预处理。2.2 数据预处理全流程拆解预处理的目标是得到一幅清晰、色彩自然、几何精度高的“底图”方便我们在上面进行精确标注。这个过程专业上叫“影像预处理流程”。第一步辐射定标与大气校正这是为了将传感器记录的原始数字量化值DN值转换为具有物理意义的地表反射率。简单理解就是消除大气散射、吸收等影响让图像的颜色更接近地物真实的反射特性。这对于后续利用光谱信息区分地物比如用近红外波段识别植被非常重要。常用工具ENVI、PCI Geomatica、或者开源工具如Sen2Cor针对哨兵但原理相通。GF-2数据通常提供定标系数可以在ENVI中使用Radiometric Calibration工具选择传感器类型为GF-2输入定标系数文件来完成。我的经验如果你的研究区域大气条件良好且你主要关注形状信息而非精细光谱分析有时为了快速验证可以跳过大气校正只做辐射定标。但对于严谨的研究尤其是涉及植被、水体等光谱敏感地物这一步建议不要省。第二步全色与多光谱图像融合这是高分影像处理的精髓。我们要把1米分辨率的全色图像细节好和4米分辨率的多光谱图像颜色好合二为一得到一幅兼具高空间分辨率和多光谱信息的新图像。融合算法选择算法很多如PCA主成分分析、Brovey、Gram-Schmidt、NNDiffuse等。对于GF-2Gram-SchmidtGS融合是公认效果较好的一种它能较好地保持光谱保真度和空间细节。实操步骤以ENVI为例分别打开经过辐射定标的全色和多光谱影像。在工具箱中搜索Image Sharpening-Gram-Schmidt Pan Sharpening。按照向导选择多光谱影像作为Low Resolution Multispectral Input全色影像作为High Resolution Pan Input。设置输出参数运行即可得到融合后的1米分辨率多光谱影像。注意事项融合后一定要目视检查看看有没有出现色彩失真比如植被变得不绿了或者“重影”现象。如果效果不佳可以尝试调整融合算法的参数或者换一种算法如NNDiffuse试试。第三步研究区裁剪与格式转换一整景GF-2影像太大了好几GB我们通常只关心其中一小块研究区。裁剪在ENVI或QGIS中根据你的研究区矢量边界或者手动画一个矩形对融合后的影像进行裁剪。这能极大减小数据量加快后续标注和模型训练的速度。格式转换将裁剪后的影像保存为标注工具兼容的格式。labelme支持直接读取GeoTIFF但有时大尺寸的GeoTIFF在labelme中浏览会卡顿。一个稳妥的做法是将影像输出为标准的RGB三波段JPEG或PNG图片。具体操作是在ENVI中选择File - Save As - Image File选择输出格式为JPEG/PNG并在Spatial Subset中确认裁剪范围在Spectral Subset中选择RGB Bands通常对应红、绿、蓝三个波段例如GF-2的Band3 Band2 Band1。这样得到的是一张普通的图片文件但坐标信息会丢失。务必备份好原始的GeoTIFF文件和其对应的坐标信息文件.jgw或 .tfw以备后续可能需要的坐标回溯。重要提示预处理流程并非一成不变。如果你的原始数据已经是经过正射校正和融合的“2级产品”那么前两步可能已经由数据提供商完成。你需要仔细阅读数据说明文档。我们的核心原则是为标注人员提供一幅视觉解释性最强的底图。3. 使用Labelme进行语义分割标注3.1 Labelme的安装与基础配置labelme是一个用Python编写的图形化图像标注工具特别适合多边形标注是语义分割数据制作的利器。它比一些商业软件轻量且完全免费、开源。安装强烈推荐使用Conda环境# 创建并激活一个专门的标注环境 conda create -n labelme python3.8 conda activate labelme # 使用pip安装labelme pip install labelme安装完成后在命令行输入labelme即可启动图形界面。为什么用Conda避免与系统中其他Python项目的包版本冲突。标注可能是个长期工作一个独立的环境更干净。启动labelme后界面很简洁。我们先进行关键配置点击顶部菜单栏的File - Change Output Dir设置一个文件夹用于存放所有标注产生的.json文件。建议为每个项目建立清晰的目录结构例如My_GF2_Dataset/ ├── images/ # 存放预处理后的JPEG底图 ├── annotations/ # 存放labelme生成的json文件 └── labels/ # 后续存放转换得到的掩码图3.2 制定标注规范与实操标注在开始狂点鼠标之前花时间制定一份清晰的《标注规范》是事半功倍的关键。这能保证不同标注人员甚至不同时间的你自己结果的一致性。1. 定义类别及其对应颜色 在labelme中类别是通过你在标注时输入的label名字来区分的。你需要预先规划好所有类别。例如一个简单的城市地块分类类别名称 (Label)含义说明建议颜色 (RGB)备注building建筑物屋顶轮廓红色 (255,0,0)包含居民楼、厂房等忽略屋顶附属物road主干道、铺装道路灰色 (128,128,128)包含路面不含路肩、绿化带water河流、湖泊、池塘蓝色 (0,0,255)静止或流动的水体vegetation树木、草地、农田绿色 (0,255,0)连片的绿色植被区域background背景/未标注区域黑色 (0,0,0)无需手动标注是默认值2. 标注实操步骤与技巧打开图像在labelme中点击Open Dir选择你的images/文件夹。创建多边形点击左侧工具栏的Create Polygon按钮或按快捷键Ctrl P然后沿着目标地物的边界依次点击形成闭合多边形。双击最后一个点或按回车键完成闭合。输入标签闭合后会自动弹出标签输入框。从你预定义的类别列表中选择或输入。强烈建议使用英文标签避免后续脚本处理出现编码问题。高级技巧放大与导航用鼠标滚轮放大缩小按住空格键拖动画布。标注精细边界如建筑屋檐时必须放大到像素级进行操作。编辑形状标注错了选中已创建的多边形拖动顶点可以调整形状。右键点击多边形可以选择Edit Label修改标签或Delete Shape删除。复杂形状处理对于形状特别复杂的地物如不规则湖泊不必追求一个多边形搞定。可以用多个多边形Multi-polygon来拼接只要它们都属于同一个label如water后续转换时会自动合并。“洞”的处理如果建筑物中间有天井或中空部分你需要先标注外部轮廓再在里面标注一个内部轮廓并在输入标签时将其指定为background或其他特定标签。labelme支持这种“孔洞”结构。保存标注完一张图后点击Save会在你设置的annotations/目录下生成一个同名的.json文件。这个文件记录了所有多边形顶点的坐标和对应的标签。3. 标注质量把控边界紧贴多边形边界应尽可能紧贴地物边缘避免留出过多空白或包含无关区域。类别一致确保同类地物标签完全一致比如不要有些写building有些写Building。定期检查标注一段时间后随机抽查几张图的.json文件用labelme重新打开看看效果。也可以让同事交叉检查。4. 将Labelme标注转换为模型训练格式4.1 理解标注文件与目标格式labelme生成的.json文件是便于人类编辑和软件读取的中间格式但绝大多数语义分割模型如U-Net, DeepLab, SegFormer训练时需要的是像素级的标签掩码图。通常这是一张单通道的PNG图像图像中每个像素点的值是一个整数代表其所属的类别索引例如0代表背景1代表建筑2代表道路...。我们的核心任务就是将包含多边形信息的.json文件“渲染”成这种单通道的掩码图。4.2 使用脚本进行批量格式转换手动转换是不可能的。我们需要编写或使用一个Python脚本进行批量处理。labelme官方提供了一些示例脚本我们可以在此基础上修改。1. 准备标签名到索引的映射文件 创建一个名为labels.txt的文本文件内容如下__ignore__ _background_ building road water vegetation注意前两行__ignore__和_background_是labelme转换脚本通常要求的_background_对应索引0。后面的行就是我们的类别索引从1开始自动分配。2. 执行转换脚本labelme安装后自带一个命令行工具labelme_json_to_dataset但它一次只能处理一个文件。我们需要其批量版本。你可以使用以下Python脚本保存为json_to_dataset.pyimport os import json import numpy as np import PIL.Image import PIL.ImageDraw # 定义路径 json_dir path/to/your/annotations # 存放json文件的文件夹 img_dir path/to/your/images # 存放原图的文件夹用于获取图像尺寸 label_file path/to/your/labels.txt # 标签映射文件 output_dir path/to/your/labels # 输出掩码图的文件夹 os.makedirs(output_dir, exist_okTrue) # 读取标签列表 with open(label_file, r) as f: labels f.read().splitlines() label_map {name: idx for idx, name in enumerate(labels)} # 创建标签到索引的映射 # 遍历所有json文件 for json_name in os.listdir(json_dir): if not json_name.endswith(.json): continue json_path os.path.join(json_dir, json_name) base_name os.path.splitext(json_name)[0] # 加载json数据 with open(json_path, r) as f: data json.load(f) # 获取图像尺寸 img_path os.path.join(img_dir, base_name .jpg) # 假设原图是jpg img PIL.Image.open(img_path) img_width, img_height img.size # 创建全零的掩码图背景为0 mask np.zeros((img_height, img_width), dtypenp.uint8) # 遍历json中的每个形状多边形 for shape in data[shapes]: label_name shape[label] # 忽略 __ignore__ 标签 if label_name __ignore__: continue points shape[points] polygon [(p[0], p[1]) for p in points] # 将点列表转换为多边形坐标 # 获取该标签对应的索引 label_idx label_map.get(label_name) if label_idx is None: print(f警告在文件 {json_name} 中发现未定义标签 {label_name}已跳过。) continue # 使用PIL将多边形绘制到掩码图上 img_mask PIL.Image.new(L, (img_width, img_height), 0) draw PIL.ImageDraw.Draw(img_mask) # 注意PIL的多边形填充要求坐标是整数元组 int_polygon [(int(x), int(y)) for (x, y) in polygon] draw.polygon(int_polygon, filllabel_idx) # 将绘制好的多边形合并到总掩码中使用np.maximum后绘制的覆盖先绘制的 mask np.maximum(mask, np.array(img_mask)) # 保存掩码图 mask_img PIL.Image.fromarray(mask) mask_save_path os.path.join(output_dir, base_name _label.png) # 常用后缀 _label.png 或 .png mask_img.save(mask_save_path) print(f已处理: {json_name} - {mask_save_path}) print(所有标注文件转换完成)3. 运行与检查 在配置好labelme环境的终端中运行python json_to_dataset.py。脚本会遍历所有.json文件并在output_dir中生成对应的掩码PNG图。关键检查用图片查看器打开生成的掩码图它应该看起来是黑乎乎的带有不同灰度的区域。你可以用简单的Python代码或图像处理软件将其映射为彩色查看确保每个类别的区域都正确无误。4.3 构建最终数据集目录转换完成后我们就有了模型训练所需的“图像-标签”对。标准的语义分割数据集目录结构如下GF2_Segmentation_Dataset/ ├── images/ │ ├── train/ # 训练集原图 │ ├── val/ # 验证集原图 │ └── test/ # 测试集原图可选 ├── masks/ # 或 labels/ │ ├── train/ # 训练集掩码图 │ ├── val/ # 验证集掩码图 │ └── test/ # 测试集掩码图可选 └── dataset_info.json # 可选记录类别信息、数据统计等你需要将预处理好的JPEG原图和对应的_label.png掩码图按照一定的比例如70%训练15%验证15%测试分别放入images/train,masks/train等文件夹。务必确保原图和掩码图的文件名严格对应例如area1.jpg对应area1_label.png。5. 标注过程中的常见问题与解决策略制作数据集是个细致活踩坑是常态。下面是我总结的几个典型问题及解决办法。5.1 图像尺寸过大导致标注卡顿或崩溃问题GF-2融合后1米分辨率的图像即使裁剪后单边可能也有上万像素。直接在labelme中打开这样的巨型图片会非常卡顿甚至导致程序无响应。解决方案预先分块在预处理裁剪阶段不要直接裁剪出整个研究区。用一个脚本将大图切割成重叠的小图块例如1024x1024像素。用labelme标注这些小图块速度会快很多。训练时也直接使用这些小图块。调整labelme设置在labelme中点击File - Settings可以调整缓存大小。但这对巨型图像帮助有限。使用金字塔技术高级将影像处理为金字塔式TIFF但labelme支持有限。更实用的方法是使用专业的GIS软件如QGIS进行初标注再导出为矢量格式最后转换为labelme的json格式但这流程更复杂。5.2 地物边界模糊或存在阴影问题建筑物阴影投射在道路上或者水体边界因为反光而不清晰导致标注时难以判断精确边界。解决策略多源辅助判断如果有时间序列影像可以查看不同时相的图帮助判断边界。例如阴影位置会随时间变化但建筑物边界不会。参考更高分辨率数据如果条件允许可以购买或寻找0.5米甚至更高分辨率的商业卫星影像如WorldView作为参考。制定规则在标注规范中明确这类情况的处理方式。例如“建筑物边界以屋顶投影到地面的可见边缘为准忽略阴影部分”“水体边界以水陆分界线的平均位置为准”。保持一致性最重要的是所有模糊边界的处理方式在整个数据集中要保持一致。可以保留少量“不确定”区域将其标注为__ignore__如果转换脚本支持这样模型在训练时会忽略这些区域。5.3 类别不平衡与样本量不足问题城市影像中“建筑”和“道路”的像素可能占80%而“水体”只占5%。这会导致模型严重偏向多数类。解决策略数据层面过采样在划分训练集时刻意多选择一些包含稀有类别的图块。数据增强对包含稀有类别的图块进行更强烈的数据增强旋转、翻转、色彩抖动等生成更多变体。专门采集如果水体是你的关键研究目标可以专门寻找包含湖泊、河流的影像区域进行标注补充到数据集中。算法层面损失函数使用加权交叉熵损失Weighted Cross-Entropy Loss或Dice Loss、Focal Loss等对类别不平衡不敏感的损失函数。在损失计算时给稀有类别赋予更高的权重。评估指标不要只看整体的准确率Accuracy更要关注每个类别的交并比IoU或F1分数特别是稀有类别的。5.4 标注一致性检验与质量控制问题自己标注时间长了会疲劳多人标注标准可能不统一。质量控制流程规范文档一份详细的、图文并茂的标注规范文档是基石必须人手一份并定期讨论更新。试标与校准项目开始前所有人对同一小块区域进行标注然后开会讨论差异点统一认识修正规范。中间检查标注完成30%时进行一轮集中检查。随机抽取每人一定数量的样本由负责人或交叉检查记录错误类型和频率。工具辅助可以使用一些简单的脚本计算标注的一致性指标如两个人对同一张图的标注之间的IoU。最终验收全部完成后再次抽样检查。只有通过验收的标注才能进入最终数据集。6. 数据集制作后的下一步模型训练初步准备数据集做好后你已经完成了最艰巨的80%的工作。在投入模型训练前还有几个重要的准备步骤。1. 创建数据加载器 你需要编写一个PyTorch的Dataset类或TensorFlow的tf.data管道来读取images/train和masks/train下的文件对。这个类的主要工作是读取图像和掩码。进行实时的数据增强如随机裁剪、翻转、旋转、亮度对比度调整。将图像像素值归一化如除以255.0缩放到[0,1]将掩码图转换为类别索引的张量。返回(image_tensor, mask_tensor)对。2. 划分训练集与验证集 确保划分是随机的但也要保证验证集中包含所有类别的样本。可以使用scikit-learn的train_test_split函数。3. 计算类别权重 如果你打算使用加权损失函数需要根据训练集掩码统计每个类别的像素频率。权重通常与频率成反比例如使用中值频率平衡weight median_freq / class_freq。4. 选择与适配模型 对于遥感语义分割U-Net及其变体如Attention U-Net是经典且有效的起点。DeepLabv3在处理大尺度上下文信息方面表现优异。近年来基于Transformer的模型如SegFormer也展现出强大性能。你可以从这些模型入手将数据加载器接入开始你的训练迭代。从一张原始的GF-2卫星影像到一份规整的、可用于训练深度学习模型的数据集这个过程确实充满了细节和挑战。但每一步都有其明确的目的和可操作的方法。我个人的体会是前期在数据预处理和标注规范上多花一小时后期在模型调试上可能就能省下一天。标注数据虽然枯燥但它是整个AI项目的基石基石不稳后面的大楼再华丽也容易倒塌。当你第一次用自己制作的数据集训练出一个能准确识别出图中建筑物的模型时那种成就感是完全不一样的。最后再分享一个小技巧在标注过程中定期备份你的labelme的.json文件到云端或另一块硬盘你永远不知道意外和手滑哪个先来。

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

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

免费获取报价