尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

高分二号遥感影像语义分割数据集构建全流程:从Labelme标注到训练格式转换

高分二号遥感影像语义分割数据集构建全流程:从Labelme标注到训练格式转换 1. 项目概述从零构建遥感专属数据集的必要性如果你正在研究遥感图像的语义分割无论是做土地覆盖分类、建筑物提取还是灾害评估第一个拦路虎往往不是模型而是数据。网上公开的遥感分割数据集像DeepGlobe、ISPRS Vaihingen虽然质量不错但要么分辨率、传感器类型和你的项目需求对不上要么地物类别不是你想要的。更常见的情况是你需要针对某个特定区域、特定任务比如用高分二号影像监测城市绿化率变化来定制数据。这时候从原始遥感影像开始亲手制作一个高质量、可用的数据集就成了绕不开的硬功夫。这个项目我们就以国产高分二号GF-2卫星影像为例完整走一遍从拿到原始数据到最终生成可用于模型训练的数据集如PASCAL VOC或COCO格式的全流程。高分二号具有亚米级空间分辨率全色0.8米多光谱3.2米在城乡规划、环境监测等领域应用广泛用它做例子非常典型。整个过程会涉及遥感影像的预处理、标注工具如Labelme的深度使用、标签格式的转换与校验以及数据集的组织与管理。我踩过的坑、总结的技巧都会毫无保留地分享给你。无论你是遥感方向的研究生还是希望将AI技术落地到地理信息领域的工程师这篇内容都能给你提供一份可直接“抄作业”的实操指南。2. 核心思路与工具选型为什么是这套组合拳制作遥感语义分割数据集核心目标就一个将原始的、多波段的栅格影像转化为“图像-标签”对其中标签是与图像像素一一对应的、用不同整数值表示类别的掩膜图。围绕这个目标流程可以拆解为数据准备 → 影像预处理 → 人工/半自动标注 → 格式转换与后处理 → 数据集划分与组织。2.1 工具链选型背后的逻辑为什么选择Labelme而不是其他这是一个关键决策点。市面上标注工具很多比如专业的ENVI、ArcGIS或者深度学习的CVAT、LabelImg、EISeg。我的选择基于以下几点考量轻量与开源Labelme基于Python和PyQt安装简单跨平台Windows/macOS/Linux对硬件要求不高。这对于个人研究者或小团队来说降低了入门和部署成本。对遥感影像支持尚可虽然Labelme最初是为自然图像设计但它能加载GeoTIFF等常见遥感格式需依赖gdal库。对于高分二号这种已经做过几何校正的影像直接加载显示坐标问题不大。它的多边形标注方式非常适合遥感中不规则的地物边界如水体、农田。格式转换生态成熟Labelme生成的JSON标注文件有非常丰富的转换脚本可以轻松转为PASCAL VOC的PNG掩膜、COCO格式甚至是直接用于训练的各种脚本。社区活跃遇到问题容易找到解决方案。与“SAM大模型”等前沿结合的可能性最近Meta的Segment Anything Model (SAM) 展示了强大的零样本分割能力。虽然SAM直接处理大尺寸遥感影像有挑战但Labelme的标注结果可以作为SAM微调或提示工程的基础为未来引入交互式、半自动标注预留了可能性。当然它也有缺点处理超大影像如整景高分二号数据会卡顿需要预先裁剪没有内嵌的地理坐标直接导出功能但我们可以通过其他方式保留。对于超大规模标注团队CVAT可能更合适。但对于我们从零开始、追求灵活性和控制力的场景Labelme是目前最平衡的选择。其他工具辅助GDAL/OGR遥感领域的“瑞士军刀”。我们将用它来完成影像的读取、裁剪、坐标信息获取与嵌入。几乎所有后续处理都离不开它。OpenCV PIL (Pillow)进行基础的图像读写、颜色映射、格式转换。NumPy标签数组处理的基石。自己写的Python脚本这是灵魂所在。工具是固定的但流程是灵活的我们需要用脚本把各个工具像管道一样连接起来实现自动化。2.2 高分二号数据特点与预处理要点高分二号数据通常以景为单位分发包含一个全色波段PAN0.8米和四个多光谱波段MS蓝、绿、红、近红外3.2米。我们拿到手的往往是已经过辐射校正和系统几何校正的产品如L1A级。预处理的核心步骤波段融合Pan-sharpening为了获得兼具高空间分辨率和高光谱信息的影响需要将3.2米的多光谱影像与0.8米的全色影像融合。常用方法有PCA变换、Brovey变换、Gram-Schmidt变换等。可以使用ENVI、PCI Geomatica等专业软件或者gdal_pansharpen.pyGDAL自带等开源工具。这一步的目的是提升多光谱影像的视觉清晰度便于人工判读和标注。裁剪Clipping一景GF-2影像可能覆盖上百平方公里直接扔进Labelme会卡死。必须将其裁剪成小块比如1024x1024或512x512像素。裁剪时有两个关键点重叠区Overlap为了防止在训练时物体在切块边缘被切断导致模型难以学习相邻切块之间需要保留一定的重叠区域例如256像素。在预测时也可以采用重叠切块和滑动窗口的方式来还原整图。地理信息保留裁剪时必须使用GDAL来操作以确保每一块小影像都携带正确的空间参考和仿射变换参数Geotransform。这为后续可能的地理空间分析或结果回溯打下基础。命令示例gdal_translate -srcwin xoff yoff width height input.tif output_patch.tif。色彩增强与可视化标准假彩色近红外、红、绿或真彩色合成后影像可能对比度不足。可以简单进行一个2%的线性拉伸让地物特征更明显减轻标注员的视觉疲劳。注意预处理的所有步骤尤其是裁剪的起始坐标和尺寸务必记录在案。一个简单的CSV文件记录每个切块的原始文件名、起始行号列号、尺寸等信息在后期需要将预测结果拼回整图时至关重要。3. 基于Labelme的标注实战效率与质量的平衡术预处理后我们得到了一堆小块的TIFF图像。现在进入最耗时但也最核心的环节——人工标注。3.1 Labelme的配置与高效标注技巧安装Labelme很简单pip install labelme。启动后打开一个TIFF文件。如果你的TIFF带有地理信息可能会弹出坐标系统提示忽略或确认即可。创建标签在右侧边栏定义你的语义类别。例如background(0),building(1),road(2),water(3),vegetation(4)。建议从一开始就规划好一个label.txt文件固定类别名和对应的颜色Labelme会自动分配但自己定义更可控。标注操作心法从宏观到微观从简单到复杂不要一上来就死磕一栋结构复杂的大楼。先标注大片的、轮廓清晰的类别如水体、成片林地。这有助于建立标注节奏和信心。多边形点的密度要适中遥感影像边界往往不规则。点太密每个拐点都标效率极低点太疏用很少的点拟合曲线会导致边界失真。我的经验是在保持边界拟合精度的前提下尽量用少的点。对于长而直的边缘如道路、田埂两点确定一条边即可。活用“编辑多边形”功能标注完一个闭合多边形后可以随时点击它进行编辑移动顶点、增加或删除顶点。对于初步勾勒的粗糙边界这是一个精细化利器。“复制多边形”的妙用对于连续、重复的地物比如一排规格相似的温室大棚标注好一个后可以复制其形状然后移动到下一个位置稍作调整能极大提升效率。缩放与导航遥感影像细节丰富必须频繁缩放。使用鼠标滚轮缩放按住空格键拖拽画布。标注时放大到能清晰辨别边界为止。一个常见的难题是阴影和遮挡建筑物阴影可能被误标为水体或植被被树冠部分遮挡的道路边界难以确定。这里的处理原则是以可见部分为准保持一致性。如果项目允许可以增加一个shadow类别如果不允许则阴影部分归入其覆盖的地物类别例如建筑物阴影下的草地仍标为vegetation。关键在于所有标注员要遵循同一套规则最好能形成简单的《标注规范文档》。3.2 标注质量管理如何减少返工一个人标注容易陷入思维定式产生系统性偏差。如果条件允许建议双人背对背标注与核对同一张图由两位标注员独立完成。然后对比结果对于不一致的区域进行讨论确定最终标准。这是保证标注质量最有效但成本最高的方法。抽样检查与迭代修正负责人定期随机抽查已标注图片。重点检查几类常见错误① 漏标明显的地物没标② 错标类别错误③ 边界粗糙或错误。将发现的问题整理成案例同步给所有标注员更新标注规范。利用影像时序辅助判断如果你有多时相的高分二号数据可以同时打开不同时间的影像进行对比。比如某块区域在夏季是植被绿色在冬季是裸土褐色这能帮助你更准确地判断其真实类别。标注完成后每张图片都会生成一个同名的.json文件。这个文件里保存了所有多边形的顶点坐标基于图像像素坐标和对应的标签名。4. 从Labelme JSON到训练用的掩膜格式转换全解析Labelme生成的JSON文件不能直接用于训练。我们需要将其转换为模型能读懂的格式——通常是单通道的PNG掩膜图像每个像素的值是其类别索引。4.1 核心转换脚本详解Labelme官方提供了转换工具但我们需要一个更健壮、适合遥感场景的脚本。以下是一个增强版转换流程的关键部分import json import os import numpy as np from PIL import Image import labelme def json_to_mask(json_file_path, label_name_to_value, output_mask_path): 将Labelme JSON文件转换为语义分割掩膜PNG。 参数: json_file_path: Labelme JSON文件路径。 label_name_to_value: 字典映射标签名到整数值如 {building: 1, road: 2}。 output_mask_path: 输出的掩膜PNG文件路径。 # 读取JSON数据 with open(json_file_path, r) as f: data json.load(f) # 获取图像尺寸 img_height data[imageHeight] img_width data[imageWidth] # 创建一个全零数组背景为0 mask np.zeros((img_height, img_width), dtypenp.uint8) # 处理每个形状多边形 for shape in data[shapes]: label_name shape[label] # 忽略不在我们类别字典中的标签比如可能存在的错误标注 if label_name not in label_name_to_value: print(f警告: 在文件 {json_file_path} 中发现未知标签 {label_name}已跳过。) continue # 将多边形点列表转换为NumPy数组 points np.array(shape[points], dtypenp.int32) # 使用labelme.utils.polygons_to_mask将多边形填充到临时掩膜 # 注意这里假设所有形状都是多边形。如果是矩形、圆形需要额外处理。 shape_mask labelme.utils.shape_to_mask( (img_height, img_width), points, shape_typeshape.get(shape_type, polygon) ) # 将当前形状对应的类别值赋给mask中对应区域 # 这里有一个重要决策如果多边形有重叠后处理的会覆盖先处理的。 # Labelme的绘制顺序通常就是JSON中的顺序所以标注时应注意上下层关系。 mask[shape_mask] label_name_to_value[label_name] # 将NumPy数组保存为PNG图像 mask_img Image.fromarray(mask) mask_img.save(output_mask_path) print(f已保存掩膜至: {output_mask_path}) # 用法示例 label_map {_background_: 0, building: 1, road: 2, water: 3, vegetation: 4} json_to_mask(image1.json, label_map, image1_mask.png)这段代码有几个关键点和潜在陷阱标签映射字典label_name_to_value必须包含所有可能出现的标签名并且为背景指定一个值通常是0。这个字典应该与你的模型训练代码中的类别定义完全一致。重叠处理代码中后绘制的多边形会覆盖先绘制的。这意味着如果两条道路交叉后标注的道路会“盖在”先标注的上面。在语义分割中这通常不是问题因为一个像素只属于一个类别。但在标注时应尽量避免不必要的重叠。对于不可避免的层级如车辆在道路上需要定义优先级规则例如vehicleroad。形状类型代码默认处理多边形。Labelme也支持矩形、圆形等。labelme.utils.shape_to_mask函数能处理多种类型但确保你的JSON中shape_type字段正确。性能如果图像很大如2048x2048且多边形数量极多几百个纯Python循环可能较慢。对于大规模转换可以考虑使用rasterio或cv2.fillPoly进行优化。4.2 生成配套的文件列表与数据集元数据转换出一堆image.jpg和mask.png后我们需要生成数据集划分文件。生成训练/验证/测试集列表随机或按地理位置将数据划分为三部分例如70%训练15%验证15%测试。生成三个文本文件train.txt,val.txt,test.txt每行包含一对图像和掩膜文件的路径相对路径或绝对路径。# train.txt 内容示例 images/train/image_001.jpg annotations/train/image_001_mask.png images/train/image_002.jpg annotations/train/image_002_mask.png ...生成类别信息文件创建一个class_dict.csv或info.yaml文件记录类别信息供训练脚本读取。name,id,color_rgb background,0,0,0,0 building,1,255,0,0 road,2,0,255,0 water,3,0,0,255 vegetation,4,0,255,0这里color_rgb用于可视化与训练无关但能让结果更直观。(可选) 转换为COCO格式如果你想使用MMDetection或Detectron2等框架可能需要COCO格式。这需要更复杂的转换将每个多边形实例作为annotation记录并包含category_id和segmentation多边形点列表。网络上有成熟的labelme2coco.py脚本可以参考但需要仔细调试确保类别ID映射正确。5. 数据集质量检查与常见问题排雷在投入训练之前必须对生成的数据集进行严格检查否则垃圾数据进去垃圾模型出来浪费大量算力和时间。5.1 系统性检查清单图像-掩膜对齐检查尺寸一致性随机抽取一批样本用Python检查图像和对应掩膜的height和width是否完全一致。可视化叠加检查写一个脚本将掩膜以半透明的颜色叠加在原图上显示。目视检查边界是否贴合、有无明显错位。这是发现标注错误最直观的方法。import cv2 import matplotlib.pyplot as plt img cv2.imread(image.jpg) mask cv2.imread(mask.png, cv2.IMREAD_GRAYSCALE) # 为每个类别创建彩色掩膜 colored_mask np.zeros((mask.shape[0], mask.shape[1], 3), dtypenp.uint8) colored_mask[mask1] [255, 0, 0] # 建筑-红色 colored_mask[mask2] [0, 255, 0] # 道路-绿色 # ... 其他类别 overlay cv2.addWeighted(img, 0.7, colored_mask, 0.3, 0) plt.imshow(overlay) plt.show()标签值域检查确保掩膜PNG中所有像素值都在你定义的类别ID范围内例如0-4。用np.unique(mask)检查。出现255或其他异常值说明转换过程可能有问题可能是Labelme中未定义标签的填充值。类别平衡性分析计算数据集中每个类别的像素总数。严重的类别不平衡例如background占95%road只占0.5%会导致模型严重偏向多数类。你需要记录这个情况并在训练时考虑使用加权损失函数如nn.CrossEntropyLoss的weight参数、过采样少类别的图像或使用Dice Loss、Focal Loss等对不平衡数据更友好的损失函数。5.2 常见问题与解决方案实录问题1转换后的掩膜全是黑色0值。排查首先检查JSON文件是否为空或损坏。然后检查label_name_to_value字典中的键名是否与JSON中shape[label]的字符串完全一致包括大小写和空格。这是最常见的原因。解决打印出JSON中的第一个shape[label]与你的字典键名对比。使用.strip()方法去除意外空格。问题2掩膜边界出现锯齿或“洞”。原因Labelme的多边形在渲染和转换时由于坐标取整或填充算法可能导致边界像素不连续或内部出现未填充的像素。解决在转换后可以对掩膜进行轻微的形态学操作如cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)进行一次闭运算填充小洞平滑边界。但kernel要小如3x3避免过度改变物体形状。问题3大尺寸影像标注JSON文件巨大导致转换脚本内存不足。原因一张图上有成千上万个多边形如密集建筑区JSON文件可能几百MB。解决优化标注考虑是否能用更大范围的“超级类别”来标注或者是否必须标注到如此细致的程度流式处理不要一次性将整个JSON加载到内存。可以使用ijson库流式解析JSON文件边解析边处理多边形并写入掩膜。分块处理如果影像本身是分块的这个问题自然缓解。这也反过来说明了预处理时裁剪的重要性。问题4训练时发现模型完全学不会某个类别。回溯检查首先检查数据集中这个类别的样本数量是否极少比如少于10个实例。然后检查这些少数样本的标注质量是否极差错误标注。最后检查该类别的像素在整批数据中是否占比过低导致损失函数对其梯度贡献可以忽略不计。解决针对性补充标注该类别数据如果像素占比过低强烈建议使用类别权重。6. 数据集管理、版本化与后续迭代建议一个项目的数据集很少一蹴而就。随着模型训练和评估你会发现某些类别识别效果差可能需要打标补充数据或者发现新的应用需求需要增加类别。建立清晰的目录结构GF2_Segmentation_Dataset/ ├── raw_images/ # 原始高分二号影像分景存放 ├── processed/ # 预处理后的影像切块 │ ├── images/ # 用于标注的RGB图像 (JPEG/PNG) │ └── geotiff/ # 对应的带地理信息的TIFF可选用于回溯 ├── annotations_labelme/ # Labelme生成的JSON文件 ├── annotations_mask/ # 转换后的PNG掩膜 ├── splits/ # 划分文件 (train.txt, val.txt, test.txt) ├── label_map.txt # 标签-ID映射文件 └── README.md # 数据集说明文档标注规范、版本、统计信息使用Git LFS或DVC进行版本控制图像和掩膜文件很大不适合直接用Git。可以使用Git LFS大文件存储或DVC数据版本控制来管理数据集的版本。每次数据增补或修正都对应一个清晰的提交信息如“v1.1新增200张包含阴影的建筑物样本”。编写数据加载器Dataloader根据你的框架PyTorch/TensorFlow编写一个专用的数据加载器。这个加载器要能正确读取你的文件列表、应用必要的在线数据增强如随机翻转、旋转、色彩抖动并正确处理类别不平衡如采样权重或损失权重。考虑引入半自动标注当你有了一部分高质量标注数据并训练出一个初步模型后可以利用这个模型对未标注数据进行预测生成伪标签pseudo-labels。然后标注员只需要对伪标签进行修正和确认可以大幅提升后续批次的标注效率。这就是“人机回环”Human-in-the-loop的迭代模式。从一张原始的高分二号影像到一份规整的、可直接喂给深度学习模型的数据集这条路每一步都需要耐心和细心。标注是体力活但更是认知活你对地物的理解深度直接决定了数据集的上限从而决定了模型性能的上限。亲手制作数据集的过程也是你深入理解任务、定义问题边界的过程这份经验远比直接下载一个现成数据集来得宝贵。
返回列表