概述
语义分割是将遥感影像中的每个像素分配到特定语义类别的任务,如建筑物、道路、水体、植被等。在 GeoAI 中,与“文本提示式分割”关系最密切的是下面两类工具:
1. GroundedSAM - 结合 Grounding DINO 和 Segment Anything Model (SAM),先按文本提示检测目标,再由 SAM 生成实例级掩码 2. CLIPSegmentation - 使用 CLIP-Seg 模型,根据单个文本提示生成目标类别的概率图和二值掩码
需要注意:严格意义上的“多类别语义分割”通常依赖训练好的 U-Net、DeepLabV3+、SegFormer、timm/SMP 等模型;GroundedSAM 和 CLIPSegmentation 更像是开放词汇、文本提示驱动的分割工具,适合快速探索、辅助标注和特定类别提取。
主要特点
• 基于文本提示:通过自然语言描述指定要分割的目标 • 支持大影像:通过瓦片处理技术处理大幅遥感影像 • 地理空间输出:保留输入 GeoTIFF 的坐标参考信息,便于后续 GIS 分析 • 矢量化能力:GroundedSAM 可选导出边界框和多边形 GeoJSON • 实例级表达:GroundedSAM 能在同一类别中保留多个目标实例,CLIPSegmentation 则主要输出单类别概率/二值掩码
语义分割流程
1. 整体流程

图:不同遥感语义分割模型在影像切片上的结果对比,可直观看到道路、建筑、水体、森林、农田等类别的像素级输出。该图适合理解“每个像素一个类别”的标准语义分割任务。
┌─────────────────────────────────────────────────┐│ 语义分割流程 │├─────────────────────────────────────────────────┤│ 1. 加载输入影像 ││ 2. 切分影像为小瓦片 ││ 3. 对每个瓦片执行分割 ││ - 转换为RGB格式 ││ - 检测目标(仅GroundedSAM) ││ - 生成分割掩码 ││ - 后处理(平滑、去噪等) ││ 4. 合并瓦片结果 ││ 5. 生成输出文件 ││ - 分割掩码(GeoTIFF) ││ - 边界框(GeoJSON,可选) ││ - 多边形(GeoJSON,可选) │└─────────────────────────────────────────────────┘2. GroundedSAM 流程

图:GroundedSAM 的核心思路是“文本提示 -> Grounding DINO 检测框 -> SAM 掩码”。它更接近开放词汇实例分割,最后可以把实例掩码合成为语义类别掩码。
┌─────────────────────────────────────────────────┐│ GroundedSAM 分割流程 │├─────────────────────────────────────────────────┤│ 1. 初始化模型 ││ - 加载 Grounding DINO 检测器 ││ - 加载 SAM 分割模型 ││ 2. 处理输入影像 ││ - 切分影像为瓦片 ││ - 转换为RGB格式 ││ 3. 目标检测 ││ - 使用 Grounding DINO 检测目标 ││ - 应用非极大值抑制(NMS) ││ 4. 实例分割 ││ - 使用 SAM 生成精确掩码 ││ - 细化掩码(可选) ││ 5. 后处理 ││ - 高斯平滑减少块状效应 ││ - 合并重叠掩码 ││ 6. 输出结果 ││ - 保存分割掩码 ││ - 导出边界框和多边形(可选) │└─────────────────────────────────────────────────┘3. CLIPSegmentation 流程
┌─────────────────────────────────────────────────┐│ CLIPSegmentation 分割流程 │├─────────────────────────────────────────────────┤│ 1. 初始化模型 ││ - 加载 CLIP-Seg 模型 ││ 2. 处理输入影像 ││ - 切分影像为瓦片 ││ - 转换为RGB格式 ││ 3. 文本提示分割 ││ - 输入文本提示和影像 ││ - 生成概率图 ││ 4. 后处理 ││ - 高斯平滑 ││ - 应用阈值生成二值掩码 ││ 5. 输出结果 ││ - 保存二值分割掩码 ││ - 保存概率分数 │└─────────────────────────────────────────────────┘核心算法
GroundedSAM 算法
GroundedSAM 结合了两个强大的模型:
• Grounding DINO:一个开放词汇目标检测器,能够根据文本提示检测图像中的目标 • Segment Anything Model (SAM):一个通用的分割模型,能够生成精确的分割掩码
工作原理:
1. 使用 Grounding DINO 根据文本提示检测目标,生成边界框 2. 将检测到的边界框作为输入传递给 SAM 3. SAM 根据边界框生成精确的分割掩码 4. 对掩码进行后处理,如高斯平滑、多边形细化等 5. 合并瓦片结果,生成综合掩码、按提示分离的掩码,以及可选的边界框/多边形矢量数据
因此,GroundedSAM 的输出可以服务于语义分割任务,但它本身的技术路线是“检测 + 实例分割”,不是传统的端到端多类别语义分割网络。
CLIPSegmentation 算法
CLIPSegmentation 使用 CLIP-Seg 模型。CLIP-Seg 在冻结的 CLIP 视觉/文本骨干上增加轻量解码器,可根据文本或图像提示生成二值分割结果。在 GeoAI 的封装中,它接收一个文本提示,输出两波段 GeoTIFF:第一波段是二值掩码,第二波段是概率分数。
工作原理:
1. 将输入影像切分为瓦片,并转换为 RGB 图像 2. 将文本提示和瓦片影像输入 CLIP-Seg 处理器和模型 3. 通过模型 logits 经 sigmoid 得到像素级概率图 4. 根据 threshold生成二值分割掩码5. 对概率图进行平滑处理,减少瓦片边界和块状效应
核心代码分析
GroundedSAM 类
初始化方法
def__init__( self, detector_id: str = "IDEA-Research/grounding-dino-tiny", segmenter_id: str = "facebook/sam-vit-base", device: Optional[str] = None, tile_size: int = 1024, overlap: int = 128, threshold: float = 0.3,) -> None:# 设置模型和参数self.detector_id = detector_idself.segmenter_id = segmenter_idself.tile_size = tile_sizeself.overlap = overlapself.threshold = threshold# 设置设备if device isNone:self.device = "cuda"if torch.cuda.is_available() else"cpu"else:self.device = device# 加载模型self._load_models()代码说明:
• 初始化 GroundedSAM 类,设置模型参数和设备 • 自动检测可用设备,优先使用 CUDA • 加载 Grounding DINO 和 SAM 模型
核心分割方法
defsegment_image( self, input_path: str, output_path: str, text_prompts: Union[str, List[str]], polygon_refinement: bool = False, export_boxes: bool = False, export_polygons: bool = True, smoothing_sigma: float = 1.0, nms_threshold: float = 0.5, min_polygon_area: int = 50, simplify_tolerance: float = 2.0,) -> Dict[str, str]:# 处理文本提示ifisinstance(text_prompts, str): text_prompts = [text_prompts]# 打开输入影像with rasterio.open(input_path) as src:# 获取元数据 meta = src.meta height = src.height width = src.width transform = src.transform crs = src.crs# 创建输出元数据 out_meta = meta.copy() out_meta.update( {"count": len(text_prompts) + 1, "dtype": "uint8", "nodata": 0} )# 创建结果数组 all_masks = np.zeros((len(text_prompts), height, width), dtype=np.uint8) all_boxes = [] all_polygons = []# 计算有效瓦片大小 effective_tile_size = self.tile_size - 2 * self.overlap# 计算瓦片数量 n_tiles_x = max(1, int(np.ceil(width / effective_tile_size))) n_tiles_y = max(1, int(np.ceil(height / effective_tile_size)))# 处理瓦片for y inrange(n_tiles_y):for x inrange(n_tiles_x):# 计算瓦片坐标 x_start = max(0, x * effective_tile_size - self.overlap) y_start = max(0, y * effective_tile_size - self.overlap) x_end = min(width, (x + 1) * effective_tile_size + self.overlap) y_end = min(height, (y + 1) * effective_tile_size + self.overlap)# 读取瓦片 window = Window(x_start, y_start, x_end - x_start, y_end - y_start) tile_data = src.read(window=window)# 处理瓦片# 1. 转换为RGB格式# 2. 检测目标# 3. 分割目标# 4. 处理结果# 生成合并掩码 combined_mask = np.any(all_masks, axis=0).astype(np.uint8)# 保存输出with rasterio.open(output_path, "w", **out_meta) as dst: dst.write(combined_mask, 1)for i, mask inenumerate(all_masks): dst.write(mask, i + 2)# 导出边界框和多边形# ...return result_files代码说明:
• 处理输入影像和文本提示 • 计算瓦片数量和位置 • 遍历处理每个瓦片 • 对每个瓦片执行目标检测和分割 • 合并瓦片结果,生成最终分割掩码 • 导出分割结果和可选的边界框、多边形
目标检测方法
def_detect(self, image: Image.Image, labels: List[str]) -> List[DetectionResult]:# 确保标签以句号结尾 labels = [label if label.endswith(".") else label + "."for label in labels] results = self.object_detector( image, candidate_labels=labels, threshold=self.threshold ) results = [DetectionResult.from_dict(result) for result in results]return results代码说明:
• 使用 Grounding DINO 检测目标 • 确保标签格式正确(以句号结尾) • 将检测结果转换为 DetectionResult 对象
实例分割方法
def_segment( self, image: Image.Image, detection_results: List[DetectionResult], polygon_refinement: bool = False,) -> List[DetectionResult]:ifnot detection_results:return detection_results boxes = self._get_boxes(detection_results) inputs = self.processor( images=image, input_boxes=boxes, return_tensors="pt" ).to(self.device) outputs = self.segmentator(**inputs) masks = self.processor.post_process_masks( masks=outputs.pred_masks, original_sizes=inputs.original_sizes, reshaped_input_sizes=inputs.reshaped_input_sizes, )[0] masks = self._refine_masks(masks, polygon_refinement)for detection_result, mask inzip(detection_results, masks): detection_result.mask = maskreturn detection_results代码说明:
• 从检测结果中提取边界框 • 使用 SAM 生成分割掩码 • 后处理掩码,如多边形细化 • 将掩码添加到检测结果中
CLIPSegmentation 类
初始化方法
def__init__( self, model_name: str = "CIDAS/clipseg-rd64-refined", device: Optional[str] = None, tile_size: int = 512, overlap: int = 32,) -> None:self.tile_size = tile_sizeself.overlap = overlap# 自动选择设备from .utils.device import get_deviceself.device = str(device or get_device())# 加载模型和处理器self.processor = CLIPSegProcessor.from_pretrained(model_name)self.model = CLIPSegForImageSegmentation.from_pretrained(model_name).to(self.device )代码说明:
• 初始化 CLIPSegmentation 类,设置模型参数和设备 • 自动检测可用设备 • 加载 CLIP-Seg 模型和处理器
核心分割方法
defsegment_image( self, input_path: str, output_path: str, text_prompt: str, threshold: float = 0.5, smoothing_sigma: float = 1.0,) -> str:# 打开输入影像with rasterio.open(input_path) as src:# 获取元数据 meta = src.meta height = src.height width = src.width# 创建输出元数据 out_meta = meta.copy() out_meta.update({"count": 2, "dtype": "float32", "nodata": None})# 创建结果数组 segmentation = np.zeros((height, width), dtype=np.float32) probabilities = np.zeros((height, width), dtype=np.float32)# 计算有效瓦片大小 effective_tile_size = self.tile_size - 2 * self.overlap# 计算瓦片数量 n_tiles_x = max(1, int(np.ceil(width / effective_tile_size))) n_tiles_y = max(1, int(np.ceil(height / effective_tile_size)))# 处理瓦片for y inrange(n_tiles_y):for x inrange(n_tiles_x):# 计算瓦片坐标 x_start = max(0, x * effective_tile_size - self.overlap) y_start = max(0, y * effective_tile_size - self.overlap) x_end = min(width, (x + 1) * effective_tile_size + self.overlap) y_end = min(height, (y + 1) * effective_tile_size + self.overlap)# 读取瓦片 window = Window(x_start, y_start, x_end - x_start, y_end - y_start) tile_data = src.read(window=window)# 处理瓦片# 1. 转换为RGB格式# 2. 处理CLIP-Seg# 3. 生成概率图# 4. 后处理# 生成二值分割掩码 segmentation = (probabilities >= threshold).astype(np.float32)# 保存输出with rasterio.open(output_path, "w", **out_meta) as dst: dst.write(segmentation, 1) dst.write(probabilities, 2)return output_path代码说明:
• 处理输入影像和文本提示 • 计算瓦片数量和位置 • 遍历处理每个瓦片 • 对每个瓦片执行 CLIP-Seg 分割 • 生成概率图和二值分割掩码 • 保存输出结果
使用示例
示例 1:使用 GroundedSAM 提取建筑物
import geoai# 初始化 GroundedSAM 模型grounded_sam = geoai.GroundedSAM( detector_id="IDEA-Research/grounding-dino-tiny", segmenter_id="facebook/sam-vit-base", device="cuda")# 提取建筑物result = grounded_sam.segment_image( input_path="satellite_image.tif", output_path="buildings_segmented.tif", text_prompts="building", export_polygons=True, min_polygon_area=100, simplify_tolerance=2.0)print("建筑物提取完成!")print(f"分割结果保存到: {result['segmentation']}")print(f"多边形结果保存到: {result['polygons']}")示例 2:使用 GroundedSAM 提取多种地物
import geoai# 初始化 GroundedSAM 模型grounded_sam = geoai.GroundedSAM( detector_id="IDEA-Research/grounding-dino-tiny", segmenter_id="facebook/sam-vit-base", device="cuda")# 提取建筑物、道路和水体result = grounded_sam.segment_image( input_path="aerial_image.tif", output_path="multiple_features.tif", text_prompts=["building", "road", "water"], export_polygons=True, min_polygon_area=50, simplify_tolerance=1.0)print("多特征提取完成!")print(f"分割结果保存到: {result['segmentation']}")print(f"多边形结果保存到: {result['polygons']}")示例 3:使用 CLIPSegmentation 提取水体
import geoai# 初始化 CLIPSegmentation 模型clip_seg = geoai.CLIPSegmentation( model_name="CIDAS/clipseg-rd64-refined", device="cuda")# 提取水体output_path = clip_seg.segment_image( input_path="satellite_image.tif", output_path="water_segmented.tif", text_prompt="water body", threshold=0.5, smoothing_sigma=1.0)print(f"水体提取完成!结果保存到: {output_path}")示例 4:批量处理多个影像
import geoaiimport os# 初始化 CLIPSegmentation 模型clip_seg = geoai.CLIPSegmentation( model_name="CIDAS/clipseg-rd64-refined", device="cuda")# 批量处理多个影像input_folder = "input_images"output_folder = "output_segmented"text_prompt = "building"# 创建输出目录os.makedirs(output_folder, exist_ok=True)# 获取所有影像文件image_files = [f for f in os.listdir(input_folder) if f.endswith('.tif')]# 批量处理output_paths = clip_seg.segment_image_batch( input_paths=[os.path.join(input_folder, f) for f in image_files], output_dir=output_folder, text_prompt=text_prompt, threshold=0.5, smoothing_sigma=1.0)print(f"批量处理完成!处理了 {len(output_paths)} 个影像")业务应用场景
1. 城市规划
应用:提取建筑物、道路、绿地等城市要素,生成城市现状图
优势:
• 快速获取城市建成区范围 • 监测城市扩张 • 辅助城市规划决策
示例:
# 提取城市建筑物和道路grounded_sam.segment_image( input_path="city_image.tif", output_path="city_features.tif", text_prompts=["building", "road", "park"], export_polygons=True)2. 环境监测
应用:提取水体、植被等环境要素,监测环境变化
优势:
• 快速识别水体边界 • 监测植被覆盖变化 • 评估环境质量
示例:
# 提取水体和植被clip_seg.segment_image( input_path="environment_image.tif", output_path="water_vegetation.tif", text_prompt="water and vegetation", threshold=0.5)3. 农业管理
应用:提取农田、作物等农业要素,监测农业生产
优势:
• 识别农田边界 • 监测作物生长状况 • 辅助精准农业决策
示例:
# 提取农田clip_seg.segment_image( input_path="agriculture_image.tif", output_path="farmland.tif", text_prompt="farmland", threshold=0.5)4. 灾害响应
应用:提取建筑物、道路等要素,评估灾害损失
优势:
• 快速评估建筑物受损情况 • 识别道路阻塞 • 辅助救援决策
示例:
# 提取建筑物和道路grounded_sam.segment_image( input_path="disaster_image.tif", output_path="disaster_assessment.tif", text_prompts=["building", "road"], export_polygons=True)性能优化
1. 内存优化
• 瓦片大小调整:根据 GPU 内存调整 tile_size参数• 逐景处理:对多个影像逐一处理,避免一次性加载过多数据 • 模型选择:选择轻量级模型,如 "grounding-dino-tiny" 和 "sam-vit-base"
2. 速度优化
• GPU 加速:使用 GPU 加速模型推理 • 合理放大瓦片:在显存允许的前提下适当增大 tile_size,减少瓦片数量• 模型缓存:缓存模型,避免重复加载 • 瓦片重叠:合理设置 overlap参数;overlap越大,边缘更稳定,但有效步长会变小、瓦片数量会增加
3. 质量优化
• 阈值调整:根据具体任务调整 threshold参数• 平滑处理:使用 smoothing_sigma参数减少块状效应• 多边形简化:使用 simplify_tolerance参数控制多边形复杂度• 面积过滤:使用 min_polygon_area参数过滤小面积多边形
常见问题解决
1. 内存不足
解决方案:
• 减小 tile_size参数• 选择更小的模型 • 使用 CPU 模式(速度会变慢)
2. 分割结果不准确
解决方案:
• 调整 threshold参数• 使用更具体的文本提示 • 增加 min_polygon_area参数,过滤小面积噪声• GroundedSAM 场景下可调高检测阈值或 NMS 阈值,减少误检和重复框 • CLIPSegmentation 场景下可对同一区域尝试多个等价英文提示,如 "water body"、"river"、"lake"
3. 处理速度慢
解决方案:
• 使用 GPU 加速 • 在显存允许的前提下增大 tile_size• 适当减小 overlap参数,减少重复推理区域• 选择轻量级模型
4. 边缘效应
解决方案:
• 增加 overlap参数• 使用平滑处理减少边缘差异
5. 多边形质量差
解决方案:
• 增加 simplify_tolerance参数• 启用 polygon_refinement参数• 增加 min_polygon_area参数
GeoAI 的 GroundedSAM 和 CLIPSegmentation 能够基于文本提示从遥感影像中提取建筑物、道路、水体等地理要素。更准确地说,GroundedSAM 是“开放词汇检测 + SAM 实例分割”的组合,CLIPSegmentation 是“单文本提示 -> 概率图/二值掩码”的分割工具;二者都可以用于语义分割工作流,但不等同于经过训练的多类别语义分割模型。
这些方法具有以下优势:
1. 基于文本提示:通过自然语言描述指定要分割的目标,无需手动标注 2. 支持大影像:通过瓦片处理技术处理大幅遥感影像 3. 地理空间输出:输出 GeoTIFF 掩码,并保留空间参考信息 4. GIS 工作流友好:结果可继续用于叠加分析、矢量化、面积统计和人工校核 5. 实例/矢量导出:GroundedSAM 可导出边界框和多边形,便于后续 GIS 编辑
通过合理配置参数和选择适当的模型,可以高效地从遥感影像中提取各种地理要素,为城市规划、环境监测、农业管理和灾害响应等应用提供有力支持。
夜雨聆风