乐于分享
好东西不私藏

GeoAI矢量转标签源码分析

GeoAI矢量转标签源码分析

在深度学习语义分割任务中,像素级标签(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 = {11}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. 1. 使用 geopandas 加载矢量数据
  2. 2. 检查并转换坐标系,确保与影像一致
  3. 3. 应用缓冲区
  4. 4. 从矢量数据中提取类别信息并构建映射
  5. 5. 生成 COCO 格式的类别信息
  6. 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. 1. 初始化标签掩码为全零
  2. 2. 使用空间查询提取与瓦片相交的特征
  3. 3. 遍历每个特征,获取其类别 ID
  4. 4. 裁剪特征到瓦片边界
  5. 5. 使用 rasterio 的 rasterize 函数将特征栅格化为像素值
  6. 6. 合并多个特征的栅格化结果
  7. 7. 记录是否包含特征和错误信息
  8. 8. 返回标签掩码、特征存在标志、相交特征和错误计数
Fundamentals of GIS and GPS (Chapter 2) - Spatial Analysis in Field Primatology

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. 1. 计算瓦片的像素坐标
  2. 2. 确保瓦片不超出影像边界
  3. 3. 创建窗口对象并计算地理变换
  4. 4. 计算窗口的地理边界
  5. 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
str
必填
输入影像路径
out_folder
str
必填
输出目录路径
in_class_data
str
None
矢量数据路径
class_value_field
str
"class"
存储类别值的字段名
buffer_radius
float
0
缓冲区半径(CRS单位)
all_touched
bool
True
是否包含所有接触的像素
skip_empty_tiles
bool
False
是否跳过无特征的瓦片
metadata_format
str
"PASCAL_VOC"
注释格式("PASCAL_VOC"、"COCO"、"YOLO")

瓦片参数

参数
类型
默认值
说明
tile_size
int
256
瓦片大小(像素)
stride
int
128
步长(像素)
max_tiles
int
None
最大处理瓦片数

常见问题解决

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. 1. 多格式支持:支持多种矢量格式和注释输出格式
  2. 2. 自动投影转换:确保矢量数据与影像的坐标系一致
  3. 3. 灵活的参数配置:支持缓冲区、类别映射等多种参数调整
  4. 4. 高效的空间处理:利用空间索引和分块处理提高性能
  5. 5. 完整的错误处理:妥善处理各种异常情况

通过合理配置参数和选择适当的处理策略,可以高效地将矢量数据转换为高质量的像素级标签,为深度学习模型训练提供有力支持。