恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
SAM2图像分割在自动驾驶场景的复现实录
首页
资讯中心
/
SAM2图像分割在自动驾驶场景的复现实录
SAM2图像分割在自动驾驶场景的复现实录
发布时间:2026/10/13 4:30:52
简介这是面向计算机视觉研究者、开发者和技术人员的SAM2图像分割项目完整跑通版本基于Segment Anything Model 2实现任意图像的像素级实例分割。压缩包内含297个文件涵盖预训练模型权重pt、Python运行脚本py、模型配置文件yaml、示例图像jpg及详细说明文档md整体大小344.72MB目录结构清晰支持快速定位与二次开发。项目提供图像预测、自动掩码生成与视频分割推理三种应用示例可广泛用于物体识别、医学影像处理、自动驾驶等领域兼顾科研实验与产品原型开发。目前已有3596人学习下载。资源附有环境配置指南、数据集处理脚本与可视化演示用户可参照README快速跑通项目掌握核心调用方式和调参思路高效完成从图像到分割掩膜的转换提升分析精度与研发效率。1. 拆跑通版SAM2资源包通用图像分割在自动驾驶场景的复现实录SAM2图像分割项目是“分割一切”模型的第二代开源版本用点、框、文本提示就能把任意目标从背景中抠出来视频序列也能按帧追着分割。做成跑通版本之后下载解压就能直接出分割掩码省去了环境编译、权重对齐、参数猜谜的过程。如果你正在做自动驾驶数据标注、路面设施巡检或者只是想给批量图片做前景目标分割这份segment-anything-2.zip比从零复制源码要省两到三天。我这边实际拆过一遍点提示、框提示、视频帧分割三条链路都验证过能跑下面把推理链路、环境坑位和参数取舍一次性讲透。2. SAM2核心机制拆解从图像编码器到流式掩码解码的推理链2.1 图像编码器视觉Transformer如何把一张图变成特征张量先搞清楚SAM2的前向链路这样才能在出问题时知道该查哪一层。SAM2的图像编码器核心是一个分层视觉Transformer输入是经过预处理的RGB图像输出是三个层级的特征一个低分辨率特征用于掩码解码器做粗粒度匹配一个高分辨率特征用于后续的细节掩码修正还有一个多尺度特征堆栈用于视频帧之间的记忆匹配。和传统分类网络不同编码器输出不接全连接分类头它只负责把图像转成“该图像中每个位置有什么结构”的特征张量真正决定分割边界的逻辑在掩码解码器里。预处理这一步直接决定编码器能不能正常出结果。SAM2官方权重默认要求输入尺寸按1024×1024处理不管原图是1920×1080还是800×600都要先等比例缩放再对短边做像素填充颜色通道必须是RGB三通道。我在实际项目里遇到过有人把灰度图强行复制成三通道喂进去分割效果直接崩原因是编码器在灰度数据上学不到正常的纹理对比特征。预处理代码可以复用资源包里的transforms模块它会自动完成缩放、填充和归一化。import torch from PIL import Image from sam2.build_sam import build_sam2 from sam2.sam2_image_predictor import SAM2ImagePredictor # 加载配置和权重路径根据实际解压目录调整 config_file configs/sam2/sam2_hiera_l.yaml checkpoint checkpoints/sam2_hiera_large.pt model build_sam2(config_file, checkpoint, devicecuda) predictor SAM2ImagePredictor(model) # 读取的图像统一走set_image接口做内部预处理 image Image.open(demo_frame.jpg).convert(RGB) predictor.set_image(image)这段代码里set_image内部会把PIL图像转成张量缩放到1024×1024再做归一化最后送入编码器得到特征张量。build_sam2负责按配置文件组织网络结构配置文件里定义的是编码器层级数、注意力头数、掩码解码器的深度等结构参数。使用这份跑通包时不建议换用其他版本的Hiera配置文件不同尺寸模型对应的config和checkpoint是一一绑定的混用会造成维度不匹配的报错。编码器输出特征后不会立即得到掩码它还要结合提示信息在解码器里做二次推理。这一步的关键点在于编码器本身不需要针对每个目标单独运行一批图片只要推理一次编码器后续的多次提示推理都复用同一份特征。批量标注场景下这个特性非常值钱先批量抽出视频关键帧统一过一遍编码器再逐个目标点提示整体耗时能下降一个数量级。习惯用传统语义分割模型的人往往会忽略这一点把编码器和解码器绑在一起循环调用等于每点一个目标就重算一遍全图特征显存和时间双双浪费。2.2 提示编码器点、框、文本三路输入的嵌入方式与坐标归一化规则提示编码器是SAM2区别于传统分割模型的核心部件。它接收三类输入点提示、框提示、文本提示。点提示用(x, y)坐标加上一个标签1表示目标点0表示背景点框提示用(x1, y1, x2, y2)四点坐标表示目标所在矩形区域文本提示则走文本编码器转成向量再映射到提示嵌入空间。坐标归一化是个容易翻车的细节。SAM2内部处理坐标时要求输入坐标已经归一化到图像原始尺寸的像素坐标系里而不是归一化到0到1的浮点区间。很多初学者习惯把坐标缩放到0到1之间传入结果分割区域会和点位置差一大截。我一般会在点提示前先拿到原图的宽高把点击坐标直接用原始像素值传入。资源包里的示例脚本封装了一个predict_with_points函数内部会做坐标映射但自己写代码时要把这个规则记牢。# 原始像素坐标不用归一化 input_point np.array([[860, 420]], dtypenp.float32) input_label np.array([1], dtypenp.int32) # 传入原始图像尺寸对应的坐标 masks, scores, _ predictor.predict( point_coordsinput_point, point_labelsinput_label, multimask_outputTrue, )这段代码中multimask_outputTrue会返回三个候选掩码对应同一提示下的不同分割粒度。初次使用时可以全打印出来目检选IoU分数最高的那个。如果目标边缘精细度要求高可以把multimask_output改成False只出最稳妥的一条掩码但换来的是可能漏掉细节边缘。参数本身没有绝对优劣需要根据数据集场景来回调我习惯在混合场景先用True看三路输出再决定固定用哪个策略。框提示适合快速给出目标大概位置时使用。资源包里有一段把检测框转成掩码的代码但要注意框提示不能和点提示同时放置在同一个predict调用里实际代码是先构造框的box_coords再作为参数传入。框的大小如果覆盖到背景太多解码器会倾向输出更大范围的前景这时候可以在框内补一个目标点做修正SAM2官方支持这种多提示组合掩码解码器会综合所有提示计算最终结果。2.3 记忆机制SAM2做视频分割为什么比逐帧调SAM更值得第二代模型最大的变化是加入视频记忆机制。它把时序上的一组帧分割结果压缩成记忆特征存储起来在后续帧的掩码解码时作为条件输入这样目标外观发生变化、遮挡后重新出现、或者相机抖动导致像素位移模型都能借助记忆特征找回目标。逐帧调用第一代模型分割只能得到独立帧的结果没有时序一致性目标ID也无法跨帧保持。记忆机制的实际效果在道路巡检场景特别明显。画面里一辆白色轿车从左往右行驶中间经过一棵树被短暂遮挡带记忆的SAM2能在遮挡结束后继续分割同一辆车的车身而逐帧分割的结果往往会把同一辆车当成多个不同目标。资源包里的SAM2VideoPredictor封装好了这个记忆流程使用时要按帧调用init_state、predict_next_frame等接口同时注意用于存储记忆的特征图会占用额外显存视频分辨率越高占用越多。from sam2.sam2_video_predictor import SAM2VideoPredictor video_predictor SAM2VideoPredictor.from_pretrained( config_file, checkpoint, devicecuda ) # 初始化视频状态传入视频帧目录和帧率 state video_predictor.init_state(video_pathframes/) for frame_idx in range(len(state.video_frames)): # 首帧用点提示后续帧走记忆推理 if frame_idx 0: _, _, _ video_predictor.add_new_points_or_box( state, frame_idxframe_idx, pointspoint, labelslabel ) else: mask, score, _ video_predictor.predict_next_frame(state, frame_idx)这段代码展示了视频分割的最小流程。init_state内部会读取指定目录下的按序命名的帧图片add_new_points_or_box只在首帧注入提示信息后续predict_next_frame会利用之前的掩码特征自动跟踪目标。参数上state内部有一个memory_bank_size控制记忆缓存长度默认值在长视频里会越占越多建议根据需求限制在合理范围我一般设置在30到50帧之间超出就淘汰旧帧特征。3. 环境与权重文件跑通SAM2前的依赖匹配与目录布局3.1 版本选型Python、PyTorch与CUDA的兼容性判断顺序跑通SAM2最常见的失败原因不是模型代码本身而是依赖环境错位。我拆这份资源包时先看的就是环境要求文件里面锁定了Python、PyTorch和CUDA版本。经验上Python选择3.8到3.10之间的版本比较稳妥太新的版本可能导致部分编译组件不兼容PyTorch建议2.0以上版本因为第二代模型有些算子依赖新版APICUDA则根据显卡驱动版本选择11.8或12.1等常见版本不一定要最新版。版本匹配有个判断顺序先根据显卡驱动确定能支持的CUDA版本再选匹配的PyTorch版本最后确认Python版本。很多人反着来先装了最新的Python再配PyTorch结果不得不重装环境。我在一台只有单张16GB显存显卡的机器上用的是Python 3.10、PyTorch 2.1、CUDA 12.1的组合跑Hiera-L模型验证过整个流程。显存低于8GB的机器建议换用Hiera-S或Hiera-B配置对应权重文件在资源包里有单独存放。# 参考环境组合Python 3.10 PyTorch 2.1 CUDA 12.1 conda create -n sam2 python3.10 -y conda activate sam2 pip install torch2.1.2 torchvision0.16.2 --index-url https://download.pytorch.org/whl/cu121执行环境安装时不要一股脑装最新版最好把PyTorch单独优先安装再装其他依赖因为torchvision、torchaudio会和PyTorch主版本强绑定。索引地址里的cu121代表CUDA 12.1版本的预编译包如果驱动已经支持12.1用这个就能省去自己编译算子的时间。装完通过一行命令验证GPU可用性torch.cuda.is_available()返回True才继续往下走。3.2 checkpoint目录布局权重文件和配置文件如何配套下载后的segment-anything-2.zip解压后核心内容分成三类源码目录、配置文件目录、权重目录。源码目录包含sam2核心推理代码配置文件目录存放不同模型尺寸的yaml配置权重目录存放对应的.pt权重文件。这三者的对应关系是严格一一绑定的模型配置里写了编码器深度、Transformer层数、掩码解码器通道数权重文件则是基于这些结构训练出来的参数。错误做法是把权重文件随意丢在某个路径再通过路径引用这样不仅容易破坏目录可移植性还会让换机器部署时反复改代码。我一般会保留解压后的原始目录结构只增加一个单独的weights/目录存放权重然后在读取权重时使用相对路径加环境变量的方式。配置文件和权重文件名里通常带有模型尺寸标识例如hiera_b对应基础版hiera_l对应大模型显存和精度要求随尺寸线性增长。# sam2_hiera_l.yaml 关键内容摘录 model: _target_: sam2.modeling.sam2_base.SAM2Base image_encoder: _target_: sam2.modeling.backbones.hieradet.Hiera embed_dim: 144 num_heads: [2, 4, 8, 16] global_attn_indexes: [2, 5, 8, 11] window_size: 8 mask_decoder: _target_: sam2.modeling.sam2_base.MaskDecoder这个配置片段说明的是结构参数embed_dim决定特征通道维度num_heads是Transformer注意力头数量window_size控制窗口注意力的局部范围。改动这些参数前要掂量清楚直接修改而不重新训练会让权重加载报shape mismatch错误。正常使用中不修改配置只需要根据显存挑选不同尺寸的配置和权重。如果确实想改动模型结构必须同时准备好对应的权重重训流程这超出了工程应用范畴。3.3 最小可复现推理流程从读图到保存掩码的完整代码环境装好了权重放对了下一步就是跑通最小推理脚本。下面这段代码是单张图片的最小闭环适合用来验证整个环境是否正常。跑通以后再去改参数、加批量逻辑、接视频流都会顺利很多。import numpy as np from PIL import Image from sam2.build_sam import build_sam2 from sam2.sam2_image_predictor import SAM2ImagePredictor config_file configs/sam2/sam2_hiera_l.yaml checkpoint checkpoints/sam2_hiera_large.pt # 构建模型并切换到推理模式 model build_sam2(config_file, checkpoint, devicecuda) predictor SAM2ImagePredictor(model) # 读取图片并送入predictor image Image.open(test_image.jpg).convert(RGB) predictor.set_image(image) # 构造一个前景点提示坐标为原始图像像素值 input_point np.array([[500, 300]], dtypenp.float32) input_label np.array([1], dtypenp.int32) # 执行推理 masks, scores, _ predictor.predict( point_coordsinput_point, point_labelsinput_label, multimask_outputTrue, ) # 取分数最高的掩码保存为单通道PNG best_idx int(np.argmax(scores)) mask masks[best_idx].astype(np.uint8) * 255 Image.fromarray(mask).save(output_mask.png)这段代码的推理逻辑很清晰先构建模型和预测器设置图片传入点提示解码出候选掩码最后按分数挑选一条保存。scores对应每个掩码的置信度一般取最高分即可但在目标重叠场景中最高分掩码可能覆盖了多个相近目标可以人工介入选择其他候选。astype(np.uint8) * 255是把布尔掩码转成可视化灰度图的关键步骤不加这一步直接保存会得到一张全黑图片。4. 实战把SAM2接入自动驾驶图像分割与标注流水线4.1 自动驾驶场景的数据形态车载视频帧、街景图片与标注目标定义自动驾驶相关的图像分割任务通常接触两类数据车载摄像头录制的连续视频帧以及从公开数据集或采集车导出的街景图片。前者要用视频分割链路做时序掩码后者更适合用单图提示做精细标注。目标定义主要围绕车辆、行人、骑行者、交通标志、车道线等交通参与者SAM2的优势在于不需要针对每个类别训练专门的模型点一下目标就能出掩码标注人员的工作重心从“画多边形”变成“点目标”。实际标注流水线里我的做法是第一遍用SAM2自动生成粗掩码第二遍由人工检查并修正边缘修正的方式不是重新画而是补充一个背景点让模型重新推理。这个交互式修正流程相比传统标注工具效率高很多尤其是车辆边缘的雨刷、后视镜、轮胎间隙这些复杂轮廓手工多边形画一帧要一两分钟SAM2点几下就能出合格掩码。资源包里有一段自动遍历图片目录并保存掩码的脚本每次推理结束后会顺手把坐标点和掩码一并存成json方便对接后续的标注平台。# 一个典型的标注流程终端命令序列 python auto_segment.py --input_dir ./frames --output_dir ./masks --model hiera_l python convert_masks.py --mask_dir ./masks --format coco python verify_results.py --mask_dir ./masks --image_dir ./frames上面的命令序列对应三段式流程先批量分割生成掩码再把掩码转成COCO格式的标注文件最后做一轮可视化校验。auto_segment.py里的--model参数控制模型尺寸显存紧张时换hiera_s。转换脚本会把掩码轮廓转成多边形坐标注意轮廓点数过多会撑大标注文件转换时设置simplify_threshold合并相近点。4.2 目标提示策略用点提示分割车辆、行人与车道线区域不同交通目标适合不同的提示策略。车辆目标轮廓相对紧凑一个中心点加一个背景点就能稳定收敛行人目标姿态变化大如果视频里有遮挡建议使用框提示框住身体主体外加一个目标点修正头部位置车道线这类细长连续目标单点提示效果不稳我一般沿着线段的两个端点各给一个目标点SAM2会把它识别成同一条线状目标。这里的关键是背景点负样本的摆放位置目标边缘贴近其他物体时背景点要放在干扰物体的那一侧强制模型把两者切开。# 车辆目标中心点边界外背景点 foreground np.array([[960, 540]], dtypenp.float32) background np.array([[600, 540]], dtypenp.float32) # 靠近干扰物一侧 points np.concatenate([foreground, background], axis0) labels np.array([1, 0], dtypenp.int32) masks, scores, _ predictor.predict( point_coordspoints, point_labelslabels, multimask_outputFalse )这个方法的逻辑在于背景点告诉解码器“从这里往外的区域不属于目标”相当于在网络推理路径上加了一个硬约束。labels数组里的0和1和坐标一一对应顺序不能乱。multimask_outputFalse在这种精修场景里更合适只输出一条包含语义约束的掩码避免多个候选掩码里混入不想要的变体。如果目标本身非常小比如远处的行人可以只给一个前景点不配背景点让模型自行估计边界。4.3 掩码后处理从布尔数组到多边形标注的格式转换细节SAM2输出的掩码是布尔类型的二维数组标注平台通常不接受这种格式需要转换成Pascal VOC格式的PNG标签图、COCO格式的多边形标注或者YOLO格式的归一化分割标签。转换过程中最常踩的坑是掩码坐标和原图尺寸不对齐。如果推理时用的是缩放后的图像输出掩码尺寸对应的是缩放后的分辨率必须通过插值把掩码恢复成原图尺寸否则标注框会在画布上错位。import cv2 mask masks[best_idx].astype(np.uint8) # 掩码尺寸是1024x1024原图是1920x1080 original_size (1920, 1080) mask_resized cv2.resize( mask, original_size, interpolationcv2.INTER_NEAREST ) # 提取轮廓多边形 contours, _ cv2.findContours( mask_resized, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE )这里必须用INTER_NEAREST而不是默认的线性插值。线性插值会在掩码边缘引入中间灰度值导致轮廓提取出现非0即255之间的过渡带多边形点数成倍增加。RETR_EXTERNAL只提取外层轮廓内部孔洞不会形成独立多边形对于大多数交通目标足够了。如果目标存在明显镂空区域比如自行车车轮辐条处的空隙需要换成RETR_LIST把所有内外轮廓都提取出来再单独组织标注层级。5. 跑通SAM2的避坑记录五个高频异常从现象到解决方案5.1 现象首次推理报CUDA out of memory进程直接退出原因大概率是模型尺寸和显存不匹配Hiera-L在1024分辨率下前向推理的峰值显存接近8GB加上PyTorch运行时的缓存开销16GB的卡也容易被撑爆。解决方式是先检查nvidia-smi确认当前没有其他进程占用显存然后换小尺寸配置或者用自动混合精度推理。我用的实践方案是加载权重时先尝试半精度让模型参数和中间激活值都跑在FP16上显存占用直接减半分割精度的下降在绝大多数场景里可以忽略。# 半精度推理模型参数转fp16 model build_sam2(config_file, checkpoint, devicecuda) model model.half() # 关键参数量减半这段代码里model.half()把全部可训练参数转为半精度浮点数但输入图片仍然以FP32传入前向过程中张量会自动在FP16和FP32之间转换。要注意的是若显卡不支持FP16加速老架构卡除外半精度反而会变慢这时优先用降低输入分辨率来省显存比如把图像短边压缩到768精度损失比切模型尺寸更小。5.2 现象保存的掩码图是全黑的什么内容都没有这个问题不是推理失败而是保存环节数据类型错误。模型输出的候选掩码是布尔数组直接Image.fromarray(bool_array)不会得到预期图像因为PIL库不支持布尔类型的直接转换或者转换后所有值被压缩成0。解决方式是把掩码转成uint8再乘以255缺少乘法这一步True变成1在8位灰度图里仍然是肉眼不可见的。确认掩码是否有效还有一个更直接的方法打印masks数组的sum()值如果远大于0说明掩码区域存在。# 保存前做严格类型检查 assert mask.dtype np.uint8, mask dtype must be uint8 assert mask.max() 0, mask seems empty Image.fromarray(mask * 255).save(output_mask.png)5.3 现象点击目标中心分割结果却是旁边的物体这类错位通常源于坐标输入尺寸和模型内部处理尺寸不一致。如果前端界面展示的是缩放后的预览图点击坐标也是预览图上的像素值直接传给SAM2就会产生偏移。解决方式有两种一是让点击坐标始终基于原始图片尺寸计算二是调用predictor.set_image之前对预览图坐标乘以缩放比例系数还原成原图坐标。这个还原操作要在传给predict之前完成不要试图让模型内部去做映射。5.4 现象视频分割时目标从第二十几帧开始丢失掩码变成空白这是视频记忆机制的边界效应。默认的memory_bank_size有限目标在长时间未更新记忆特征后解码器会逐渐失去对目标的追踪能力。解决方式是在目标丢失后重新在最新帧上注入提示点把新的掩码作为记忆重置。资源包的add_new_points_or_box接口在同一时刻再次调用时就是在已有状态基础上追加提示信息而不是从头开始。5.5 现象批量处理视频帧时CPU占用异常高GPU利用率却上不去这通常是数据加载环节的瓶颈。读取视频帧、做图像缩放、转张量的操作都在CPU上执行而GPU推理速度快两者吞吐不匹配时GPU会频繁等待数据。解决方式是使用预加载缓存提前把帧读入内存或者把帧序列先批量转成张量再送推理。显存不够大时用前一种方案我用的是把视频抽帧后按时间窗口分组每个窗口内并行加载再串行推理GPU利用率能从30%提升到80%以上。6. 进阶技巧把SAM2从单点分割升级为区域性批量分割工作流6.1 特征缓存复用一次图像编码多次提示推理最后讲一个实际工作流里最能提升效率的技巧。SAM2的图像编码器输出特征张量只依赖输入图像和提示点无关。所以在一张图里有多个目标需要分割时不要反复调用set_image只需要调用一次编码然后针对每个目标传入各自的点提示和框提示执行解码。我把这个逻辑封装成一个简单的类初始化时传入图片路径内部只做一次编码后续每次调用segment方法都复用已缓存的特征10个目标的标注耗时从几十秒降到了几秒。class FastSegmenter: def __init__(self, config_file, checkpoint, image_path): model build_sam2(config_file, checkpoint, devicecuda) self.predictor SAM2ImagePredictor(model) self.predictor.set_image(Image.open(image_path).convert(RGB)) def segment(self, points, labels): masks, scores, _ self.predictor.predict( point_coordspoints, point_labelslabels, multimask_outputTrue, ) return masks, scores逻辑上set_image只是编码一次predict可以被反复调用。但我自己实践后提醒一句不要在循环内部修改同一个预测器的schema参数部分版本在前向传播时会受上一次勾选multimask_output的影响循环里最好固定multimask_output的值避免结果忽好忽坏。6.2 输出格式验证与结果抽检跑通批量流程后一定要做一轮抽检测试。我习惯从结果中随机抽取5%的掩码叠加在原图上检查掩码边缘是否准确贴合目标轮廓有没有把背景道路错分成车辆目标。抽检代码里会用matplotlib把原图和掩码半透明叠加显示肉眼扫一遍基本能发现大部分质量问题。自动化的验证指标可以计算掩码的边界完整度比如轮廓与目标像素亮度的贴合程度但这个指标在不同场景差异大参考价值有限。从那以后我每次拆新的分割资源包都会强制自己先跑一遍最小推理脚本再谈效率优化顺序不能反。跑通一个能出图的版本比读三遍源码都管用先看到掩码再回头理解网络内部逻辑会发现卡了很久的问题不过是坐标类型或者掩码类型不一致。希望帮到你。本文还有配套的精品资源点击获取