对象级空间智能图斑生产平台实践记录(2026-04-22)

一、背景

这次工作的核心目标,不是单纯把遥感影像“分出来”,而是建立一条更完整的对象级图斑生产链路:

  1. 先用分割模型从遥感影像中提取图斑几何。
  2. 再用大模型或多模态模型对每个要素赋予属性。
  3. 最终把几何和属性一起写进成果文件的属性表。

从方法论上看,这已经不只是“分割脚本优化”,而是在往“面向遥感图斑智能生产的对象级空间智能方法”推进。

本次实践涉及的主目录是:

  • /root/sam21file
  • /root/codexfile

二、基础分割脚本与原始启动方式

最初的基础分割脚本是:

  • /root/sam21file/sam21_remote_sensing_v2style_union.py

结果文件主要是:

  • /root/sam21file/sam21_remote_sensing_v2style_union_out/sam21_remote_sensing_v2style_union.shp

原始启动命令是:

source /root/miniconda3/etc/profile.d/conda.sh
conda activate sam21
cd /root/sam21file
nohup python sam21_remote_sensing_v2style_union.py > sam21_remote_sensing_v2style_union.log 2>&1 &

这个脚本的核心思路是:

  1. 按重叠瓦片切分影像。
  2. 在每个 tile 内执行 SAM 自动掩膜生成。
  3. 掩膜转多边形。
  4. 先做 tile 内 union。
  5. 再做全局 union。

这一版的优点是拼缝控制较好,但问题也很明显:它更偏向“大块面”和“连续边界”的场景,对居民区里的小屋顶、小院落、小建筑,并不敏感。


三、遇到的第一个关键问题:居民区大面积漏分

在下面这个截图位置,出现了一大片居民区没有被很好分割:

  • /root/sam21file/sam21_remote_sensing_v2style_union_out/Snipaste_2026-04-21_10-27-04.png

我对原脚本和输出做了排查,结论不是“tile 被跳过了”,而是“居民区这种密集小目标场景,本身就不适合当前这组参数和后处理策略”。

1. 不是 tile 被跳过

查看:

  • /root/sam21file/sam21_remote_sensing_v2style_union_out/sam21_remote_sensing_v2style_union_tile_summary.csv

结果显示:

  • 121 / 121 个 tile 全部是 OK
  • 没有出现 skip_low_valid_ratio
  • 也没有出现 skip_low_texture

所以问题不在于“居民区对应瓦片没跑”,而在于“跑了,但结果不理想”。

2. 主要原因判断

结合脚本参数和 tile 统计,问题集中在以下几类:

原因 A:对小目标的采样密度不够

原脚本参数:

"points_per_side": 32
"crop_n_layers": 1

对于 512 x 512 的 tile,这意味着采样点间距偏大。农田地块边界足够长,容易命中;居民区小屋顶、小院落、窄巷子,则容易漏掉。

原因 B:阈值偏保守

原脚本在 sam_params 和后处理里用了较高筛选阈值:

"pred_iou_thresh": 0.84
"stability_score_thresh": 0.92

并且在主循环里再次用这两个值过滤 ann

这会导致很多“小而不稳定”的居民区 mask 被刷掉。

原因 C:形态学和 union 会吞掉细碎结构

原脚本还有两层对小目标不友好的处理:

  1. mask_morph_kernel = 3
  2. merge_tile_polygons = True

这样会出现两种后果:

  • 小建筑、小巷道、小空隙被形态学操作抹平
  • 多个相邻小目标在 tile 内被 union 合成更少的面

所以居民区不是“完全没识别”,而是“识别出来的一部分又被后处理吞掉了”。

3. 一个裁块测试的结果

我对居民区裁了一个 512 x 512 小块测试原版脚本,统计结果是:

  • 85 masks -> 19 polygons

说明原版在居民区里并不是没有 mask,而是最终留下来的 polygon 数量偏少。


四、边界优化与直线化的两次尝试

在处理中间阶段,我还做过两次边界方向的迭代。

1. 边界平滑版

尝试目标:

  • 让输出边界更平滑
  • 去掉锯齿和小毛刺

但这不符合“更像人工画的直线边界”的目标,而且在部分区域会过度平滑,因此后来放弃。

2. 直线化版

后来改成了“直线化/人工描边风格”的思路,相关脚本保留在:

  • /root/sam21file/sam21_remote_sensing_v2style_union_straightedge_20260421_v1/sam21_remote_sensing_v2style_union_straightedge_20260421_v1.py

这版主要用于:

  • 让地块边界更板正
  • 让建筑边界更接近人工描绘

但它解决的是“边界形式”问题,不直接解决“小建筑漏分”的问题。所以后续重点还是转回了“分割参数”和“交互修补流程”。


五、Web UI 平台化改造

在确认单纯改脚本不够后,我开始搭建一个完整的前端界面,把生产作业、预览、局部修补、结果替换合并整合起来。

项目目录:

  • /root/sam21file/sam21_seg_webui_20260421_v1

1. 后端代码

app.py

作用:

  • 提供本地 Web 服务
  • 提供任务启动、状态查询、预览生成、修补提交、文件访问等接口

路径:

  • /root/sam21file/sam21_seg_webui_20260421_v1/app.py
worker_cli.py

作用:

  • 后台执行生产作业
  • 执行局部修补
  • 管理 job 状态写回

路径:

  • /root/sam21file/sam21_seg_webui_20260421_v1/worker_cli.py
pipeline_utils.py

作用:

  • 生成预览图
  • 处理裁切逻辑
  • 处理 polygon 区域裁切
  • 执行合并替换
  • 读取和写出矢量成果

路径:

  • /root/sam21file/sam21_seg_webui_20260421_v1/pipeline_utils.py

2. 前端代码

页面结构
  • /root/sam21file/sam21_seg_webui_20260421_v1/static/index.html
页面逻辑
  • /root/sam21file/sam21_seg_webui_20260421_v1/static/app.js
页面样式
  • /root/sam21file/sam21_seg_webui_20260421_v1/static/styles.css

3. 启动脚本

  • /root/sam21file/sam21_seg_webui_20260421_v1/run_server.sh
  • /root/sam21file/sam21_seg_webui_20260421_v1/start_webui_bg.sh
  • /root/sam21file/sam21_seg_webui_20260421_v1/stop_webui.sh

六、Web UI 的目标闭环

这个平台不是为了“看个图”,而是为了把整条图斑生产链路做成可交互、可修补、可落地的工程流程。

最终闭环是:

  1. 选择影像、脚本、输出目录,提交生产作业。
  2. 后台执行图斑生产。
  3. 发现某些区域没分好,可以再导入修补影像。
  4. 在预览图上勾绘多边形修补区。
  5. 对这块区域重新执行分割。
  6. 用新结果替换旧结果中对应区域。
  7. 输出新的成果文件,不覆盖原始结果。

七、Web UI 迭代中遇到的关键问题与修复

1. 标准 Web 框架缺失

sam21 环境里检查后发现:

  • 没有 FastAPI
  • 没有 Flask
  • 没有 uvicorn

所以最终采用了 Python 标准库实现轻量本地服务,而不是额外引入新依赖。

2. 本地端口绑定与沙箱问题

在当前环境下,localhost 服务的启动和检测需要额外处理。前期我多次通过前台/后台两种方式验证,最终确认:

  • 前台直接启动是稳定的
  • 后台启动有时会因环境导致进程退出

因此调试阶段更可靠的方式是前台直接运行:

cd /root/sam21file/sam21_seg_webui_20260421_v1
/root/miniconda3/envs/sam21/bin/python app.py

3. 动态导入原脚本时 dataclass 出错

最开始 worker_cli.py 通过动态导入原脚本调用 main(),结果触发了 dataclasssys.modules 上下文中的问题:

  • AttributeError: 'NoneType' object has no attribute '__dict__'

最终通过在动态导入时提前把模块注册进 sys.modules 修复。

4. 修补流程最初依赖“已选基准任务”

前端最初要求:

  • 先在“基准任务”里选一个完成的 segmentation 任务

这会导致如果用户已经有自己的 shp,但没有先选任务,点击“开始区域重跑并合并”时看起来像“没反应”。

后来改成:

  • 只要提供 基准成果 SHP
  • 校修影像
  • 多边形修补区

就可以直接提交修补作业,不再强依赖任务列表。

5. 基准矢量最初没有上传入口

起初只有一个文本框:

  • 第一次分割矢量 SHP 路径

但没有上传按钮,不符合实际使用习惯。

后来补上了:

  • 矢量上传按钮
  • 支持上传 shp/shx/dbf/prj
  • 也支持直接上传 zip

6. 输出目录不能覆盖原结果

这是很关键的一条工程要求。

最终处理方式是:

  • 修补合并结果默认单独写到:
    /root/sam21file/sam21_seg_webui_20260421_v1/workspace/merged_outputs
  • 不覆盖第一次分割的原始 shp

7. 浏览器缓存导致前端看起来“没变化”

前端多次迭代后,浏览器很容易缓存旧版 JS/CSS。

所以我最终在静态资源 URL 上加了版本号,例如:

  • styles.css?v=20260421d
  • app.js?v=20260421d

这样每次关键迭代都能强制页面加载新版本。


八、把修补交互升级成真正可用的生产工具

Web UI 不是停留在“矩形框选”的层面,而是逐步升级为更贴近生产的交互:

已实现能力

  • 可缩放预览
  • 可平移视图
  • 多边形勾绘修补区
  • 基准成果矢量叠加到影像上
  • 修补影像上传
  • 基准成果矢量上传
  • 修补结果与原成果按区域替换合并

当前平台名称

前端最终改成了更偏正式项目名称:

  • 对象级空间智能图斑生产平台

这个名字比早期的 GeoSage 更适合对外表达,因为它直接对应业务对象和方法论。


九、小建筑补漏:新建小目标优先脚本

为了解决“居民区里小建筑漏分”的问题,我没有去改动原脚本,而是单独新建了一版参数增强脚本:

  • /root/sam21file/sam21_remote_sensing_v2style_union_smallbuildings_20260421_v1.py

这版本质上是一个参数封装器,它会加载原始脚本,然后覆盖关键参数。

主要参数调整方向

采样更密
points_per_side: 32 -> 64
crop_n_layers: 1 -> 2
crop_n_points_downscale_factor: 2 -> 1

作用:

  • 提升对小屋顶、小建筑、小目标的命中率
阈值放宽
pred_iou_thresh: 0.84 -> 0.72
stability_score_thresh: 0.92 -> 0.88

作用:

  • 让边界不那么稳定的小目标也有机会保留下来
最小面积下调
min_area_px: 120 -> 24
min_mask_region_area: 50 -> 16

作用:

  • 避免小建筑、小院落在后处理里被直接过滤掉
形态学弱化
mask_morph_kernel: 3 -> 1

作用:

  • 减少细小目标被平滑或吞并
tile 内 union 关闭
merge_tile_polygons: True -> False

作用:

  • 尽量保留居民区内部碎小要素,而不是在单个 tile 里先合成少量大面
局部对比增强开启
use_clahe: False -> True

作用:

  • 提升建筑区、道路、树影混杂区域的小目标对比度

启动命令

source /root/miniconda3/etc/profile.d/conda.sh
conda activate sam21
cd /root/sam21file
nohup python sam21_remote_sensing_v2style_union_smallbuildings_20260421_v1.py > sam21_remote_sensing_v2style_union_smallbuildings_20260421_v1.log 2>&1 &

使用建议

不建议直接拿这版去整图跑全流程。

更合理的用法是:

  • 保持原版脚本跑整图
  • 对于居民区漏分的小块,在 Web UI 里用这版脚本做局部校修

这样兼顾:

  • 整图稳定性
  • 局部小建筑补漏能力

十、这一轮实践的核心结论

1. 分割不是终点,图斑生产才是终点

单纯的“分割效果好不好”只是第一步。

真正有价值的是:

  • 几何生产
  • 属性赋值
  • 属性表写入
  • 人机协同修补
  • 成果交付

也就是说,系统目标应该是图斑生产闭环,而不是单点模型优化。

2. 农田和居民区不是同一个参数空间

一套参数可以在农田地块上表现好,但在居民区就会明显漏分。

因此更合理的策略不是“全图统一参数”,而是:

  • 大范围先用稳定参数跑一遍
  • 对困难区域局部校修
  • 必要时针对小目标用专门参数版脚本

3. 企业级项目不能只停留在脚本阶段

当需求从“跑一遍模型”升级到:

  • 可视化校修
  • 局部替换
  • 成果单独输出
  • 后续属性赋值

就必须从“脚本”进入“平台化工程”。

这次搭出来的 Web UI,其价值就在于:

  • 它把单点脚本串成了一条可交付流程

十一、当前保留的关键代码与目录

分割脚本

  • /root/sam21file/sam21_remote_sensing_v2style_union.py
  • /root/sam21file/sam21_remote_sensing_v2style_union_smallbuildings_20260421_v1.py

Web UI 平台

  • /root/sam21file/sam21_seg_webui_20260421_v1/app.py
  • /root/sam21file/sam21_seg_webui_20260421_v1/worker_cli.py
  • /root/sam21file/sam21_seg_webui_20260421_v1/pipeline_utils.py
  • /root/sam21file/sam21_seg_webui_20260421_v1/static/index.html
  • /root/sam21file/sam21_seg_webui_20260421_v1/static/app.js
  • /root/sam21file/sam21_seg_webui_20260421_v1/static/styles.css

启动与停止

  • /root/sam21file/sam21_seg_webui_20260421_v1/run_server.sh
  • /root/sam21file/sam21_seg_webui_20260421_v1/start_webui_bg.sh
  • /root/sam21file/sam21_seg_webui_20260421_v1/stop_webui.sh

十二、后续可继续扩展的方向

如果继续往正式项目推进,下一步我会优先做下面三件事:

1. 把属性赋值模块正式接进流程

也就是把 Gemma 或后续属性生成模块做成第二阶段:

  • 输入:图斑几何
  • 输出:图斑属性
  • 最终写入属性表

2. 加生产驾驶舱

增加平台首页的管理视图:

  • 今日作业数
  • 完成率
  • 待校修区域数
  • 最新成果时间

3. 做分区策略

让平台支持:

  • 农田模式
  • 居民区模式
  • 小建筑补漏模式

本质上变成“按对象类型切换参数策略”,而不是所有区域共用一套参数。


十三、结语

这一轮工作,从最初的一个分割脚本,逐步演化为:

  • 问题诊断
  • 参数分析
  • 边界优化尝试
  • 小建筑专用参数版
  • 前端平台化
  • 局部校修替换
  • 面向属性表写入的闭环思路

这说明一个事实:

遥感智能生产真正难的,往往不是“某个模型能不能跑”,而是如何把几何、属性、交互和成果组织成一条稳定的生产链。

而“对象级空间智能图斑生产平台”,正是在这个方向上的一个阶段性落点。

Logo

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

更多推荐