← 主页 胡洋的博客
← 返回博客首页

InsightAT:Simple Automated SfM

Abstract

InsightAT 面向输入信息不完整、影像规模增长和计算资源异构条件下的自动化稀疏重建。系统将检索模型、特征阈值和内参初始化等判断放入流程内部,用户可以在任务可拆分、结果可检查和失败可恢复的前提下完成 SfM。为此,系统采用任务描述驱动的阶段式架构,以独立 CLI 和文件产物连接计算阶段,使用 IDC、SoA 和异步 I/O 管理大规模中间数据,并通过 Electron UI 提供面向用户的工作流入口。

算法层以 SIFT 为基础,采用全局降阈值与逐影像二次降阈值保留弱纹理影像的候选特征,以低分辨率像对检索、GPU 级联哈希匹配和 F 矩阵验证兼顾候选召回与匹配效率;在此基础上,系统自动建立相机分组,从 F 矩阵搜索焦距初值,并通过多假设初始化、增量注册、可逆 Track 状态、渐进式内参优化以及 Global/Local BA 调度提高重建稳定性。当前版本已经形成可运行的单机增量式稀疏重建系统;面向超大规模场景的自动分块、跨块合并和跨机器调度仍属于后续扩展方向。

关键词:自动化 SfM;稀疏重建;任务化架构;GPU 级联哈希;焦距估计;增量式重建;可恢复轨迹;光束法平差

1. Motivation

InsightAT 从 SfM 系统的组织方式入手,重新设计一套面向自动化重建的计算流程。

现有的开源实现已经包含了大量成熟的几何算法,但许多系统主要围绕单机运行、交互式使用或研究实验展开:中间状态依赖长期运行的进程或中心化数据结构,计算阶段难以自然地拆分、并行和重试;同时,图像检索、相机分组、焦距估计以及各种阈值往往需要用户根据数据反复调整。这些方案能够完成重建,但在任务隔离、失败恢复和零配置运行方面仍有进一步适应生产环境的空间。

InsightAT 的目标是面向云端超大规模三维重建,构建一个自动化、鲁棒且高性能的 SfM 系统。这里的“Simple”主要指用户侧简单:用户不需要理解内部的算法选择,也不需要为每一批数据手工调整大量参数;系统内部则负责完成这些判断,并在不确定输入下保持稳定。围绕这一目标,InsightAT 的总体设计包含以下四个方面。

1.1 面向云端的任务化架构

InsightAT 将计算组织为一组可以独立执行的任务,每个任务由输入文件、执行命令、参数和输出文件定义。每个算法模块都可以作为命令行程序处理一个批次的数据,并根据算法规模拆分为任务准备、批量执行和结果合并三个阶段。

模块之间通过文件交接,任务可以在单机上顺序执行,也可以在多个进程或多台机器上并行执行;某个批次失败时,只需要重跑受影响的部分。任务调度、队列管理和机器分配可以交给外部系统,SfM 算法本身只需要提供清晰、稳定且可复用的任务边界。

1.2 面向终端用户的自动化与鲁棒性

SfM 包含图像关联、特征提取、两视图几何、轨迹构建、相机注册、三角化和光束法平差等多个环节。每个环节都有大量参数,而这些参数之间还会相互影响。若把这些选择全部交给用户,系统就很难称为一个真正面向生产的自动化工具。

因此,InsightAT 将复杂性留在系统内部:提供默认的处理流程、自适应的策略组合和必要的回退机制,使用户在没有 EXIF、图像弱纹理、相机混用、关联不完整或初始像对不理想等情况下,也能直接运行完整流程。算法模块仍然保留丰富的参数接口,以便调试、评测和特殊场景使用;但默认路径不要求用户参与这些选择。

这种设计会增加部分计算量,也可能牺牲理想数据上的峰值性能。InsightAT 将生产环境中的稳定完成率放在理论吞吐之前,并把鲁棒性落实到整个 pipeline,贯穿候选检索、几何验证和增量优化。

1.3 计算与数据通路的高性能

三维重建同时受到计算量和数据规模的限制。算法内核需要利用并行硬件,数据通路则需要避免大文件读写成为瓶颈。因此,InsightAT 在计算和 I/O 两个层次同时进行优化。

这些设计共同构成了系统的基础设施:CUDA 或 GLSL 负责计算效率,IDC、SoA 和异步 I/O 负责数据效率,任务边界则负责把这种效率扩展到并行执行环境。

1.4 面向超大规模场景的 SfM 路线

全局式 SfM 通常更容易建立大范围的关系,也具有较好的并行潜力;增量式 SfM 则能够逐步检查相机注册、三角化和优化结果,在不确定输入下更容易控制和恢复。InsightAT 采用分阶段路线:先以增量式 SfM 建立可靠基座,再向混合式和层级式重建扩展。

1.0 版本首先实现一个完整、稳定的增量式 SfM 内核,把它作为后续系统扩展的可靠基座。对于超大规模场景,后续版本将在此基础上引入混合式或层级式策略:局部区域继续使用增量式方法进行稳健重建,更大范围的关系和合并则通过并行化、分层处理和全局优化来解决。这样既保留增量式方法的可检查性和鲁棒性,也为未来的规模和效率留出空间。

后续章节将先介绍支撑这些目标的系统基础设施,包括任务拆分、批量并行、任务合并、IDC、SoA、命令行接口、异步 I/O 以及 UI 与 CLI 的关系;然后再进入 SfM 具体算法,说明这些系统设计如何落实为图像关联、初始化、轨迹管理、三角化和 BA 中的具体策略。

2. System Philosophy

上一章说明了 InsightAT 面向云端、自动化、鲁棒和高性能的目标。本章先给出系统层面的基本判断:计算的边界是什么,任务如何组织,算法与运行环境如何解耦,以及在没有人工干预时应该如何理解鲁棒性。

这些判断决定了后续的 CLI、IDC、SoA、异步 I/O 和 UI 设计,也规定了具体 SfM 算法需要遵守的运行条件。InsightAT 的核心是为一次可执行、可保存、可并行和可恢复的 SfM 计算建立清晰边界。

2.1 File is the boundary

在 InsightAT 中,文件是不同阶段之间最稳定的交接边界。一个阶段读取明确的输入文件,按照指定的命令和参数执行计算,并写出明确的结果文件。阶段完成后,结果文件就成为下一阶段的输入;下游程序不需要继承上游进程中的对象、指针或全局内存状态。

文件边界首先使中间状态能够被保存。程序退出之后,已经生成的结果仍然存在,后续流程可以从已有产物继续,而不必从头开始。文件也使阶段结果具备可检查性:开发者可以单独查看某一阶段的输入、输出和日志,判断问题发生在图像关联、特征、匹配、轨迹还是增量重建阶段。

文件边界还决定了失败处理的粒度。一个完整流程失败时,可以定位到具体阶段;一个批次失败时,可以只重跑该批次;结果合并失败时,可以保留已有的局部结果并重新执行合并。对于未来的云端运行环境,外部调度器也可以依据文件、命令和参数安排执行,而不需要理解 SfM 内部的相机、轨迹和三维点关系。

这里的文件具有明确的结构和语义。IDC 负责描述数据块的类型、形状、偏移、长度和含义,二进制块负责保存实际数据。文件因此同时承担阶段通信、任务状态保存、调试和失败恢复等职责。

2.2 Task is the unit of computation

InsightAT 将任务作为计算和调度的基本单位。一个任务至少包含输入数据、执行命令、参数和预期输出;输入既可以是全部数据,也可以是任务准备阶段划分出的一个批次。

根据算法规模和数据特点,一个模块通常可以组织为以下三个逻辑部分:

任务准备与拆分(可选) → 批次处理(必须) → 结果合并(可选)

任务准备负责生成清单、划分批次和准备参数;批次处理负责执行实际算法;结果合并负责把多个批次的结果整理成下游阶段可以读取的产物。模块是否拆分、是否合并,取决于数据规模和算法特点:小规模数据可以直接执行一个任务,适合并行的模块才需要拆分,存在多个局部结果时才需要合并。

任务化组织的价值在于,它把计算从一个不可分割的长流程变成一组可以观察、保存、并行和重试的单元。小数据集可以在单机上顺序执行;单机环境可以使用多个进程或线程;未来的外部任务系统也可以将不同批次分配到不同机器或不同类型的计算资源上。某个批次失败时,不需要让整个阶段从头开始。

任务边界还为 InsightAT 2.0 的大场景路线留下接口。未来的局部重建、跨块匹配、模型对齐和模型合并,都可以继续使用输入文件、批次任务和结果文件的组织方式。当前系统尚未实现跨机器调度和大场景合并,但这些未来能力不需要改变底层算法模块的基本调用形态。

2.3 Algorithm–Scheduler Decoupling

算法模块不应该知道自己由哪个调度器启动、由哪个界面调用,或者运行在哪一台机器上。它只需要理解自己的输入文件、参数和输出文件,并在给定资源范围内完成一个任务或一个批次。

因此,InsightAT 将 SfM 流程拆分为多个独立 CLI。isat_sfm 的职责是组织阶段顺序、启动子进程、传递参数、转发进度并记录耗时;它不持有贯穿整个重建过程的全局算法状态,也不实现特征提取、匹配、几何估计或 BA。具体算法位于各自的命令行模块中,模块之间通过文件产物连接。

这种设计将算法和调度器解耦。当前调用方可以是单机命令行程序,也可以是桌面 UI、服务端接口、RPC 或外部任务平台。调用方式可以改变,但命令、输入输出文件和任务边界保持稳定。UI 的职责是创建任务、启动处理、跟踪进度、查看日志和展示结果,算法实现仍由独立的 CLI 负责。

当前 InsightAT 提供的是适合调度的算法程序和任务边界。任务队列、资源管理、跨机器调度、对象存储和服务端重试属于外部运行环境;这种职责划分让算法内核保持独立,不绑定某个特定的调度器、云平台或 UI 框架。

2.4 Automation changes the definition of robustness

交互式工具可以在中间步骤停下来,让用户检查匹配、修改焦距、指定相机分组、替换初始像对,或者重新运行某个阶段。自动化系统没有这个前提:用户通常只提供影像并启动流程,程序需要自己完成主要判断。因此,自动化不仅减少了用户操作,也提高了系统对不确定输入的责任。

在 InsightAT 中,鲁棒性同时体现在结果质量、过程判断和失败处理上:

这也是 InsightAT 选择增量式 SfM 作为 1.0 基础的重要原因。增量过程可以逐步检查相机注册、PnP、三角化和 BA 的结果,在每一步拒绝不可靠状态,也可以在后续条件变好时重新评价。图像关联中的召回补全、未知焦距下基于 F 的判断、多假设初始化、轨迹和观测的可逆状态,以及保守的 BA 调度,都是这一系统思想在具体算法中的体现。

自动化通常会带来额外计算、更多候选和更复杂的状态管理。InsightAT 将这些复杂性放在系统内部,优先保证未知输入下的稳定完成;“Simple”指的是用户侧的使用方式,而非算法内部的实现复杂度。

3. Architecture

本章把上一章的系统思想落实为具体架构。InsightAT 由 CLI、文件、任务和数据结构组成一条处理链路。每个阶段负责一类明确的工作,阶段之间通过文件交接,阶段内部再根据数据规模选择顺序处理、批量处理或并行处理。

如图 1 所示,InsightAT 的架构可以从上到下分为五个相互衔接的部分:用户入口与输入、任务编排层、算法执行层、数据交接与计算运行时、阶段产物与最终结果。

整体关系如图 1 所示。图中同时展示了用户入口、任务编排、独立算法阶段、数据交接和计算后端之间的关系。

图 1 InsightAT 总体架构

图 1 InsightAT 总体架构。当前执行形态是单机阶段式流水线;任务、CLI 和文件边界为后续外部调度保留了扩展接口。

这五个部分共同构成一条从任务启动到结果查看的处理链路。最上层的 Electron UI、CLI 和影像目录提供用户入口与任务输入;任务编排层负责创建任务、安排阶段顺序、传递参数并管理执行状态;算法执行层由多个独立 CLI 阶段组成,完成特征、匹配、几何、轨迹和 SfM 等计算;数据交接与计算运行时使用 IDC、JSON、SoA、异步 I/O 以及 CUDA、GLSL/EGL 和 CPU 后端,分别组织阶段数据、内存访问、数据流动和实际计算;最下层则保存阶段产物、日志、进度和最终重建结果。

图中的实线箭头表示主要的数据和控制流,数据交接与计算运行时则贯穿算法阶段,为每个阶段提供统一的数据格式、内存布局、I/O 机制和计算后端。各部分通过明确的输入、输出和状态边界协作,阶段之间不需要共享贯穿全流程的内存状态。

这五个部分通过任务、命令、文件和状态事件连接。核心算法不依赖具体的界面或调度方式,只要遵守这些边界,同一套算法既可以由命令行直接调用,也可以由 Electron UI 或其他上层系统调用。这样,系统的复杂性被保留在内部,而用户面对的是一个相对简单、连续的重建流程。

3.1 CLI pipeline

3.1.1 流水线阶段

InsightAT 的 SfM 流程由多个独立的命令行程序组成。当前默认流程可以表示为:

create
  → extract
  → match
  → tracks
  → seed_eval
  → incremental_sfm
  → undistort(可选)

当前默认流程以单机执行为基本形态:一次 isat_sfm 运行在一台机器上,由驱动器按顺序启动各阶段;阶段内部根据计算特点使用线程、OpenMP 或 GPU 并行。阶段之间通过任务和文件连接,因此同样的边界也适合进一步拆分为批次进行调度。

各阶段遵循一般 SfM 的数据顺序,但每个阶段都有清晰的输入、输出和任务边界:

3.1.2 任务快照与续跑

其中,create 会依次完成项目创建、图像组导入、相机内参估计、任务快照创建和输入清单导出。create-at-task 将当前项目冻结为一个 ATTask,随后 extract -t <task-id> 和 intrinsics -t <task-id> 只从这份快照读取数据,生成本次重建使用的 images_all.json 和逐图相机内参。这样,项目在任务创建之后发生的修改不会悄悄改变已经开始的重建。

GUI 的续跑流程也依赖这个任务契约:先创建任务快照,再从任务快照导出输入,之后使用 isat_sfm --existing-task 继续执行。--existing-task 可以跳过项目准备阶段,直接复用已有的输入清单。这使一次重建的输入、图像索引和相机信息保持稳定,也是阶段能够独立重跑的前提。

完整流程由 isat_sfm 负责编排。它启动各个子进程,传递输入路径和参数,转发结构化进度并记录阶段耗时;具体算法则位于对应的 CLI 模块中。isat_sfm 不保存贯穿整个重建过程的全局算法状态,也不实现特征、匹配、几何估计或 BA。

3.1.3 CLI 接口

从接口角度看,CLI 之间通过几类稳定接口协作:

这几类接口共同构成 CLI pipeline 的通信协议。它们都是可以序列化、保存和检查的外部状态,因此 UI、命令行脚本和外部任务系统都可以用不同方式启动同一套算法,而不需要改变算法模块本身。

每个阶段既可以处理完整输入,也可以处理任务准备阶段划分出的一个批次。因此,小规模数据可以在单机上顺序运行;适合并行的阶段则可以同时启动多个 CLI。阶段之间不依赖共享地址空间,前一阶段的输出文件就是后一阶段的输入文件。这样,流程图中的每条边同时也是一条可保存、可检查和可重试的数据依赖。

3.1.4 工作目录和阶段产物

一次运行的主要工作目录大致如下:

<work>/
├── project.iat
├── images_all.json
├── camera_estimate_meta.json
├── feat/                       # 全分辨率特征
├── feat_retrieval/             # 候选对发现用的低分辨率特征
├── match/                      # 候选对、匹配结果和 .isat_match
├── geo/                        # 几何验证结果和 .isat_geo
├── tracks/tracks.isat_tracks
├── seed_eval_all/              # 初始像对评估结果
├── incremental_sfm/            # 位姿、轨迹和稀疏模型
├── sfm_interval/               # 可选的增量过程快照
├── logs/run_<timestamp>/
└── sfm_timing.json

这些目录构成流水线的阶段产物。images_all.json 固定图像身份,*.isat_feat、*.isat_match、*.isat_geo 和 *.isat_tracks 负责保存二进制中间数据,poses.json、Bundler 和 COLMAP 稀疏目录负责保存最终或中间重建结果,日志和耗时文件则负责记录执行过程。

3.2 IDC

3.2.1 数据交接目标

阶段之间的数据使用 IDC(InsightAT Data Container)进行组织。IDC 参考了 glTF/glb 一类“描述信息加二进制数据载荷”的设计,将数据的结构描述与实际数据分开保存。

IDC 的描述部分记录数据块的名称、数量、类型、形状、偏移、长度和语义信息;二进制部分保存特征、匹配、几何和轨迹等大块数据。读取程序先解析描述信息,再根据需要定位和读取数据块,而不需要继承上一个进程中的内存对象或全局状态。

3.2.2 物理文件布局

在当前实现中,一个 IDC 文件的物理布局可以概括为:

┌────────┬─────────┬───────────┬────────────────┬──────────┬─────────┐
│ "ISAT" │ version │ json_size │ JSON 描述符    │ padding  │ payload │
│  4 B   │  u32    │    u64    │    UTF-8       │ 对齐到 8B │ 二进制  │
└────────┴─────────┴───────────┴────────────────┴──────────┴─────────┘

描述符中的每个数据块需要声明 name、dtype、shape、offset 和 size。头部和数据载荷之间使用 8 字节对齐,便于 SIMD 访问、GPU 上传和跨平台读取。当前工作目录中常见的 IDC 产物包括 .isat_feat、.isat_match、.isat_geo 和 .isat_tracks;不同产物通过描述符声明各自的数组结构,阶段之间不依赖 C++ 对象布局。

3.2.3 典型数据产物

例如,特征文件可以保存关键点和描述子,匹配文件可以保存特征索引、像素坐标和距离,几何文件可以保存通过 F/E/H 验证的对应关系,轨迹文件则保存轨迹、观测和 view graph。像素坐标在匹配和几何阶段以像素域保存,后续在需要使用内参时再进行归一化。这种安排让不同阶段可以按照自己的计算方式读取同一份数据。

3.2.4 IDC 的系统作用

IDC 的作用是为阶段间交接建立稳定的数据边界,具体体现在:

IDC 与任务系统是配套的。任务描述决定某个 CLI 如何执行,IDC 文件决定这个任务产生什么数据。前者定义“做什么”,后者定义“数据如何交接”,二者共同构成了可拆分和可恢复的计算边界。

3.3 SOA

3.3.1 为什么采用 SoA

SfM 的数据访问具有多种模式:特征提取和匹配按影像访问,轨迹构建按对应关系访问,增量重建按轨迹和相机访问,BA 按变量块和观测关系组织数据。若所有属性都封装在大量相互关联的对象中,连续访问、批量处理、状态更新和 GPU 传输都会变得困难。

因此,InsightAT 的内部数据结构倾向于采用 SoA(Structure of Arrays)布局。坐标、索引、影像编号、特征编号、观测属性和状态信息分别存储在连续数组中,算法可以只读取或更新自己需要的字段。例如,轨迹数据可以分别保存三维坐标、轨迹状态、观测范围;观测数据则分别保存所属影像、特征序号、像素坐标和观测状态。

3.3.2 TrackStore 与稳定索引

当前的 TrackStore 是 SoA 设计最典型的例子。轨迹坐标以连续数组保存,轨迹和观测分别拥有自己的状态标志,观测通过扁平数组和 obs_track_id 关联到轨迹;同时维护从图像到观测下标的反向索引。这样,删除某一幅图像上的外点观测时,不需要扫描全部轨迹,也不需要重新组织整个对象图。

图像身份也被设计成稳定的稠密索引:images_all.json 中 images[] 的数组下标就是图像在本次任务中的身份,后续阶段使用同一套 image_index。相机索引则通过 image_to_camera_index[] 关联。系统不在阶段之间反复建立外部 ID 到内部 ID 的映射,从而减少任务快照、IDC 数据和求解器之间的身份转换。

3.3.3 连续访问与批量计算

SoA 的价值主要体现在三个方面:

  1. 连续数组适合顺序访问和批量计算,能够减少对象跳转带来的访问开销;
  2. 不同算法只需要读取相关数组,避免加载不必要的字段;
  3. 数组可以更直接地传输到 GPU,也更容易与批量 I/O 对接。

3.3.4 状态位与可逆更新

InsightAT 将 SoA 与状态位或 mask 结合使用。三维点和观测的有效性通过状态标记控制。剔除一个观测、暂时关闭一个三维点或在后续条件变好时恢复它,通常只需要修改状态数组,无需搬移整条轨迹或重建完整的对象关系。

当前轨迹状态包含“有效”“需要重三角化”“已经三角化”和“跳过 BA”等信息;观测状态除了“有效”之外,还可以标记为“可恢复”。由重投影误差造成的暂时剔除可以在相机内参明显变化后重新评价,而由负深度、三角化几何或 PnP 外点等原因造成的剔除不会被自动恢复。状态分类让可逆性具有明确的算法语义,并区分了暂时失效与永久失效。

这种设计会增加状态信息和存储空间,但换来了增量重建所需要的可逆性。轨迹结构可以在整个过程中保持相对稳定,算法在不同阶段只改变数据的有效状态。这为后续的三角化、重三角化、观测剔除和子集 BA 提供了共同的数据基础。

3.4 Async I/O

3.4.1 加载、计算与写出

对于三维重建而言,端到端速度同时取决于计算和数据流动。影像、特征、匹配和轨迹文件通常较大,如果计算必须等待读取或写出,CPU 和 GPU 都会出现空闲。因此,I/O 是计算链路的一部分。

InsightAT 的阶段通常按照“加载—计算—写出”的方式组织:

加载下一批数据 → 计算当前批次 → 写出上一批结果

加载过程准备下一批数据,计算过程处理当前批次,写出过程保存上一批结果。三个阶段通过有界队列连接,队列满时限制继续加载,避免为了追求吞吐而无限增加内存占用。这样,I/O 和计算可以在受控的资源范围内重叠。

3.4.2 批次与背压

阶段内通过 I/O 线程参数控制数据通路,并在特征、匹配、几何和轨迹等阶段按照数据规模进行批量处理。BA 使用独立的线程参数,增量主循环、轨迹状态管理和 Ceres 求解主要运行在 CPU 上。异步 I/O 与 GPU 加速分别作用于数据流动和计算过程,二者共同构成端到端的性能路径。

批次大小需要在吞吐、内存和设备传输之间取得平衡。批次过小会增加调度和 I/O 次数,批次过大则会增加内存压力和失败重试的成本。因此,几何验证、级联哈希匹配、轨迹构建等阶段根据各自的数据规模选择批处理方式。

3.4.3 计算后端与 I/O 协同

当前计算后端大致遵循 CUDA、GLSL/EGL、CPU 的降级路径。特征提取、级联哈希匹配和 F/E/H 几何验证在具备 CUDA 时默认使用 GPU;无 CUDA 或显式选择时可以使用 GLSL/EGL 或 CPU 路径。增量 SfM 主循环仍由 CPU 负责,BA 主要使用 CPU Ceres,稀疏线性求解器在环境具备条件时可以使用 CUDA_SPARSE,否则回退到其他稀疏或迭代求解器。

异步 I/O 还与 SoA、IDC 和 GPU 后端相互配合:IDC 负责描述和保存批次数据,SoA 让批次内的数据能够连续访问和传输,GPU 或 CPU 负责计算,有界队列负责在不同处理速度之间形成背压。只有这几部分共同工作,单独加速某一个计算 kernel 才不会被数据路径的等待抵消。

3.5 UI as the Workflow Layer

3.5.1 UI 作为工作流入口

InsightAT 当前已经提供 Electron UI。它是 CLI pipeline 的桌面工作流入口,负责创建或打开工作目录、添加影像目录、启动 SfM、跟踪进度、查看日志以及打开重建结果。用户通过 UI 操作项目和任务,但实际的 SfM 计算仍然由独立的 isat_* CLI 完成。

Electron UI 通过调用 CLI 与算法内核通信,算法实现仍位于独立的 CLI 进程中。当前 GUI 的实际工作流包括创建项目、添加图像组、估计相机内参、创建 ATTask 快照、从快照导出输入,以及调用 isat_sfm --existing-task 执行或续跑重建。CLI 的输入文件、参数和输出文件构成 UI 与算法之间的接口;任务状态和重建结果则由工作目录中的阶段产物保存。用户改用命令行时,仍然可以执行同一套核心流程。

3.5.2 进度、日志与错误

GUI 通过子进程调用 CLI,并读取 CLI 的机器可读事件。CLI 的 stdout 只输出带 ISAT_EVENT 前缀的 NDJSON 事件,日志、警告、错误和文本进度走 stderr;退出码表示阶段是否成功。这个约定避免第三方库的普通输出污染机器可读通道,也使 GUI 可以可靠地显示阶段进度和错误信息。

3.5.3 结果查看与内核分离

重建结果查看也遵循同样的分工。Electron UI 可以启动独立的 sfm-viewer,通过 Electron + Three.js/WebGL 读取 COLMAP 稀疏目录,显示稀疏点云、相机视锥和轨迹;查看器负责解析和可视化,不负责重新计算 SfM。UI、CLI 和 viewer 可以各自演进,但它们围绕同一套任务文件和结果文件协作。

这种分离让 UI 成为算法的调用方和观察者。界面关闭后,已经生成的阶段文件仍然存在;命令行可以直接重跑或检查任务;未来增加其他调用方式时,也只需要复用已有的 CLI、文件和任务边界。

3.6 架构的演进边界

InsightAT 以单机、单卡优先的阶段式流水线作为当前基础,并将更大规模能力拆分为可以独立演进的扩展方向。任务队列和跨机调度属于执行层的扩展,大场景分簇、Sim3 合并、位姿图优化和跨块全局 BA 属于场景层的扩展;这些能力都可以沿用现有的 CLI、任务快照和阶段产物边界。

当前的计算路径采用分层后端:特征、匹配和几何阶段提供 CUDA 加速,并通过 GLSL/EGL 和 CPU 路径适应不同运行环境;增量 SfM 主循环和 BA 以 CPU 实现为主。后续的分布式调度、跨块模型合并和全 CUDA 增量 SfM,可以沿着现有的 CLI、任务快照、IDC、SoA 和阶段产物边界继续扩展。

4. Building a Robust Automated SfM

自动化 SfM 的难点在于输入信息不完整时仍然建立可靠关系并继续向前推进。影像可能缺少可靠焦距,候选图像对可能检索不完整,相机可能混用,初始像对的选择也可能不够稳定。InsightAT 将这些不确定性放在流程内部处理,减少用户对每个判断的介入。

本章按照处理流程介绍构建自动化 SfM 的五个入口策略:特征提取、自动建立相机分组、候选图像对检索、稳定估计焦距,以及用多假设选择增量重建的起点。这些策略共同决定了后续增量 SfM 的输入质量。

4.1 Feature Extraction: Global Threshold Lowering and Per-Image Retry

为覆盖弱纹理、低对比度和不同成像条件,InsightAT 使用 SIFT 作为基础局部特征。描述子默认采用 RootSIFT 归一化,提取后端优先使用 GPU;在 CUDA 不可用时,可以切换到 GLSL/EGL 或 CPU 路径。特征提取阶段采用“全局降阈值 + 逐影像二次降阈值”的两级机制,兼顾基础召回率和弱纹理影像的补救。

第一层是全局降阈值。默认流程向特征提取阶段传入的峰值响应阈值为 0.0067,使梯度较弱但仍可能包含稳定结构的区域产生候选特征,避免系统在最早阶段就因为统一阈值过高而丢失纹理信息。

第二层是逐影像的二次降阈值。系统检查每幅影像在全局阈值下得到的特征数量;如果特征数仍低于 10000,则只对这幅影像把峰值阈值再降低一个数量级,即除以 10,然后重新提取。重新提取的影像会在元数据中留下标记,供后续候选图像对检索阶段使用。

与对全部影像统一使用更低阈值相比,这种策略把额外的计算量和潜在噪声限制在确实需要的影像上。全局降阈值提供基础召回率,逐影像二次降阈值负责补救弱纹理输入;被标记的影像还会触发后续候选关系补全。

特征提取阶段同时承担两个职责:生成后续匹配所需的局部描述,并识别需要特殊召回策略的弱纹理影像。阈值判断通过元数据传递到候选检索阶段,形成从特征数量检查到候选像对补全的连续链路。

4.2 Automatic Camera Grouping

4.2.1 分组的必要性

增量 SfM 通常需要让同一相机的影像共享合理的内参。不同相机、不同分辨率或不同成像条件混在一个相机模型中,优化会把相机差异错误地归入焦距和畸变,随后结构和位姿也会受到影响。

相机分组直接影响重建稳定性,也是焦距估计的前置条件。不同相机的视场和内参需要在各自的组内统计和优化。

4.2.2 无需用户建立相机表

InsightAT 默认先按影像目录组织图像组,再结合厂牌、型号和实际分辨率等信息自动拆分。焦距不作为主要分组键,因为同一相机的 EXIF 焦距可能存在小幅变化,把焦距直接加入分组会把本应共享参数的影像拆散。

用户只需要提供影像,系统负责准备相机组和初始内参。评测和特殊数据仍然可以通过 CLI 指定手工分组,默认流程不要求用户预先建立相机表。

4.3 Candidate Image Retrieval: Preserve Potential Relations

4.3.1 候选图像对检索的目标

候选图像对检索的目标,是尽可能找到真实存在重叠关系的影像对。若检索阶段过早依赖某个模型或单一相似度判断,漏掉的候选关系不会在后续特征匹配和几何验证阶段重新出现。对于自动化 SfM,漏检可能使视图图断裂,减少可用于相机注册的三维支持,造成增量过程不稳定,甚至导致部分影像无法注册。多计算一些候选像对主要增加匹配和几何验证的计算成本,通常不会直接破坏重建。

因此,InsightAT 在候选检索阶段优先保证召回率,再利用特征匹配和几何验证控制错误关系。候选集合保留足够的余量,避免潜在的真实关系在早期被永久丢弃。经过全分辨率匹配和几何验证后,保留下来的有效关系才进入视图图和后续 SfM。

InsightAT 当前采用 retrieval-by-matching 的方式进行候选发现:先在低分辨率特征上发现候选图像对,再对候选关系执行全分辨率特征匹配和几何验证。因此,本节讨论的是候选图像对检索,不把它与最终的特征匹配或图像关系图混为一谈。

4.3.2 为什么不把全局描述子或深度检索作为默认路径

VLAD、NetVLAD、词袋/词汇树以及各种深度学习检索模型,都是成熟的候选图像检索技术。它们通常先把一幅图像压缩为全局描述,再通过索引快速找出相似图像,能够显著降低大规模数据上的候选搜索成本。InsightAT 的默认路径优先保证跨场景的稳定性和召回率,因此采用基于局部特征匹配的候选发现方式。

全局描述子和学习式检索模型对数据分布、训练数据、成像条件和候选数量都有一定依赖。输入图像可能来自不同相机、不同成像尺度、不同光照和不同场景,也可能包含弱纹理、重复纹理、季节变化或较大的视角差异。一个在某类数据上表现良好的模型,换到另一类数据后可能改变候选排序;当系统只保留前若干个候选时,这种排序误差就可能直接变成候选关系的漏检。

词汇树同样需要依赖特征分布和词汇表。它可以高效地组织大规模检索,但词汇表、树深、分支数和候选数量都会影响召回率。对于一个希望用户无需选择模型、无需准备训练数据、无需调整检索参数的默认流程,这些外部依赖会增加系统的不确定性。

SIFT 是具有尺度和旋转不变性的局部特征,不依赖特定场景的训练集。在低分辨率影像上直接进行像对匹配,可以从局部特征支持关系判断潜在重叠;后续的 F 几何验证再排除外观相似但没有真实几何关系的像对。对于场景类型变化较大的默认流程,这种方法具有较好的泛化能力和候选召回潜力。

小图像匹配的代价是候选搜索可能接近全量像对,计算量随影像数量增加。因此,InsightAT 采用分层处理:影像数量较少时直接全量匹配;影像数量较多时先在低分辨率上进行候选发现,再对候选像对做全分辨率匹配;级联哈希则降低单个像对内部的描述子比较成本。系统用更多的前端计算换取默认路径的稳定性。

GNSS 或其他空间先验可以作为额外的候选条件。当影像带有可靠的 GNSS 信息时,空间检索可以缩小候选范围,或用于对候选关系重新排序。但 GNSS 的可用性、精度、坐标系和时间同步质量并不总是可靠,不能成为基本 SfM 流程的必要前提。因此,GNSS 检索适合作为可选的先验和加速手段,而以小图像匹配为基础的候选发现仍然是 InsightAT 的默认底座。

4.3.3 低分辨率检索与全分辨率匹配

影像数量较少时,系统直接生成全量像对。影像数量较多时,先对影像生成低分辨率特征,在低分辨率上进行像对级别的匹配,再用 F RANSAC 验证候选关系,最后将通过验证的关系交给全分辨率匹配。

这里的穷举发生在像对层面;描述子层面的搜索由级联哈希限制候选范围,从而在扩大候选关系的同时控制匹配成本。级联哈希的具体作用和实现代价见下一节。

4.3.4 GPU 级联哈希匹配:让小图像穷举具备规模效率

低分辨率检索需要在影像对层面保持召回率,同时控制每个像对内部的描述子搜索。若每幅影像保留 mm 个 SIFT 描述子,单个像对的朴素匹配成本近似为 O(m2)O(m^2);当像对数量本身接近全量组合时,这一成本会很快成为大规模系统的主要瓶颈。降低图像分辨率只能减少部分成本,还需要进一步缩小描述子候选范围。

InsightAT 为此实现了 GPU 级联哈希匹配。系统首先将 128 维描述子通过随机投影压缩为 128 位二进制码,再使用多组相互独立的投影把描述子分配到哈希桶中。当前实现使用 6 组哈希,每组包含 28=2562^8=256 个桶;查询时优先在相同桶及必要的邻近桶中寻找候选,并将每组参与比较的候选数量限制在较小范围内。候选经过双向最近邻检查和距离比值检验后,才作为像对匹配输出;匹配数量不足的像对直接被过滤。

这种方法把“所有描述子互相比较”改成“先通过哈希桶缩小候选,再对候选计算真实距离”。GPU 路径将投影、桶内候选搜索、双向最优匹配、交叉检查和结果紧凑化组织为批量计算,并让多个像对合并进入一次或少量 kernel 调用。描述子、哈希索引和匹配结果使用连续布局,适合与 SoA 数据结构和批量异步 I/O 配合。

CPU 与 CUDA 实现共享同一组级联哈希参数和桶索引逻辑,GPU 加速只改变执行效率,匹配判据保持一致。没有 CUDA 时可以使用 CPU 或其他后端完成同一阶段;具备 CUDA 时,多个像对可以根据可用显存组成批次,下一批数据加载、当前批 GPU 计算和上一批结果写出能够重叠执行。

GPU 级联哈希使 InsightAT 能够同时保留两项通常相互冲突的性质:在小图像上进行接近穷举的候选发现,以获得较高召回率;在每个像对内部避免全量描述子比较,以控制匹配时间。没有这一层高效的匹配实现,像对层面的穷举虽然在逻辑上简单,却很难成为面向较大规模图像集合的默认检索底座。

4.3.5 候选关系的自动补全

低分辨率检索仍然可能漏掉弱纹理、视角变化较大或特征数量不足的关系。因此,系统对候选检索结果进行补全:

这些补全会增加全分辨率匹配量,但可以避免把“是否重新执行全量匹配”交给终端用户。自动化流程用前段多做一些计算,换取后续重建拥有更多恢复路径。

图 2 Candidate image-pair discovery and recall recovery

图 2 候选图像对检索流程。影像规模决定直接穷举或低分辨率检索;邻居不足和弱纹理分别触发两条召回补全路径,候选并集随后进入全分辨率匹配与几何验证。

4.4 Stable focal-length estimation under incomplete intrinsics

4.4.1 为什么焦距需要单独处理

焦距是两视图几何和后续增量重建中的关键内参。焦距过小或过大都会改变归一化坐标、两视图运动和三角化深度;但输入图像可能缺少可靠的 EXIF,或者 EXIF 中的焦距只是一个默认值。若要求用户先提供准确焦距,自动化流程的入口就被破坏;若直接相信不可靠的焦距,错误又会反过来影响匹配内点判断。

焦距估计需要设计成一个分层、延迟和可修正的过程:

  1. 不让不可靠的焦距承担过多的早期判断;
  2. 不根据单个像对直接决定整台相机的焦距;
  3. 将多个视图关系中的信息聚合起来;
  4. 在后续 BA 中逐步放开内参自由度,并允许结构和观测重新评价。

4.4.2 以 F 为主的对应关系判断

在两视图阶段,InsightAT 同时估计基础矩阵 F、本质矩阵 E 和单应矩阵 H,并检查退化情况。三者承担不同职责:

因此,匹配关系是否保留,主要依据对应关系对 F 的符合程度;E 用于已有内参条件下的运动恢复和两视图重建,H 用于退化判断。这样可以把“对应关系是否可信”和“焦距是否准确”两个问题分开,避免错误焦距直接决定哪些匹配被保留。

4.4.3 从 F 矩阵搜索焦距

焦距初值是增量 SfM 能否稳定启动的关键。焦距进入内参矩阵后,会影响像素坐标的归一化、E 矩阵的构造、相对位姿分解和三角化深度。初值偏差过大时,错误会从两视图初始化传播到相机注册、三维点生成和后续 BA,使整个增量过程变得不稳定。因此,焦距估计应在初始化阶段优先解决,并在后续优化中持续修正。

系统首先尝试利用 EXIF 中的等效焦距,并结合相机传感器信息将其转换为像素焦距,作为相机内参的先验。当图像没有 EXIF、EXIF 不完整、传感器信息无法匹配,或者 EXIF 中的焦距只是默认值时,这个先验就不再可靠。此时,系统利用已经估计出的 F 矩阵搜索焦距;当 EXIF 先验可用时,F 搜索也可以用于检查和修正该先验。

F 矩阵适合承担这一任务,是因为它描述像素坐标之间的极几何关系,不要求事先知道相机内参。对于一对共享相机模型的影像,给定候选焦距 f,构造相机内参矩阵 K(f),再计算:

E(f) = K(f)^T F K(f)

理想的本质矩阵具有两个相等的非零奇异值和一个接近零的奇异值。因此,系统在由 EXIF 先验、相机模型和图像尺寸共同确定的合理范围内进行一维搜索,使 E(f) 的前两个奇异值尽可能接近:

loss(f) = |sigma_1(E(f)) - sigma_2(E(f))|
          --------------------------------
          sigma_1(E(f)) + sigma_2(E(f))

这个过程把原本依赖用户输入的内参初始化转化为受约束的一维搜索。更重要的是,搜索过程建立在不依赖内参的 F 之上,避免使用一个未经验证的焦距去决定对应关系是否有效。每个像对只提供一个候选估计,单个像对的失败不会阻断整个流程;最终焦距还需要结合相机组内的多个像对进行聚合。

4.4.4 多像对聚合与异常抑制

单个像对的焦距估计可能受到匹配数量、视差、退化模型和错误对应的影响,因此系统不会直接把第一个估计结果写入相机模型。系统以相机分组为单位,从视图图中收集多个通过几何验证的像对,过滤退化和支持不足的估计,再对剩余候选进行聚合。

聚合让多个独立视图关系共同约束焦距,降低异常像对的影响;当有效支持不足时,系统保留已有先验或使用默认策略,避免单个不稳定估计主导整组影像。

焦距估计还应当记录来源和支持信息,例如参与估计的像对数量、有效视图范围以及候选估计的一致性。这些信息可以用于后续内参优化和异常诊断,也使焦距不再是一个无法追溯的黑盒参数。

4.4.5 渐进优化与结构恢复

从几何关系得到的焦距只是重建初期的起点。增量 SfM 开始时,系统先固定或限制内参变化;随着注册影像和可靠三维点增加,再逐步放开焦距和畸变参数。这样可以避免优化器在结构尚不稳定时,用过多的内参自由度吸收位姿误差和错误观测。

焦距发生明显改善后,之前因重投影误差被暂时抑制的观测可以重新评价,新的焦距也可以支持重三角化。焦距估计、结构优化和观测恢复因此形成闭环:

更可靠的焦距
    → 更稳定的三角化结构
    → 更准确的位姿与 BA
    → 更可靠的焦距

稳定焦距估计关注焦距在整个增量过程中的逐步收敛,并防止早期误差永久写入结构。

4.5 Multi-hypothesis initialization

4.5.1 初始像对决定增量起点

初始像对决定增量过程从哪一段运动开始。基线太小,三角化深度不稳定;视角差过大,匹配和两视图几何又可能变差。一个固定阈值无法覆盖不同的运动路径、不同重叠度和不同拍摄姿态。

初始像对的选择还受到焦距质量、轨迹支持和相机分组的影响。因此,像对得分用于生成候选,最终选择还需要经过短窗口重建验证。

4.5.2 短窗口重建与候选比较

InsightAT 根据视图图、支持轨迹、视差角和运动条件生成多组候选。每组候选都执行一个短窗口重建,检查:

最后根据短窗口重建的综合结果选择起点。匹配数量最多的像对只有在短窗口验证通过后才会被接受,失败候选则被丢弃。

4.5.3 用额外计算换取可验证的启动

多假设初始化会增加一段短暂的计算,但它把初始化从一次不可逆的决定变成了可以比较和验证的选择。对于没有人工检查的默认流程,这种额外计算能够减少错误起点对整个增量过程的影响。

5. Keeping Incremental SfM Stable

增量 SfM 是一个不断接收新影像、更新相机、生成三维点并重新评价已有观测的状态演化过程。每一步的结果都会成为下一步的输入,早期错误可能逐步传播,最终表现为相机注册失败、结构变形或 BA 发散。

稳定性设计的核心是让不确定判断拥有继续被检查和修正的机会。InsightAT 通过状态化的 Track、可控的轨迹构建、可逆的观测删除、反复三角化、渐进式内参优化和克制的 Local BA,把增量过程组织成一个可以回旋的估计系统。

图 3 Incremental SfM stability loop

图 3 增量 SfM 的稳定性循环。每次相机注册都经过候选选择、姿态解算、质量检查、三角化和 BA 调度;优化后的模型再用于状态恢复和下一轮候选选择。

5.1 Track as a State

5.1.1 Track 的生命周期

Track 通常被理解为多幅影像中相互对应的特征集合,但在增量 SfM 中,它还需要承载一个持续变化的状态。影像注册后,Track 可能被三角化;相机位姿或焦距更新后,已有三维点可能需要重新计算;某些观测可能被判定为外点,之后又可能因为模型改善而恢复。

因此,一个适合增量 SfM 的 Track 需要同时支持:

如果每次观测变化都要求重新构造完整 Track,增量更新本身就会成为主要开销;如果一开始只保留少量“干净”的观测,早期内参和结构的不确定性又可能使真正有用的信息永久丢失。

5.1.2 几何身份与有效状态分离

InsightAT 将 Track 的几何身份与当前有效状态分开保存。Track 和观测可以继续存在于同一个稳定的数据结构中,但是否参与当前三角化、PnP 或 BA,由状态位决定。这样,算法可以在不改变 Track 身份的情况下改变它的使用范围。

这种分离让 Track 同时承担匹配结果容器和增量估计状态载体两个角色。后续的 Union-Find、SoA、mask、观测恢复和重三角化都建立在这个判断之上。

5.2 Why Union-Find

5.2.1 从匹配图直接构建 Track

经过匹配和几何验证后,每个特征可以看作一个节点,通过验证的对应关系可以看作一条边。Track 构建就是在这张图上寻找连通分量。InsightAT 使用 Union-Find 直接合并这些连通关系,一次性构建初始 Track。

Union-Find 适合这个阶段的原因是结构简单、合并速度快,并且能够直接把大量像对关系转换成连续的轨迹数据。它不要求增量重建已经开始,也不需要依赖当前相机位姿去动态发现轨迹。

5.2.2 冲突处理与误差延后

错误匹配可能把本属于不同三维点的观测连接到同一个 Track 中。因此,Union-Find 并不意味着初始 Track 已经是最终正确的三维点。InsightAT 将这类不确定性延后到后续几何阶段处理:通过三角化、重投影误差、PnP、BA 和观测状态决定哪些观测继续有效。

同一幅影像中不能有两个观测属于同一个 Track。合并两个连通分量之前,系统检查它们占用的影像集合;如果发生冲突,则拒绝当前匹配边,保留两个原有分量。这样,错误处理局限在当前匹配边,不会破坏已经建立的轨迹。

5.2.3 与增量过程中动态合并 Track 的比较

使用 Union-Find 的代价是,错误的匹配边可能把原本属于不同三维点的观测连接到同一个 Track 中。一个被错误连接的 Track 可能包含多个真实结构,后续算法需要通过三角化、重投影误差、PnP、BA 和观测状态来判断哪些观测应该继续生效。Union-Find 本身只负责建立连通关系,并不保证每个连通分量已经是一个准确的三维点。

与之相对,另一种做法是在增量 SfM 过程中逐步发现和合并 Track。它可以利用当前的相机位姿、三维点和重投影关系进行判断,在模型已经稳定时,理论上能够减少错误连接并保持更纯的轨迹。但这种方法也依赖一个重要前提:当前模型必须已经足够准确,系统才有能力判断两个 Track 是否应该合并。

在增量早期,这个前提往往并不成立。此时相机位姿、焦距和三维结构都在变化,原本属于同一个真实点的观测可能暂时被分成多个 Track。如果过度依赖后续动态合并,这些 Track 可能因为模型误差一直无法合并,最终形成重复的三维点和割裂的观测支持。增量过程中不断修改 Track 的身份关系,还会带来额外的图结构维护、索引更新、数据搬移和状态同步成本,并使 SoA 布局和阶段间文件交接更加复杂。

Union-Find 的优势则是能够在几何验证之后快速、稳定地建立初始连通分量,并尽早固定 Track 的数据身份。Track 建立之后,三维点和观测的生效、失效、重三角化和恢复主要通过 mask 或状态位完成,不需要频繁重建对象关系,也不需要在每次结构变化时重新分配大量数据。这种方式特别适合批量处理、连续数组布局和后续的可恢复状态管理。

InsightAT 选择 Union-Find,基于的是速度、数据布局、状态可恢复性和几何纯度之间的综合取舍。系统先建立尽可能完整且稳定的候选 Track,再把错误连接交给后续几何验证、BA、观测剔除和重三角化处理。对于默认流程,这种“先建立关系、后判断有效性”的组织方式更适合作为稳定的基础数据结构。

5.3 Why deletion should be reversible

5.3.1 早期判断与延迟删除

增量 SfM 的早期阶段通常同时面临不稳定的焦距、初始位姿、三维结构和畸变参数。此时某个观测的高重投影误差,可能来自观测本身错误,也可能来自当前相机模型还不准确。如果根据一次 BA 的结果物理删除观测,就会把一个暂时判断变成不可逆的事实。

内参和结构之间存在相互依赖:更好的焦距可以产生更好的三角化结构,更好的结构又可以帮助估计焦距和位姿。如果早期观测已经被删除,后续模型改善就无法重新利用它们。

5.3.2 可恢复与不可恢复状态

InsightAT 使用 mask 或状态位表示轨迹和观测是否参与当前计算。由重投影误差、暂时的视差不足或早期模型偏差导致的观测,可以标记为可恢复;当焦距或相机位姿明显改善后,系统重新检查这些观测。

删除状态需要区分恢复条件。负深度、明确的几何方向错误、初始像对中的非内点以及 PnP 判定的几何外点,通常表示观测本身不满足当前模型的基本约束,因此不进入自动恢复路径。可恢复状态与永久失效状态的区分,使“可逆删除”具有明确的几何含义。

5.3.3 状态记录也是结果的一部分

由于删除只是状态变化,Track 文件可以保留观测从生效、抑制到重新评价的全过程。最终结果不仅包含最后使用的三维点和观测,也保留了模型在增量过程中如何形成的依据。这有助于调试失败案例,也使系统能够从中间状态继续处理。

5.4 Triangulation and re-triangulation

5.4.1 三角化是持续过程

三角化贯穿 Track 建立后的整个增量过程。新影像注册后,新的观测可以形成三维点;BA 更新相机位姿和焦距后,已有三维点可能需要重新计算;观测被剔除或恢复后,Track 的有效视图集合也会发生变化。

因此,三角化需要随着相机注册、局部 BA、全局 BA 和状态恢复反复执行。

5.4.2 几何条件与质量检查

新三维点需要经过多重检查:

没有通过检查的观测不必立即从 Track 中删除,可以根据原因进入暂时失效或永久失效状态。对于与当前注册影像相关的轨迹,系统优先进行局部重三角化;经过若干轮优化后,再对待处理轨迹或全部轨迹进行更大范围的扫描。

5.4.3 为相机注册保留空间支持

增量注册主要依赖已有三维点进行 PnP。若早期只保留少量看起来最干净的点,后续影像可能得不到足够的空间覆盖和稳定的三维支持。因此,InsightAT 在 Track 建立阶段保留足够的结构信息,再通过子集 BA、重三角化和可恢复状态逐步减少错误。

这样,当前 BA 的计算子集与整个模型的有效信息是分开的:一轮优化可以只处理一部分点,但没有进入本轮优化的点仍然可以在后续条件改善后参与计算。

5.5 Progressive intrinsics optimization

5.5.1 内参与结构的相互依赖

焦距、畸变、相机位姿和三维结构相互影响。影像数量较少时,如果同时放开焦距、主点和全部畸变参数,优化器可能使用内参自由度吸收错误匹配、错误结构或位姿误差。这些变化会继续影响后续的相机注册和三角化。

InsightAT 根据每个相机已经注册的影像数量逐步增加内参自由度。每个相机独立判断解锁阶段,使影像支持数量不同的相机采用各自合适的优化时机。

5.5.2 分阶段解锁参数

当前策略可以概括为:

注册影像较少  → 固定内参
获得初步支持  → 放开焦距和低阶畸变
观测数量增加  → 增加更高阶畸变参数
结构充分稳定  → 放开完整内参模型

在当前实现中,参数解锁大致按每个相机的注册影像数量分阶段进行:影像数量少于 3 张时保持固定,达到 3 张后放开焦距和一阶径向畸变,达到 10 张后增加二阶径向畸变,达到 50 张后再放开完整模型。需要保持内参不变时,也可以使用固定内参选项。

图 4 Progressive intrinsics optimization

图 4 渐进式内参优化。每个相机根据自身已注册影像数量逐步解锁焦距和畸变参数,局部 BA 保持内参克制,全局 BA 在支持充分时更新已解锁参数。

渐进式优化还可以配合焦距先验和每轮参数变化限制,使焦距不会在单次 BA 中发生过大的跳变。内参明显改善后,再按照可恢复观测策略重新检查此前被暂时排除的观测。

5.6 Conservative Local BA

5.6.1 Local BA 的稳定性风险

Local BA 可以快速调整新注册影像附近的相机和三维点,但它也引入了一个风险:在模型较小、内参和畸变尚未稳定时,局部窗口中的自由度可能把误差吸收到相机参数中,然后将带偏的结果传递给更大的模型。

Local BA 的价值取决于调度时机:当前模型拥有足够结构和参数支持局部自由度后,局部优化才能有效减少全局优化的开销。

5.6.2 随模型规模变化的调度

注册影像较少时,系统优先使用 Global BA,让所有已注册相机和主要结构共同调整;模型规模增加后,再逐步引入 Local BA,并周期性执行 Global BA 重新校正整体模型。Local BA 主要处理新影像及其邻近的三维点,内参在早期局部优化中保持克制。

当前调度可以概括为:

小规模模型  → 频繁 Global BA
中等规模模型 → 降低 Global BA 频率
大规模模型  → Local BA 为主,周期性 Global BA

当局部优化不能继续改善模型时,系统可以回到 Global BA、重三角化或状态恢复路径。用适量的全局计算约束局部优化,是增量 SfM 在稳定性和效率之间的主要平衡方式。

6. Controlling BA Problem Size and Numerical Conditioning

BA 联合优化相机参数和三维点,使观测的重投影误差最小。随着注册影像和轨迹增加,观测数量通常增长得更快,Jacobian、Schur 补和线性求解器的规模也随之增加。因而需要同时控制两件事:一轮 BA 处理多少数据,以及这些数据是否具有足够的几何约束。

这一章把相关策略分成两个层次。Global BA 和 Local BA 决定相机位姿的优化范围,属于增量过程的调度问题;Subset BA 决定在给定范围内使用哪些 Track 和观测,属于单轮求解的规模控制问题。二者可以组合,但不能互相替代。除此之外,坐标尺度、参数约束和数据通路也会影响 BA 的数值稳定性和实际耗时。

6.1 Observation Redundancy and Effective Information

6.1.1 观测冗余与求解规模

增加观测通常能够提高冗余度,使模型对部分错误匹配更加鲁棒。但当同一相机、同一局部区域和相似视角已经提供足够约束后,继续增加相似观测,带来的新增几何信息会逐渐减少;与此同时,Jacobian、Schur 补和线性系统的规模仍然继续增长。

如果每一轮都把所有有效观测放入联合优化,BA 会同时承担两个任务:利用新的信息改善模型,以及重复处理大量已经足够的冗余信息。前一个任务带来收益,后一个任务主要带来计算和内存成本。

6.1.2 BA 的目标是有效约束

InsightAT 优先保留能够改变相机和结构状态的有效约束,观测数量只作为规模控制的一部分。这类约束通常具有以下特征:

没有进入本轮联合 BA 的已三角化点仍保留在模型状态中,可以在固定位姿下单独更新,或在后续条件改善后重新进入联合优化。BA 控制的是单轮求解规模,模型信息则持续保留。

6.2 Subset BA: Control Data Volume

6.2.1 子集 BA 与 BA 调度的边界

这里需要区分两个选择维度。Global BA 通常让全部已注册相机参与优化,Local BA 则只让选定的相机位姿可变,并固定其他相机。Subset BA 用于在既定 BA 范围内筛选 Track 和观测,减少本轮需要构建的残差、Jacobian 和线性系统。

在当前实现中,全局 BA 的相机范围仍然是已注册影像;启用子集策略后,主要减少进入联合 BA 的三维点及其观测。对 Local BA,子集选择还可以配合变量相机集合,优先保留新注册相机或变量相机上的约束。

6.2.2 基于网格和几何质量的 Track 选择

当前的全局 BA 子集策略以影像网格为基础。对每幅已注册影像,将有效的已三角化 Track 投影到自适应网格中,每个网格单元保留得分较高的候选,再对所有影像的候选 Track 取并集。候选选择同时利用以下信息:

  1. 轨迹被已注册影像观察的数量;
  2. 对于只有两幅影像观察的轨迹,其三角化视差质量;
  3. 轨迹在影像中的空间位置。

其中,前两项参与 Track 得分,空间位置决定候选在网格中的竞争关系。

图 5 Subset BA and reversible masks

图 5 子集 BA 与可恢复状态。完整 TrackStore 保持稳定,网格覆盖和几何质量用于选择当前 BA 子集;mask 只改变本轮是否参与求解,不改变 Track 身份或观测的可恢复性。

因此,单轮 BA 得到的是跨越已注册模型的代表性 Track 集合,空间上可以分布在多个区域,而非集中于某个连续窗口。对于一条 Track 观测过多的情况,还可以设置每条 Track 的观测上限,并优先保留重投影误差较小、视线方向互补且能够约束变量相机的观测。

6.2.3 子集之外的数据如何处理

没有进入本轮联合 BA 的 Track 仍保留在 TrackStore 中,并通过状态位标记为暂不参与 BA。这个状态只影响本轮 BA 输入,不影响 Track 的身份、观测、重三角化和外点检查。下一次重新选择子集时,Track 可以根据新的相机位姿、视差和覆盖情况重新进入 BA。

在相机位姿已经固定时,被跳过的三维点还可以执行独立的点优化,从已有观测中更新空间位置。这样,系统将“相机与结构的联合优化”和“固定相机下的点更新”分开处理,避免为了更新所有点而扩大每一轮的相机-点联合问题。

6.2.4 子集 BA 的稳定性收益

较小的 BA 问题更容易检查残差、外点和数值状态,也更容易在失败时回退到上一状态。减少参与求解的 Track 和观测后,单轮 Jacobian、Schur 补和线性系统的规模更加可控;同时,网格覆盖、轨迹可见性和视差筛选可以避免把计算预算集中在同一小片高密度区域。

这些收益来自问题规模和数据质量的控制。Local BA 解决“哪些相机位姿可以变化”,Subset BA 解决“在这些相机和相关结构中使用哪些数据”。两者可以组合,也可以分别使用;周期性 Global BA 则负责重新校正整体模型,属于增量过程的调度策略。

6.3 Observation Coverage

6.3.1 数量不足以代表观测质量

如果只按照轨迹数量或匹配数量选择观测,BA 很容易把同一局部区域的高密度特征全部选入。这样的子集虽然观测很多,却不能充分约束相机在整幅影像上的变化,优化结果可能只对局部区域有效。

空间覆盖是子集选择的第一层约束。影像网格使候选分布在不同位置,跨影像取候选并集则使最终 Track 集合覆盖多个视图和区域。各区域无需等量采样,有限预算应优先用于避免明显的空间偏置。

6.3.2 覆盖、可见性与视差

覆盖保证观测分布在影像的不同位置;轨迹可见性反映一条 Track 被多少幅已注册影像共同观察;视差则决定三维点对深度和相机运动的约束强度。一个具有良好约束的 BA 子集通常需要同时满足:

这使有限的 BA 预算优先分配给空间上分散、视图上互补、几何上有支撑的观测。

6.3.3 覆盖策略与增量注册

增量注册主要依赖已有三维点进行 PnP。如果 BA 长期只处理局部密集区域,其他区域的三维点和相机约束会逐渐变弱,后续影像就可能缺少稳定的注册支持。子集选择因此不仅服务于当前 BA,也要为下一轮相机注册保留足够的空间覆盖和多视图连接。

6.4 Numerical Conditioning

6.4.1 坐标尺度对 BA 的影响

BA 的稳定性不仅取决于变量数量,也取决于变量的数值尺度。相机中心和三维点坐标如果处在差异很大的数量级,法方程和 Schur 补的条件可能变差,导致线性求解对舍入误差更加敏感。

InsightAT 在增量过程中提供场景尺度归一化:从当前有效三维点计算各坐标分量的中位数作为中心,再用点到该中心的典型径向距离作为尺度,将有效三维点和已注册相机中心变换到更适合数值计算的范围。旋转和投影关系不变,坐标系的平移与尺度变化不会改变 SfM 的相似几何目标。

这种归一化作用于场景状态,保持坐标变换与完整模型的一致性。它可以按增量过程的调度条件周期性执行,并与固定锚点、尺度先验等约束配合使用。

6.4.2 规范自由度与求解器选择

SfM 本身具有坐标系和尺度自由度,因此 BA 必须固定一个锚定相机,避免整个解在迭代中发生无意义的刚体漂移。需要额外控制尺度或相机间距离时,可以加入弱先验,但这不等同于外部地理定位。

求解器也需要随问题规模变化。相机变量较少时,稠密 Schur 求解具有较低的管理开销;变量增加后,稀疏 Schur 更适合控制内存,优先使用可用的 CUDA 稀疏后端或 SuiteSparse,最后回退到 Eigen 稀疏或迭代求解。焦距先验、Tikhonov 正则以及渐进式内参解锁,则用于限制内参在约束不足时吸收结构和位姿误差。

数值归一化、规范约束和内参先验分别解决不同问题:归一化改善坐标尺度,规范约束去除无意义的自由度,先验限制弱约束参数的漂移。三者共同决定 BA 是否能够在当前数据条件下稳定收敛。

6.5 CPU, GPU, and I/O as One BA Pipeline

6.5.1 BA 是完整数据通路的一部分

BA 的墙钟时间不仅由线性求解器决定,还受到轨迹读取、观测选择、Jacobian 构建、内存分配和结果写出的影响。即使某个求解 kernel 得到加速,如果数据准备和传输仍然串行等待,端到端收益也会受到限制。

因此,InsightAT 将 BA 放在完整的数据通路中考虑:

读取轨迹与观测
    → 选择 BA 子集
    → 构建残差与 Jacobian
    → 求解与更新
    → 外点检查、重三角化和写出状态

6.5.2 后端分工

特征提取、级联哈希匹配和两视图几何可以使用 CUDA,也提供 GLSL/EGL 和 CPU 路径;增量 SfM 主循环和 BA 主要由 CPU Ceres 完成,部分稀疏线性求解可以在条件满足时使用 CUDA 后端。

不同后端共享同一套任务和数据边界。SoA 让观测和变量能够连续访问与批量传输,IDC 让阶段结果可以保存和重新读取,批量异步 I/O 则负责把数据准备、计算和结果写回组织成有界流水线。

因此,本章关注的是整条 BA 数据通路:让每轮 BA 的数据量、数值尺度、内存使用、求解器选择和数据传输都处于可控范围。

7. Design Choices and Trade-offs

InsightAT 在输入不完整、场景规模变化和硬件条件不同的情况下,优先保持重建结果可检查、可恢复。系统因此在多个位置保留冗余、回退路径和兼容边界,代价是增加计算、存储和实现复杂度。

7.1 Robustness vs. Computation

自动化 SfM 最直接的取舍是鲁棒性与计算量。为了降低漏检对后续注册的影响,InsightAT 在候选图像对阶段倾向于保留较高的候选召回,再通过 SIFT 匹配、F 矩阵验证和后续轨迹质量检查逐步筛选。这样做会产生更多候选像对和几何验证任务,但把错误尽可能挡在增量重建之前,避免错误连接进入后续相机注册。

增量 SfM 中也采用类似策略:候选影像先经过可见性和 3D-2D 数量筛选,再通过 PnP RANSAC 和重投影误差检查;相机注册后继续进行三角化、BA、外点剔除和重三角化。早期阶段优先使用 Global BA,模型变大后再引入 Local BA,并周期性执行 Global BA。这种调度不会让每一轮都承担最高计算成本,但会增加整体运行时间和调度逻辑。

InsightAT 将计算预算投入到能够减少错误传播的位置:候选检索、几何验证、相机注册和关键 BA 节点。其代价是需要处理更多中间结果,并维护多条失败恢复路径。

7.2 Generality vs. Scene-specific Priors

第二类取舍是通用性与场景先验之间的平衡。InsightAT 以 SIFT 和低分辨率图像匹配作为基础候选检索策略,对 GNSS、严格时序、可靠 EXIF 或特定航线布局没有强制依赖。系统因此可以处理没有完整 EXIF、没有 GNSS 或不符合典型航拍顺序的图像集合,也可以将 GNSS 等信息作为后续的检索或约束条件接入。

这种通用底座牺牲了一部分先验带来的效率。若 GNSS 可靠,按空间邻近关系限制候选像对通常比基础匹配策略更快;若相机元数据完整,焦距初始化也可以更直接。InsightAT 因此采用分层方式使用先验:EXIF 等效焦距可以作为焦距估计的初始值,但缺少 EXIF 时仍能通过两视图几何和 F 矩阵搜索获得焦距候选;GNSS 等信息可以减少搜索范围,但不改变基础几何链路的独立性。

这种设计使算法对输入条件的依赖更少,但也意味着系统需要承担更大的候选搜索和几何验证成本,并需要在没有外部先验时处理更宽的初始化不确定性。

7.3 Reversibility vs. Storage

在自动化重建中,错误并不总能在产生时被准确识别。如果一旦发现异常就物理删除 Track、观测或中间文件,后续即使焦距、相机位姿或三角化结果得到改善,也很难恢复原始信息。因此,InsightAT 将可恢复性作为状态管理的一部分。

任务快照保存一次重建所使用的输入边界,IDC 文件保存阶段产物,Track 和观测通过状态位表达有效、待重三角化、暂不参与 BA 以及可恢复等状态。被 BA 子集排除的 Track 不会因此从模型中删除;因重投影误差暂时失效的观测,也可以在相机内参明显改善后重新评估。这样,系统能够在新的几何条件出现时重新利用已有数据。

可恢复性带来的代价是状态和存储开销增加。系统需要保存更多中间产物,明确区分“当前不参与计算”和“永久无效”,并在恢复、重三角化和快照回退时保持状态一致。换句话说,InsightAT 用额外的存储和状态管理复杂度,换取了错误处理过程中的回退空间。

7.4 Performance vs. Implementation Complexity

InsightAT 根据算法特征分配执行后端:特征提取、级联哈希匹配和两视图几何可以使用 CUDA,也提供 GLSL/EGL 与 CPU 路径;增量 SfM 主循环和 BA 主要由 CPU Ceres 完成,稀疏线性求解在条件满足时使用 CUDA 后端。SoA 布局、批量异步 I/O 和 IDC 产物则用于减少数据准备、计算和写回之间的等待。

这种异构设计可以在不同硬件条件下取得更好的端到端性能,也避免把仍然依赖复杂动态状态的增量 BA 过早迁移到不适合的执行模型中。但它同时增加了实现和验证成本:不同后端需要保持相同的数据契约,CPU 与 GPU 之间需要处理数据传输和同步,GLSL/EGL 路径还存在上下文和线程安全边界。后端越多,性能诊断、结果复现和故障定位也越复杂。

因此,系统保留 CPU 路径作为稳定基线,把 GPU 加速放在适合批处理和高并行度的阶段,并通过清晰的阶段输入输出隔离后端差异。性能优化由此从“迁移某个 kernel”扩展为对数据布局、任务边界、异步 I/O 和求解器选择的整体优化。

8. Current System

前面的章节介绍了 InsightAT 的设计目标、系统边界和核心算法。本章将这些内容收束到当前可运行的系统形态中,区分已经落地的能力与仍属于路线图的扩展方向。

8.1 任务启动与阶段执行

当前系统以一次重建任务的输入快照作为起点。项目中的图像、相机分组和相关参数先被冻结为任务输入,再由各阶段读取并生成自己的结果产物。这样,同一个任务在重新执行时仍然使用明确的输入边界,而不会随着项目后续变化而改变。

用户可以通过 Electron 工作流界面创建项目、准备任务、启动重建和查看进度,也可以直接调用命令行程序执行同一条处理链路。Electron UI 负责用户交互、任务管理和结果展示,实际算法仍由独立的无头阶段完成。界面退出不会改变已经写出的阶段产物,任务也可以从已有结果继续。

当前的主要处理链路可以概括为:

任务输入快照
    → 图像与内参清单
    → 候选图像对检索
    → 特征匹配与两视图几何验证
    → Track 构建
    → 焦距与相机参数初始化
    → 初始像对选择
    → 增量相机注册、三角化与 BA
    → 稀疏模型和诊断快照

每个阶段通过文件产物交接数据。阶段产物既是下一阶段的输入,也是故障定位、断点续跑和结果检查的依据。

8.2 当前的 SfM 内核

当前版本已经形成了完整的单机增量式 SfM 闭环。系统从候选初始像对开始建立坐标系,然后逐次选择待注册影像,通过 3D-2D 关联和 PnP 完成相机注册;新相机注册后进行三角化,再根据模型规模调度 Global BA 或 Local BA。

在增量过程中,系统还会执行稳健核与 MAD 外点剔除、待处理 Track 重三角化、可恢复观测重新评估以及渐进式内参解锁。早期阶段固定更多内参自由度,随着同一相机获得足够影像支持,再逐步放开焦距和畸变参数。焦距既可以使用 EXIF 等效焦距作为先验,也可以从两视图几何中估计。

数据结构方面,Track、观测、相机和位姿采用适合批量访问的布局,逻辑状态通过标志位维护。IDC 负责保存阶段产物和大块数据,任务快照负责保存输入边界,调试目录则保存增量过程中的周期性状态。这些机制共同支撑了当前系统的可检查性和可恢复性。

8.3 当前的计算后端

当前的计算任务按算法特征分配到不同后端:

当前系统已经具备异构计算的阶段边界,完整增量 SfM 尚未全部迁移到 GPU;相机注册、状态管理和 BA 仍然以 CPU 路径为主。

8.4 当前边界

当前系统的实际运行范围是单机、单任务或有限批次的稀疏重建。它已经具备任务快照、阶段产物、GPU 几何计算、增量 SfM、Electron 工作流界面和稀疏模型查看器,但以下能力仍未进入默认重建链路:

这些边界并不改变当前系统作为单机 SfM 基座的完整性,但决定了它距离面向超大规模场景的 2.0 版本还需要哪些扩展。

9. Toward Cloud-scale SfM 2.0

InsightAT 2.0 的目标是将当前单机增量内核扩展为面向超大规模任务的分层重建系统。这里的内容属于设计路线,不代表当前代码已经提供这些能力。核心思路是:在局部范围内保留增量 SfM 的可检查性,在更大范围内通过分块、对齐和全局优化建立统一模型。

9.1 Partition

第一步是将大规模图像集合划分为若干具有较强内部连接的块。分块依据可以来自候选图像对的视图图、图像空间分布、航线结构以及可选的 GNSS 先验。每个块应尽量具有足够的内部重叠和几何约束,同时控制单块的图像数、Track 数和 BA 规模。

分块结果需要同时携带块的输入快照、边界图像、候选跨块连接以及任务参数。这样,块内重建、跨块匹配和后续合并都可以成为独立任务,并能在失败时单独重试。

9.2 Local Reconstruction

每个块内部继续使用当前的增量 SfM 内核完成局部重建,包括候选检索、初始像对、相机注册、三角化、渐进式内参优化和 BA。局部任务输出不仅包括相机和三维点,还应包括:

局部重建先以受控规模建立可靠的局部几何,再为跨块连接和全局合并提供稳定输入。

9.3 Cross-block Matching

块之间的关系应优先在边界图像和候选重叠区域中建立,而不必对所有图像进行全量匹配。第一阶段可以使用低分辨率 SIFT 和 F 矩阵验证发现可能的跨块连接;当块间关系足够明确后,再对候选边界进行全分辨率匹配和更严格的几何验证。

跨块匹配的输出应区分两类信息:一类是可以直接连接两个局部模型的共享 Track 或相机观测,另一类是只用于估计块间相对关系的几何约束。这样可以避免未经验证的跨块匹配直接污染局部 Track,并允许在合并阶段重新检查连接质量。

9.4 Sim3 Alignment

局部 SfM 通常具有独立的坐标原点、方向和尺度,因此合并前需要根据共享相机、共享 Track 或跨块几何约束估计块间 Sim3 变换。对齐过程应使用鲁棒估计和残差检查,拒绝由错误跨块匹配导致的异常变换。

当没有可靠的外部地理约束时,Sim3 主要由视觉连接决定;当 GNSS、IMU 或 GCP 可用时,它们可以作为软约束或块间对齐的辅助信息,而不必成为局部 SfM 成立的必要条件。对齐完成后,应保留每个块的原始局部坐标和变换参数,便于回退和诊断。

9.5 Global Optimization

块间对齐后,可以先构建跨块位姿图,对相机之间的相对关系进行全局校正,再根据资源预算执行分层 Global BA。第一轮全局优化可以优先使用边界相机、共享 Track 和高质量跨块约束;模型关系稳定后,再逐步扩大参与优化的相机、三维点和观测范围。

未来的 Global BA 仍然需要沿用当前报告中关于子集选择、空间覆盖、数值归一化和可恢复状态的原则。对于超大规模模型,完整 BA 不一定适合一次性执行,可以采用分层求解、周期性全局校正和局部回写的方式控制内存与计算时间。

这条路线最终形成:

图像分块
    → 块内增量重建
    → 跨块候选匹配
    → Sim3 对齐
    → 位姿图与分层 Global BA
    → 统一稀疏模型

其中,当前版本已经提供块内重建和文件化任务边界;分块调度、跨块合并、位姿图优化和跨机器执行仍属于 2.0 的后续工作。

10. Conclusion

InsightAT 的核心工作在于围绕自动化重建重新定义计算边界:系统将任务输入冻结为快照,以文件产物连接阶段,以独立 CLI 执行算法,并通过 Electron UI 提供面向用户的工作流入口。

在算法层,系统以 SIFT 和两视图几何建立具有较强泛化性的候选关系,通过 F 矩阵焦距搜索、稳健初始化、增量注册、渐进式内参优化、可恢复 Track 状态和 Global/Local BA 调度,减少错误在重建过程中的传播。Subset BA、空间覆盖和数值条件控制则使 BA 在模型增长后仍保持可检查的规模。

当前实现已经形成了一个可运行的单机稀疏重建基座。它的主要限制也很明确:大规模分块、局部模型合并、Sim3 对齐、位姿图优化和跨机器调度尚未实现。

InsightAT 2.0 将以当前增量内核作为可靠的局部重建单元,再通过任务拆分、跨块关系建立和分层全局优化扩展到更大规模。当前系统解决“如何在不确定输入下稳定完成一次重建”,后续系统将进一步解决“如何把许多可恢复的局部重建组织成一个可扩展的全局模型”。