Metashape 1.8.2 Python API 参考手册:批处理与自动化实战指南
简介面向 Metashape Professional 用户的 Python 脚本开发参考文档聚焦 Agisoft 官方 1.8.2 版 Python API 的完整说明适合已具备 Python 基础、希望将摄影测量流程自动化的测绘、三维重建与视觉工程从业者。资源包仅含 1 个 PDF 文件约 1.16MB内容涵盖 API 概览、应用模块、变更日志与 Python 模块索引并给出从打开项目、对齐照片、构建密集云与网格到导出成果的示例代码。读者可据此掌握 Document 类与 Metashape.app.document 的用法了解相机校准、地面控制、坐标投影及网络任务控制等接口快速搭建批量处理脚本并查阅各函数参数。已有 311 人学习适合作为日常开发时随手查阅的案头手册。1. 拿到这份 1.8.2 参考手册先搞清楚它能替你省掉哪些手工活如果你正在用 Metashape Professional 做航测或近景摄影测量手上有一批项目要反复走「对齐照片 → 稠密点云 → 网格 → 纹理 → 导出」这套流程那这份 1.8.2 的 Python API 参考手册就是给你准备的。它不是教程是一本把Metashape模块里每个类、每个方法、每个枚举值摊开给你看的工具书——Document、Chunk、Camera、Calibration、Application、ModelView这些对象到底有哪些属性、方法签名长什么样、参数类型是什么全在里面。适合两类人一类是想把重复劳动脚本化的从业者另一类是需要在批处理管线里嵌入摄影测量步骤的开发者。前提是 Professional 版Standard 版没有脚本引擎这一点手册开篇就写死了。2. 脚本引擎与三种执行入口先让代码跑起来再谈自动化2.1 Python 3.8 引擎与 Professional 版的硬门槛手册第一章明确写了Metashape Professional 内置的脚本引擎是 Python 3.8。这个信息很关键因为它决定了你写脚本时能用哪些语法、哪些标准库特性。比如海象运算符:是 3.8 才有的可以用但 3.9 之后才有的dict合并运算符|、list[int]这种内置泛型写法就不能用写了在控制台里直接语法报错。我一般会在脚本开头加一行版本断言避免把脚本拷到别的机器上跑出莫名其妙的错误import sys import Metashape # 引擎版本兜底检查低于 3.8 直接退出避免语法层面翻车 if sys.version_info (3, 8): raise RuntimeError(需要 Python 3.8 及以上当前为 %s % sys.version) # 顺手确认是 Professional 版Standard 版没有 Metashape 模块 print(Metashape version:, Metashape.app.version)这段代码的逻辑很简单sys.version_info拿当前解释器版本做元组比较Metashape.app.version打印软件版本字符串。参数上没什么可调的但要注意Metashape.app这个全局实例只有在 Professional 版里才存在Standard 版导入模块就会失败。所以如果你在别人的机器上跑脚本报ModuleNotFoundError: No module named Metashape先别怀疑代码先确认版本。2.2 控制台、Run Script、命令行 -r 三种入口怎么选手册列了三种执行方式实际用起来各有各的场合。控制台面板适合调试一行一行敲看变量、看返回值跟标准 Python REPL 差不多但它的历史记录不会持久化关掉就没了。Tools → Run script...适合跑已经写好的完整脚本缺点是每次都要点菜单、选文件批量场景下很烦。命令行-r参数才是自动化的正路# Windows 下典型调用-r 后面跟脚本绝对路径 C:\Program Files\Agisoft\Metashape Pro\metashape.exe -r D:\scripts\batch_align.py # Linux 下同理注意路径引号避免空格截断 metashape -r /home/user/scripts/batch_align.py-r的含义是「启动后立即执行指定脚本」脚本跑完软件不会自动退出除非你在脚本末尾调Metashape.app.quit()。这一点很多人第一次用会愣住——以为命令行跑完就返回了结果进程挂在那里。如果你要做无人值守批处理记得在脚本最后加退出逻辑或者在外部用任务计划配合超时控制。另外命令行模式下没有 GUI 交互所有getOpenFileName、getCoordinateSystem这类弹窗方法都会阻塞或返回空值脚本里要提前用参数把路径写死别指望弹窗。2.3 Document 与 Chunk项目数据模型的骨架手册第二章的核心是Document类它代表一个.psz项目文件。一个 Document 下可以挂多个 Chunk每个 Chunk 是一套独立的处理单元——相机组、对齐结果、稠密点云、网格都挂在 Chunk 上。理解这层关系后面所有 API 调用才不会迷路。下面这段是手册里给的完整处理链示例我加了注释和异常处理让它更接近能直接用的形态import Metashape doc Metashape.app.document doc.open(rD:\projects\site_a.psz) # 取当前活跃 chunk多 chunk 项目里要确认取的是哪一个 chunk doc.chunk print(当前 chunk 标签:, chunk.label) # 照片对齐downscale1 表示不降采样精度最高但最慢 chunk.matchPhotos( downscale1, generic_preselectionTrue, # 通用预选适合无序照片集 reference_preselectionFalse # 没有 POS 数据时关掉 ) chunk.alignCameras() # 深度图降采样 4 倍过滤模式用激进适合纹理丰富的场景 chunk.buildDepthMaps( downscale4, filter_modeMetashape.AggressiveFiltering ) chunk.buildDenseCloud() chunk.buildModel( surface_typeMetashape.Arbitrary, interpolationMetashape.EnabledInterpolation ) chunk.buildUV(mapping_modeMetashape.GenericMapping) chunk.buildTexture( blending_modeMetashape.MosaicBlending, texture_size4096 ) doc.save()逐段说参数。matchPhotos的downscale取值 0/1/2/4/8数值越大越粗越快1 是原分辨率适合小数据集精修generic_preselection打开后会用图像内容做预筛选无序航片必须开reference_preselection依赖相机位置信息没有 POS 或 GCP 就关掉否则会误筛。buildDepthMaps的downscale4是速度与质量的折中AggressiveFiltering对弱纹理区域更狠能压掉不少飞点但代价是边缘可能被削。buildModel的surface_typeArbitrary适合复杂地形和建筑HeightField只适合近似平面的大范围地形选错了网格会糊成一片。buildTexture的texture_size4096是单张纹理贴图边长项目大、细节多就往上加但显存和导出体积跟着涨。提示doc.chunk返回的是当前激活的 chunk多 chunk 项目里如果脚本依赖特定 chunk用doc.chunks[i]按索引取或者遍历比对chunk.label别默认第一个就是你要的。3. 相机标定与坐标系统把内参和外参钉死在脚本里3.1 Calibration 对象的读写与畸变系数映射Calibration类是手册里信息密度很高的一块。它承载了相机内参焦距f、主点cx/cy、径向畸变k1~k4、偏心畸变p1~p4、仿射与非正交b1/b2还有width/height图像尺寸。做多相机、多镜头批处理时把标定文件读进来统一套用比每台相机手动填靠谱得多。手册给了load和save两个方法格式默认是 XMLimport Metashape # 从 XML 标定文件加载内参 calib Metashape.Calibration() calib.load(rD:\calib\camera_a.xml, Metashape.CalibrationFormatXML) print(焦距 f , calib.f) print(主点 cx, cy , calib.cx, calib.cy) print(径向畸变 k1~k3 , calib.k1, calib.k2, calib.k3) # 把标定套到 chunk 里所有相机上同型号镜头批量场景 chunk Metashape.app.document.chunk for camera in chunk.cameras: camera.sensor.calibration calibload的第二个参数是格式枚举手册里默认CalibrationFormatXML如果你的标定来自其他工具导出的格式先确认枚举里有没有对应项没有就得自己解析后逐字段赋值。camera.sensor.calibration是赋值入口注意是挂在sensor上而不是camera上——同一个 sensor 下的多张照片共享一套内参这个层级关系搞错了会报属性不存在。calib.error(point, proj)和calib.project(point)可以用来验证标定质量前者算重投影误差后者把三维点投到像素坐标拿已知控制点跑一遍误差在亚像素级才算标定可用。3.2 CoordinateSystem 与 GCP投影和地面控制点的脚本化手册里Application.getCoordinateSystem是弹窗选坐标系但批处理场景下弹窗是灾难。更稳的做法是直接构造或从已有 chunk 继承 CRS再配合 GCP 做绝对定向。下面这段演示了从参考 chunk 拷 CRS、批量赋给其他 chunk 的写法import Metashape doc Metashape.app.document ref_chunk doc.chunks[0] target_crs ref_chunk.crs # 从参考 chunk 继承坐标系 for chunk in doc.chunks[1:]: chunk.crs target_crs # 标记GCP也要跟着换投影否则坐标对不上 for marker in chunk.markers: marker.projections # 访问投影点确认已关联 print(已同步 CRS 到 chunk:, chunk.label)chunk.crs赋值后chunk 内所有以地理坐标存储的标记、相机位置都会按新 CRS 解释。这里有个容易忽略的点GCP 的projections是它在各张照片上的像素位置跟 CRS 无关真正受 CRS 影响的是marker.position这类三维坐标。如果你只换 CRS 不重新导入 GCP 坐标绝对定向会偏。手册里Marker相关方法没在这段摘录里展开但add/remove markers在功能列表里明确列了实际用法是chunk.addMarker()建标记再给marker.projections[camera]赋像素坐标。3.3 用 Application 做参数收集与结果落盘Application类除了全局属性还提供了一堆getInt/getFloat/getString/getSaveFileName之类的交互方法。做内部工具时用它们快速搭一个参数输入界面很省事但记住这些方法在命令行-r模式下不可用。下面是一个「选保存路径 异常兜底」的典型写法手册示例里也有类似结构import Metashape doc Metashape.app.document path Metashape.app.getSaveFileName(另存项目为, rD:\projects) if not path: Metashape.app.messageBox(未选择路径操作取消) else: try: doc.save(path) print(已保存到:, path) except RuntimeError as e: # 磁盘满、权限不足、文件被占用都会走到这里 Metashape.app.messageBox(保存失败: %s % e)getSaveFileName返回空字符串表示用户取消这个判断不能省否则doc.save()会抛 RuntimeError。try/except RuntimeError是手册示例里的写法Metashape 的底层错误基本都包成 RuntimeError捕获后弹框提示比直接崩掉友好。Metashape.app.update()在长循环里定期调用可以刷新界面避免软件看起来假死但别在 tight loop 里每轮都调会拖慢处理速度。4. 批处理管线搭建从单项目脚本到多项目队列4.1 遍历目录批量建项目与对齐单项目脚本跑通后下一步就是把它套进目录遍历。下面这段是我常用的批处理骨架扫一个根目录下的所有子文件夹每个子文件夹当独立项目处理照片全加进去、对齐、存盘。关键点是每个项目新建Document而不是复用app.document避免状态串味import os import Metashape root rD:\survey_batch for name in os.listdir(root): proj_dir os.path.join(root, name) if not os.path.isdir(proj_dir): continue # 每个项目独立 Document互不干扰 doc Metashape.Document() chunk doc.addChunk() chunk.label name # 收集该目录下所有 jpg按文件名排序保证可复现 photos sorted( os.path.join(proj_dir, f) for f in os.listdir(proj_dir) if f.lower().endswith((.jpg, .jpeg)) ) if not photos: print(跳过空目录:, name) continue chunk.addPhotos(photos) chunk.matchPhotos(downscale2, generic_preselectionTrue) chunk.alignCameras() out os.path.join(proj_dir, name .psz) doc.save(out) print(完成:, out)Metashape.Document()直接实例化是手册明确支持的——「Multiple Document instances can be created simultaneously if needed」。addChunk()建空 chunkaddPhotos接收路径列表内部会按文件创建 Camera 对象。downscale2在批处理里比 1 更务实速度快一倍、精度损失可接受先出粗对齐结果再决定哪些项目值得精修。sorted那一步别省文件系统返回顺序不保证稳定排序后同样的输入每次跑出同样的结果排查问题时才有可比性。4.2 处理链的参数分级与失败重试批处理最怕的是某个项目中途失败把整个队列带崩。我的做法是把处理链拆成阶段函数每阶段包 try/except失败记录到日志继续下一个。参数上做分级粗对齐用downscale4精修再downscale1重跑。下面是一个带阶段日志的片段import traceback def run_stage(chunk, stage_name, func): try: func() print([OK], stage_name) return True except Exception: # 记录完整堆栈方便事后定位是哪个项目哪一步翻车 print([FAIL], stage_name) traceback.print_exc() return False # 用法阶段失败不中断继续下一阶段或下一项目 run_stage(chunk, match, lambda: chunk.matchPhotos(downscale4)) run_stage(chunk, align, chunk.alignCameras) run_stage(chunk, depth, lambda: chunk.buildDepthMaps(downscale4))lambda包一层是为了把带参调用塞进统一接口traceback.print_exc()输出完整调用栈比只打印异常消息有用得多——Metashape 的 RuntimeError 消息有时很笼统堆栈能告诉你到底卡在哪个 API。阶段之间是否要继续取决于业务对齐失败后面建云建网格基本没意义可以判断align返回 False 就continue跳过该项目但深度图失败有时网格还能用别的路径出可以继续。4.3 导出环节模型、正射、DEM 的格式选择手册功能列表里明确列了导出模型、纹理、正射影像、DEM。导出 API 在摘录里没展开细节但按这个模块的组织方式常见做法是chunk.exportModel、chunk.exportOrthomosaic、chunk.exportDEM这几个方法格式参数用枚举或字符串。实操上要注意两点一是导出前确认对应产物已经生成没建网格就导模型会报错二是正射和 DEM 的分辨率参数跟项目坐标系挂钩地理坐标系下单位是米局部坐标系下是任意单位搞混了导出的图尺寸会离谱。批处理里我一般把导出放在最后单独一个阶段前面任何一步失败就跳过导出避免产出半成品文件污染下游。5. 避坑与排查那些手册不会明说但一定会遇到的坑5.1 坑一Standard 版导入模块直接失败现象脚本在控制台里import Metashape报ModuleNotFoundError或者Metashape.app属性不存在。原因Python 脚本功能只在 Professional 版提供Standard 版根本没有这个模块。解决确认授权版本Standard 版只能走 GUI 手工操作没有脚本替代方案。团队协作时把这条写进环境检查清单别让新人拿着 Standard 版折腾半天。5.2 坑二命令行 -r 跑完进程不退出现象用-r跑批处理脚本脚本逻辑都执行完了但进程一直挂着不返回任务计划里显示「运行中」。原因-r只负责执行脚本不负责退出应用GUI 进程会一直等用户操作。解决脚本末尾显式调Metashape.app.quit()或者在外部调度层加超时强杀。注意quit()前确保doc.save()已经完成否则可能丢结果。5.3 坑三downscale 参数理解反了导致精度崩现象对齐结果稀稀拉拉连接点很少重建出来缺块。原因把matchPhotos的downscale当成「降采样倍数越大越精细」实际是数值越大图像被缩得越狠、特征越少。解决精修用 1 或 2快速预览用 4 或 8批处理先粗后精两遍跑别一上来就用 8 还指望出好模型。5.4 坑四多 chunk 项目里 doc.chunk 取错对象现象脚本对 A 区域的处理结果跑到了 B 区域的项目里或者报「chunk 没有相机」。原因doc.chunk返回当前激活 chunkGUI 里点选过哪个就是哪个脚本无法感知你的意图。解决显式用doc.chunks[i]或按label匹配取 chunk处理前打印chunk.label确认别依赖隐式激活状态。5.5 坑五标定赋值挂错层级现象camera.calibration calib报属性错误或者赋值成功但处理结果没变化。原因标定挂在camera.sensor上不是camera上同一 sensor 多相机共享内参改一个全变。解决用camera.sensor.calibration批量赋值前先确认相机分组是否符合预期不同镜头别共用一个 sensor。6. 用 captureView 做结果快照与脚本自检手册里ModelView.captureView和OrthoView.captureView这两个方法容易被忽略但它们在自动化验收里很好用。参数是width、height、transparent、hide_items返回一个Image对象。批处理跑完几十个项目人工一个个打开看模型不现实用脚本在每个项目结束时抓一张模型视图快照存成图片事后翻图就能快速筛出明显翻车的项目——比如网格破面、纹理错位、模型整个是空的一眼就能看出来。import Metashape doc Metashape.app.document chunk doc.chunk # 切到模型视图设置着色模式便于观察几何 view Metashape.app.model_view view.view_mode Metashape.ModelViewShaded # 抓 1024x768 快照透明背景关掉隐藏辅助项让画面干净 img view.captureView(1024, 768, False, True) img.save(rD:\snapshots\%s_preview.png % chunk.label)view_mode设成ModelViewShaded看几何最直观ModelViewTextured看纹理贴图有没有接缝ModelViewWireframe查网格密度。hide_itemsTrue会把相机视锥、标记这些辅助元素藏掉快照更像成品预览。img.save的路径要提前确保目录存在Metashape 不会自动建目录路径不存在直接抛异常。我一般会在批处理开头统一os.makedirs建好快照目录。另一个自检手段是用Calibration.error算重投影误差对齐完成后遍历相机算一遍平均误差超过阈值比如 1.5 像素就在日志里标红该项目。这比肉眼看连接点靠谱也能量化对比不同downscale参数的效果。手册里error(point, proj)接收三维点和像素坐标返回二维误差向量配合chunk.tie_points和相机投影矩阵可以批量算具体遍历方式取决于项目数据结构思路是先取连接点、再逐相机投影、最后统计。从那以后我每次搭批处理管线都会在第一个项目上先手动跑一遍完整流程、抓快照、看误差确认参数组合没问题再放开跑全量——这个习惯帮我省过好几次因为downscale设错导致整批返工的麻烦。希望帮到你。本文还有配套的精品资源点击获取