在深度学习语义分割任务中,像素级标签(mask)是训练模型的关键输入。GeoAI 提供了一套完整的工具,用于将矢量数据(如 GeoJSON、Shapefile 等)转换为与影像对应的像素级标签,为模型训练提供准确的标注数据。
主要功能
• 多格式矢量支持:支持 GeoJSON、Shapefile、GeoPackage 等多种矢量格式 • 自动投影转换:确保矢量数据与影像的坐标系一致 • 缓冲区处理:可选择为矢量特征添加缓冲区,控制标签的粗细 • 多类别支持:支持多类别的矢量数据,并自动构建类别映射 • 瓦片级处理:支持将大幅影像和矢量数据切分为小瓦片进行处理 • 多种注释格式:支持生成 PASCAL VOC、COCO、YOLO 等格式的注释文件
基本流程
┌─────────────────────────────────────────────────┐│ 矢量数据转像素级标签流程 │├─────────────────────────────────────────────────┤│ 1. 加载矢量数据 ││ 2. 投影转换(与影像CRS一致) ││ 3. 应用缓冲区(可选) ││ 4. 构建类别映射 ││ 5. 提取与瓦片相交的特征 ││ 6. 栅格化每个特征到瓦片大小的掩码 ││ 7. 合并特征掩码生成最终标签 ││ 8. 保存标签掩码和注释文件(可选) │└─────────────────────────────────────────────────┘核心算法
1. 矢量数据加载与预处理
• 数据加载:使用 geopandas 读取矢量文件,支持多种格式 • 投影转换:将矢量数据转换为与影像相同的坐标系 • 缓冲区处理:为矢量特征添加缓冲区,控制标签的空间范围 • 类别映射:从矢量数据中提取类别信息,构建类别到 ID 的映射
2. 特征提取与栅格化
• 空间过滤:使用空间索引快速提取与瓦片相交的特征 • 几何裁剪:裁剪特征到瓦片边界,避免超出范围 • 栅格化:使用 rasterio 的 rasterize 函数将矢量特征转换为像素值 • 掩码合并:合并多个特征的栅格化结果,处理重叠情况
3. 标签后处理
• 空值处理:处理无特征的瓦片,生成空白掩码 • 错误处理:捕获和记录栅格化过程中的错误 • 格式转换:根据需要转换为不同的注释格式
核心代码分析
1. 矢量数据加载与处理
_load_class_data_vector()
功能:加载矢量数据并构建类别映射
核心参数:
• vector_path:矢量文件路径• src_crs:影像的坐标系• class_value_field:存储类别值的字段名• buffer_radius:缓冲区半径
核心代码:
def_load_class_data_vector( vector_path, src_crs, class_value_field="class", buffer_radius=0, quiet=False, metadata_format=None,): coco_categories = []try:# 加载矢量数据 gdf = gpd.read_file(vector_path)ifnot quiet: logger.info(f"Loaded {len(gdf)} features from {vector_path}") logger.info(f"Vector CRS: {gdf.crs}")# 投影转换if gdf.crs != src_crs:ifnot quiet: logger.info(f"Reprojecting features from {gdf.crs} to {src_crs}") gdf = gdf.to_crs(src_crs)# 应用缓冲区if buffer_radius > 0: gdf["geometry"] = gdf.buffer(buffer_radius)ifnot quiet: logger.info(f"Applied buffer of {buffer_radius} units")# 构建类别映射if class_value_field in gdf.columns: unique_classes = gdf[class_value_field].unique()ifnot quiet: logger.info(f"Found {len(unique_classes)} unique classes: {unique_classes}" ) class_to_id = {cls: i + 1for i, cls inenumerate(unique_classes)}# 生成 COCO 类别信息if metadata_format == "COCO":for cls_val in unique_classes: coco_categories.append( {"id": class_to_id[cls_val],"name": str(cls_val),"supercategory": "object", } )else:# 无类别字段时使用默认类别ifnot quiet: logger.warning(f"'{class_value_field}' not found in vector data. ""Using default class ID 1." ) class_to_id = {1: 1}if metadata_format == "COCO": coco_categories.append( {"id": 1,"name": "object","supercategory": "object", } )return gdf, class_to_id, coco_categoriesexcept Exception as e:raise ValueError(f"Error processing vector data: {e}")代码说明:
1. 使用 geopandas 加载矢量数据 2. 检查并转换坐标系,确保与影像一致 3. 应用缓冲区 4. 从矢量数据中提取类别信息并构建映射 5. 生成 COCO 格式的类别信息 6. 返回处理后的 GeoDataFrame、类别映射和 COCO 类别信息
2. 矢量特征栅格化
_rasterize_label_from_vector()
功能:将矢量特征栅格化为瓦片大小的标签掩码
核心参数:
• gdf:GeoDataFrame 格式的矢量数据• window_bounds:瓦片的空间边界• window_transform:瓦片的地理变换• tile_size:瓦片大小• class_value_field:存储类别值的字段名• class_to_id:类别到 ID 的映射• all_touched:是否包含所有接触的像素
核心代码:
def_rasterize_label_from_vector( gdf, window_bounds, window_transform, tile_size, class_value_field, class_to_id, all_touched=True,):# 初始化标签掩码 label_mask = np.zeros((tile_size, tile_size), dtype=np.uint8) has_features = False errors = 0# 提取与瓦片相交的特征 window_features = gdf[gdf.intersects(window_bounds)]iflen(window_features) == 0:return label_mask, has_features, window_features, errors# 处理每个特征for idx, feature in window_features.iterrows():# 获取特征的类别 IDif class_value_field in feature: class_val = feature[class_value_field] class_id = class_to_id.get(class_val, 1)else: class_id = 1# 裁剪特征到瓦片边界 geom = feature.geometry.intersection(window_bounds)ifnot geom.is_empty:try:# 栅格化特征 feature_mask = features.rasterize( [(geom, class_id)], out_shape=(tile_size, tile_size), transform=window_transform, fill=0, all_touched=all_touched, )# 合并到标签掩码(使用最大值避免重叠冲突) label_mask = np.maximum(label_mask, feature_mask)if np.any(feature_mask): has_features = Trueexcept Exception as e: logger.error(f"Error rasterizing feature {idx}: {e}") errors += 1return label_mask, has_features, window_features, errors代码说明:
1. 初始化标签掩码为全零 2. 使用空间查询提取与瓦片相交的特征 3. 遍历每个特征,获取其类别 ID 4. 裁剪特征到瓦片边界 5. 使用 rasterio 的 rasterize 函数将特征栅格化为像素值 6. 合并多个特征的栅格化结果 7. 记录是否包含特征和错误信息 8. 返回标签掩码、特征存在标志、相交特征和错误计数

3. 辅助函数
_compute_tile_window()
功能:计算瓦片的像素窗口和地理空间边界
核心代码:
def_compute_tile_window(x, y, stride_x, stride_y, tile_w, tile_h, src): window_x = x * stride_x window_y = y * stride_y# 确保瓦片不超出影像边界if window_x + tile_w > src.width: window_x = src.width - tile_wif window_y + tile_h > src.height: window_y = src.height - tile_h# 创建窗口对象 window = Window(window_x, window_y, tile_w, tile_h)# 计算窗口的地理变换 window_transform = src.window_transform(window)# 计算窗口的地理边界 minx = window_transform[2] maxy = window_transform[5] maxx = minx + tile_w * window_transform[0] miny = maxy + tile_h * window_transform[4]# 创建边界几何对象 window_bounds = box(minx, miny, maxx, maxy)return window, window_transform, window_bounds, minx, miny, maxx, maxy代码说明:
1. 计算瓦片的像素坐标 2. 确保瓦片不超出影像边界 3. 创建窗口对象并计算地理变换 4. 计算窗口的地理边界 5. 返回窗口相关信息
使用示例
示例 1:基本矢量转掩码
import geoai# 将矢量数据转换为与影像对应的标签geoai.export_geotiff_tiles( in_raster="image.tif", out_folder="output", in_class_data="buildings.geojson", # 矢量数据 tile_size=256, stride=128, class_value_field="class", # 矢量数据中的类别字段 buffer_radius=0.5# 为建筑物添加 0.5 单位的缓冲区)print("矢量数据转掩码完成!")示例 2:多类别矢量转掩码
import geoai# 处理多类别的矢量数据geoai.export_geotiff_tiles( in_raster="satellite.tif", out_folder="output_multi_class", in_class_data="landcover.shp", # 多类别矢量数据 tile_size=512, stride=256, class_value_field="landcover_type", # 存储类别信息的字段 metadata_format="COCO"# 生成 COCO 格式的注释)print("多类别矢量数据转掩码完成!")示例 3:自定义栅格化参数
import geoai# 自定义栅格化参数geoai.export_geotiff_tiles( in_raster="aerial.tif", out_folder="output_custom", in_class_data="roads.geojson", tile_size=256, stride=128, class_value_field="road_type", buffer_radius=1.0, # 为道路添加 1.0 单位的缓冲区 all_touched=False, # 只包含完全包含的像素 skip_empty_tiles=True# 跳过无特征的瓦片)print("自定义参数的矢量转掩码完成!")参数说明
核心参数
in_raster | |||
out_folder | |||
in_class_data | |||
class_value_field | |||
buffer_radius | |||
all_touched | |||
skip_empty_tiles | |||
metadata_format |
瓦片参数
tile_size | |||
stride | |||
max_tiles |
常见问题解决
1. 矢量与影像坐标系不一致
解决方案:
• GeoAI 会自动检测并转换坐标系,但建议在处理前确保两者一致 • 可以使用 QGIS 或其他工具预先转换矢量数据的坐标系
2. 矢量特征过多导致处理缓慢
解决方案:
• 使用 skip_empty_tiles=True跳过无特征的瓦片• 增加 stride参数,减少瓦片数量• 考虑对矢量数据进行简化或过滤
3. 栅格化结果不完整
解决方案:
• 检查 buffer_radius参数是否合适• 确保 all_touched参数设置正确• 检查矢量数据是否有几何错误
4. 类别 ID 映射错误
解决方案:
• 确保 class_value_field参数指向正确的字段• 检查矢量数据中是否存在空值或无效值 • 手动指定类别映射以确保一致性
5. 内存不足
解决方案:
• 减小 tile_size参数• 使用 max_tiles参数限制处理的瓦片数量• 对大型矢量数据进行分块处理
GeoAI 提供了一套强大的工具,用于将矢量数据转换为像素级标签,为深度学习语义分割任务提供准确的训练数据。核心功能包括:
1. 多格式支持:支持多种矢量格式和注释输出格式 2. 自动投影转换:确保矢量数据与影像的坐标系一致 3. 灵活的参数配置:支持缓冲区、类别映射等多种参数调整 4. 高效的空间处理:利用空间索引和分块处理提高性能 5. 完整的错误处理:妥善处理各种异常情况
通过合理配置参数和选择适当的处理策略,可以高效地将矢量数据转换为高质量的像素级标签,为深度学习模型训练提供有力支持。
夜雨聆风