开放集检测加分割实战:GroundingDINO与SAM组合落地指南

发布时间:2026/10/11 14:58:18

开放集检测加分割实战:GroundingDINO与SAM组合落地指南 简介结合GroundingDINO与SAM的目标检测与分割增强项目源码面向计算机视觉算法开发者和研究人员。项目利用GroundingDINO的文本引导定位能力生成目标候选框再由SAM输出高质量掩码实现精确识别与细粒度分割适用于自动驾驶、遥感图像分析和医学影像处理等复杂场景。压缩包内共一百三十二个文件主体为五十八个Python脚本另有Jupyter Notebook交互演示、C/CUDA高性能算子、TypeScript/JS可视化组件、YAML/JSON配置文件、Markdown文档及多张PNG/JPG/GIF效果图完整覆盖工程实现与部署全貌包体约三十点六三MB。目前平台显示已有一百二十五人学习下载源码采用清晰的模块化结构从模型加载、文本编码、框回归到掩码生成各环节均有完整实现便于复现整个推理流程并二次开发可快速接入自有检测或分割项目。1. GroundingDINO SAM当检测框变成了掩码提示词这套组合拳能省多少事做工业质检时最难受的一件事就是检测类别总在变今天要看划痕明天要查溢胶后天又要分割异物区域。传统YOLO目标检测每换一次类别就要重新标数据、重新训练一周时间就没了。我后来把流程改成 GroundingDINO SAM 这套组合GroundingDINO 负责用一句话找出图上所有目标框SAM 负责把框内的边缘精确抠出来。整个过程不需要微调只需要一个 Python 脚本把两个模型串起来检测和分割能力同时拿到。本文就把我在这类项目里落地的完整步骤、参数设置和踩过的坑写出来适合手里有图片、缺标注、想快速验证开放集检测加分割能力的工程师也适合要批量生成伪标注的前期选型。2. 先搞懂两个模型的分工GroundingDINO 为什么能取代 YOLO 的预定义类别SAM 又是怎么吞下检测框的2.1 GroundingDINO 不是另一个 YOLO开放集检测的推理流程传统目标检测模型把类别编码成固定索引比如 0 代表猫、1 代表狗最后的输出维度是固定的。GroundingDINO 的核心变化是把检测任务改成了文本-图像匹配。你给它一句话模型内部先用文本编码器把这句话转成一组 query再用这些 query 和图像特征做 cross-attention最后输出每个短语对应的目标框和置信度。这意味着类别完全由提示词控制不需要为每个新类别准备标注集更不用重新训练。我在项目里经常只改一个字符串就完成类别切换比如把 划痕 . 溢胶 改成 划痕 . 溢胶 . 异物模型就能开始找第三类目标。下面是 GroundingDINO 的最小推理代码主要用来理解它的输入输出格式from groundingdino.util.inference import load_model, predict # 加载模型第一个参数是配置文件路径第二个是权重路径 model load_model(configs/GroundingDINO_SwinT_OGC.py, weights/groundingdino_swintog.pth) # image 需要是 RGB 的 numpy 数组text_prompt 里多个类别用英文句点加空格分隔 boxes, logits, phrases predict( model, image, # HWC RGB 划痕 . 溢胶 . 异物, # 提示词 box_threshold0.35, # 框置信度阈值 text_threshold0.25, # 文本匹配阈值 )这里最关键的是text_prompt的写法多个类别之间用英文句点.分隔不是逗号也不是中文句号。boxes返回的是归一化的cxcywh格式后面给 SAM 用之前必须转成原图的xyxy像素坐标。logits是每个检测框的置信度phrases是这个框命中的文本短语这三样是一一对应的。初次跑的时候如果发现什么框都没有先别怀疑模型先检查这几个因素图像是不是 RGB、提示词是不是英文标点、两个阈值是不是设得太高。2.2 SAM 的输入不只有点box prompt 才是与检测器耦合的正道SAM 本身不知道什么是划痕或溢胶它只知道把图像里语义连贯的区域切出来。要让它干活必须给它一个提示可以是点、框、掩码甚至文本。最常见的交互式用法是鼠标点击目标中心SAM 自动生成掩码。但在自动化管线里我们不可能每次都用鼠标去点所以才需要把 GroundingDINO 检测到的框作为 SAM 的 box prompt。为什么优先用框而不是点因为框天然携带目标的整体范围。SAM 的 prompt encoder 在 box 模式下会把框内当前景、框外当背景分割结果通常比在框内随机取点更稳尤其是目标有遮挡或者背景杂乱的时候。我在做遥感目标检测数据集的时候也试过用点提示遇到物体挨得近的情况SAM 会把两个目标切在一起但换成 box 提示后误切少了很多。SAM 的推理代码看起来很简单但有几个参数直接影响效果from segment_anything import sam_model_registry, SamPredictor # 加载 SAM 模型权重按模型结构对应vit_h 就要配 sam_vit_h 的权重 sam sam_model_registry[vit_h]( checkpointweights/sam_vit_h_4b8939.pth).to(cuda) predictor SamPredictor(sam) # 把整张图编码成特征后续多次预测不需要重复编码 predictor.set_image(image_rgb) # box 是原图尺度的 xyxy 坐标顺序不能错 mask, scores, _ predictor.predict( boxbox_xyxy, multimask_outputTrue, # 输出 3 个候选掩码 ) # scores 长度 3每个候选掩码对应一个置信度取最大的 best int(scores.argmax()) final_mask mask[best]multimask_outputTrue是 SAM 的默认推荐因为一个框往往对应多个合理的分割结果。比如一个框里同时有目标主体和它的影子SAM 会给出三个不同解释让后续取最高置信度。predictor.set_image会缓存图像编码特征如果要对同一张图处理多个框这一步只做一次能省很多时间。3. 搭建最小可跑环境用 conda 把 GroundingDINO 和 SAM 装进同一套 Python 环境3.1 版本选型CUDA、torch、模型权重这三者的匹配关系这套管线最大的环境风险在 GroundingDINO不在 SAM。SAM 的依赖非常干净一个pip install segment-anything就能装好。GroundingDINO 需要编译它的一个核心算子模块这个模块对 PyTorch 版本和 CUDA 版本很敏感版本不对会直接编译失败或者编译完推理报奇怪的内存错误。我一般会按这样的顺序定版本先看自己的显卡驱动支持到什么 CUDA再定 PyTorch 版本最后再选 GroundingDINO 对应的权重。工程习惯是新建一个独立的 conda 环境不要往 base 环境里装。推荐 Python 3.10配 PyTorch 2.1.0。这个组合在 GroundingDINO 官方仓库的 issue 里翻车率最低。SAM 对 PyTorch 没什么特殊要求2.0 以上就行。显存方面如果你只有 8G 显存建议 SAM 用vit_b权重GroundingDINO 用SwinT配置两张模型同时放一张卡勉强够16G 及以上再考虑vit_h。3.2 安装命令与目录规划从克隆仓库到下载权重下面是创建环境并安装 PyTorch 的命令注意 CUDA 版本要换成你机器上对应的版本conda create -n odin-sam python3.10 -y conda activate odin-sam # 安装 PyTorchcu118 表示 CUDA 11.8可按实际版本调整 pip install torch2.1.0 torchvision0.16.0 --index-url https://download.pytorch.org/whl/cu118 # 安装 SAM 和依赖 pip install segment-anything opencv-python pycocotools matplotlib然后拉取两个项目的源码。这里不贴具体地址仓库名分别是 GroundingDINO 和 segment-anything官方 GitHub 上一搜就有。拉下来之后SAM 直接pip install -e .GroundingDINO 需要先装它的requirements.txt再执行编译git clone GroundingDINO 仓库地址 cd GroundingDINO pip install -r requirements.txt python setup.py build develop # 回上一级目录继续拉 SAM cd .. git clone segment-anything 仓库地址 cd segment-anything pip install -e .最后是权重。GroundingDINO 的权重文件名一般是groundingdino_swintog.pthSAM 的权重是sam_vit_h_4b8939.pth在各自 release 页面都能下载。我习惯建一个weights/目录把两个权重丢进去和代码目录隔离开。整个工程目录大致长这样project/ ├── GroundingDINO/ ├── segment-anything/ ├── weights/ │ ├── groundingdino_swintog.pth │ └── sam_vit_h_4b8939.pth ├── configs/ ├── run_pipeline.py └── data/configs/里放 GroundingDINO 的配置文件不要随便改它的内容特别是 class_name_list 相关的部分开放集检测不需要预定义类别列表留空即可。setup 过程中如果看到 ninja、C 编译相关的报错大概率是 torch 版本和 CUDA 不对付优先换 torch 版本而不是去改编译参数。4. 把检测框转成分割掩码一个 Python 脚本跑通检测加分割的完整管线4.1 核心脚本GroundingDINO 输出 boxesSAM 输出 masks把前面几个环节拼在一起就是一个完整的run_pipeline.py。这段脚本可以直接复制保存只需要按你的目录改路径和提示词。我用中文注释把关键步骤标出来了。import cv2 import numpy as np import torch from groundingdino.util.inference import load_model, predict from segment_anything import sam_model_registry, SamPredictor DEVICE torch.device(cuda if torch.cuda.is_available() else cpu) # 1. 加载 GroundingDINO dino load_model(configs/GroundingDINO_SwinT_OGC.py, weights/groundingdino_swintog.pth).to(DEVICE) # 2. 读图并转成 RGB。OpenCV 默认 BGR这里必须转 image_bgr cv2.imread(data/demo.jpg) image_rgb cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB) H, W image_rgb.shape[:2] # 3. 检测。提示词里每个类别用英文句点加空格分隔 boxes, logits, phrases predict( dino, image_rgb, 划痕 . 溢胶 . 异物, box_threshold0.35, text_threshold0.25, ) # 4. 把归一化 cxcywh 转成原图 xyxy 像素坐标 boxes_xyxy [] for box in boxes: cx, cy, bw, bh box * [W, H, W, H] x1, y1 cx - bw / 2, cy - bh / 2 x2, y2 cx bw / 2, cy bh / 2 boxes_xyxy.append([x1, y1, x2, y2]) # 5. 加载 SAM 并编码图像特征 sam sam_model_registry[vit_h]( checkpointweights/sam_vit_h_4b8939.pth).to(DEVICE) predictor SamPredictor(sam) predictor.set_image(image_rgb) # 6. 每个检测框都作为 box prompt 送给 SAM for i, box in enumerate(boxes_xyxy): mask, scores, _ predictor.predict( boxnp.array(box, dtypenp.float32), multimask_outputTrue, ) best int(np.argmax(scores)) final_mask mask[best].astype(np.uint8) cv2.imwrite(foutput/mask_{i}.png, final_mask * 255) print(f{phrases[i]}: box_score{logits[i]:.3f}, mask_score{scores[best]:.3f})这段脚本的逻辑很直白先检测再分割。检测结果里的boxes是归一化坐标必须转成像素坐标再传给 SAM。转换公式就是先乘宽高得到cx,cy,bw,bh再算出左上角和右下角。很多第一次跑的人忘了归一化这一步SAM 收到一组零点几的坐标分割结果自然也跑到图上错误的位置。4.2 参数详解box_threshold、text_threshold、multimask_output 怎么调四个参数决定了这套管线能不能用box_threshold、text_threshold、multimask_output还有 SAM 内部的scores选取策略。我调参的经验是先从宽松阈值开始再逐步收紧。box_threshold控制框的置信度下限默认我开 0.35。如果检测结果里漏了目标就降到 0.2代价是误检会变多。text_threshold控制文本短语和图像内容的匹配程度这个参数容易被忽略但它直接影响能不能框出目标。比如提示词写的是 划痕 . 溢胶如果text_threshold设到 0.5模型会非常保守可能一个框都不给。我习惯把text_threshold设在 0.25比box_threshold低一档这样文本匹配更敏感多出的候选框再由 box 置信度去过滤。SAM 的multimask_outputTrue会输出三个候选掩码这是我很推荐的设置。因为同一个框可能同时覆盖目标主体、背景和阴影三个候选相当于给了三次解释机会拿scores选最高的通常都能选到主体。如果把这个参数改成FalseSAM 只输出一个全局最优虽然省了后处理但遇到遮挡目标容易漏。predictor.set_image是另一个重要优化点同一张图跑多个框时只编码一次你可以把几百个框循环塞给 SAM不会重复计算图像特征。5. 避坑指南这套检测加分割管线我踩过的 5 个坑现象、原因、解决5.1 一个框都检测不出来提示词其实是罪魁祸首现象GroundingDINO 跑完boxes数组是空的连误检框都没有。模型权重也换了阈值也调低了依然无效。原因提示词用了逗号分隔比如 划痕, 溢胶或者写了中文句号。GroundingDINO 的文本编码器把整段话当成一个整体去匹配逗号并不能拆出多个目标短语。我在第一个项目里就因为这行改了一个小时。解决把提示词改成英文句点加空格也就是划痕 . 溢胶 . 异物。每个类别之间要保证空格和点号都在半角状态。另外检查一下image是不是 RGB 顺序BGR 输入会导致特征识别严重偏移。5.2 SAM 分割掩码偏移到背景上检测框明明是对的现象GroundingDINO 框到了目标SAM 生成的 mask 却包住了周边背景甚至把另一个目标切了进去。原因两个模型对图像分辨率的要求不一样。GroundingDINO 内部会做自己的 resize而 SAM 的predict要求输入框坐标必须在set_image时的原图坐标系里。如果你先把图缩放过再检测检测框是缩放图坐标直接传给 SAM位置就会偏移。解决统一坐标系。检测图片和 SAM 输入图片必须保持同一尺寸。如果是先 resize 再检测就把 resize 后的图和坐标保存好或者对检测框做逆变换还原到原图坐标。实践中我一般不缩放整图只限制最长边不超过 1600 像素这样两个模型都能接受。5.3 显存直接爆掉尤其是多框循环生成 mask现象单张图跑几十个检测框SAM 循环到中途弹出 CUDA out of memory进程崩溃。原因predictor.set_image会缓存全图特征本身占一批显存每次predict又会临时开辟中间张量。GroundingDINO 也同时驻留在 GPU 上两者叠加8G 卡根本扛不住。另一个隐藏原因是循环中创建的 mask、scores 张量没有被及时释放Python 里masks列表一直累积显存只进不出。解决两个方向。一是用vit_b替代vit_h或者把 GroundingDINO 放到 CPU 上推理。二是在循环里只保留最终 mask 的 numpy 副本及时del掉中间变量并每处理完一张图调用一次torch.cuda.empty_cache()。我实际项目里用了 GroundingDINO 跑 CPU、SAM 跑 GPU 的混合方式速度慢一点但很稳。5.4 mask 结果忽大忽小视频帧之间闪烁严重现象把管线跑在视频序列上相邻两帧同一目标的 mask 面积变化剧烈检测框也一跳一跳的。原因GroundingDINO 对每一帧独立推理帧间模糊、运动拖影都会让 logits 轻微波动一旦某个帧的置信度跨过阈值框就出现或消失。SAM 的 mask 对框的边界非常敏感框稍微扩大一点分割范围就会大幅变化。解决不要对每一帧做检测。常见做法是每三到五帧跑一次 GroundingDINO中间帧沿用上一帧的检测框只让 SAM 用那个框做分割。如果担心目标移动可以在两帧之间做简单的 IoU 匹配框位移不大就继续沿用。这样既保住分割连续性也省了一半以上的检测耗时。5.5 GroundingDINO 编译成功但推理报错看到 CUBLAS 字眼不要慌现象python setup.py build develop顺利通过但推理时出现CUBLAS_STATUS_INTERNAL_ERROR之类的报错一次次重启环境也没用。原因大多是 PyTorch 的 CUDA 版本与编译器版本不匹配或者机器上存在多个 PyTorch 环境当前 shell 的LD_LIBRARY_PATH指向了错误的环境。解决先确认torch.version.cuda和你显卡驱动支持的 CUDA 版本对齐。还有一招在启动脚本里不要主动去修改LD_LIBRARY_PATH让 conda 环境自己管理。如果还是报错卸载 PyTorch 重装为同一个版本的 CPU 版本先验证代码逻辑再换回 CUDA 版排查环境这能快速判断问题是出在模型代码还是底层库。6. 进阶把 SAM 掩码转成 COCO RLE 格式直接喂给下游实例分割模型整套管线跑通后最实用的一步是把 SAM 生成的二值掩码转成标准数据格式。无论是做稳定训练还是给 YOLO 实例分割或 Mask R-CNN 准备伪标注COCO 的 RLE 格式都比多边形通用。SAM 输出的 mask 边缘经常是不规则曲线用findContours转多边形会有大量折点RLE 则天然支持任意形状面积和 IoU 计算也快。下面这段是我在脚本中最常用的转换函数import pycocotools.mask as mask_util def mask_to_coco_rle(mask, image_id, annotation_id): # mask 必须是 Fortran 连续内存pycocotools 才接受 rle mask_util.encode(np.asfortranarray(mask)) rle[counts] rle[counts].decode(ascii) return { image_id: image_id, category_id: 1, segmentation: rle, score: float(mask.mean()), # 可以作为伪标注的置信度 area: float(mask.sum()), bbox: [int(x) for x in mask_util.toBbox(rle).tolist()], iscrowd: 0, id: annotation_id, }这里最容易翻车的点是np.asfortranarray。PyCOCO 的编码函数要求传入的二维数组在内存中按列优先存储Python 的numpy默认是行优先直接传进去会得到看似成功但内容完全错误的 RLE或者是编码时报错。养成习惯所有传给mask_util.encode的 mask 都先包一层np.asfortranarray。另外rle[counts]在 decode 之后需要转回字符串否则写入 JSON 会失败。我现在的习惯是把这套管线当成伪标注生成器来用先用 GroundingDINO 在未标注图片上跑出一批框和掩码再由人工只校正置信度低的部分。比起从零标注效率提升非常明显。如果你也要做实例分割数据准备我建议在第一次大规模跑之前先拿十张图完整走一遍流程把阈值和坐标转换确认清楚再批量执行。希望这篇实战笔记能帮你少走几步弯路这套组合值得投入。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/11 14:53:18

Oracle项目实战:开放式基金交易平台数据库完整设计

简介:这是一份面向 Oracle 数据库学习者的项目实战资料,围绕开放式基金交易平台的后台数据表设计展开,适合有 SQL 基础、希望锻炼数据库建模与表结构设计能力的读者。资料完整阐述了基金公司、基金、活期账户、理财账户、基金账户、购买基金及…

2026/10/11 14:53:18

轻日历瘦身版实战:绿色安装、自启优化与日程ICS导出指南

简介:轻日历是一款基于人生日历瘦身而来的桌面日历小工具,面向需要快速查看农历、黄历、节假日及日常备忘的普通用户。它在保留天气、便签、记事、纪念日、截图、报时等高频功能的同时,去除了冗余模块,界面清爽、体积小巧&#xf…

2026/10/11 14:53:18

物业管理系统软件招标书样本拆解:六件套与投标避坑要点

简介:这份招标书样本以万科物业管理系统软件项目招标为背景,完整收录了招标邀请函、投标单位须知、项目合伙模式、程序需求报告、投标承诺书与合同样本等核心章节,直面物业公司、软件开发商及招投标从业人员的使用需求。内容详细列出领标与回…

2026/10/11 15:58:22

跨江桥梁病害检测与资产标定:YOLOv8数据集构建与训练调参实战

简介:这份资源面向计算机视觉研究者、桥梁监测工程师及目标检测学习者,提供跨江桥梁路面病害与道路资产标定的专用数据集,用于训练裂缝、破损、积水等病害及桥墩、拉索、桥面等结构元素的识别模型,弥补通用数据集在桥梁场景下的适…

2026/10/11 15:58:22

跨江桥梁病害检测与资产标定:YOLOv8训练全流程与避坑指南

简介:这份资源面向计算机视觉研究者、桥梁工程监测人员及目标检测学习者,提供跨江桥梁路面病害与道路资产标定的专用数据集,用于训练裂缝、破损、积水等病害及桥墩、拉索、桥面等结构元素的识别模型,弥补通用数据集在桥梁场景下的…

2026/10/11 15:58:22

ScriptX打印控件详解:ActiveX安装激活与静默打印实战

简介:ScriptX打印控件安装包是一套面向Windows环境的打印控件部署文件,主要服务于需要在浏览器或桌面应用中调用本地打印机完成票据、报表等文档输出的场景。无论是前端开发、系统集成还是IT运维,都可以借助这份安装包快速解决ScriptX打印组件…

2026/10/11 15:58:22

显示驱动板卡电容触控校准原理与实操指南

1. 从一块“飘移”的触控板说起如果你拆过带触控功能的显示模组,大概率见过这样一块板子:上面密密麻麻排着走线,边缘引出一排FPC座子,中间一颗主控芯片旁边围着几颗电容和电阻。这块板子就是显示驱动板卡,它同时干两件…

2026/10/11 15:58:22

鸿蒙Flutter BLE透传数据错乱?CRC16校验实战与避坑指南

前阵子在鸿蒙设备上调试一个 Flutter 的 BLE 透传模块,遇到一个挺磨人的问题。两块开发板通过串口转发数据,偶尔会多收、漏收或者错一两个字节,设备端的动作就跟着乱套。查了半天链路层,最后发现根本不是蓝牙连接问题,…

2026/10/11 15:53:21

Linux连接跟踪机制解析:从conntrack命令到生产环境排查

排查生产环境里的访问异常时,我做得最多的一个动作不是急着抓包,而是先看一眼防火墙设备上的连接跟踪表:这条连接到底在不在表里?状态是 NEW 还是 ESTABLISHED?有没有回包方向的记录?这个习惯帮我省下过大量…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/11 0:02:13

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/11 0:02:13

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/11 0:02:13

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/11 0:02:13

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑