611. Image Matching Challenge 2024 - Hexathlon | image-matching-challenge-2024
我很高兴能够分享参加 IMC 2024 的经历,并衷心感谢组织者 @oldufo @eduardtrulls、赞助商以及 Kaggle 团队!这是我第一次参加 IMC 和 Kaggle,收获非常丰富。
我的实现基于 IMC2024 Starter(作者 @nartaa)的公开代码。这个 baseline 使用 ALIKED+LightGlue 和 pycolmap 进行重建。和其它参赛者一样,我把训练集当作评估集,共 50 个样本。
下面是我的 IMC 2024 解决方案。
我的方案的核心是 VGGSfM: Visual Geometry Grounded Deep Structure From Motion(https://vggsfm.github.io/)。该工作已被接受为 CVPR 2024 的亮点论文。
简单来说,给定 N 张输入帧,VGGSfM 首先使用相机预测器估计初步的相机外参和内参。在选定一张查询帧以及若干 2D 查询点后,使用轨迹预测器估计 2D 轨迹。这些轨迹结合初步的相机信息,可以进行三角化得到三维点,随后进行束束调整(bundle adjustment)以优化相机和点的组合。更多细节请参阅论文。
我首先在所有输入帧上运行 VGGSfM,这在 IMC2024 评估集上表现出色。当输入帧数为 50 时,它的 mAA 比 baseline 高出 4%(0.04)。然而,由于 Kaggle 服务器的 16 GB GPU 限制,将这种方案直接用于 Kaggle 提交十分困难——显存不足十分痛苦。因此,为了适应服务器限制,我把 VGGSfM 集成到现有的 pycolmap 流程中,详见下文。
第一个思路是使用 VGGSfM 的轨迹预测器估计轨迹,并将它们作为额外的 2D 匹配输入到 pycolmap。对每张图片,我使用 NetVLAD 或 DINO V2 找到其最近的 N 张帧。以该图片为查询帧,使用 Superpoint 选取查询点,并在最近的 N 张帧上找出对应的轨迹。当 N=5 时,这帮助在评估集上提升了 3% 的 mAA。但 public leaderboard 上仅从约 0.17 提升到约 0.18。我怀疑更高的 N 可能会取得更好的结果,但没有足够的提交次数来验证。我是在比赛进行到一半时才加入的,总共提交了约 120 次。
该策略对每张输入帧只运行一次轨迹预测,避免了穷举匹配带来的二次复杂度。在 Kaggle 集群上,每帧需要约 1.8 秒,总计 90 秒处理 50 张图片的场景。在本地的 A100 集群上,每帧仅需 0.7 秒。
VGGSfM 的轨迹预测器采用两阶段设计:先预测粗糙轨迹,再通过局部外观进行细化。受去年 ZJU3DV(@xingyihezju3dv)冠军方案的启发,我发现可以对 pycolmap 重建的 SfM 轨迹进行精化。具体做法是:先使用 ALIKED+LightGlue(或其它方法)运行 baseline,得到最佳重建(即注册图片最多的重建)。该重建中每个有效的三维点对应若干 二维点,这些二维点组成一条 SfM 轨迹。于是,我对这些轨迹提取 31×31 的图像块,使用 VGGSfM 的精细轨迹预测器对这些块进行细化,并使用细化后的二维点更新 pycolmap 重建。随后再运行一次全局束束调整,以基于细化后的轨迹优化相机和三维点。例如,在 Church 场景中,平均重投影误差从 0.64 降至 0.55。
重要的是,这一过程无需重新编译 colmap。我在 此处提供了使用 pycolmap 与 VGGSfM 模型实现该步骤的代码示例。
在提交时,我们仅对重投影误差最高的 4096 条 SfM 轨迹进行精化。每条场景约需 150 秒,即约每秒 30 条轨迹。在 public leaderboard 上,这一步将我们的分数从约 0.18 提升至约 0.20。
我们还观察到,colmap 通常无法将场景中所有图像全部注册。因此,我们尝试使用 VGGSfM 对缺失图像进行重新定位。对于每张缺失图像,我们找出与其有匹配的前 5 张已注册图像。如果找不到 5 张已注册图像,则使用 DINO v2 找最近的帧。
于是我们得到一个包含 6 张图像(1 张未注册 + 5 张已注册)的子集。使用 VGGSfM 重建这些图像的相机姿态。然而,VGGSfM 预测的相机姿态位于与 pycolmap 重建的原始相机坐标系不同的坐标系中。我们使用 Umeyama 算法基于 5 张已注册图像的中心找到对齐变换,并将该变换应用到未注册图像的相机姿态上。
每张缺失图像的处理大约需要 5 秒。这将 public leaderboard 分数从约 0.20 提升至约 0.21。需要注意的是,有时候缺失的图像难度较大,可能与其它帧的重叠(匹配)不足。此时束束调整可能会失败,我们就只使用 VGGSfM 相机预测器预测的相机姿态。实话实说,这部分代码写得比较匆忙,可能在坐标系转换上有些小错误,但效果还不错。
除上述方法外,我们的最终方案还包括:
三周的比赛历程非常精彩且收获颇丰,尽管期间睡眠不足。最大的收获之一是发现了多种降低 VGGSfM GPU 消耗的方法,我将在 VGGSfM 的 GitHub 上尽快更新。此外,令人欣慰的是,在计算资源有限的情况下,VGGSfM 能够有效地与 colmap 互补。熟悉 Kaggle 本身也花费了我不少时间。希望明年能够取得更好的成绩!
(本文撰写较为匆忙,后续可能还会继续更新。先休息一下,如果您对 VGGSfM 有任何问题,欢迎给我发邮件。)