ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

2022年广州建筑轮廓GIS数据实战:从清洗到三维白模与空间分析

2022年广州建筑轮廓GIS数据实战:从清洗到三维白模与空间分析

简介:2022年广州建筑轮廓GIS数据面向城市规划、建筑设计、土地利用、环境评估及交通管理等方向的研究者与从业者,提供覆盖广州全域的建筑物矢量轮廓与属性信息,可用于空间结构分析、日照与风环境模拟、灾害应急定位等场景。资源包共6个文件,约80.59MB,以shp矢量主文件为核心,配套dbf属性表、prj空间参考、shx索引、cpg编码及xml元数据,构成一套可直接在ArcGIS、QGIS中加载分析的完整数据集。属性字段涵盖建筑高度、用途、年代等信息,便于开展城市形态量化与专题制图。目前已有610人学习下载,适合需要真实城市底图数据支撑课题研究、规划设计或GIS技能练习的用户参考使用。

1. 广州建筑轮廓GIS数据:一份2022年城市底图能拿来做什么

手上拿到一份「2022年广州建筑轮廓GIS数据」,第一反应往往不是兴奋,而是犯嘀咕:这玩意儿跟我平时用的OSM建筑面、高德POI、天地图矢量到底差在哪?说白了,它是一份以面要素(polygon)记录广州全市建筑物平面投影轮廓的矢量数据集,属性里通常带层数、高度、结构类型这类字段,坐标系大概率落在CGCS2000或WGS84系。它能干的事很具体:做城市三维白模、算容积率、跑日照分析、做人口空间化、给GIS二次开发当底图。适合谁?做城市研究的高校师生、做空间数据产品的开发、做规划辅助的从业者。但别急着全量加载——这份数据体量不小,字段质量参差,直接拖进ArcGIS或QGIS很容易卡死。下面按「先搞懂它是什么、再动手清洗、最后落到具体分析」的路径拆开讲,中间会穿插gis字段计算器、数据绑定、矢量转txt这些高频操作。

2. 先搞清楚2022年广州建筑轮廓数据的字段与坐标系

2.1 建筑轮廓面要素到底存了哪些属性

拿到shp或geojson,第一步不是画图,是看属性表。常见的字段结构大致如下,不同来源会有出入,但核心就这几列:

字段名类型含义常见取值/单位
height浮点建筑高度米,部分为空
floors整型层数层,部分为0或空
structure文本结构类型框架/砖混/钢构等
source文本数据来源影像提取/竣工图等
area浮点占地面积平方米,可字段计算得出

这里有个血泪经验:height和floors经常只有一个靠谱。影像提取的建筑轮廓,高度多半是估算的,层数反而来自竣工备案更准。所以做三维白模时,我一般优先用floors×3米反推高度,而不是直接信height字段。

2.2 坐标系认准CGCS2000和EPSG:4490

广州的建筑轮廓数据,官方口径基本是CGCS2000地理坐标系,EPSG代码4490。但实际流通的版本里,有人转成了WGS84(EPSG:4326),有人投影成了广州本地坐标(比如EPSG:4547,CGCS2000 3度带中央经线114E)。坐标系搞错,建筑会整体偏移几百米,这种翻车现场我见过不止一次。

判断方法很简单,在QGIS里加载后叠加一份已知正确的高德或天地图底图,看建筑是否贴合路网。如果偏移,用「矢量 → 数据管理工具 → 重新投影图层」转成EPSG:4490再试。注意:4490和4326在米级精度上差异极小,但和投影坐标系之间必须做正经的投影变换,不能靠改.prj文件糊弄。

# 用ogr2ogr查看并转换坐标系,先看源坐标系 ogrinfo -al -so guangzhou_buildings_2022.shp | grep -i "PROJCRS\|GEOGCRS" # 若源是投影坐标,转回CGCS2000地理坐标 ogr2ogr -f "ESRI Shapefile" -t_srs EPSG:4490 guangzhou_buildings_4490.shp guangzhou_buildings_2022.shp

这段命令先用ogrinfo读出源数据的坐标系描述,确认是地理坐标还是投影坐标;再用ogr2ogr的-t_srs参数指定目标坐标系4490做转换。参数-f决定输出格式,shp对字段名长度有限制,字段多的话建议输出GeoJSON或GPKG。

2.3 数据体量与分块加载策略

广州全市建筑轮廓面,量级在几十万到上百万要素。直接全量加载进QGIS,内存不够的机器会直接卡死。常见做法是按行政区切分,或者用空间索引加速。我一般先用GDAL切成区级文件,再逐区处理。

import geopandas as gpd # 读取全量数据,low_memory=True降低内存峰值 gdf = gpd.read_file("guangzhou_buildings_4490.shp", low_memory=True) # 按行政区字段分组导出,假设有district字段 for name, group in gdf.groupby("district"): group.to_file(f"gz_buildings_{name}.gpkg", driver="GPKG") print(name, len(group))

逻辑说明:geopandas读shp时low_memory参数能减少中间对象占用;groupby按区拆分后逐个写GPKG,GPKG比shp更适合大字段和中文。参数上,如果district字段缺失,可以先用空间连接把行政区边界属性挂上来,再分组。

3. 清洗建筑轮廓数据:字段计算器与拓扑修复实操

3.1 用字段计算器补全高度和层数

原始数据里height为空、floors为0的情况很常见。gis字段计算器在这里是主力工具。QGIS和ArcGIS都有字段计算器,逻辑一样:按表达式批量赋值。

在QGIS里打开属性表,进入字段计算器,新建一个字段calc_height,表达式写:

CASE WHEN "height" IS NOT NULL AND "height" > 0 THEN "height" WHEN "floors" IS NOT NULL AND "floors" > 0 THEN "floors" * 3.0 ELSE 6.0 END

这段表达式的逻辑是:优先用原始height;height缺失时用层数乘3米估算;两者都缺时给一个默认值6米(约两层)。参数上,3.0是层高经验值,住宅偏2.8到3.0,商业可能4米以上,按数据主要类型调整。默认值6.0是为了避免空值导致后续三维渲染报错,但要在属性里标记出来,别当成真实高度用。

ArcGIS字段计算器用Python解析器写法类似:

def calc_h(height, floors): if height and height > 0: return height if floors and floors > 0: return floors * 3.0 return 6.0

调用时表达式写calc_h(!height!, !floors!)。注意ArcGIS里字段名用感叹号包裹,QGIS用双引号,这是两个平台最容易搞混的地方。

3.2 拓扑修复:自相交、重叠、缝隙怎么处理

建筑轮廓面常见的拓扑问题有三类:自相交(一个面自己拧巴)、重叠(两个面压在一起)、缝隙(相邻建筑之间不该有的空隙)。自相交会让面积计算出错,重叠会让统计翻倍,缝隙影响后续空间连接。

修复顺序建议:先去自相交,再处理重叠,最后管缝隙。QGIS里用「矢量几何 → 修复几何」能解决大部分自相交。重叠用「矢量叠加 → 对称差」或者按面积保留大的那个。缝隙一般不管,除非做建筑密度分析。

from shapely.validation import make_valid # 修复无效几何 gdf["geometry"] = gdf["geometry"].apply(make_valid) # 检查修复后是否还有无效几何 invalid = gdf[~gdf.is_valid] print("剩余无效几何数:", len(invalid))

make_valid是shapely的几何修复函数,能处理自相交和部分重叠。参数上无需额外配置,但修复后要重新检查is_valid,因为有些极端情况make_valid也救不回来,只能手动删。修复完记得重算area字段,别用旧的。

3.3 面积字段重算与异常值剔除

建筑占地面积是后续所有分析的基础。原始area字段如果是投影坐标下算的,转成地理坐标后会失真,必须重算。在EPSG:4490地理坐标下直接算面积得到的是平方度,没有意义,得先投影到米制坐标系再算。

# 投影到广州本地米制坐标系再算面积 gdf_m = gdf.to_crs(epsg=4547) gdf["area_m2"] = gdf_m.geometry.area # 剔除异常值:小于10平米或大于10万平米的建筑 gdf = gdf[(gdf["area_m2"] >= 10) & (gdf["area_m2"] <= 100000)]

逻辑说明:to_crs(4547)把地理坐标转成广州本地投影坐标,单位是米,此时geometry.area才是平方米。异常值阈值10和100000是经验值,小于10平米多半是提取噪声,大于10万平米可能是体育场馆或数据错误,按实际场景调整。剔除后要素数会减少,属正常。

4. 建筑轮廓数据的典型分析场景与避坑

4.1 容积率与建筑密度计算

有了清洗后的轮廓和高度,就能算容积率和建筑密度。容积率=总建筑面积/用地面积,建筑密度=建筑基底面积/用地面积。这里需要一份用地地块数据做空间连接。

# 建筑与地块空间连接,按地块汇总 joined = gpd.sjoin(gdf, parcels, how="inner", predicate="within") summary = joined.groupby("parcel_id").agg( total_footprint=("area_m2", "sum"), building_count=("area_m2", "count") ).reset_index() # 合并回地块 parcels = parcels.merge(summary, on="parcel_id", how="left") parcels["building_density"] = parcels["total_footprint"] / parcels["parcel_area"]

sjoin的predicate="within"表示建筑完全落在地块内才计入,跨界的建筑会被排除。参数上,如果地块边界和建筑边界不完全吻合,可以改用intersects,但要做面积比例分摊,否则密度会偏高。groupby汇总后merge回地块,缺失值填0。

4.2 矢量转txt给外部系统用

有些分析平台或自研系统不认shp,只吃txt坐标串。gis矢量如何转txt是高频需求。常见格式是每行一个建筑,字段用逗号或制表符分隔,几何用WKT或坐标对。

# 导出为txt,几何用WKT表示 with open("buildings.txt", "w", encoding="utf-8") as f: for _, row in gdf.iterrows(): wkt = row.geometry.wkt f.write(f"{row['building_id']}\t{row['area_m2']}\t{row['calc_height']}\t{wkt}\n")

逻辑说明:逐行写txt,字段用制表符分隔,最后一列是WKT几何。参数上,WKT比坐标对更通用,但体积大;如果目标系统只要中心点坐标,改成row.geometry.centroid.x和.y即可。注意编码用utf-8,否则中文属性会乱码。

4.3 避坑:建筑轮廓数据处理的5个常见翻车点

现象一:加载后建筑整体偏移几百米。原因:坐标系搞错,把投影坐标当地理坐标用。解决:用ogrinfo确认源坐标系,用ogr2ogr正经转换,别改.prj糊弄。

现象二:面积字段数值离谱,一栋楼几万平方公里。原因:在地理坐标下直接算面积,得到平方度。解决:先to_crs投影到米制坐标系再算area。

现象三:字段计算器执行后全是空值。原因:表达式里字段名引用方式不对,QGIS用双引号,ArcGIS用感叹号,混用就报错。解决:确认平台,按对应语法写,先在小样本上试。

现象四:空间连接后建筑数量翻倍。原因:建筑面跨多个地块,sjoin的intersects会重复计数。解决:改用within,或对跨界建筑做面积分摊。

现象五:导出txt后中文乱码。原因:默认编码不是utf-8。解决:open时显式指定encoding="utf-8",目标系统也要支持utf-8。

5. 把2022年广州建筑轮廓数据用出进阶价值

5.1 结合人口数据做空间化

建筑轮廓最大的进阶价值是当人口空间化的载体。思路是:用建筑总面积或总层数作为权重,把街道级人口分摊到每栋建筑上。这样得到的人口分布比行政区级别精细得多,适合做商业选址、应急疏散。

# 按建筑加权分摊人口 gdf["weight"] = gdf["area_m2"] * gdf["calc_height"] total_weight = gdf.groupby("street")["weight"].transform("sum") gdf["pop_est"] = gdf["street_pop"] * gdf["weight"] / total_weight

逻辑说明:weight用占地面积乘高度,近似建筑体量;transform("sum")按街道汇总权重,保持行数不变;pop_est就是每栋建筑的估算人口。参数上,street_pop需要提前挂到每栋建筑上(通过空间连接),weight的算法可以换成纯面积或纯层数,看数据质量。

5.2 三维白模快速生成

建筑轮廓加高度字段,直接能在QGIS的2.5D渲染或Cesium里出白模。QGIS里用「图层属性 → 3D视图 → 拉伸」,高度字段选calc_height。导出成GeoJSON后丢给Cesium或Mapbox,加个拉伸表达式就是城市白模。

// Mapbox GL JS 建筑拉伸示例 map.addLayer({ id: "buildings-3d", type: "fill-extrusion", source: "gz-buildings", paint: { "fill-extrusion-height": ["get", "calc_height"], "fill-extrusion-color": "#aaa", "fill-extrusion-opacity": 0.8 } });

逻辑说明:fill-extrusion-height绑定calc_height字段,Mapbox按米拉伸;color和opacity控制外观。参数上,calc_height必须是数值型,字符串会渲染失败。数据量大时建议切分或做矢量瓦片,否则浏览器扛不住。

5.3 一个我常用来验证数据质量的小技巧

拿到任何一份建筑轮廓数据,我都会先做一件事:随机抽100栋建筑,叠加到最新卫星影像上,肉眼比对轮廓贴合度。这一步花不了十分钟,但能暴露坐标系偏移、提取年代过旧、边界粗糙这些问题。比任何自动化检查都直接。

具体操作:QGIS里加载影像底图(XYZ Tiles),把建筑轮廓设成半透明红色填充、无边框,缩放到18级以上逐栋看。如果整体偏移,是坐标系问题;如果个别偏移,是提取误差;如果轮廓明显是旧建筑,说明数据年份存疑。2022年的数据,理论上应该和2022年前后的影像吻合,对不上就要警惕。

我自己的习惯是,每份新数据入库前都跑一遍这个抽检,过了才进正式流程。这个习惯帮我省过好几次返工。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进