做数据的人,尤其是经常和矢量、栅格打交道的,应该都有过这种体验:来了几十个乡镇的边界文件,每个都要裁剪一遍遥感影像、再重投影到统一坐标系、最后还要按面积字段排个序。文件不多不少,工具也不复杂,但就是得一个一个点,点到最后人都麻了。我最早用QGIS的时候也这样,后来真正把模型构建器用起来,才明白什么叫"批量处理"——不是把同一个工具多运行几遍,而是把整条流程固化成模型,输入换一批数据,结果自动出来。
这篇内容就是围绕《QGIS快速入门与应用基础》里"利用模型构建器批量处理"这个主题展开的实操记录。适合已经会QGIS基础操作、但还没认真用过模型构建器的读者,也适合那些不愿意为了批处理去写Python脚本、又想大幅减少重复劳动的人。我会从批量处理的三种思路讲起,用一个典型的裁剪流程做例子,再专门把迭代器、命名、坐标系、几何质量这些最容易翻车的环节拆开说清楚。
1. 批量不只是"多点几次":模型构建器解决的是流程固化问题
1.1 三种批处理方式,适用场景完全不同
很多刚接触QGIS的人以为,批量处理就是选中一堆图层,对着某个工具右键,选"执行批处理"。这个理解没错,但只是最浅的一层。QGIS里实际上有三条批量处理的路线,解决的问题并不一样。
第一条:单个工具的批处理模式。 在工具箱里右键任意处理算法,选"执行批处理",会弹出一个表格界面,一行代表一次执行,一列代表一个参数。你可以自己填,也可以从CSV文件导入。这种方式适合"同一个算法、不同参数组合"的场景。比如我要把10个矢量文件批量重投影,每一行填一个输入文件和一个输出路径,跑完收工。它的问题是:如果这条流程有三四个步骤,你还是要分三四个工具去各自做批处理,中间文件怎么衔接、命名怎么对应,全靠自己记。
第二条:历史记录复用。 处理工具箱最下面的"历史"里,每次跑过的算法都会留下记录,可以右键重新执行。这个很适合单次复现,但没法把多个步骤串起来,参数换了还得手动改。
第三条:模型构建器。 这才是真正意义上的流程批量。你打开图形化模型设计器,把输入数据、处理算法、输出文件拖到画布上,用连线确定数据流向,保存成一个模型。以后无论面对多少份数据,双击模型、指定输入、点运行,内部所有步骤自动按顺序执行。更关键的是,模型里可以放迭代器,让它自己遍历一个文件夹里的所有文件,逐个处理、逐个输出。
三种方式我实际用下来的感受是:批处理模式适合"一次性的多组参数",历史记录适合"回头找上次怎么跑的",模型构建器适合"同一个流程今天跑一遍、下周还要跑一遍、下个月换批数据还要跑一遍"。后面这种需求在国土、规划、测绘、环境这类数据更新频繁的行业里遍地都是。
1.2 模型构建器比单个工具批处理强在哪
单个工具的批处理模式,本质上是一个"参数表格"——你把参数填好,工具循环执行。但它有几个明显的短板。
第一,中间数据没法自动衔接。比如"修复几何→裁剪→重投影"三步流程,如果每一步都单独做批处理,你要手动管理中间的临时文件,稍不注意就不知道哪个文件是第几步的产物。而在模型构建器里,上游算法的输出可以直接作为下游算法的输入,中间可以走临时数据通道,不用落地成文件,也不会弄混。
第二,流程本身没有保存下来。单工具的批处理做完就做完了,下次想复现,还得重新填一遍几十行的参数表。模型则是一个独立文件,可以把参数设置成变量,下次运行直接换输入路径就行。
第三,模型可以"参数化"。你可以把一个图层定义成"运行模型时用户自己选择",也可以定义成"每次自动遍历文件夹"。这种灵活性,批处理模式给不了。
所以我的判断标准很简单:如果一件事你一年要做五次以上,每次只是换数据,那就该搭模型。哪怕第一次搭建花半小时,后面每一次都在赚时间。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 搭第一个模型:用县界批量裁剪影像,并在文件名里保留辖区名
2.1 认识模型设计器界面
在QGIS菜单栏点"处理 → 图形化模型设计器",打开的窗口就是模型构建器。初次打开你可能觉得它有点像流程图编辑器,左边是面板,中间是画布,上方是工具栏。
左侧面板有三个页签:输入、算法、迭代器。"输入"里可以添加矢量图层、栅格图层、字段、数值、字符串、布尔值等作为模型的入口参数;"算法"里可以搜索所有处理工具箱的算法,搜到之后双击或拖拽到画布上;"迭代器"在最下方,是后面讲到的循环处理核心。
画布上的每个元素,可以简单理解成一个节点。算法节点有输入端口和输出端口,把鼠标悬停在节点上会看到可连接的接口。真正用起来你会发现,它跟ArcGIS的ModelBuilder逻辑很像,如果你从那边转过来,上手会非常快。
2.2 从数据输入到算法连线
我拿一个最常见的需求做例子:一个省内有多份县界矢量,每份对应一个县,现在要拿每个县界去裁剪同一景遥感影像,然后统一重投影到CGCS2000坐标系。这个流程如果用传统方式,每个县至少要点三次工具,50个县就是150次操作。用模型构建器,只需要做一次。
第一步,在左侧"输入"面板里添加一个"栅格图层",命名为"原始影像";再添加一个"矢量图层",命名为"县界",类型选"任意几何类型"。添加之后,建议把两个输入都勾选为"必填",这样运行时系统才会强制你选择数据,避免漏填。
第二步,在"算法"面板搜索"修复几何",拖到画布上。它的输入选择"县界"这个参数。这一步不是多余的,后文会专门讲为什么批量处理前一定要修几何,这里先放上去。
第三步,搜索"栅格裁剪(按掩膜图层)",也就是Clip raster by mask layer,拖到画布。栅格输入选择"原始影像",掩膜图层选择上一步"修复几何"的输出,而不是原始的"县界"。这一步的连接方式很重要:掩膜必须用修复后的几何,否则一个县界文件里有几个无效几何,裁剪结果就会少几个。
第四步,搜索"重投影图层",拖到画布。输入选择上一步裁剪输出的栅格,目标坐标系填EPSG:4490。如果原始影像本身就是CGCS2000,这一步可以省略,但放在模型里也无妨,因为坐标统一这件事在批量处理里太常见了,模型多一步不会错。
2.3 关键一步:输出文件怎么命名
模型运行时,每个算法可以生成临时输出,也可以写到你指定的文件夹。批量处理千万别用临时输出——模型每次运行只能保留最后的结果,前面的会被覆盖,等于白跑。
点击重投影算法节点下方的"输出"区域,有一个设置按钮,搜索结果可以选"保存到临时文件"或"保存到文件路径"。选择后者,然后在路径里填:
code复制D:/result/裁剪_%县界%.tif
这里的%县界%是一个变量占位符,QGIS运行时会把当前输入的县界图层名替换进去。比如输入文件叫"安宁市.shp",输出就是"裁剪_安宁市.tif"。不用占位符的后果是,每次循环覆盖同一个文件,跑完50个县只剩最后一个。
这里有个细节:占位符的名字必须跟你在输入面板里定义的参数名完全一致。你把矢量输入命名为"县界",就写%县界%;如果命名为"mask",就写%mask%。名字错了,模型运行时会直接提示变量不存在,倒不会静默出错,但新手第一次遇到还是容易懵。
2.4 保存、运行、验证
画布上的流程搭完后,按Ctrl+S保存,新版QGIS的模型文件后缀是.model3。保存完不要急着关窗口,先点工具栏上的绿色运行按钮,模型会弹出一个参数对话框,让你指定"原始影像"和"县界"分别是什么。
我第一次跑模型时习惯只试一个小数据。比如拿一个县界测试,看输出文件是不是生成在了预期路径、命名是否符合规则、打开属性表确认坐标系没跑偏、裁剪范围是否吻合。测试通过,再拿全部数据批量跑。这个习惯后来帮我省了很多事,因为模型一旦跑起来,中间错了很难定位,小样本验证花不了两分钟,但能把流程层面的问题一次性暴露出来。
跑完后,也可以顺手把"历史"面板里的执行记录点开,看每一步算法实际用的参数值。如果某个环节没按预期走,历史记录是排查的第一手资料。
3. 迭代器:让模型自己遍历一整个文件夹
3.1 迭代器能省掉什么
上面那个模型,每次运行还要手动选择"县界"图层。如果50个县界散落在同一个文件夹里,你总不能在模型参数框里一次选50个图层,然后期待它自动循环——模型构建器默认不会这么做。
这就是迭代器存在的意义。迭代器相当于给模型加了一层"循环"能力:它指定一个输入源,比如一个文件夹、一组矢量图层、一组栅格图层,模型运行时自动遍历输入源里的每一个成员,把当前成员塞进流程里跑一遍。
比如面对"文件夹里有50个乡镇边界shp,每个都要重投影并计算面积"这种需求,用迭代器的话,你只需要在模型里指定一次文件夹路径,剩下50次循环全部自动完成。配合上节讲的占位符命名,每次循环生成一个独立文件,整个过程不用任何人工干预。
3.2 文件夹迭代的操作细节
要遍历一个文件夹,先在"输入"面板添加一个"文件夹"输入,命名为"输入目录"。然后在左侧面板底部的"迭代器"里找到关于文件列表的迭代器(不同版本名称略有差异,有的叫"文件夹中的文件"、有的在"矢量图层/栅格图层"里选择),拖到画布上,把它的数据来源指向"输入目录"这个文件夹参数。
接下来,下游所有算法在设置输入时,不要选择"输入目录"本身,而应该选择"迭代器"的输出。比如"栅格图层"输入参数,应选择迭代器输出的那个文件或图层。这样模型就知道:每循环一次,就用当前文件作为输入。
命名上,迭代器会自动暴露一些变量。比如你把文件夹参数命名为inputFolder,在输出路径里通常可以用%inputFolder%代表当前文件的完整路径,用%inputFolder_baseName%代表不带扩展名的文件名。我在不同QGIS版本里见过变量名略有出入,所以最稳妥的做法是:添加完迭代器后,在模型设计器菜单里查看当前模型的变量列表,看清楚哪些变量可用,再运用到输出路径里。
举个例子,文件夹里是"地块A.shp、地块B.shp……",输出路径填:
code复制D:/output/%inputFolder_baseName%_重投影.shp
循环结束后你就能得到"地块A_重投影.shp、地块B_重投影.shp……"。
3.3 嵌套循环的现实限制
说到这里必须提醒一个限制:在大多数QGIS版本里,一个模型只允许放置一个输入迭代器作为主循环。你想实现"外层遍历县、内层遍历每个县的影像切片"这种双层循环,模型构建器做不到。
面对双层循环,我的做法通常是:模型里先只做内层或外层其中一层,另一层用文件夹迭代解决;如果真的要双层嵌套,就直接把模型导出成Python脚本,在脚本里写两个for循环,这个问题会在第5节展开。模型构建器是图形化的利器,但也有表达力上限,知道它的边界在哪,才不会在构建时白费力气。
4. 批量处理最容易翻车的三个环节:命名、坐标系、几何质量
4.1 输出命名里的占位符引错,所有结果互相覆盖
这是批量处理里出现频率最高的问题。表现是:模型跑完了,输出文件夹里只有一个文件,或者文件数量对但内容全是同一个地方处理的。原因基本上就是输出路径没有用占位符,或者占位符引用错了参数。
我见过最典型的错误写法是这样的:把输出路径设置成D:/result/裁剪.tif,然后模型循坏100次,每次都是同一个文件名,最后一次覆盖前一次。跑完那一刻你也不知道,等回头用数据时才发现只有一份。正确写法是像前面那样,把图层名或迭代变量拼进路径。
另一个细节:如果输出的是shapefile,它不是一个单文件,而是包括.shp、.shx、.dbf、.prj等多个附属文件。批量删除或覆盖时要整组处理,否则容易留下残留文件导致下次写入报错。
4.2 坐标系不一致,批量重投影之后的"隐性"错误
批量处理里坐标系问题比命名问题隐蔽。表面上看,所有输出文件都在,属性表也正常,但放到一起叠加时,边界就是差那么一截。最常见的场景就是:原始数据里有CGCS2000(地理坐标系,度为单位),有Web Mercator(投影坐标系,米为单位),你直接批量跑了裁剪,输出坐标系五花八门,后面做面积统计全是错的。
解决办法有两个层面。第一,在模型运行前,先加载一份要处理的数据,查看图层属性里的坐标系,确认所有输入是否一致。如果来源杂,建议在模型最前面就放一个"重投影图层"节点,把所有矢量先统一到同一个坐标系,再进入后续流程。第二,栅格数据要重点检查像元大小和范围,重投影后如果范围对不齐,裁剪结果容易出现几像素的白边或黑边。必要时在重投影节点里设置好输出像元大小和重采样方法。
我一般会在模型里放一个"提取图层范围"之类的辅助节点,先看一眼每个图层实际范围,确认没有偏移,再继续。这点在批量处理时代尤其重要,因为一旦批量跑完才发现问题,回头100个文件全部重跑,代价很大。
4.3 无效几何导致裁剪数量比输入少一半
这个坑我踩得特别深。有一批来自不同渠道的矢量数据,里面不少要素带自相交、重复节点这类几何错误。做单文件操作时,QGIS某些工具会对无效几何弹出警告,但在模型里,警告可能被吞掉,模型照跑不误,结果却缺了一些要素。
后来我把"修复几何"作为批处理流程的默认第一步,放在所有用到几何运算的算法之前。它在处理工具箱里的名称是"修复几何"(Fix geometries),它会把自相交、环方向错误之类的几何问题清理掉,再做裁剪、相交、擦除这些操作就稳多了。
如果你处理的矢量是从CAD转换过来的,或者经过多次格式转换,那修复几何基本是必须的。我的原则是:批量处理越省人工,前置校验越要做足,因为人一旦离开循环,就没有机会中途干预了。
4.4 批量处理问题排查参考表
| 现象 | 常见原因 | 排查手段 |
|---|---|---|
| 输出文件只有一个 | 输出路径缺少占位符,每次循环覆盖 | 打开模型变量列表,核对输出路径 |
| 输出文件名乱码或含异常字符 | 输入文件名有中文/空格/特殊符号,部分算法处理不规范 | 输入前先批量重命名,统一用英文、下划线 |
| 裁剪后边界偏移 | 坐标系不一致或重投影参数设置错误 | 在模型中加"重投影图层",并在测试时叠加验证 |
| 结果要素变少 | 输入矢量存在无效几何 | 流程最前面加"修复几何"节点 |
| 栅格有黑边 | 掩膜范围与栅格边界未对齐,或NoData值未设置 | 检查裁剪参数中的NoData值,必要时设置重采样范围 |
5. 模型只是开始:保存到工具箱、对接PyQGIS才是完全体
5.1 把模型变成处理工具箱里的普通算法
模型保存后,默认会出现在处理工具箱的"模型"分组里。打开处理工具箱(处理 → 处理工具箱),找到"模型"下的模型名称,可以像普通算法一样双击运行。这意味着两件事:一是你可以在批处理对话框里直接调用这个模型,逐行填参数,实现"模型+批处理"的组合;二是你可以把模型丢给同事用,对方不用打开模型设计器,只需要会填参数。
把模型当作工具箱算法,还有一个优势:它能被嵌套进另一个模型。我先搭一个"单文件重投影"的模型,然后在另一个更大的模型里调用它作为其中一个步骤,流程组织更灵活。这也是这个功能让我觉得物超所值的地方——模型的颗粒度可以由你自己控制,小模型可以自由组合成大模型。
5.2 加Python脚本节点处理算法外的逻辑
模型构建器毕竟是个图形化环境,遇到"如果要素数量大于100就输出A,否则输出B"这类条件逻辑,处理起来就很别扭。好在QGIS允许在模型里添加Python脚本作为算法节点。
操作方式:在处理工具箱"脚本"分组里新建一个Python处理脚本,把它当普通算法一样拖进模型构建器。脚本里可以写processing.run()调用其他处理算法,也可以写普适的PyQGIS逻辑去操作图层。加了脚本节点之后,模型的表达能力会提升一大截,很多"非标准"的批处理逻辑都能融进去。
比如我需要按某个属性字段的值拆分矢量文件,模型构建器里本来没有现成的"按字段拆分"节点,但脚本里调一下native:splitvectorlayer,就解决了。这种混合模式的体验很好:能可视化连接的地方用图形界面,逻辑分支的地方用脚本节点,兼顾可读性和灵活性。
5.3 导出为Python脚本,实现真正的双层批量
如果模型里需要双层循环,或者你想在循环过程中做更复杂的判断,我建议把模型导出成Python脚本:在模型设计器菜单"模型 → 导出为Python脚本"即可。导出的脚本是一个标准的QGIS处理脚本,骨架清晰,里面每一步算法都是一个processing.run()调用。
在这个脚本基础上,用Python在两个循环里改写,就会非常顺手。比如:
python复制for county in counties:
for image in images:
processing.run("gdal:cliprasterbymasklayer", {
"INPUT": image,
"MASK": county,
"OUTPUT": f"D:/result/{county}_{image}_clip.tif"
})
这个写法看起来简单,但它在图形化界面里实现起来很麻烦。所以我会根据工作量来决定:流程简单用模型,流程需要双重循环、条件分支、复杂命名规则时,直接导出脚本改。模型给了我一个很好的起点,不用从零写算法调用参数,导出后在PyQGIS里改的体验,比纯手写脚本快得多。
说句实话,模型构建器是我用QGIS这几年里,性价比最高的功能之一。以前两小时才能处理完的批量任务,现在基本控制在几分钟内。而且模型文件可以跟着项目走,换电脑、换同事、换项目,只要数据格式没大变,流程就能复用。如果你手里正堆着一批数据需要重复处理,真心建议花半小时搭一次模型,跑完第一轮你会发现,这个时间花得太值了。
