☰
基于GroundingDINO与SAM的开放词汇检测与分割实战指南
2026/10/11 20:41:46 网站建设 项目流程

简介:本资源面向计算机视觉开发者与研究人员,提供将GroundingDINO与SAM融合以增强目标检测和图像分割能力的完整项目源码,适合具备一定深度学习基础、希望快速上手文本引导定位与通用分割实战的读者。压缩包共132个文件,约30.63MB,以58个Python脚本为核心,辅以6个Jupyter Notebook实验文件、10个tsx与5个js前端组件、若干png/jpg/jpeg示例图,以及cpp、cu、cuh等CUDA算子源码和Dockerfile、yaml、sh等部署配置,覆盖算法实现、可视化演示与工程化部署多个层面。目前已有125人学习下载。通过源码可直观理解GroundingDINO的文本到图像定位机制与SAM的灵活分割流程,掌握二者协同工作的接口设计与推理细节,并借助示例图与Notebook快速复现检测分割效果,为自动驾驶、遥感分析、医学图像处理等场景的二次开发提供可复用的工程模板与排错参考。

1. 从「框不准、分不细」说起:这套 GroundingDINO + SAM 组合到底解决什么问题

做视觉项目的人大多经历过这种场景:检测模型能框出目标,但框得歪歪扭扭,边缘糊成一团;想再叠一个分割模型,又得重新标注、重新训练,标注成本直接劝退。更麻烦的是遇到开放词汇场景——训练集里没见过的类别,传统检测器直接哑火。这套基于 GroundingDINO 和 SAM 的增强方案,核心思路就是用「开放词汇检测 + 通用分割」两段式流水线,把检测和分割解耦开,让你不用为每个新类别重训模型。

GroundingDINO 负责根据文本提示(比如 "person"、"red car")输出候选框,SAM 接过这些框作为 prompt,生成像素级掩码。两者都是零样本能力极强的模型,组合起来就是一套「文本进、掩码出」的通用管线。适合谁?做数据标注预处理的、做机器人感知原型的、做图像编辑工具的,以及想快速验证开放词汇检测效果但不想从头训模型的从业者。源码包里把推理脚本、权重加载、后处理都串好了,拿到就能跑通。

2. GroundingDINO 与 SAM 的协作机制:为什么这样拼比单模型香

2.1 两阶段解耦:检测管「在哪」,分割管「是什么形状」

传统实例分割模型(如 Mask R-CNN)把检测和分割塞进一个网络联合训练,好处是端到端,坏处是每换一个数据集就得重训,而且类别闭集。GroundingDINO + SAM 走的是另一条路:检测阶段用文本编码器把类别描述变成 embedding,和图像特征做跨模态对齐,输出的是与文本相关的候选框;分割阶段 SAM 不关心类别,只根据框或点生成掩码。

这种解耦带来两个实际好处。第一,换类别不用重训——改文本提示就行,比如把 "dog" 改成 "cat",检测框立刻跟着变。第二,分割质量不依赖检测模型的训练数据分布,SAM 在 SA-1B 上见过足够多的物体形态,泛化性有保障。常见做法是先用 GroundingDINO 以较低 box_threshold 召回尽可能多的候选,再用 SAM 批量生成掩码,最后按面积或置信度过滤。

2.2 文本提示工程:prompt 怎么写直接影响召回

GroundingDINO 对文本提示的写法比较敏感。实测下来,用英文单词或短语效果最稳,比如 "person"、"traffic light"、"red apple"。如果写成 "a photo of a person",反而可能因为语义漂移导致框偏移。多个类别用英文句点分隔,例如 "person . car . dog",注意句点前后加空格,这是官方推荐的格式。

# 文本提示构造示例 # 用句点分隔多个类别,前后加空格,避免语义粘连 TEXT_PROMPT = "person . bicycle . car . dog . traffic light" # 如果只想检测单一类别,直接写单词即可 # TEXT_PROMPT = "person"

这里的关键参数是box_threshold和text_threshold。box_threshold控制框的置信度门槛,调低召回多但误检也多;text_threshold控制文本与区域的匹配门槛。我一般先把box_threshold设到 0.25 左右跑一遍看召回,再根据误检情况往上调。如果发现某类目标总是漏,优先检查文本提示是不是写得太复杂。

2.3 从框到掩码:SAM 的 prompt 编码与批量推理

SAM 接受两种 prompt:点集和框。这里用框模式,把 GroundingDINO 输出的每个框作为独立 prompt 送进 SAM 的 prompt encoder。SAM 的图像编码器只跑一次,得到 image embedding,然后每个框复用这个 embedding 做 mask decoder,这样批量推理时不会重复计算图像特征,速度能快不少。

# 伪代码示意:复用 image embedding 做批量掩码生成 # 实际源码中会有更完整的封装 image_embedding = sam.image_encoder(image) # 只跑一次 masks = [] for box in boxes: # 每个框单独作为 prompt,复用 image_embedding mask = sam.mask_decoder(image_embedding, box_prompt=box) masks.append(mask)

参数上注意multimask_output,设为 True 时 SAM 会为每个框输出三个候选掩码(不同粒度),通常选 IoU 预测分数最高的那个。如果做精细分割,可以三个都保留,后续按面积或边缘平滑度筛选。源码包里默认走的是单掩码输出,想改的话在 mask decoder 调用处把参数打开即可。

3. 环境搭建与推理跑通:从零把管线拉起来

3.1 依赖安装与权重准备

这套管线依赖 PyTorch、torchvision、以及 GroundingDINO 和 SAM 各自的代码库。常见做法是建一个干净的 conda 环境,Python 3.8 或 3.9 都行,PyTorch 版本跟 CUDA 对齐。GroundingDINO 需要编译 CUDA 算子,如果机器上没有 nvcc,可以走纯 Python 推理路径,速度慢一些但能跑通。

# 创建环境并安装基础依赖 conda create -n gdino_sam python=3.9 -y conda activate gdino_sam # 安装 PyTorch,按自己的 CUDA 版本选对应命令 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 安装 GroundingDINO 和 SAM 的依赖 pip install groundingdino-py segment-anything

权重文件需要单独下载:GroundingDINO 的 Swin-T 或 Swin-B 权重,SAM 的 ViT-H 或 ViT-B 权重。ViT-H 精度高但显存占用大,单卡 8G 显存建议用 ViT-B。权重放到源码包指定的weights/目录下,配置文件里的路径要对上。

提示:GroundingDINO 的 CUDA 算子编译容易因为 nvcc 版本不匹配翻车,如果报错先检查nvcc -V和 PyTorch 的 CUDA 版本是否一致,不一致就装纯 Python 版绕开。

3.2 推理脚本拆解:输入输出与关键参数

源码包里的推理脚本一般长这样:读图 → GroundingDINO 检测 → 框送 SAM → 掩码后处理 → 可视化保存。核心参数集中在检测和分割两个阶段。

# 检测阶段关键参数 BOX_THRESHOLD = 0.3 # 框置信度门槛,调低召回多误检多 TEXT_THRESHOLD = 0.25 # 文本匹配门槛,影响类别判定 # 分割阶段关键参数 MULTIMASK = False # 是否输出多个候选掩码 MIN_MASK_AREA = 100 # 过滤过小掩码,避免噪点

BOX_THRESHOLD和TEXT_THRESHOLD需要联合调。如果发现框位置对但类别标错,多半是TEXT_THRESHOLD太低,把不相关的文本匹配进来了;如果框本身就不准,先调BOX_THRESHOLD。MIN_MASK_AREA按像素算,小目标场景可以降到 50 甚至更低,但要注意别把噪点也留下。

3.3 可视化与结果导出:掩码叠加和 COCO 格式转换

跑通推理后,可视化能帮你快速判断效果。常见做法是把掩码以半透明色叠加在原图上,框和类别标签一起画。如果要接下游任务,比如训练自己的分割模型,可以把结果导成 COCO 格式,省去手工标注。

# 掩码叠加可视化示意 import cv2 import numpy as np def overlay_mask(image, mask, color=(0, 255, 0), alpha=0.5): # mask 是二值掩码,image 是 BGR 图像 colored = np.zeros_like(image) colored[mask] = color return cv2.addWeighted(image, 1 - alpha, colored, alpha, 0)

导出 COCO 格式时注意segmentation字段要存多边形或 RLE,bbox存[x, y, w, h],category_id从 1 开始。源码包里如果有导出脚本,直接改输出路径就行;没有的话按这个结构自己写一个,半小时能搞定。

4. 避坑与排查:那些让我重跑三遍的坑

4.1 现象:检测框正常但掩码全图乱飞

原因:SAM 的输入框坐标格式和 GroundingDINO 输出格式不一致。GroundingDINO 输出的是归一化的[cx, cy, w, h],SAM 要的是绝对坐标的[x1, y1, x2, y2]。中间少了一步反归一化和格式转换,框的位置就全错了。

解决:在送 SAM 之前加一步转换,把归一化中心宽高转成绝对角点坐标,并 clip 到图像边界内。

# 归一化 [cx, cy, w, h] 转绝对 [x1, y1, x2, y2] def xywh_to_xyxy(boxes, img_w, img_h): cx, cy, w, h = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3] x1 = (cx - w / 2) * img_w y1 = (cy - h / 2) * img_h x2 = (cx + w / 2) * img_w y2 = (cy + h / 2) * img_h return np.stack([x1, y1, x2, y2], axis=1)

4.2 现象:显存爆了,batch size 调到 1 还是 OOM

原因:SAM 的 ViT-H 图像编码器对高分辨率图像显存占用很大,加上 GroundingDINO 的 Swin-B backbone,两张卡都不一定扛得住。另外如果没开torch.no_grad(),中间激活值会一直留着。

解决:推理全程包在torch.no_grad()里,图像先 resize 到长边 1024 以内,SAM 换 ViT-B 权重。如果还不行,把 GroundingDINO 和 SAM 分两个进程跑,中间用文件传框坐标。

4.3 现象:文本提示换了但检测结果没变

原因:文本 embedding 被缓存了,或者 tokenizer 把提示截断了。GroundingDINO 的文本编码器有最大 token 限制,提示太长会被截断,后面的类别就丢了。

解决:检查 tokenizer 输出长度,超过 256 的截断;确认每次换提示时重新跑文本编码,别复用上一次的 embedding。多个类别时拆成多次推理再合并,比一次性塞长提示更稳。

4.4 现象:小目标掩码边缘锯齿严重

原因:SAM 的图像编码器下采样倍率较高,小目标在特征图上占的像素太少,mask decoder 恢复出来的边缘就粗糙。

解决:把小目标区域裁剪出来单独放大后再送 SAM,或者用multimask_output=True取三个掩码里边缘最平滑的那个。如果做批量处理,可以按框面积分两组,小框走裁剪放大路径,大框走原图路径。

5. 进阶技巧:把两段式管线压进实时场景的几个手段

跑通之后最现实的问题是速度。GroundingDINO + SAM 原版在单张 3090 上处理一张 1080P 图大概要 1.5 到 2 秒,离实时差得远。我一般从三个方向压:第一,GroundingDINO 换 Swin-T backbone,精度掉一点但速度翻倍;第二,SAM 图像编码器只跑一次,多个框复用 embedding,这个前面提过,批量场景下收益明显;第三,把图像 resize 到长边 800 而不是 1024,掩码精度略降但肉眼几乎看不出差别。

还有一个取巧办法:如果类别固定,可以把 GroundingDINO 的文本 embedding 预计算好存下来,推理时直接加载,省掉文本编码那几十毫秒。源码包里如果没做这个缓存,自己加一个字典按提示字符串做 key 就行。

验证效果时别只看可视化图,量化指标更靠谱。检测阶段算 recall 和 precision,分割阶段算 mask IoU。我习惯留 20 张图做固定测试集,每次调参后跑一遍对比数值,避免被单张图的视觉效果带偏。从那以后我每次改参数都强制走一遍测试集,再也没出现过「看着挺好、一上量就崩」的情况。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询