从 SAM 到 SAM 2.1 的遥感分割复盘

1. 背景

这次工作的起点,是想把一套基于 SAM 的遥感地物分割流程,逐步迁移到 SAM 2.1,并验证它是否真的适合火城这类大尺度遥感影像。

最初的目标并不复杂:

  • 先理解已有脚本到底在做什么
  • 在不破坏原始可用流程的前提下,逐步优化
  • SAM 2.1 环境和推理流程打通
  • 最终判断:SAM 2.1 是否值得替换当前 SAM 1 工作流

2. 第一阶段:理解并重构原始 SAM 脚本

最开始分析的文件是:

  • E:\PycharmProjects\deeplearning_pj\SAM_code\SAMhuocheng.py

这个脚本本质上做了几件事:

  1. 读取遥感 tif
  2. 分块
  3. 每块转成 RGB
  4. SAM 自动分割
  5. 把 mask 转成多边形
  6. 合并后导出 GeoJSON / Shapefile

原始脚本的问题

原始实现存在一些明显问题:

  • 重复导入和设备写死
  • tile 内部和 tile 之间亮度风格不稳定
  • SAMAutomaticMaskGenerator 基本走默认参数
  • 分块拼接逻辑偏粗糙
  • 输出流程比较散

做过的第一版优化

我先新建了一版优化脚本,不覆盖原文件:

  • SAMhuocheng_v2.py

核心改动是:

  • 统一全图拉伸统计,减少 tile 间风格漂移
  • 重写分块逻辑
  • 引入 keep_box 核心区思想,减少边界重复
  • mask 转 polygon 后先做 tile 内聚合,再做全局聚合
  • 补充 CSV / GeoJSON / Shapefile

这一步的重要结论是:

真正决定边界是否稳定的,不只是模型本身,而是“分块 + 保留核心区 + tile 内融合 + 全局融合”这一整套流程。


3. 第二阶段:切样方,而不是直接跑全图

在发现全图推理成本太高之后,先没有继续全图暴力试,而是切样方验证。

做过的切图脚本

先后写过这些脚本:

  • cut_huocheng_random_8km.py
  • cut_huocheng_random_single_8km.py

主要用途是:

  • 从大图里随机切 8km 样方
  • 先在样方上验证参数和分割效果
  • 避免一上来就在全图上跑几十小时

过程中遇到的坑

  1. Windows 与 WSL 路径不一致
    一开始脚本里用了 /mnt/e/... 风格路径,在 Windows 下直接跑就报错。
    后来改成“优先使用当前系统可访问路径,必要时再做路径映射”。

  2. LOCAL_CS 坐标系判断太严格
    遇到 LOCAL_CS["unnamed", UNIT["metre",1,...]] 时,脚本最初误判为“非投影坐标系不可用”。
    实际上它的单位就是米,所以对于 8km 切图是可用的。
    后来把 CRS 判断放宽成“只要是 meter-based 就允许继续”。

切样方的意义

这个阶段的结论很明确:

在遥感任务里,先切一个能代表问题的样方,再做模型与参数对比,是比直接跑全图更理性的工作方式。


4. 第三阶段:尝试把 SAM 脚本推到更细、更强

SAMhuocheng_v2.py 基础上,又做过一些“效果优先”的试验版,比如:

  • SAMhuocheng_v3_quality.py
  • SAMhuocheng_v3_balanced.py

这些版本想解决什么

目标主要有两类:

  • 分得更细
  • 利用更多上下文和增强视图提高目标发现率

做过的尝试

  • 多套 mask_generator 参数一起跑
  • 多视图输入,例如原图、CLAHE、锐化图
  • 更细的 points_per_side
  • 更低的区域门槛
  • 更激进的候选保留

实际遇到的问题

这些版本虽然“更细”,但副作用非常明显:

  • 单块时间暴涨
  • 候选 mask 爆炸
  • 后处理去重成本大幅上升
  • 容易出现过分细碎

一个比较典型的日志是:

[TILE 1/25] offset=(0,0) size=1024x1024 valid=1.000 gray_std=44.58 views=4 masks=5541 cand=3841 kept=1026 time=742.75s

这说明:

  • 不是代码卡死
  • 而是每块做了太多轮推理
  • 掩膜数量和后处理复杂度都过高

这个阶段最重要的认识是:

“更细”不等于“更好”。
在遥感地块任务里,过度提升局部敏感性,往往换来的是过分碎裂,而不是更稳定的边界。


5. 第四阶段:判断 GPU 利用率问题

过程中还怀疑过“是不是 GPU 没吃满”,于是做了针对性的分析。

结论

SAM 这类流程里,GPU 只是其中一部分:

  • mask_generator.generate(...) 主要吃 GPU
  • rasterio 读图、拉伸、轮廓提取、矢量化、shapely 融合,大量在 CPU 上

所以监控里看到 GPU 不持续满载,并不一定意味着脚本有问题,很可能是:

  • GPU 在等 CPU 后处理
  • 或者 tile 太小,单块前向时间不够长

后来也尝试过这些优化方向:

  • AMP / TF32
  • 更高 points_per_batch
  • 推理与后处理并行

但这些优化更多影响吞吐,不会从根本上改变“地块边界好不好”。


6. 第五阶段:思考“先转 RGB 再做分割”是否更合理

中间还讨论过一个路线:

  • 先把遥感 tif 转成 RGB 图
  • 在 RGB 图上做分割
  • 最后再把结果映射回坐标系

结论

这个思路本身没问题,但最稳的做法不是:

  • 转成普通 jpg/png

而是:

  • 先转成一份 RGB uint8 GeoTIFF
  • 保留 transform / CRS
  • 然后再做分割

这样既能减少每块重复拉伸和读取高位深数据的成本,又不会丢失地理信息。

不过这一条在这次没有推进到生产版,更多停留在思路验证。


7. 第六阶段:搭建 SAM 2.1 环境

新环境

新建了一个独立的 conda 环境:

  • sam21

环境里安装了:

  • python 3.11
  • torch 2.11.0+cu126
  • torchvision 0.26.0+cu126
  • SAM-2
  • rasterio
  • opencv-python
  • matplotlib
  • jupyter
  • eva-decord
  • pyshp
  • shapely

期间的坑

  1. git clone 从 GitHub 拉取 sam2 仓库不稳定
    最后改用本地已有源码目录:

    • /mnt/e/downloads/sam2-main
  2. 构建 CUDA 扩展时,需要显式设置:

CUDA_HOME=/usr/local/cuda-12.6
  1. SAM 2.1 在这台机子上最终是成功可用的,sam2._C 扩展也编译成功。

这一阶段的结果是:

SAM 2.1 环境已经完全可用,后面所有实验都建立在这个环境上。


8. 第七阶段:先用社会场景图验证 SAM 2.1 是否真的跑通

在正式上遥感之前,先用了一个社会场景图做最小验证:

  • lots-of-people-crossing-the-street-at-the-traffic-lights-photo.jpg

先做了基线版

使用 SAM2AutomaticMaskGenerator,大约得到了:

  • 74 个 mask

结果表明:

  • SAM 2.1 的环境、模型、推理链路都已经打通
  • 对自然图像 / 社会场景推理没有问题

再做了偏人物细分版

为了看 SAM 2.1 是否能通过参数调优挖出更多中小目标,又试了一组更偏细分的配置。

后来用了一个更实用的中间版参数,大约得到:

  • 391 个 mask
  • 94 个“更像单个人”的候选

这个测试说明:

  • SAM 2.1 在自然图像上的自动 mask 能力很强
  • 参数空间也比 SAM 1 更丰富

但这并不能直接说明它在遥感地块任务上就一定更好。


9. 第八阶段:把 SAM 2.1 迁到遥感样方

第一版遥感测试脚本

写了一个样方级测试脚本:

  • sam21_remote_sensing_test.py

它做的是:

  • 读取 random_8km.tif
  • 自动分块
  • SAM 2.1 自动 mask
  • 导出可视化图、GeoJSON、Shapefile、summary

这个脚本的意义是:

  • SAM 2.1 在遥感任务上第一次真正落地

后续又尝试过很多版本

为了追求不同目标,又写过很多实验版:

  • sam21_remote_sensing_full8km_light.py
  • sam21_remote_sensing_full8km_balanced_single.py
  • sam21_remote_sensing_full8km_balanced_single_v2.py
  • sam21_remote_sensing_full8km_seamfix_single.py
  • sam21_remote_sensing_v2style.py

这些版本之间的差异主要是:

  • tile size 是否 512
  • overlap 大小
  • 是否做 CLAHE
  • SAM2AutomaticMaskGenerator 的筛选阈值
  • 是否走更多 crop / 更细采样
  • 是否尝试修复 seam

出现的核心问题

虽然很多版本都能跑通,但真正的问题开始暴露:

  • 遥感地块分割会出现 tile 边界不连续
  • 复杂地块边界会碎裂
  • 一些版本会过分切碎农田

这是一个决定性的信号:

SAM 2.1 automatic mask 虽然能跑,但不一定天然适配遥感地块边界任务。


10. 第九阶段:发现真正的关键不是模型,而是拼接逻辑

在多轮试验后,逐渐确认一个核心事实:

  • 之前写的很多 SAM 2.1 版,虽然有分块和 keep-core
  • 但没有完整复现 SAMhuocheng_v2.py 的拼接收口逻辑

真正关键的两步

原始 SAMhuocheng_v2.py 里真正起作用的不是单纯 overlap,而是:

  1. tile 内 polygons 先 unary_union
  2. 全局 polygons 再 unary_union

也就是说,真正让边界更稳的不是“裁掉重叠区”这么简单,而是:

  • 先局部融合
  • 再全局融合

为什么前面那些版本效果不好

之前一些 SAM 2.1 版本只是:

  • mask 裁成 tile 核心区
  • 直接写出

这就导致:

  • 相邻 tile 各自产生的边界并没有真正被统一
  • 最后视觉上还是像“被分块切开了”

这一步是这次复盘里最重要的技术认识之一:

边界问题的关键不在分块本身,而在分块之后有没有做真正的几何融合。


11. 第十阶段:写出真正参考 v2 逻辑的 SAM 2.1 版本

基于这个判断,最终重写了一个更关键的版本:

  • sam21_remote_sensing_v2style_union.py

这个脚本的目标非常明确:

  • 尽量把 SAMhuocheng_v2.py 的逻辑原样迁到 SAM 2.1

它的核心流程是:

  1. overlap tiles
  2. keep box
  3. mask -> polygon
  4. tile 内 unary_union
  5. 全局 unary_union
  6. 输出 GeoJSON / SHP

这一步是目前 sam21file 目录里保留的唯一“样方级有效版本”。

当前保留结果目录是:

  • sam21_remote_sensing_v2style_union_out

12. 第十一阶段:上全图 huocheng_opt.tif

最后开始把逻辑迁到全图:

  • huocheng_opt.tif

对应新脚本:

  • sam21_huocheng_v2style_union.py

第一次启动为什么直接被系统杀掉

启动日志很短:

[INFO] Device: cuda:0
[INFO] CUDA name: NVIDIA RTX 5880 Ada Generation
Killed

这不是模型报错,而是进程被系统直接杀掉。

根因

脚本一开始整幅读了 3 波段全图做预览:

  • 图像大小:77164 x 87634
  • 单份 uint8 RGB 数据大约:18.9 GiB
  • 再加 preview / overlay / contours 这些副本,很快超过 50 GiB

所以进程在还没进入真正 tile 推理前,就被系统 OOM 终止了。

后续修正

修成了:

  • 不再整图 full read
  • 只生成低分辨率预览图
  • preview_max_dim = 4096

这一步说明:

对超大遥感图,光是“做预览图”这件事本身就必须按大图思路写,不能拿样方逻辑直接套。


13. 当前保留状态

在多轮试验和清理之后,当前目录里只保留:

  • huocheng_opt.tif
  • sam21_remote_sensing_v2style_union.py
  • sam21_remote_sensing_v2style_union_out
  • sam21_huocheng_v2style_union.py

这意味着当前有效状态很清晰:

  • 样方版保留一版
  • 全图版保留一版
  • 所有中间试验版已清掉

14. 这次工作的核心结论

结论 1:SAM 2.1 环境和推理链路已经完全打通

这部分没有问题,SAM 2.1 已经具备随时继续实验的基础条件。

结论 2:SAM 2.1 在自然图像上表现很好,但在遥感地块任务上不一定自然优于 SAM 1

这不是说它不能用,而是:

  • 模型升级并不自动等于地块边界更稳

结论 3:对这个任务来说,真正重要的是拼接与几何融合逻辑

也就是:

  • overlap
  • keep box
  • tile 内 union
  • 全局 union

这套逻辑比单纯调 SAM 参数更决定最终结果。

结论 4:大图处理不能直接照搬样方代码

尤其是:

  • 整图预览
  • 全局 overlay
  • 大量 polygon 汇总

这些在 19G 级遥感图上都必须按内存受控方式重写。


15. 如果后面继续推进,建议怎么做

建议 1:先把全图版跑通到稳定输出

目前最优先的不是继续调更多参数,而是:

  • sam21_huocheng_v2style_union.py 在全图上稳定跑完

建议 2:如果块边界仍然不好,就不要再继续小修小补

那时就要非常坦率地接受一个现实:

  • SAM 2.1 automatic mask 可能就不是这类遥感地块任务的最佳工具

建议 3:如果最终比不过 SAMhuocheng_v2.py

那就应该:

  • 回到 SAM 1 v2 这条更稳定的路线
  • 或者换成更像遥感地块分割的专门模型

而不是继续在 SAM 2.1 automatic mask 上无限调参。


16. 最后总结

这次工作最大的收获,不是“成功升级到了 SAM 2.1”,而是更清楚地认识到:

  • 模型不是唯一变量
  • 工作流、分块逻辑、几何融合、内存管理,往往比模型升级本身更重要

从结果上看,这次已经完成了几件关键的事:

  • 原有 SAM 流程被拆解和理解
  • SAM 2.1 环境完整搭建成功
  • 自然图像与遥感样方都完成了验证
  • 块边界问题的真正关键逻辑被重新识别出来
  • 全图脚本也有了明确可继续推进的版本

这已经足够作为后续继续推进或及时止损的依据。


17. 当前关键文件清单

样方验证保留版

  • \\wsl.localhost\gkubuntu2004\root\sam21file\sam21_remote_sensing_v2style_union.py
  • \\wsl.localhost\gkubuntu2004\root\sam21file\sam21_remote_sensing_v2style_union_out

全图版

  • \\wsl.localhost\gkubuntu2004\root\sam21file\sam21_huocheng_v2style_union.py
  • \\wsl.localhost\gkubuntu2004\root\sam21file\huocheng_opt.tif

复盘文档

  • \\wsl.localhost\gkubuntu2004\root\codexfile\sam_remote_sensing_recap_2026-04-20.md
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐