尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

SAM在遥感图像语义分割中的实战:从标注提速到DeepLabV3训练全流程

SAM在遥感图像语义分割中的实战:从标注提速到DeepLabV3训练全流程 最近一年只要做图像分割基本绕不开SAM这个词。Segment Anything ModelMeta开源的那个零样本分割模型在自然图像上的各种玩法大家应该都见过了。但把它拿到遥感图像上做语义分割很多人第一反应是这是不是有点水土不服我的答案是能行而且如果你有大量标注需求它简直是提效神器。这篇文章不聊虚的就讲讲我用SAM做遥感图像语义分割的完整思路、实操流程和踩过的坑适合正在做遥感影像标注、语义分割数据集制作以及想用SAM辅助训练DeepLabV3这类语义分割模型的同学参考。1. 为什么我会拿SAM来做遥感图像语义分割1.1 遥感影像和日常照片差在哪儿做遥感图像语义分割的人应该都对标注这件事深有体会。一张航拍图或者卫星图动辄上万像素起步地物类型复杂建筑物、道路、水体、植被、裸土混在一起不同季节、不同光照条件下同一类地物的纹理差异又特别大。你用传统的全监督语义分割模型比如DeepLabV3、U-Net这一套第一步就要处理大量标注数据但遥感图像的标注成本远高于自然图像。大家平时拍照随手就能标注猫和狗但在遥感图上画一栋楼的轮廓或者勾勒一片水域的边界那是像素级的精细活人工一天标不了几张。这就是SAM这类模型最吸引人的地方。它不需要针对遥感数据重新训练拿过来就能做“零样本分割”。也就是说给一张你从没见过的影像只要给它点提示或者框提示它就能把目标轮廓抠出来。这个能力在自然图像上已经很惊艳放到遥感图像上反而是刚需因为遥感图像的目标往往边界清晰、结构规则SAM对这类“物体感”强的目标分割效果相当稳定。1.2 SAM解决的核心问题把“标轮廓”这个环节自动化我做遥感语义分割项目的时候最耗时间的环节不是模型调参而是做数据集。以前做一个区域的建筑物提取任务标注团队要先加载影像手动描绘几百栋建筑的边缘标完还要人工复核边界有没有偏差。用SAM之后整个流程可以改成人只需要在每栋建筑上点一个点SAM就能预测出完整的建筑轮廓然后人工在少量错误结果上做修正就行。实测下来同样一个区域标注时间能压缩到原来的三分之一都不到。所以要理解SAM在遥感里的定位不要把它当成一个“完整的语义分割模型”。它最核心的价值其实是“分割器”负责把目标形状找出来至于这个目标属于哪个类别那是分类的事。你把这两个环节拆开就能明白为什么SAM可以和DeepLabV3这类语义分割模型形成完美的配合而不是互相替代。1.3 和DeepLabV3、点云语义分割这些方向是什么关系先说DeepLabV3。它是一种典型的全监督语义分割模型输入图像输出每个像素的类别概率图。它能告诉你“这是建筑物”“这是路”但它需要大量像素级标注来训练。SAM恰恰相反它输出了目标掩膜但不会告诉你掩膜是什么类别。所以我在实际项目里最常见的用法是先用SAM帮助标注人员快速生成精确掩膜人工补类别标签再拿去训练DeepLabV3让DeepLabV3在推理阶段批量预测整幅影像。至于热搜里出现的“点云语义分割”那是另一套技术路线处理的是LiDAR点云数据输入是三维坐标和反射强度而不是二维图像。SAM本身处理不了点云输入但如果你需要从点云里做目标分割和语义分类思路依然可以参考先做“目标部件级分割”再做“类别判断”。不要指望SAM直接帮你解决点云问题那是PointNet这类模型的战场。2. SAM的核心机制和遥感场景下的选型分析2.1 SAM的模型结构到底长什么样SAM的结构可以压缩成三个部分Image Encoder、Prompt Encoder和Mask Decoder。Image Encoder用MAE预训练的ViT把整幅图像编码成特征Embedding这是计算量最大的部分。Prompt Encoder把点、框、掩膜这类提示信息也编码成Embedding。Mask Decoder把图像Embedding和提示Embedding融合输出分割掩膜和置信度分数。理解这个结构有个实际意义Image Encoder的输出只跟图像有关跟提示无关。所以如果你对同一张图反复做不同的点提示、框提示图像特征只需要计算一次后续每次提示都只用重新跑Mask Decoder。这个特性在遥感大图上特别值钱我后面讲实操的时候会再强调。2.2 多种提示方式在遥感场景下的适用场景SAM支持三种常见的提示方式分别对应不同使用场景。点提示在目标内部点一下SAM会把目标抠出来。适合建筑物、车辆、船只这类独立目标。负样本点背景点也很有用当目标旁边有紧邻干扰物时主动点一个背景点能显著改善分割结果。框提示给一个目标包围框SAM在框内精细分割。场景是目标检测模型先出框SAM再补精分割形成“检测定位分割抠图”的流水线。全图自动分割Everything模式用SamAutomaticMaskGenerator对整幅图生成大量候选mask。适合快速摸底比如先看看影像里大概有哪些可分割目标但生产环境不建议直接用因为SAM不区分类别它会连草丛阴影都当成一个目标生成几百个mask筛选成本极高。在遥感图像场景里我个人用点提示最多因为遥感目标界线清楚“点一下就出轮廓”的交互方式对标注员特别友好上手成本几乎为零。2.3 为什么交互式提示比全自动分割更适合遥感场景我见过不少人拿到SAM第一件事就是把整张遥感图丢进Everything模式期待它自动分割出所有目标。结果跑完之后面对几百个mask还得人工一个个看哪些是要的效率反而更低。核心原因是SAM对“目标的定义”是无感知的。在遥感图上同一块地方可能是停车场、屋顶、混凝土广场三者像素纹理非常相似只有人知道它们对应什么语义。如果你不告诉SAM“现在我要提取屋顶”它就会把停车场也一并分割出来。交互式提示的好处就在这里——你把语义先验通过点或框喂给模型让SAM只在局部搜索你关心的目标这样既保留了SAM强大的轮廓预测能力又把“语义选择”的主动权攥在手里。遥感的标注流程本来就是人工在中间环节把关的这个特性天然匹配。2.4 权重选型vit_h、vit_l、vit_b怎么选SAM官方给了三个权重vit_h精度最高、代价是模型大推理慢vit_b速度最快、精度稍逊。我自己的建议如下权重参数量显存占用1024x1024输入适用场景vit_h约6亿8GB以上服务器离线处理追求最高分割质量vit_l约3亿约6GB一般实验和中等规模标注vit_b约9000万约4GB个人电脑、快速原型、批量交互标注显存占用只是个大概参考跟你用的推理框架、是否开半精度、batch大小都有关系。我的经验是如果是公司内部做标注工具直接上vit_h或者vit_l精度高标注员少生气如果是自己电脑上做实验先用vit_b跑通流程再换大模型出最终结果。3. 遥感图像语义分割的实操全过程3.1 数据准备从GeoTIFF到SAM能识别的RGB图像遥感影像最常见的是GeoTIFF里面可能包含RGB三波段也可能包含红、绿、蓝、近红外等多波段甚至还有单波段的SAR数据。SAM的Image Encoder训练时使用的是自然RGB图像所以输入必须是三通道每通道取值范围0到255的uint8数组。我的建议流程是这样的先用rasterio读取影像保留transform坐标信息再判断波段数。如果是三通道且顺序就是RGB直接用如果是四通道R、G、B、NIR只要R、G、B三个波段如果是单波段比如只有全色波段或者SAR灰度图不能直接喂给SAM需要先转成三通道伪彩色图最简单的方式是把同一个灰度波段复制三份效果虽然不算完美但目标轮廓依然能分割出来。import rasterio import numpy as np with rasterio.open(remote_sensing.tif) as src: transform src.transform band_count src.count if band_count 3: rgb src.read([1, 2, 3]) else: gray src.read(1) rgb np.stack([gray, gray, gray], axis-1) rgb rgb.transpose(1, 2, 0).astype(np.uint8)有个细节要注意遥感影像经常是16位存储的取值范围0到65535直接转uint8会白茫茫一片。需要先做归一化比如用百分比截断取2%到98%分位做线性拉伸再映射到0到255这样SAM看到的影像细节更清楚。3.2 环境搭建和最小可运行示例安装SAM官方库最简单的方式是直接从GitHub装pip install githttps://github.com/facebookresearch/segment-anything.git pip install torch torchvision opencv-python rasterio然后下载对应的checkpointvit_b的checkpoint大约375MBvit_h大约2.5GB下载完放好路径下面的代码可以直接跑import cv2 import torch import numpy as np from segment_anything import sam_model_registry, SamPredictor sam sam_model_registry[vit_b](checkpoint./checkpoints/sam_vit_b_01ec64.pth).to(cuda) predictor SamPredictor(sam) image cv2.cvtColor(cv2.imread(test_tile.png), cv2.COLOR_BGR2RGB) predictor.set_image(image) input_point np.array([[256, 512]]) # 点坐标x, y input_label np.array([1]) # 1表示正样本0表示负样本 masks, scores, logits predictor.predict( point_coordsinput_point, point_labelsinput_label, multimask_outputTrue, ) best_mask masks[np.argmax(scores)]这里有一点很多人会踩input_point是图像原始分辨率下的像素坐标不是归一化坐标。如果你在标注界面看到的是屏幕坐标而图像经过缩放显示必须先做坐标换算否则提示点会落到错误位置切割结果惨不忍睹。predict返回的masks数量取决于multimask_output参数设为True时返回3个候选每个候选的分数不同选分数最高的通常是最稳的。3.3 用点提示和框提示做目标提取的完整流程实际做标注时单点提示往往不够。我推荐一个更稳的交互策略正样本点至少一个目标边界模糊时再加一个负样本点。比如在提取水体时水面中间点一个正点河岸上点一个负点SAM就会尽量把分割边界控制在河道内部不会漫到岸上。框提示和点提示可以组合使用。比如你有一个建筑物检测框可以通过下面的方式提升分割精度input_box np.array([100, 200, 300, 400]) # x1, y1, x2, y2 input_point np.array([[200, 300]]) input_label np.array([1]) masks, scores, logits predictor.predict( point_coordsinput_point, point_labelsinput_label, boxinput_box, multimask_outputTrue, )框给模型一个“区域约束”点给模型一个“目标锚定”。配合使用的效果是在建筑物密集区域SAM不会把相邻屋顶连到一起因为点提示已经明确告诉它要关注的是哪个目标。如果你做过遥感标注一定知道密集建筑物分割是最容易翻车的地方。3.4 大影像切片推理和拼接避免边缘断裂遥感影像太大直接整幅图送进SAM不现实必须先切成小块再推理最后拼回来。切片逻辑很简单确定切片大小我一般用512×512或者1024×1024。设置重叠区域相邻切片之间重叠50到100像素。不要不重叠否则目标一旦跨切片边界就会被切成两半。每个切片独立推理得到mask按原位置贴回全图坐标系。拼接时有个常见的坑如果同一目标出现在两个切片里两个切片推理出的mask可能有细微差异直接拼会导致边界错位。我的解决办法是拼接时记录每个像素位置的mask得分重叠区域取得分更高的那个mask。说白了就是“谁置信度高听谁的”。保存地理坐标信息也很关键。如果你只是做标注工作mask按像素保存成PNG就够了如果你想让分割结果直接进入GIS流程输出GeoJSON或者带地理参考的TIFF才是首选。做法其实不复杂切片的时候记录每个切片左上角在原图中的行列号推理完成后把mask的像素坐标加上偏移量再用rasterio的transform把像素坐标投影到经纬度坐标即可。3.5 用SAM生成语义分割数据集再训练DeepLabV3这里给一条完整的链路也是我推荐的最实用的工作流第一步目标分割。对原始影像切片用SAM对每块做交互式分割得到前景mask。第二步类别标注。SAM输出的mask没有类别人工给每个mask打标签比如“建筑”“水体”“道路”。这一步比从头画轮廓轻松多了你只需要看形状判断类别不需要再描边。第三步栅格化。把多个mask合并成一张整数标签图建筑像素设为1水体设为2背景设为0。注意类别叠加时要有优先级比如道路和建筑重叠时通常允许建筑压道路。第四步训练模型。用标签图配合原始影像训练DeepLabV3。torchvision里有现成的deeplabv3_resnet50加载预训练权重后把输出类别数改成你的类别数直接训练就行。训练时一般把影像裁成256×256或512×512的小块做随机翻转和颜色抖动增强。这条链路最大的价值是你把“人工描边”这种低效劳动转换成了“人工确认类别”这种高效劳动数据集制作速度提升非常明显。语义分割数据集如何制作这个话题本质上绕不开标注效率SAM给了一个很具体的答案自动分割、人工分类。4. 踩坑实录与常见问题排查4.1 显存不够、推理太慢怎么破很多人在自己笔记本上跑vit_h加载模型直接报CUDA out of memory。解决办法优先级如下第一换小模型vit_b通常能覆盖大部分需求精度并没有差到不能接受。第二开半精度推理用model.half()把模型转成fp16显存占用能降不少速度还能提升。注意输入图像也要转成fp16否则类型不匹配。第三缩小输入图像。SAM内部会把图像resize到1024×1024所以如果你输入的是2048×2048的图内存和显存都会多耗。与其一次喂大图不如先切片再推理。第四复用Image Embedding。这是最容易被忽略的优化点。对同一张影像多次做点提示时不要每次都调用set_image这个函数会重新计算整张图的特征。正确做法是第一次set_image后面每次只调用predict速度能快好几倍。4.2 大影像切片后结果不一致怎么办切片之间分割结果不一致本质上是因为目标被切断后模型看到的上下文变了。比如一栋长条形建筑在一个切片里只露出局部SAM可能把它分割成两段。我的经验是重叠区域不能省至少50像素起步。第二个技巧是如果你知道某个目标跨切片尽量在切片时不要让重要目标正好卡在边缘可以先跑一遍目标检测或者直接用人工观察调整切片偏移。第三个技巧是拼接后再做一次形态学闭运算把细小的断裂带连接起来。4.3 提示点落在边界导致分割飘了点提示如果点在了目标边界附近SAM经常会出现分割结果“犹豫不定”要么把旁边的干扰物包进来要么漏掉目标的大半部分。遇到这种情况最简单的办法是点提示和框提示一起用框先把目标大致框住模型就不会跑太远。还有一种很实用的方法先用自动分割找个粗糙mask然后用这个mask作为提示输入SAM支持用mask作为提示进行二次分割。不过操作上稍微绕我一般更推荐多给几个点正点打在目标中心区域负点打在干扰物上基本就能定住。4.4 遥感地物类别太多SAM分不清怎么办要再次强调SAM不是分类模型它不会告诉你这块是农田还是裸地。如果你拿SAM做多类别语义分割正确思路是“一类别一轮分割”先针对建筑做一轮把所有建筑mask提取出来再针对水体做一轮把水体mask提取出来。每一轮人只关注一个类别SAM不会被多类别混淆数据集的类别质量也会更高。如果是自动化程度要求高的场景合理方案是SAM做目标候选再接一个轻量分类网络或者直接用DeepLabV3去做语义分类。SAM负责的是“提候选目标”分类网络负责“给候选目标定语义”两个任务分开处理比指望一个模型通吃要稳得多。4.5 关于PVS、SAM目标跟踪这些周边概念简单说两句有些同学会在代码或者文章里看到“SAM-PVS”这类写法。PVS是Promptable Visual Segmentation的缩写翻译过来就是“可提示视觉分割”描述的就是“通过点、框、提示来驱动分割”这一类交互式分割范式SAM算是这个范式目前最有代表性的实现。看到类似命名的时候不用慌把它理解为交互式分割的新叫法就行。至于“SAM目标跟踪”SAM本身确实不是目标跟踪模型它只有单帧分割能力。视频目标跟踪需要在帧间增加关联逻辑比如SAM 2就是SAM在视频域的扩展版本。遥感图像大多还是静态影像用到目标跟踪的场景通常是视频卫星或者无人机连续帧目标监测需要额外加时序约束模块单纯拿SAM处理连续帧会丢失目标身份信息。4.6 问题速查表问题现象可能原因解决思路加载模型报显存不足模型规格太大、输入图过大换vit_b、缩小输入、开fp16分割结果把相邻目标连在一起提示点太接近边界、目标密集增加负样本点、配合框提示大图拼接处目标断裂切片重叠太小或没有重叠加50~100像素重叠拼接后闭运算输出mask在地理位置偏移切片坐标偏移量没加、transform丢失记录切片起始坐标正确回投影灰度影像分割效果差SAM输入需要三通道RGB灰度复制三通道或伪彩色增强同一目标不同切片漏检目标被截断、上下文缺失目标避开切片边缘重叠设置大一点5. 我自己的几点使用体会把SAM用在遥感图像语义分割上最重要的心态调整是别把它当“一键导出工具”而是当“智能标注员”。交互式提示这个设计决定了它的工作流必然是人机协同人也必须参与到“要提取什么目标”的决策里但那些原本最耗时的轮廓描绘工作确实可以放心交给它。我现在做标注项目基本流程已经固化成先跑自动分割做快速摸底再按目标类别逐轮做点提示提取最后人工只处理那些边界模糊的低置信度样本。这套流程跑下来数据质量稳定标注成本大幅下降也更愿意在训练数据上多花精力做类别均衡和样本筛选模型的最终精度提升其实比单纯换更大参数的网络更明显。如果你正准备开始用SAM做遥感分割我的建议是拿一小块你最熟悉的数据先跑通把提示交互、切片拼接、坐标输出这几环理顺再上生产也不晚。
返回列表