OpenCV与AI深度学习 | 使用 SAM 和 Grounding DINO 分割卫星图像

本文来源公众号“OpenCV与AI深度学习”,仅用于学术分享,侵权删,干货满满。

原文链接:使用 SAM 和 Grounding DINO 分割卫星图像

Echo 和 Shapes 简介

    Echo 的使命是让世界变得易于理解,使公司能够更快地创新。我们拥有各种各样的客户,包括杂货连锁店、保险公司、广告代理商等。

    我们的产品线大致可分为三个主要领域:数据(地点和形状)、洞察(移动数据和 GeoPersona)和技术(位置 SDK)。在本文中,我们将重点介绍我们的数据产品之一:Shapes 。

    简而言之,Shapes 数据集由地理空间多边形数据组成,表示建筑物覆盖区、停车场、太阳能电池板等特征。我们的 Shapes 数据集是我们业务不可或缺的一部分。我们直接向客户销售它,它也是我们许多其他数据集的必要输入。例如,要计算特定地点内的停留时间,我们需要知道它的边界。

    免费许可的数据集

    从头开始构建卫星图像分析管道非常复杂。那么,我们为什么不简单地使用一些可用的、免费许可的数据集来构建覆盖区呢?

    有一些值得注意的自由许可的建筑物覆盖区数据集:

    • OpenStreetMap (OSM)

    • Microsoft Building Footprints

    • Google Open Buildings

    • Overture Maps Foundation (OMF)

    在大多数情况下,Microsoft 和 Google 数据集要么过时,要么在美国或欧洲没有得到足够的覆盖——我们的大多数客户都位于这些地区。

    OSM 是一个开源的地图项目,由世界各地高度活跃的志愿者网络维护,在概念上类似于维基百科。它往往质量非常高,因为其他志愿者经常手动定义和检查足迹。尽管它在美国和欧洲都有很好的覆盖范围,但在大都市地区之外,尤其是郊区或工业区等非商业区域,它的覆盖范围非常有限。

    OMF 是一项相对较新的计划,旨在结合多个开源和免费许可的地理空间数据集。他们的建筑足迹数据主要来自 OSM,因此具有相同的局限性。

    这些数据集不足以满足我们的目的有几个原因:

    如前所述,这些数据集中的大多数要么已过时,要么覆盖范围不足。OSM 是最好的,但即便如此,在主要大都市地区之外也是零散的。

    所有这些数据集主要集中在建筑物覆盖区(或 OSM 中为道路),并且对城市区域以外的非建筑物特征(例如停车场、树木和太阳能电池板)的覆盖率较低。虽然 OSM 包括非建筑特征,但其覆盖范围在城市地区以外的可靠性甚至不如我们的客户可能感兴趣的建筑足迹和道路。

    对于实际上是工业联盟的计划,例如 OMF,只有当其成员继续从中受益时,这些数据集才会更新。不控制我们公司的关键数据源是一个坏主意。

    最重要的是,如果我们能够利用这些数据集,那么我们所有的竞争对手也可以。为了保持市场优势,我们需要开发自己的数据集和解决方案。当然,当有意义时,我们可以使用免费许可的数据来扩充和增强我们自己的数据集,但它不应该是我们唯一的数据源。

    确定了业务需求后,让我们开始实施。

SAM

    Segment Anything Model (SAM) 是 Meta 于 2023 年 4 月发布的用于图像分割的开源基础模型。它在高分辨率图像上具有出色的零拍摄性能。

    虽然它是在高分辨率照片上训练的,但它在卫星图像上的表现还不错。它在小于 1 米的分辨率上效果最佳,并且与基于点的提示(与边界框提示相反)一起使用时效果最佳。毫不奇怪,它可能会遇到与具有相似材料的要素 (如人行道和道路之间的边界) 以及小的不规则要素 (如树木和阴影) 的问题。

Grounded SAM

    为了知道图像的哪些特征需要分割,我们需要将其与某种对象检测模型相结合。经过一些初步测试,我们使用 Grounded SAM 看到了有希望的结果。

    方法相当简单。我们使用 Grounding DINO 和我们想要识别的特征的文本提示生成卫星图像的嵌入。这会在像素空间中生成一个边界框,然后我们可以将其用作 SAM 的提示(或使用边界框的中心作为点提示,因为这更适合卫星图像)。

    通过使用带注释的数据微调 Grounding DINO,我们可以进一步提高嵌入性能。然而,即使是零发射性能也出奇地好,因为 Grounding DINO 和 SAM 最初都没有使用卫星图像数据进行训练。

    鉴于 Grounded SAM 的零散弹性能,我们乐观地认为,使用手动注释的数据微调 Grounding DINO 编码器将产生改进。由于使用了基础模型,我们的高级架构在概念上相当简单。

    计算量最大的步骤是计算每个卫星图像的图像嵌入。尽管我们正在处理的图像在卫星图像方面被认为是高分辨率(每像素 ~30 厘米),但通过图像处理,它们很容易管理。考虑到我们正在使用的分辨率下,一公顷的卫星图像只有大约 350x350 像素,而我们感兴趣的大多数特征甚至比一公顷要小得多。

    图像嵌入也只需为每个区域和每种类型的嵌入计算一次,然后可以重复用于针对同一区域的对象检测和分割模型的不同运行。对于一些大都市地区,我们可能需要每隔几个月刷新一次图像,以考虑新建筑,但我们基本上可以将嵌入计算视为一次性成本。

    另一个有问题的步骤是 annotation。我们与专业图像注释服务 Encord 合作,对我们从卫星图像提供商处获取的图像进行注释。与计算嵌入一样,尽管注释是一个耗时且昂贵的过程,但它是生成真实数据的唯一可靠方法。随着我们积累带注释的图像,它也将为我们提供竞争优势,因为我们将能够比竞争对手更快地微调我们的模型。

    我们使用 Google (GCP) 作为我们的云平台,并选择使用 Apache Beam 作为我们的分布式计算框架来加快处理时间,因为 GCP 为 Beam 提供了一个名为 Dataflow 的执行引擎,该引擎功能相当齐全。由于我们的图像处理管道结合了自定义 Python 库以及大型外部依赖项(如机器学习模型),因此我们需要使用灵活的计算框架(如 Beam 或 Spark),而不是 BigQuery 等结构化程度更高的数据处理平台。

THE END !

文章结束,感谢阅读。您的点赞,收藏,评论是我继续更新的动力。大家有推荐的公众号可以评论区留言,共同学习,一起进步。

你说得太对了!👏 > ✅ **“既然想分割植物,为什么不直接告诉模型‘这是植物’?”** 你完全正确 —— 我们之前的方法是“猜”哪里像植物(靠颜色 + 面积),属于**启发式后处理**,不够精准、也不够智能。 而你现在提到的: > 🔥 **Grounding DINO + SAM 联合使用,用文本提示“plant”或“green vegetable”,直接提取目标区域** 这才是当前最先进的 **开集检测 + 精准分割** 方案! --- ## ✅ 为什么 Grounding DINO + SAM 更好? | 方法 | 缺点 | 优点 | |------|------|------| | 自动掩码生成(`SamAutomaticMaskGenerator`) | 生成太多候选区,不知道哪个是目标 | 快,无需提示 | | 手动框选/点选 | 需人工干预,不适合批量 | 精准 | |Grounding DINO + SAM | 需要额外安装 | **能听懂语言,直接分割“植物”、“叶子”等语义对象!** | --- ## 🚀 下面给你一个极简版完整代码: 👉 **输入一张图 + 文本提示 "plant" → 输出植物部分(带透明背景)** ```python import cv2 import numpy as np import os import torch from PIL import Image import matplotlib.pyplot as plt # 安装命令(首次运行前执行): # pip install -U transformers timm torchvision supervision groundingdino-pip from transformers import pipeline from groundingdino.util.inference import load_model, load_image, predict from segment_anything import sam_model_registry, SamPredictor # ------------------------------- # 配置路径参数 # ------------------------------- GROUNDING_DINO_CONFIG = "groundingdino/config/GroundingDINO_SwinT_OGC.py" GROUNDING_DINO_CHECKPOINT = "weights/groundingdino_swint_ogc.pth" SAM_CHECKPOINT = "weights/sam_vit_h_4b8939.pth" TEXT_PROMPT = "plant" # ← 你想分割什么?写这里!支持:"leaf", "vegetable", "crop"... BOX_THRESHOLD = 0.3 TEXT_THRESHOLD = 0.25 def setup_models(device): """加载 Grounding DINO SAM 模型""" # 加载 Grounding DINO(用于检测) dino = load_model(GROUNDING_DINO_CONFIG, GROUNDING_DINO_CHECKPOINT) dino.to(device) # 加载 SAM(用于分割sam = sam_model_registry["vit_h"](checkpoint=SAM_CHECKPOINT) sam.to(device) predictor = SamPredictor(sam) return dino, predictor, device def detect_and_segment(image_path, dino, sam_predictor, device): """使用文本提示检测并分割植物""" image_source = Image.open(image_path).convert("RGB") image_array = np.array(image_source) image_bgr = cv2.cvtColor(image_array, cv2.COLOR_RGB2BGR) # 步骤1:用 Grounding DINO 获取 bounding box boxes, logits, phrases = predict( model=dino, image=image_array, caption=TEXT_PROMPT, box_threshold=BOX_THRESHOLD, text_threshold=TEXT_THRESHOLD, device=device, ) if len(boxes) == 0: print("🔍 未检测到任何植物区域") return None # 步骤2:将图像传入 SAM Predictor sam_predictor.set_image(image_array) # 步骤3:将归一化坐标转为 SAM 所需的真实像素坐标 H, W, _ = image_array.shape boxes_xyxy = boxes * torch.tensor([W, H, W, H]).to(boxes.device) transformed_boxes = sam_predictor.transform.apply_boxes_torch(boxes_xyxy, image_array.shape[:2]) # 步骤4:用 SAM 分割 masks, _, _ = sam_predictor.predict_torch( point_coords=None, point_labels=None, boxes=transformed_boxes, multimask_output=False, ) # 取第一个 mask(最大最可信的植物) plant_mask = masks[0][0].cpu().numpy() # (H, W) return image_bgr, plant_mask def save_plant_only(image_bgr, plant_mask, output_path): """保存仅含植物的部分(PNG 带透明通道)""" os.makedirs(os.path.dirname(output_path), exist_ok=True) rgba = np.zeros((*image_bgr.shape[:2], 4), dtype=np.uint8) rgba[:, :, :3] = image_bgr rgba[:, :, 3] = (plant_mask * 255).astype(np.uint8) cv2.imwrite(output_path, rgba) ratio = plant_mask.sum() / plant_mask.size print(f"✅ 保存成功: {output_path} | 植物占比: {ratio:.2%}") # ======================== # 批量处理入口 # ======================== if __name__ == "__main__": DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") ROOT_INPUT_DIR = r"E:/work/danzhutiqu/image/xuanzhuan/yolov5-v5.0/yolov5-v5.0/runs/detect/exp/exp11/same_id_cropped_images/" ROOT_OUTPUT_DIR = r"E:/work/danzhutiqu/image/xuanzhuan/yolov5-v5.0/yolov5-v5.0/runs/detect/exp/exp11/plant_only" # 下载权重(只第一次需要) os.makedirs("weights", exist_ok=True) # 下载链接: # Grounding DINO: https://github.com/IDEA-Research/Grounded-Segment-Anything/releases/download/v1.0.0/groundingdino_swint_ogc.pth # SAM ViT-H: https://dl.fbaipublicfiles.com/segment_anything/sam_vit_h_4b8939.pth # 加载模型 dino_model, sam_predictor, device = setup_models(DEVICE) processed = 0 for root, _, files in os.walk(ROOT_INPUT_DIR): rel_path = os.path.relpath(root, ROOT_INPUT_DIR) out_dir = os.path.join(ROOT_OUTPUT_DIR, rel_path) for file in files: if file.lower().endswith(('.png', '.jpg', '.jpeg')): in_path = os.path.join(root, file) out_file = os.path.splitext(file)[0] + ".png" out_path = os.path.join(out_dir, out_file) try: result = detect_and_segment(in_path, dino_model, sam_predictor, device) if result is not None: image_bgr, plant_mask = result save_plant_only(image_bgr, plant_mask, out_path) processed += 1 except Exception as e: print(f"💥 失败 {in_path}: {e}") print(f"\n🎉 完成!共处理 {processed} 张图像。") ``` --- ## ✅ 使用说明 ### 1️⃣ 安装依赖(一次即可) ```bash pip install opencv-python numpy torch torchvision transformers timm pillow matplotlib pip install git+https://github.com/IDEA-Research/GroundingDINO.git pip install segment-anything supervision ``` ### 2️⃣ 下载权重文件 放到 `weights/` 文件夹中: - **Grounding DINO**: [https://github.com/IDEA-Research/Grounded-Segment-Anything/releases/download/v1.0.0/groundingdino_swint_ogc.pth](https://github.com/IDEA-Research/Grounded-Segment-Anything/releases/download/v1.0.0/groundingdino_swint_ogc.pth) - **SAM (ViT-H)**: [https://dl.fbaipublicfiles.com/segment_anything/sam_vit_h_4b8939.pth](https://dl.fbaipublicfiles.com/segment_anything/sam_vit_h_4b8939.pth) ### 3️⃣ 修改提示词(自由发挥) 你可以把这行改成: ```python TEXT_PROMPT = "green leaf" # 或 TEXT_PROMPT = "vegetable" # 或 TEXT_PROMPT = "crop" ``` 甚至多类别: ```python TEXT_PROMPT = "plant . flower . soil" # 返回三个类别的框 ``` --- ## 💡 优势总结 | 特性 | 实现 | |------|------| | 🗣️ 能听懂中文/英文指令 | `caption="plant"` | | 🔍 不再瞎猜 | 直接定位语义对象 | | ✂️ 分割精准 | SAM 细节保留极好 | | 🧠 AI 理解场景 | 结合视觉语言 | --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值