1. 项目概述与核心价值
搞城市气候模拟的人,对UMEP(Urban Multi-scale Environmental Predictor)这个名字应该都不陌生。它是QGIS环境下一套开源的城市环境模拟工具,偏研究向,用来评估城市热岛、通风廊道、能量平衡、水文过程这些典型的城市环境问题。而这一期要聊的Pre-Processor,也就是预处理器,是整条模拟链路里最枯燥、最容易被忽略、却又最重要的一环。
简单说,UMEP的预处理器是把“粗糙的原始城市数据”加工成“可直接喂给模型的结构化输入”的中间层。没有它,后面那些高大上的模型——比如SUEWS(城市能量和水文模型)、SPACES(街道尺度植物冠层模型)、SCUHI(城市热岛强度计算)——全都跑不起来。因为模型不认识你手里的DSM点云、建筑矢量面、土地利用图,它只认“每个栅格上有多少建筑体积、天空能看到多少、地表是不是透水的”这类形态学指标。
这一篇我打算把Urban Morphology(城市形态)这条线的预处理器讲透。围绕三件事展开:预处理器到底在干什么、关键环节怎么操作、常见问题怎么排查。适合刚接触UMEP的研究生、用GIS做城市气候分析的从业者,以及对城市形态量化有需求但对这套工具还不熟的朋友。读完你至少知道数据从哪来、参数怎么定、结果怎么判断合理性。
有一点我先说在前面:这一期讲的“城市形态处理”,本质上不是算法问题,而是数据管理问题。大多数失败不是模型选错,而是输入的栅格数据分辨率、范围、投影、像元对齐这些基础工作没做好。所以别嫌预处理器琐碎,这里才是决定模拟成败的地方。
2. 内容整体设计与思路拆解
2.1 UMEP在城市环境模拟里的位置:预处理器解决什么问题
UMEP的组织逻辑非常清晰:完整的模拟流程被拆成“Input(输入数据准备)— Pre-Processor(预处理)— Processor(模型计算)— Visualization(结果可视化)”几段。预处理器放在第二段,承上启下。
承上,它接收的是各城市常见的公开数据:航空激光雷达反演的DSM(数字表面模型)、DEM(数字高程模型)、建筑矢量面、土地覆盖分类图等。这些数据来源不同、投影各异、分辨率参差,状态非常混乱。启下,它要把这些数据统一化、参数化,输出业务模型需要输入的那些“形态描述变量”——比如逐像元的建筑高度、植被高度、天空视角因子(sky view factor,SVF)、不透水面率等。
为什么处理器不直接用原始数据?这就要回到模型本身的设计哲学。以SUEWS为例,它把城市下垫面抽象成若干个局地尺度单元(Local-Scale Zone),每个单元里的建筑高度和年内建筑体积是关键参数。如果让你手动去数一个街区里的建筑体积,你会疯掉的。预处理器就是把这个“数体积”的过程自动化,并且把误差控制在可接受的范围内。
所以,理解预处理器不能只把它当成“格式转换器”,它实际上是一套城市形态学特征工程工具集。它的输出质量,决定了后续模拟结果的上限。如果输入的城市形态数据失真,后面无论模型调参调得多精细,输出都是空中楼阁。
2.2 为什么城市形态必须先做预处理:从原始数据到模型输入的距离
举个直觉化的例子。你手里有一份三维建筑物白模,面图层非常精细,每个建筑的层数、轮廓对角线都在,建模质量很高。你心想这总能直接用了吧?但SUEWS不要多边形,它要在规则的栅格网眼里统计每个网眼内的平均建筑高度和体积分数。Polygon到Raster,这一步看似简单,坑却很多:
一是分辨率匹配。建筑矢量转栅格时,像元大小设多大?你手头的DSM是2米分辨率,地表覆盖数据是5米分辨率,建筑数据是矢量。如果统一到2米,建筑栅格太碎,计算量大;统一到5米,建筑细节丢失严重。怎么折中?
二是范围对齐。药物覆盖范围比建筑数据大很多,交叠区域哪里是有效区?
三是属性语义。建筑多边形里带的字段可能是“楼层数”,不是“高度”。有的数据直接丢给你一个“height”,有的给的却是“base elevation”和“roof elevation”。你直接拿楼层数乘层高3米,来的没那么简单。
这些细碎的问题,如果没有一个统一的处理框架,每做一次模拟就要手工配一轮数据,效率极低且极易出错。UMEP预处理器把这些繁琐操作固化成标准流程,让你把精力放在参数分析和结果解读上,而不是困在数据格式泥潭里。
2.3 方案选型:为什么要用UMEP而不是自己写脚本
有人说,我不就是做几步GIS处理吗?用QGIS原生的栅格计算器自己算不就行了?这确实可行,但有几个场景下UMEP的优势非常明显:
- 预处理器内置了很多经验公式和行业标准参数取值,比如SVF的计算方式、植被高度的校正系数,这些是作者从文献里整理出来的,你不需要自己去查论文;
- 接口与后续模型深度耦合,传参不会出错;
- 多步骤串联成一键流程,自动检查数据投影和范围一致性。
当然我也不是劝你所有事都用预处理器。如果你只是想做一次性的简单分析,现成的QGIS工具完全够用。但如果要做系列化模拟、多情景对比,或者数据会经常更新,UMEP这套标准化的预处理流程能省下的时间不是一点点。
3. 核心原理与关键技术落地
3.1 城市形态数据的主要类型与数据准备
UMEP预处理器里涉及的城市形态数据,常见的有这几类:
| 数据层 | 常见来源 | 原始格式 | 预处理后输出 |
|---|---|---|---|
| 数字表面模型(DSM) | 机载LiDAR、卫星立体像对 | 点云或TIFF | 等高程栅格 |
| 数字高程模型(DEM/DTM) | LiDAR地面点、测绘成果 | TIFF | 高程栅格 |
| 建筑轮廓 | 测绘部门、OpenStreetMap | Shapefile/GeoJSON | 建筑占地栅格 |
| 植被高度 | LiDAR多点回波分类 | TIFF/点云 | 植被高度栅格 |
| 地表覆盖分类 | 遥感影像分类、土地利用图 | TIFF | 地表类型栅格 |
准备数据阶段最重要的原则是:统一坐标系。我见过太多人在这一步翻车。比如LiDAR点云是UTM投影,地表覆盖数据是Web墨卡托投影,你如果不做转换就直接丢进工具里,结果就是图层错位,建筑跑到河对岸去了。建议在进入UMEP之前,把所有数据先行投影到同一个投影坐标系统一管理。城市尺度的研究,UTM分区投影表现很好,米制单位对后续面积、高度的计算也友好。
3.2 建筑高度提取的核心原理:DSM与DEM之间藏着什么
城市形态处理里最高频的操作是“归一化高度”提取。所谓归一化,就是把地表以上的物体实际高度算出来。数学关系很简单:
建筑/植被高度 = DSM – DEM
DSM是数字表面模型,记录的是地表以上第一个反射面的高度,包括建筑屋顶、树冠、地面等;DEM是数字高程模型,只记录裸露地表的高程。两者相减,得到的结果就叫nDSM(normalized Digital Surface Model),即地物高度。
看着简单,实际操作里有两个容易踩的坑。
第一个坑是DSM和DEM像元没对齐。很多城市公开数据集里DSM和DEM是独立生产的,分辨率一致不代表像元网格一致。如果两个栅格在空间上有半个像元的偏移,相减后的边缘会充满“椒盐噪声”,建筑边界模糊得没法看。所以在预处理前,务必用QGIS里“栅格对齐”功能把目标对象手动对齐到同一个参考网格。
第二个坑是噪声点。LiDAR点云在建筑边缘、玻璃幕墙等位置经常出现噪点,反演出来的DSM局部会出现异常凸起或凹陷。直接相减后,这些噪点会被当成“虚假建筑”或“虚假空洞”。一般会用中值滤波或形态学开闭运算先平滑一遍再相减。
3.3 天空视角因子(SVF)计算:街谷几何形态的量化
城市热岛研究老听到一个词——天空视角因子(Sky View Factor,简称SVF),简单理解就是站在地面往上看,天空占视野的比例。街谷越窄、两侧建筑越高,天空占比越小,SVF就越低,白天不容易散热,夜间热岛强度往往就更大。
UMEP的SVF预处理器是个挺有意思的模块。它有两种工作模式:一种是基于栅格DSM的模式,直接对城市表面做几何解析计算;另一种是站点模式,面向单点观测位置,输出该点的SVF值。站点模式结合鱼眼镜头拍摄的天空照片做验证,是地面实测中很常用的一种校验办法。
计算SVF为什么要放到预处理器里?因为它本质上是对DSM做几何变换,而这一步非常消耗计算资源。如果你打算跑一个百万像元的城市区域,最好先设一个合理的像元分辨率。分辨率过高会导致计算时间指数级增长,过低又会丢失街谷细节。我的经验是2到5米这个区间比较均衡。
3.4 地表覆盖类型栅格:一切参数的基础
城市形态不只是高度,地表的透水性同样关键。不透水面率直接决定降雨后的径流分配、蒸发潜力,是SUEWS水文模块的核心参数。
UMEP预处理器里提供“地表覆盖类型识别”工具,输入分类栅格后自动为每个像元生成多个物理属性,包括:不透水比例、排水路径、蒸散参数等。需要注意的是,地表覆盖栅格的分类体系要和UMEP内置的分类体系对应上。如果你用的是自己训练的分类结果,分类代号不对应,工具会直接抛错或者给出离谱属性值。建议先读一遍UMEP官方提供的土地覆盖分类说明文档,把自己的类别映射表提前整理好。
城市形态处理这里的数据,在进入预处理器前其实还需要做一步质量控制:检查栅格的数据类型。很多遥感分类结果是整数型,看起来没问题,但属性值里如果混杂了空值或0值的特殊含义,后面计算时会引起莫名其妙的误差。把数据统一转成浮点型,把NoData统一设置成固定值(常用-9999),会让后续处理稳定很多。
4. 实操过程与核心环节实现
4.1 运行环境准备:在QGIS里装好UMEP插件
UMEP是QGIS的插件,安装流程不复杂。QGIS的插件管理器里搜索“UMEP”,安装“UMEP”主插件和“UMEP for processing”辅助插件即可。需要提示版本兼容性:UMEP一般要求QGIS 3.x以上版本,太老的版本会有兼容问题。
装完以后,插件栏里会出现两个入口:一个是完整的UMEP主窗口(带界面),一个是处理工具箱里的一系列批处理命令。我个人的建议是:日常交互探索用主窗口,批量处理脚本化运行用工具箱。前者适合一步步调试,后者适合完整跑一个流程。
数据建议放在独立的项目文件夹里,目录结构可以参照下面这种:
umep_project/ ├── input/ │ ├── dsm.tif │ ├── dem.tif │ ├── building.shp │ └── landcover.tif ├── output/ │ ├── ndsm.tif │ ├── svf.tif │ └── building_height.tif └── temp/temp目录可以用来放中间成果,方便调试时对照,也不污染最终结果目录。
4.2 建筑高度提取实操:从DEM和DSM开始
建筑高度提取是预处理器里一组工具的“入口”,一般流程是:
第一步,栅格对齐。在QGIS里用“栅格对齐”工具,把DSM和DEM对齐到同一个像元网格。参考网格我一般选分辨率较低的那一个,比如DSM是2米、DEM是5米,那就把两者都重采样到2米。重采样方法选双线性插值,对高程类数据比较友好;分类栅格则用最近邻法,防止类别插出过渡值。
第二步,运行“building height”预处理器。UMEP里对应的是Pre-Processor — Urban Morphology — Building height。工具会读取DSM和DEM,自动做差值,再根据你设置的建筑最低高度阈值剔除低矮地物。
第三步,检查负值和异常值。差值的理论范围应该大于等于0,但实际会因DSM与DEM配准误差出现少量负值。可以在栅格计算器里把负值统一赋为0,把过高的异常值(比如超过该城市建筑限高加合理误差的值)做截断处理。
这里有个参数需要重点理解:建筑最低高度阈值。假设你设2米,那么低于2米的像素一律算作“非建筑”。这个阈值不是拍脑袋定的,要根据研究目的调整。如果你做的是城市冠层模型,可以设低一些(1.5米),把低矮商业建筑也算进去;如果你做的是城市热岛与通风廊道分析,为了排除噪音,设到3米左右比较稳妥,你关注的是主体建筑轮廓对风场的影响,而不是那些临时板房。这个阈值直接决定建筑占地比例的统计结果,非常关键。
4.3 植被高度提取与地表覆盖合并
植被高度的提取在原理上与建筑高度类似,也是用DSM减去地面高程。但有个特殊问题:DSM在植被区域的信号是树冠表面,不是树干底座。所以植被高度提取出来的值是树冠顶到地面的高度差,这个值对后续模型计算没有直接用,还需要对植被覆盖率、单株树冠直径做联合统计。
实际操作用到“Vegetation height”预处理器时,建议先在外部分类栅格里把“树木”“草地”分开。如果植被这层数据没有单独分类,UMEP会用DSM与“非建筑”区域判断,配合阈值提取植被。这种方法容易把高矮灌木和房屋附属物混在一起,精度一般。对于要求较高的研究,建议先单独准备植被冠层高度栅格,再导入预处理流程。
地表覆盖合并这一步我更想多说一句:UMEP里很多后续模型要求“地表覆盖类型”“不透水面比例”“植被比例”三组参数。如果你只给一个整数类型的地表分类栅格,工具也能帮你转换,但转换结果比较粗糙,不透水率是直接用类别默认值,比如“中密度居民区”默认不透水率0.5。如果你用的是自己研究区的用地分类数据,最好做一张连续的不透水率栅格(0到1之间的浮点值),这样能明显提高后续模型对水文过程的模拟能力。
4.4 天空视角因子预处理器实操过程
运行SVF预处理器,核心参数有三个:搜索半径、方位角分割数和天顶角分割数。
搜索半径决定计算单点SVF时考虑多大范围内的遮挡物。城市气象应用里常设100米到500米。半径太小,远处高层建筑的遮挡作用计算不到,SVF会偏大;半径太大,计算量剧增,而且远处建筑对近地面点的SVF贡献其实衰减很快。一般建议先设200米试算,对比几个典型点的结果,再决定是否调整。
方位角分割数和天顶角分割数,是算法里对半球空间做离散化的网格密度。分割数越多,结果越精细,计算时间也越长。默认值是36方位角×18天顶角,对多数城市街区研究够用。如果做极高精度的单点分析,可以加到72×36,但跑起来会非常慢。
输出结果是一个连续栅格,值域理论在0到1之间。打开结果时不要只看平均数,要重点看建筑密集的商务区、开阔的公园水面、南北向街谷这些不同场景下的SVF,和实际感受对照一下,非常有直觉校验作用。
4.5 跑通一条完整预处理流水线的示例
我来串一遍实际操作,假设目标是给SUEWS模型准备城市形态输入,研究区是约2km×3km的城区,数据有DSM 2m、DEM 5m、建筑底面矢量、土地覆盖分类图5m。
我实际跑的顺序如下:
第一步,统一到UTM投影。用QGIS的重投影工具把所有矢量数据转到EPSG:32650(按研究区所在带号选择)。栅格数据用“栅格投影”工具执行最近邻重采样。
第二步,将DEM重采样到2m,与DSM对齐。这里不是直接点“重采样”这么简单——需要对DEM和DSM的像元范围做一致性检查,确保两个栅格的覆盖范围完全一致。不一致的话,用“切割栅格按范围”工具,拿DSM的范围切DEM。
第三步,生成nDSM:Raster Calculator里直接相减。设定阈值2m,生成二值建筑掩膜,再用建筑矢量边界做滑动校验。如果一个建筑多边形对应的掩膜里,建筑像元占比低于50%,那就说明DSM可能没捕捉到该建筑,要么数据缺测,要么层高太矮被阈值砍掉了。这种检查能帮你发现数据里的系统性盲区。
第四步,跑Building height预处理器,输出建筑物高度栅格和体积分数栅格。体积分数这个字段是SUEWS里很关键的一个参数,它统计的是单位面积内建筑体积的比例,某种意义上反映了建筑密度的三维版。看这个值的时候,密度高的老城区中心普遍0.3~0.5,新建的低密度住宅区在0.1以下,用这个范围来验证数据可靠性很高效。
第五步,跑SVF预处理器。搜索半径先设200m,分割数用默认。如果你发现结果栅格有大量0值的“黑洞”,往往不是真黑洞,是建筑高度栅格里那些小于阈值的像元在SVF计算里被当成了“不存在地表”,导致天空遮挡反而变大了。这时需要回头看好输入参数,把像元裁剪到研究区有效范围内。
第六步,产出最终形态参数包。在结果图层上右击导出,用“保存为GeoTIFF”把建筑高度、植被高度、SVF、不透水率四个栅格全部输出到output目录。检查一下同名文件是否覆盖、NoData值是否统一,然后就可以作为下游模型的输入继续了。
5. 常见问题与排查技巧实录
说了这么多,下面这组排查经验都是实操里踩过的。整理成速查表,方便你定位:
| 现象 | 可能原因 | 排查顺序 |
|---|---|---|
| 建筑高度结果全是0 | DSM与DEM像元未对齐,差值后出现系统性偏移 | 先查范围对齐再查分辨率 |
| 建筑高度出现大量负值 | DSM局部有噪点,或DEM在建筑区域有插值 | 中值滤波DSM,负值截断为0 |
| SVF结果整个区域异常偏大 | 搜索半径过小、建筑数据缺失 | 逐步增大搜索半径试算 |
| SVF结果有大量空洞/马赛克 | 输入建筑高度栅格里有空值区域 | 将NoData统一赋0,再重试 |
| 体积分数超出合理范围 | 建筑高度被高估,或建筑掩膜范围偏大 | 检查阈值设置,拆解到单栋验证 |
| 后续模型报错“参数缺测” | 输出文件命名不符,或栅格CRS不一致 | 核对每个输出文件的投影和文件名 |
还有一个现象特别常见,就是建筑高度结果被系统性低估。原因通常是DSM不是真正的“首次回波”表面,部分区域丢失了屋顶细节,LAS数据在分类时把建筑边缘的回波滤波掉了。遇到这种情况,可以对比同一区域的高分辨率影像,目测确认是否是采集源的问题;如果是,可以将建筑高度提取的阈值适当下调,同时增加多源数据的交叉验证。
当遇到“SVF结果与实地感受差太远”的情况时,我建议先做站点校验:选一个市中心开阔广场,一个典型的东西向街谷,用站点点位提取SVF值,然后和理论值对比。开阔广场的SVF按道理应该在0.9以上,街谷中心可能在0.3到0.6之间。如果广场的SVF计算值低于0.7,多半是数据有问题,而不是算法问题。
这里补充一个我自己的习惯:做完预处理之后,不要急着跑模型。把建筑高度栅格做成山体阴影图加载到QGIS里,跟航空影像叠起来,透明度调成50%,你一眼就能看出建筑边界是干净还是糊成一片。这个检查花不了几分钟,却能节约后面调试模型的好几个小时。
关于工具选型还有个小建议:如果你要处理的区域特别大,比如整个地级市范围,那UMEP预处理器跑起来会很吃力。可以先对LiDAR点云做分块处理,再瓦片拼接。如果只想快速做概念级分析,也可以用全局的粗略栅格(30m分辨率)配合UMEP里的“区域平均形态参数”工具来批量计算,不需要精细化到每个建筑。
6. 从预处理结果到后续模型的衔接建议
预处理做完,输出的那些栅格不是终点,而是给后续模型准备的“食材”。这一步的衔接质量,会直接影响模型是不是能跑通。
以SUEWS为例,它需要的输入里至少包括:逐栅格的建成区比例、不透水比例、建筑高度、植被高度和植被覆盖率。你在预处理器里其实只生成了中间字段,正式输入模型前还有一道“参数聚合”的工序。比如SUEWS有时候要求以“局地区域”(Local-Scale Zone,通常是几百米到1公里尺度)为基本单元来聚合参数,而不是每个2米像元都单独参与模拟。这时候就要用到分区统计工具,把预处理结果按边界聚合为“均值±方差”的统计量。
聚合时要注意:建筑高度取的是平均值还是体积加权平均?SUEWS里建筑高度对湍流影响采用“平均高度”即可,但计算空气动力学粗糙度的时候,更关注“迎风面面积密度”,这是按体积和方向投影算的。如果你在聚合时选错了统计口径,后面所有能量通量结果都会偏。所以每出一个聚合结果,都要顺手把该区域的“建筑体积”“建筑占地面积”“不透水率”三个变量交叉检查一遍,确保逻辑自洽。
还有一点很多人会忽略:模型的计算时间步长和空间分辨率,反过来也会要求预处理输出栅格满足最低精度。比如你准备用30m分辨率跑SUEWS,那预处理时用2m还是10m的DSM关系不大,最终聚合到30m后信息量趋同。但如果你准备用2m分辨率跑局地尺度模型,那预处理阶段就绝不能为了图省事把DSM重采样到10m,等于自废武功。我建议你在项目启动前先定好后续模型的空间尺度,再反推预处理阶段的分辨率需求,而不是拿到数据就先处理了再说。
7. 结尾
UMEP的预处理器说白了就是一套“城市三维形态翻译机”,把千奇百怪的原始数据变成模型能统一理解的形态学参数。这一期关于城市形态处理的内容,重点讲了数据准备、高度提取、SVF和地表覆盖几个环节。我自己实际跑过几条链路的体会是:与其纠结算法细节,不如先把数据底子打牢。投影统一、范围对齐、阈值合理性这三板斧过关了,后面基本畅通;这三步偷懒了,后面每一步都在还债。
还想提醒一点:任何预处理结果都要保留完整的处理日志,包括软件版本、插件版本、数据源版本、参数设置值。城市气候模拟是一件要经得起同行评议的事,没有处理日志的结果,说服力大打折扣。最后分享一个实用小习惯——初次跑通流程后,把关键参数和当时试算的理由记在一个Markdown文件里,下次换数据就不会从头摸索了。UMEP这套预处理器就是在这些细节磨合中越用越顺手的。