说一句位置,自动提取建筑矢量
提取建筑物矢量Building Footprint是 GIS 里最高频的刚需之一人口估算、应急管理、违建排查、城市更新都要以“每一栋楼的轮廓”为底。传统做法要么人工描图——慢要么专业遥感软件加专家解译——门槛高。AI 时代这件事能做到什么程度这篇文章记录一条实测路线卫星影像 深度学习分割 自然语言交互让用户说一句“济南泉城路附近”程序自动下载影像、提取建筑、输出标注图和矢量文件。每个步骤附核心代码节选全部摘自实测项目。目录一、建筑矢量提取这件事1.1 是什么为什么重要1.2 传统做法的痛点1.3 AI 怎么做二、技术路线怎么选2.1 现成工具盘点2.2 为什么自建纯 Python 管线2.3 不是推翻是行为对齐三、核心机制与三个真坑3.1 对齐的四个核心机制3.2 坑 1rasterio 的窗口参数3.3 坑 2GeoJSON 坐标没有 CRS 声明3.4 坑 3面积过滤把两种单位混在一起四、实测一官方模型跑通4.1 用现成模型验证管线4.2 三条路线对照4.3 精度上限在模型五、实测二卫星影像自动获取与 AI 交互5.1 瓦片源连通性逐个实测5.2 全链路设计5.3 实测数据5.4 AI 交互说位置就出结果5.5 位置解析怎么实现5.6 它已经是一个任务型 GIS Agent5.7 与 LLM 结合的三个点展望5.8 小结一、建筑矢量提取这件事1.1 是什么为什么重要建筑矢量就是每一栋建筑物的轮廓多边形Footprint。它是很多业务的地基数据应急疏散要数楼、违建排查要比对楼、城市更新要算面积。数据质量直接决定业务结论的可靠性。1.2 传统做法的痛点两条老路人工数字化在影像上逐栋描边精度看人、速度以天计遥感解译软件需要专业训练和昂贵授权普通团队用不起。痛点集中在三点慢、贵、门槛高。1.3 AI 怎么做AI 路线把“找楼”变成像素分类卫星影像输入分割模型逐像元判断是不是建筑再把连续像元转成多边形。快、可复制、能批量化。剩下的问题是谁来加载模型、谁来切瓦片、谁来出矢量——这正是管线要解决的。二、技术路线怎么选2.1 现成工具盘点QGIS 有 Deepness 插件波兰 PUTvision 团队开发加载 ONNX 模型做遥感推理分割、检测都能跑是很好的现成路线。但插件与 QGIS 图形界面强耦合服务器、定时任务、Web 服务这些“无头”场景用不上。2.2 为什么自建纯 Python 管线要的是“给范围 → 出矢量”能进脚本、定时任务、甚至别人写的 Web 服务。自建管线可以把“加载模型 → 切瓦片 → 推理 → 拼接 → 矢量化”变成可编程的库随时被其他系统调用。2.3 不是推翻是行为对齐自建不是凭感觉重写而是逐项对齐 Deepness 源码的机制模型 metadata 自动参数、瓦片重叠拼接、中值滤波后处理、像素空间矢量化再变换到影像坐标系。这样 Deepness 生态的模型可以无缝复用。三、核心机制与三个真坑3.1 对齐的四个核心机制第一模型 metadata 自动读参数瓦片尺寸、瓦片重叠、概率阈值都从 ONNX 的 metadata 读取不写死在代码里。核心代码meta session.get_modelmeta().custom_metadata_map self.class_names _meta_json(class_names) or _meta_json(names) self.meta_tile_size _meta_json(tiles_size) or _meta_json(tile_size) self.meta_overlap _meta_json(tiles_overlap) or _meta_json(tile_overlap) mean _meta_json(standardization_mean); std _meta_json(standardization_std) self.meta_threshold _meta_json(seg_thresh)# 瓦片尺寸/重叠/阈值/归一化全部来自模型 metadata代码里不写死self.tile_size int(self.meta_tile_size or 512)第二瓦片重叠拼接推理时每块只取核心区去掉重叠边避免切缝伪影。核心代码stride max(tile - overlap, 1) # 步长 瓦片 - 重叠 half_overlap max((tile - stride) // 2, 0) for y0 in y_starts: for x0 in x_starts: sub rgb[y0:y0tile, x0:x0tile] p self.segmentor.predict(sub) # 每瓦片独立推理 # 只把“核心区”写回重叠边不重复累加避免切缝伪影 core_x0 x0 half_overlap if x0 0 else 0 core_y0 y0 half_overlap if y0 0 else 0 core_x1 x0 tile - half_overlap if x0tile w else w core_y1 y0 tile - half_overlap if y0tile h else h prob[core_y0:core_y1, core_x0:core_x1] p[...]第三中值滤波后处理平滑分割掩膜等价插件的 dilate_erode_size第四矢量化在像素空间做面积过滤和轮廓简化最后统一变换到影像坐标系见 3.4 代码。3.2 坑 1rasterio 的窗口参数src.window(0, 0, 宽, 高) 会把数字参数当成地理范围解析导致窗口错乱。必须改用 rasterio.windows.Window 显式构造像素窗口。修复代码 # 错误window src.window(0, 0, w, h) —— 数字会被当成地理 bounds window src.window(*bounds) full rasterio.windows.Window(0, 0, src.width, src.height) # 显式像素窗口 window window.intersection(full)3.3 坑 2GeoJSON 坐标没有 CRS 声明输出的坐标是米制投影却没有声明坐标系GIS 打开必然错位。写文件前强制重投影到 WGS84——这是 GeoJSON 规范RFC 7946的硬要求。修复代码if out_path.suffix.lower() .geojson: # RFC 7946 要求 WGS84米制投影必须重投影否则 GIS 打开错位 gdf gdf.to_crs(EPSG:4326) gdf.to_file(out_path, driverGeoJSON)3.4 坑 3面积过滤把两种单位混在一起曾把地理面积和像素阈值混比导致零输出。正确做法先在像素空间做最小面积过滤和简化最后再统一做坐标变换。核心代码# 像素空间过滤/简化单位像素²最后才变换到影像地理坐标for geom, value in features.shapes(binary_mask, transformAffine.identity()): if value ! 1: continue poly shape(geom) if poly.area min_area: continue # min_area 是像素² poly poly.simplify(simplify_tol, preserve_topologyTrue) polygons_px.append(poly) a,b,c,d,e,f (transform.a, transform.b, transform.c, transform.d, transform.e, transform.f) geoms [affinity.affine_transform(g, [a,b,d,e,c,f]) for g in polygons_px]四、实测一官方模型跑通4.1 用现成模型验证管线用 Deepness 官方 examples 自带的 deeplabv3_landcover 分割模型和波兰示例影像验证metadata 读到瓦片 512、重叠 40、阈值 0.3全流程跑通提取出 242 个建筑要素。这条验证同时确认了行为对齐成立。单瓦片推理的核心代码def predict(self, tile_hwc): x self._preprocess(tile_hwc) # [H,W,3] uint8 → [1,C,H,W] float32 raw self._session.run([self.output_name], {self.input_name: x})[0] out np.squeeze(raw) if out.ndim 3 and out.shape[0] 2: out self._softmax(out)[1] # 通道 1 建筑物 return out.astype(np.float32)4.2 三条路线对照维度人工描图QGIS 插件Deepness本工具纯 PythonAI 交互使用门槛专业软件经验会 QGIS 即可一句位置描述速度天级逐栋描边分钟级手动操作分钟级全自动影像获取自备正射影像手动加载图层按范围自动下载卫星瓦片批量化基本没有手动逐次脚本/定时/交互式多轮输出手动导出QGIS 图层GeoJSON/GPKG/SHP 标注图表1 建筑矢量提取的三条路线对照图1 分割模型 波兰示例影像提取结果4.3 精度上限在模型地物分割模型决定精度当前是欧洲航空影像训练的 landcover 模型在中国城区卫星影像上是“能用但不够专业”。换用国内城市数据集微调的分割模型即可明显提升——这也说明管线与模型解耦的价值。五、实测二卫星影像自动获取与 AI 交互5.1 瓦片源连通性逐个实测逐个测了高德、Esri、腾讯、OSM 的卫星瓦片接口高德可用国内直连、无需 keyEsri 超时WinError 10060、腾讯返回 0 字节、OSM 不可达。结论是默认源用高德卫星图层。5.2 全链路设计给一个 WGS84 范围 → 自动选 zoom目标约 0.6 米/像素受瓦片数量上限约束→ 8 线程并发下载 → 拼接 → 精确裁剪到范围 → 写 GeoTIFFEPSG:3857。核心代码zoom pick_zoom(bounds, max_tiles400) # 按 AOI 尺寸自动选级别 x0, y0 wgs84_to_tile(bounds.left, bounds.top, zoom) x1, y1 wgs84_to_tile(bounds.right, bounds.bottom, zoom) with ThreadPoolExecutor(max_workers8) as pool: # 8 线程并发拉瓦片 futures {pool.submit(_download_tile, _tile_url(template, zoom, x, y, (xy)%41)): (x, y) for y in range(y0, y11) for x in range(x0, x11)} mosaic[...] tiles[(x, y)] # 逐瓦片贴回 256×256 网格 # 精确裁剪到 AOI经纬度 → 3857 像素窗口 transform from_origin(minx_m, maxy_m, res, res) dst.write(np.transpose(mosaic, (2, 0, 1))) # 写 GeoTIFF(EPSG:3857)5.3 实测数据济南市区约 2×2 公里范围自动下载 285 张瓦片模型提取出 1605 个建筑要素输出 WGS84 合规的 GeoJSON。影像与矢量可留档复核。5.4 AI 交互说位置就出结果加一层位置解析后输入 --location “济南泉城路附近” 即可自动完成解析范围 → 下载卫星影像 → 提取建筑 → 输出标注图和矢量文件全程一条命令。--chat 交互模式则循环询问“位置”每轮自动出结果单轮失败不中断输入 q 退出。交互主循环核心代码if args.chat: print([chat] 输入位置描述开始q 退出。) while True: loc input(位置 ).strip() if not loc or loc.lower() in (q, quit, exit): break try: args.location loc run_once(args) # 每轮 解析位置→下载→提取→标注图 except Exception as e: print(f[chat] 本轮失败{e}) # 单轮失败不中断实测泉城路 1 公里半径自动下载 289 张瓦片、提取 1624 个建筑要素输入“大明湖 1公里”自动解析出 348 个要素。图2 一句“济南泉城广场附近5.5 位置解析怎么实现内置中国主要城市和济南全部区县/地标坐标库离线可用未命中且配置 AMAP_KEY 环境变量时自动走高德地理编码 API支持任意地点和 POI。两种都失败时给出明确报错与可行路径。核心代码cleaned text.replace(附近, ).replace(周边, ) # 先剥掉口语后缀 coord _match_place(cleaned) or _match_place(text) or _amap_geocode(text) r _parse_radius(text, radius_km) # 支持“2公里/1.5km”显式半径 lon, lat coord dlon r / 111.32 / max(math.cos(math.radians(lat)), 1e-6) dlat r / 111.32 # 半径 → WGS84 方形 AOIPOLYGON 四角坐标 return fPOLYGON(({lon-dlon:.6f} {lat-dlat:.6f}, ...))5.6 它已经是一个任务型 GIS Agent把流程拆开看这条管线已经具备任务型 Agent 的四要素感知读自然语言位置、读影像、规划自动选 zoom、定下载范围、行动并发下载、逐瓦片推理、矢量化、产出标注图 矢量文件。用户只需要描述目标不用管中间任何一步。5.7 与 LLM 结合的三个点展望当前位置解析靠内置地名库加地理编码 API只能解标准地名。接入大模型后有三处明显升级第一地名理解——“老火车站”“市政府对面”这种口语LLM 能消歧成坐标第二参数自适应——LLM 根据区域是城区还是郊区自动建议 zoom 和阈值第三结果解读——提取完让 LLM 总结建筑密度、面积分布。再进一步把这个工具包成 MCP 工具任意大模型DeepSeek、豆包就能直接说“给我提取 XX 的建筑”。5.8 小结建筑矢量提取这件事AI 化已经走通闭环——说一句位置自动下载影像、深度学习提取、输出标注图和矢量。管线是解耦的模型可换、影像源可换、交互可升级。真正决定结果上限的是模型和数据不是那层“自动化外壳”。再往后有三个方向MCP 化把工具包成接口让任意大模型直接调用、RAG 地名知识库覆盖小众地名与口语表达、城市级批量整市切片、分布式跑。