ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

基于GroundingDINO与SAM的开放词汇目标检测与分割实战

基于GroundingDINO与SAM的开放词汇目标检测与分割实战 简介本资源是一个面向计算机视觉开发者与研究者的实战型项目聚焦于融合GroundingDINO文本引导定位能力与SAM零样本图像分割能力显著提升开放词汇目标检测与细粒度实例分割的精度与泛化性适用于自动驾驶、遥感分析、医学影像等需高精度识别与分割的场景。压缩包共132个文件含58个核心Python脚本涵盖模型加载、推理pipeline、可视化及CUDA加速模块、6个Jupyter Notebook示例、15张效果对比图与动图演示如minidemo.gif以及Dockerfile、C/CUDA扩展源码ms_deform_attn_cuda.cu等和完整配置文件整体大小为30.63MB。已有125人学习下载提供从环境搭建、多模态提示输入、联合推理到结果后处理的全流程可运行代码结构清晰、注释完备特别包含CPU/GPU双后端适配与轻量级demo封装便于快速复现、二次开发与教学演示。1. 项目概述当GroundingDINO遇上SAM目标检测与分割的“强强联合”最近在CV圈子里一个组合拳打法挺火的用GroundingDINO做开放词汇的目标检测再用SAMSegment Anything Model做精细化分割。听起来像是把两个顶级“专家”请到了一起一个负责“指哪”一个负责“打哪”。我花了些时间把这个流程从头到尾跑通并且封装成了一个相对完整的项目。这绝对不是简单的模型调用堆砌里面涉及到不少工程上的坑和性能优化的技巧。今天就来聊聊这个“基于GroundingDINO和SAM增强目标检测和分割能力”的项目实战我会把核心思路、关键代码、避坑指南都掰开揉碎了讲清楚。简单来说这个项目的核心价值在于它解决了传统目标检测和分割流程中的几个痛点。传统流程往往是你需要一个特定类别的检测模型比如YOLO训练好的检测出框后可能还需要接一个分割模型比如Mask R-CNN去抠图。但这就限定了你只能检测训练集中有的类别。而我们的组合GroundingDINO允许你通过文本描述比如“一只棕色的狗”、“一个红色的消防栓”来指定检测目标实现了“开放词汇”检测。然后SAM这个分割界的“万金油”可以基于GroundingDINO给出的粗糙边界框生成像素级精准的分割掩码。这个流程特别适合那些需要快速适配新物体、进行零样本或少样本视觉任务的应用场景比如内容审核中的新兴违规物品识别、机器人交互中的指代物体分割、甚至是电商场景下的商品精细化抠图。2. 核心架构与工作流程拆解2.1 为什么是GroundingDINO SAM这个组合的选择背后有很强的逻辑考量并非随意拼凑。首先看GroundingDINO。它属于开放词汇目标检测器其最大优势是打破了传统检测模型类别固定的枷锁。你不需要为了检测“一个拿着咖啡杯的熊猫玩偶”而去收集数据、标注、训练一个专门的模型。你只需要输入这段文本描述它就能尝试在图像中找到对应的区域。它的原理可以简单理解为通过一个强大的视觉-语言对齐模型将图像区域的特征和文本描述的特征投射到一个共享的语义空间中进行相似度匹配得分高的区域就被认为是目标。这对于快速原型验证和应对长尾、未知类别的检测需求来说效率是革命性的。然后是SAM。Meta开源的这款分割模型其设计初衷就是成为一个通用的分割“基础模型”。它接受了海量数据的训练学会了“什么是物体”的通用概念。SAM有三种交互方式点提示、框提示和掩码提示。在我们的流程中我们利用的就是它的框提示模式。GroundingDINO输出的边界框Bounding Box对于SAM来说就是一个非常强的前景提示Positive Prompt告诉SAM“请把这个框里的主要物体精细地分割出来”。SAM基于这个提示能够生成质量远超简单框内阈值分割的掩码边缘更准确对复杂背景和粘连物体的处理也更好。所以这个组合的流水线非常清晰文本描述 - GroundingDINO检测出框- 框 - SAM生成掩码- 像素级分割结果。它把“定义目标”文本和“定位分割目标”视觉这两个任务解耦了并由各自领域最擅长的模型来处理实现了112的效果。2.2 项目整体架构设计在工程实现上我们不能简单写个脚本顺序调用就完事。一个健壮的项目需要考虑模块化、可配置性和效率。我的项目核心架构主要分为以下几个模块配置与输入模块负责读取图像、解析文本提示词、加载模型配置文件。这里的一个关键设计是支持批量处理和多提示词。例如你可以输入“狗猫汽车”这样的文本让模型一次性检测并分割多个类别的物体。GroundingDINO推理模块这是第一道关卡。模块内需要处理图像的预处理归一化、Resize等将图像和文本编码计算相似度图然后通过后处理非极大值抑制NMS、阈值过滤得到最终的检测框和置信度。这里需要仔细调整文本阈值和框阈值前者控制文本描述与区域匹配的严格程度后者控制检测框本身的质量。SAM推理模块这是第二道关卡。接收来自GroundingDINO的检测框。这里有几个工程重点一是SAM模型的选型它有ViT-H, ViT-L, ViT-B三种骨干网络体积和精度依次递减需要根据你的硬件尤其是显存和速度要求权衡。二是提示编码需要将检测框转换成SAM能理解的提示格式。三是掩码后处理SAM通常会输出多个候选掩码我们需要根据预测的IoU分数选择最好的一个并且可能需要进行简单的形态学操作如闭运算来平滑掩码边缘。结果可视化与输出模块将检测框和分割掩码叠加在原图上显示并支持将掩码保存为二值图像PNG或JSON格式的轮廓坐标方便下游任务使用。整个数据流是单向的但错误处理需要闭环。例如如果GroundingDINO没有检测到任何目标那么SAM模块就应该被跳过并给出友好提示。3. 环境搭建与核心依赖详解3.1 精准的依赖环境配置玩转这两个模型第一步就是配好环境。它们对PyTorch、CUDA版本以及一些特定库的版本比较敏感。下面是我验证过的一个稳定组合你可以直接参考。# 核心深度学习框架 pip install torch2.0.1 torchvision0.15.2 torchaudio2.0.2 --index-url https://download.pytorch.org/whl/cu118 # GroundingDINO 所需依赖 pip install transformers4.35.0 pip install timm0.9.2 # 注意GroundingDINO官方可能依赖特定版本的detectron2但这里我们通常直接用其源码不单独安装 # SAM 所需依赖 pip install opencv-python4.8.1.78 pip install matplotlib3.7.1 pip install scikit-image0.21.0 pip install onnxruntime1.15.1 # 如果考虑用ONNX加速推理可以安装 # 其他工具库 pip install numpy1.24.3 pip install Pillow10.0.0注意最关键的步骤是正确克隆和安装GroundingDINO。由于它不是一个标准的PyPI包你需要从GitHub克隆其仓库并以“可编辑”模式安装。这是很多新手遇到的第一个坑。git clone https://github.com/IDEA-Research/GroundingDINO.git cd GroundingDINO pip install -e .执行pip install -e .会读取当前目录的setup.py安装所有依赖并建立软链接这样你就能在项目的任何地方import groundingdino了。3.2 模型权重文件获取与放置模型权重需要单独下载国内用户可能需要一些网络技巧。GroundingDINO权重官方提供了多个预训练模型。推荐使用groundingdino_swint_ogc.pth它在性能和速度上比较均衡。下载后通常放在项目根目录的weights文件夹下。SAM权重根据你选择的骨干网络如vit_h,vit_l,vit_b下载对应的.pth文件。例如sam_vit_h_4b8939.pth。同样建议放在weights文件夹。你的项目目录结构应该大致如下your_project/ ├── weights/ │ ├── groundingdino_swint_ogc.pth │ └── sam_vit_h_4b8939.pth ├── GroundingDINO/ # 克隆的仓库 ├── src/ # 你的核心代码 ├── input_images/ # 待处理图片 ├── output/ # 结果输出 └── main.py # 主程序入口4. 核心代码实现与分步解析4.1 GroundingDINO检测器初始化与推理初始化GroundingDINO需要指定配置文件路径和权重路径。配置文件定义了模型结构在克隆的仓库GroundingDINO/groundingdino/config目录下。import groundingdino.datasets.transforms as T from groundingdino.models import build_model from groundingdino.util.slconfig import SLConfig from groundingdino.util.utils import clean_state_dict import torch def load_grounding_dino_model(config_file, checkpoint_path): 加载GroundingDINO模型 args SLConfig.fromfile(config_file) model build_model(args) checkpoint torch.load(checkpoint_path, map_locationcpu) model.load_state_dict(clean_state_dict(checkpoint[model]), strictFalse) model.eval() return model def predict_grounding_dino(model, image, caption, box_threshold0.35, text_threshold0.25): 执行GroundingDINO预测 # 1. 图像预处理 transform T.Compose([ T.RandomResize([800], max_size1333), T.ToTensor(), T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), ]) image_transformed, _ transform(image, None) # 2. 模型推理 with torch.no_grad(): outputs model(image_transformed[None], captions[caption]) # 3. 后处理根据阈值过滤框 logits outputs[pred_logits].sigmoid()[0] # (num_queries, num_tokens) boxes outputs[pred_boxes][0] # (num_queries, 4) # 过滤逻辑找到文本描述中每个token得分超过阈值的框 filt_mask logits.max(dim1)[0] box_threshold logits_filt logits[filt_mask] boxes_filt boxes[filt_mask] # 进一步根据文本-区域相似度得分过滤 token_scores, token_indices logits_filt.max(dim1) text_mask token_scores text_threshold final_boxes boxes_filt[text_mask] final_scores token_scores[text_mask] # 将归一化坐标转换为图像像素坐标 H, W image.size[1], image.size[0] boxes_xyxy box_ops.box_cxcywh_to_xyxy(final_boxes) * torch.Tensor([W, H, W, H]) return boxes_xyxy.numpy(), final_scores.numpy()实操心得box_threshold和text_threshold是两个最重要的超参数。box_threshold通常可以设得低一些如0.3先保证召回率把可能的框都找出来text_threshold则用于精确控制文本匹配的严格程度。如果你的文本描述很具体如“红色的跑车”阈值可以设高如0.4如果描述宽泛如“物体”阈值要设低。需要根据实际效果微调。4.2 SAM分割器初始化与掩码生成SAM的初始化相对直接但要注意内存使用。from segment_anything import sam_model_registry, SamPredictor import numpy as np def load_sam_predictor(checkpoint_path, model_typevit_h): 加载SAM预测器 sam sam_model_registry[model_type](checkpointcheckpoint_path) sam.to(devicecuda if torch.cuda.is_available() else cpu) predictor SamPredictor(sam) return predictor def segment_with_sam(predictor, image, boxes_xyxy): 使用SAM对检测框进行分割 # 设置图像SAM会预先计算图像嵌入这是耗时操作一张图只需做一次 image_np np.array(image) predictor.set_image(image_np) # 将框的格式转换为SAM所需的格式 (N, 4) input_boxes predictor.transform.apply_boxes_torch( torch.from_numpy(boxes_xyxy).to(predictor.device), image_np.shape[:2] ) # 批量预测掩码 with torch.no_grad(): masks, scores, _ predictor.predict_torch( point_coordsNone, point_labelsNone, boxesinput_boxes, multimask_outputFalse, # 设为False每个框只返回最好的一个掩码 ) # masks形状: (N, 1, H, W), scores形状: (N, 1) return masks.cpu().numpy(), scores.cpu().numpy()注意事项predictor.set_image()是计算密集型操作它会计算整张图的图像嵌入Image Embedding。务必确保对同一张图片的所有检测框只调用一次set_image。如果你在循环中每处理一个框就调用一次速度会慢得无法忍受。正确的做法是先对所有框调用一次set_image然后批量调用predict_torch。4.3 主流程串联与结果后处理将两个模块串联起来并添加一些后处理让结果更可用。from PIL import Image import cv2 def run_pipeline(image_path, text_prompt, dino_model, sam_predictor): # 1. 读取图像 image_pil Image.open(image_path).convert(RGB) image_cv2 cv2.imread(image_path) # 2. GroundingDINO检测 boxes, scores predict_grounding_dino(dino_model, image_pil, text_prompt) if len(boxes) 0: print(未检测到任何目标。) return None, None, None # 3. SAM分割 masks, mask_scores segment_with_sam(sam_predictor, image_pil, boxes) # 4. 后处理过滤低质量掩码可选 valid_masks [] valid_boxes [] for i, (mask, score) in enumerate(zip(masks, mask_scores)): if score 0.8: # 设定一个掩码质量阈值 valid_masks.append(mask[0]) # 去掉批次维度 valid_boxes.append(boxes[i]) # 5. 可视化 annotated_image image_cv2.copy() for mask, box in zip(valid_masks, valid_boxes): # 绘制半透明掩码 color np.random.randint(0, 255, 3).tolist() colored_mask np.zeros_like(annotated_image) colored_mask[mask 0] color annotated_image cv2.addWeighted(annotated_image, 1, colored_mask, 0.5, 0) # 绘制边界框 x1, y1, x2, y2 box.astype(int) cv2.rectangle(annotated_image, (x1, y1), (x2, y2), color, 2) return annotated_image, valid_boxes, valid_masks后处理中除了过滤低分掩码有时还需要对掩码进行形态学操作比如用cv2.morphologyEx进行闭运算填充掩码中的小洞或者平滑边缘锯齿。def refine_mask(mask, kernel_size3): 使用形态学操作精修掩码 kernel np.ones((kernel_size, kernel_size), np.uint8) # 先膨胀再腐蚀闭合小孔 mask_refined cv2.morphologyEx(mask.astype(np.uint8), cv2.MORPH_CLOSE, kernel) # 再腐蚀再膨胀平滑边缘 mask_refined cv2.morphologyEx(mask_refined, cv2.MORPH_OPEN, kernel) return mask_refined 05. 性能优化与高级技巧5.1 推理速度优化实战直接使用上述流程在CPU上会非常慢在GPU上也可能达不到实时。优化点主要在以下几个方面SAM模型选型vit_h精度最高但最慢vit_b最快但精度略有下降。对于大多数应用vit_l是较好的折中选择。你可以提供一个命令行参数让用户选择。图像尺寸缩放GroundingDINO和SAM的推理时间都与图像尺寸强相关。在推理前可以将长边缩放到一个固定值如1024同时保持宽高比。这能大幅减少计算量对精度影响通常可控。批处理如果要处理多张图片尽量组织成批次batch进行推理。对于GroundingDINO需要稍微修改数据加载部分对于SAM其predict_torch本身支持对多个框进行批量预测但set_image不支持批量所以批量处理是在图片级别循环但在单张图片的多个框级别是批量的。使用ONNX RuntimeSAM官方提供了导出ONNX模型的脚本。将SAM模型导出为ONNX格式并使用ONNX Runtime进行推理在某些硬件上尤其是CPU和某些移动端可以获得显著的加速。不过ONNX部署需要处理输入输出的适配稍微复杂一些。缓存图像嵌入如果你的应用场景是对同一张图片进行多次、不同的文本查询例如在一张街景图中依次找“车”、“人”、“交通灯”那么SAM的图像嵌入只需要计算一次。可以设计一个缓存机制以图片的哈希值为键存储计算好的image_embedding避免重复计算。5.2 提升检测与分割精度的策略有时候模型会漏检或分割不准可以尝试以下策略文本提示工程GroundingDINO对文本提示非常敏感。具体化用“一只白色的萨摩耶犬”代替“狗”。增加上下文用“照片中桌子上的一台银色笔记本电脑”代替“笔记本电脑”。使用同义词如果“汽车”检测不好可以试试“轿车”、“车辆”。负面提示实验性有些社区项目尝试在文本中加入负面描述如“狗 and not cat”但GroundingDINO原生支持可能有限需要看具体版本。后处理NMS调整GroundingDINO输出的框可能过于密集。适当调整NMS的iou_threshold参数可以合并重叠框避免一个物体被重复检测多次。但要注意对于密集小物体阈值要设小避免误删。SAM的多掩码输出在调用predict_torch时设置multimask_outputTrueSAM会为每个提示返回3个候选掩码。你可以根据预测的稳定性分数stability_score或与提示框的IoU来选择最好的一个有时比单一掩码效果更好。迭代式提示对于复杂物体或分割效果不佳的情况可以采用“框提示 - 得到掩码 - 从掩码中取点作为新提示 - 再次输入SAM”的迭代方式。SAM支持点提示和掩码提示的叠加通过迭代可以逐步优化分割边界。6. 常见问题排查与解决方案实录在实际跑通和使用的过程中我踩过不少坑。这里列出一个速查表希望能帮你节省时间。问题现象可能原因解决方案导入GroundingDINO失败报ModuleNotFoundError没有以可编辑模式安装或路径不对。确保在GroundingDINO目录下执行了pip install -e .并在代码中正确添加了其父目录到sys.path。GroundingDINO检测不到任何目标1. 文本阈值(text_threshold)太高。2. 文本描述与图像内容不符或太模糊。3. 图像尺寸异常预处理出错。1. 逐步调低text_threshold如从0.25调到0.15。2. 使文本提示更具体、更贴近图像。3. 打印预处理后的图像张量形状确保不是全0或NaN。SAM分割速度极慢1. 在循环中重复调用set_image。2. 使用了vit_h模型且图像分辨率太高。3. 在CPU上运行。1.确保一张图只调用一次set_image。2. 换用vit_b或vit_l模型并缩放输入图像。3. 检查PyTorch是否使用了CUDA将模型.to(‘cuda’)。SAM分割掩码质量差边缘粗糙或包含背景1. GroundingDINO给的框不准太大或太小。2. SAM的multimask_outputFalse时选到的掩码不是最优。1. 检查并优化GroundingDINO的检测框可尝试对框进行微调如等比例扩大5%。2. 尝试multimask_outputTrue然后根据iou_predictions或stability_score选择最佳掩码。显存不足(OOM)1. 同时加载了vit_h的SAM和大型GroundingDINO模型。2. 图像分辨率过高。3. 批处理大小太大。1. 使用vit_bSAM模型。2. 降低输入图像分辨率。3. 在代码中使用torch.cuda.empty_cache()及时清空缓存并减少批大小。分割结果中有很多零散小碎片SAM可能将纹理或阴影误认为物体。在后处理中对得到的二值掩码应用面积过滤只保留面积大于某个阈值如总像素的0.5%的连通区域。对于非常小的物体检测分割失败GroundingDINO和SAM对小目标都不够敏感。1. 尝试在输入GroundingDINO前将图像裁剪或放大到小目标所在的区域。2. 调低GroundingDINO的box_threshold提高召回率。7. 项目扩展与应用场景探讨这个基础流程可以作为一个强大的视觉感知基座扩展到很多实际应用中。交互式图像编辑工具构建一个前端界面用户输入文本系统自动标出并分割出物体然后用户可以一键删除、替换或移动该物体。这比传统的魔棒或钢笔工具高效得多。视频目标追踪与分割对视频逐帧应用此流程计算成本太高。可以只在关键帧或第一帧使用GroundingDINOSAM获取目标的精细掩码然后使用视频目标分割VOS算法如DeAOT或XMem在后续帧中进行追踪和分割实现高效视频抠图。训练数据自动标注对于缺乏标注数据的领域可以用这个流程生成大量的“伪标签”Pseudo Labels。虽然精度可能不如人工标注但可以作为预训练或半监督学习的起点大幅减少标注成本。机器人视觉与抓取让机器人理解“请把那个红色的马克杯拿过来”这样的指令。通过文本指定目标获得像素级分割后可以进一步计算物体的中心点、朝向甚至抓取点指导机器人操作。结合OCR的文档理解先检测图像中的文本区域使用OCR检测模型然后将识别出的文字作为提示词输入给GroundingDINO去定位图像中与该文字描述相关的图标、图章或特定区域实现更智能的文档信息提取。这个项目的魅力在于它的灵活性和通用性。GroundingDINO打开了文本驱动检测的大门SAM提供了强大的分割先验能力。将它们串联你就获得了一个能够理解自然语言指令的“视觉剪刀”。当然它也不是万能的对于极度模糊、遮挡严重或定义非常抽象的目标效果仍会打折扣。但在大多数常见场景下它已经能提供令人惊艳的零样本效果。我个人的体会是多花时间在提示词工程和后处理调参上往往比盲目更换模型更能快速提升实际任务中的表现。最后一个小技巧在处理一批图片时可以先将所有图片用GroundingDINO过一遍把有检测结果的图片筛选出来再调用SAM这样可以避免对完全没有目标的图片做昂贵的分割计算提升整体流程的效率。本文还有配套的精品资源点击获取
返回列表