返回列表

6th Place Solution - [ --- ]AffNetHardNet8 + AdaLAM

556. Image Matching Challenge 2023 | image-matching-challenge-2023

开始: 2023-04-11 结束: 2023-06-12 计算机视觉 数据算法赛
作者:MaxChen303(Kaggle Master)
比赛排名:第6名
发布时间:2023年6月14日

我想对比赛组织者和K工作人员表示诚挚的感谢,感谢他们举办了这场令人惊叹的比赛。同时,我也要感谢比赛的主办方(@oldufo@eduardtrulls)提供了丰富的资料和优秀的示例提交,这让我能够快速上手比赛。参加这次比赛以及IMC2022让我在图像匹配、Kornia和运动恢复结构(SfM)方面学到了很多。

1. 概述

我的最终解决方案基于示例提交,但我将KeyNetAffNetHardNet + AdaLAM匹配器与Colmap结合使用的性能推向了极限。

  • 我实现了四种类似于KeynetAffnetHardnet的局部特征检测器(Kornia示例),每个检测器为场景中的所有图像(有限尺寸)提取局部特征。更多非学习型关键点检测器的信息请参见这里
  • 使用HardNet8而非HardNet,尽管我没有看到性能差异。
  • 使用AdaLAM匹配器匹配所有图像对并获取场景的匹配结果。仅保留平均匹配距离 < 0.5 的图像对。设置force_seed_mnn为True,并将ransac_iters增加至256(相比示例提交)。
  • 将来自四种检测器的匹配结果进行合并。
  • 使用USAC_MAGSAC获取每对图像的基础矩阵,并仅保留内点匹配。结果作为双视图几何写入数据库。随后在不使用match_exhaustive的情况下执行incremental_mapping

检测器架构

完整流程

1.1 解决方案形成过程

在多次运行示例提交后,我认为找到优秀解决方案的关键在于识别良好的图像对候选列表,并应用IMC2022的类似方案。我注意到KeyNetAffNetHardNet解决方案只需对每幅图像运行一次较慢的局部特征检测,而使用AdaLAM匹配器的匹配过程足够快速,可以匹配所有可能的图像对。因此,我决定使用KeyNetAffNetHardNet和AdaLAM的匹配距离来寻找匹配/配对候选列表。然而,经过一些优化后,它在最后一周成为了最终解决方案。

1.2 KeyNetAffNetHardNet

在使用AdaLAM匹配所有可能的图像对后,KeyNetAffNetHardNet的性能令我惊讶。通过将特征数量增加至8000并将最大长边设为1600,我能够达到0.414/0.457(公开/私有)的分数。

在实验过程中,我发现匹配距离可用于判断两幅图像是否具有重叠区域。参见我的测试笔记本,其中有关使用KeyNetAffNetHardNet + Adalam进行配对的实验。禁用Upright选项(启用OriNet)可使AdaLAM匹配在处理旋转图像时更加鲁棒。

2. 使用Colmap的实现细节

2.1 使用焦距

在示例提交中,有一个从图像EXIF中提取焦距的部分。然而,使用image.get_exif()方法可能无法找到"FocalLengthIn35mmFilm"属性。在某些情况下,焦距信息可能存在于exif_ifd中(如此Stack Overflow帖子所述)。要从exif_ifd中提取焦距,我使用了以下代码:

exif = image.getexif()
exif_ifd = exif.get_ifd(0x8769)
exif.update(exif_ifd)

如果EXIF中找到了焦距,我还在向数据库添加相机时设置"prior_focal_length"标志为true。这提高了某些场景的mAA(urban / kyiv-puppet-theater场景的mAA从0.764提升到0.812)。

根据Colmap教程

通过设置prior_focal_length标志为0或1,可以提示重建算法是否信任焦距值。

2.2 处理随机性:绕过match_exhaustive()

在多次测试训练数据集上的解决方案后,我注意到即使使用相同的代码,评估结果也存在随机性。我发现这种随机性的来源是match_exhaustive()函数,该函数在数据库中对每对图像运行RANSAC并生成双视图几何。为了解决这个问题,我决定绕过match_exhaustive函数,使用OpenCV的USAC_MAGSAC为每对图像查找基础矩阵。然后将双视图几何直接写入数据库。通过这一更改,我在运行相同代码时能够获得确定性的mAA。通过调整USAC_MAGSAC参数,我能够为重建相同的匹配确保最佳分数。

2.3 多进程处理

我发现添加来自其他AffNetHardNet检测器的匹配可以提高整体mAA分数。为了在流程中容纳更多类似的检测器,我使用了多进程处理以确保第二个CPU核心被充分利用。使用四种检测器且边长不超过1600的最终解决方案大约需要7.5小时运行。

为了优化流程,我在处理前按图像数量降序排列所有场景。对于每个场景,有两个阶段:生成数据库的匹配和从数据库重建。不同场景的重建允许与匹配并行运行。理想情况下,流水线应如下所示:

多进程处理流程

3. 其他尝试

  • 在发现KeyNetAffNetHardNet擅长寻找匹配/配对候选列表后,我花了很多时间探索成对匹配方法,如LoFTR、SE-LoFTR和DKMv3。然而,这些方法即使在选定的图像对上运行也很慢,并且在我的实现中没有提高mAA。
  • 将AdaLAM匹配器与其他关键点检测器(如DISK、SiLK和ALIKE)结合使用:我还使用OriNet和AffNet将这些检测器的关键点转换为Lafs,并获取HardNet8描述符。然后我尝试在原生描述符、HardNet8描述符或拼接描述符上进行匹配。这种方法似乎优于在没有Lafs的情况下匹配原生描述符。如果有更多时间,我想进一步探索这个方向。
  • 通过将大图像分割成适合GPU内存的小图像来运行不调整大小的局部特征检测。然而,这种方法极其缓慢且没有提升性能。我发现超过一定分辨率后mAA不再提升。允许长边为1600或2048时得分相似。
  • 调整Colmap映射选项:选项太多且难以评估结果。

4. 本地验证分数

场景 图像数 配对数 mAA mAA_q mAA_t
urban / kyiv-puppet-theater 26 325 0.904923 0.931077 0.914154
heritage / dioscuri 174 15051 0.906996 0.982559 0.910856
heritage / cyprus 30 435 0.855172 0.868966 0.865977
heritage / wall 43 903 0.484496 0.820377 0.499336
haiper / bike 15 105 0.921905 0.999048 0.921905
haiper / chairs 16 120 0.979167 0.999167 0.979167
haiper / fountain 23 253 0.999605 1.000000 0.999605

最终指标: mAA=0.873568(耗时:1.7704436779022217秒)

同比赛其他方案