611. Image Matching Challenge 2024 - Hexathlon | image-matching-challenge-2024
首先,感谢主办方第三次在Kaggle上组织图像匹配挑战赛。同时,向获胜者表示祝贺,并祝愿所有经历这次艰难旅程的人都平安顺利。
我承认我参加比赛的时间比较晚。因此,我只能凭"感觉"行事,临场发挥。所以,你可能会发现我的方案在某些方面有点巧妙 :))。让我们开始吧!
我的解决方案架构可以总结为下图:

我的总结分为四个主要部分:
原始数据集显然太大且不切实际,无法用于评估。为了解决这个问题,我构建了3个版本的子集(通过采用一些随机采样策略)。这3个版本的结果高度相关。因此,我选择其中一个作为我的主要本地验证数据集:
| 数据集/场景 | 样本数量 |
|---|---|
| Pond | 100 |
| Lizard | 90 |
| Church | 80 |
| Dioscuri | 70 |
| Multi-temporal-temple-baalshamin | 68 |
| Transp_obj_glass_cup | 36 |
| Transp_obj_glass_cylinder | 36 |
我将在此数据集上报告我的本地交叉验证结果。
为了更好地解释,我将该流程分为3个模块:
我使用了来自timm的3个预训练模型来提取全局特征:
EVA-CLIP Base
ConvNeXt Base | -->[concat]--> [fc 2560]
Dinov2 ViT Base /
我还为不同类型的场景定制了相似度阈值(注意,我使用的是余弦相似度而不是距离)。例如,对于像Lizard这样的高度多样化场景,我使用了较低的阈值0.6。相反,对于像Cylinder和Cup这样的物体场景,较高的阈值0.95更合理。
延续我去年解决方案的精神,我只专注于基于检测器的方法,因为它们比半密集或密集模型轻量得多。由于缺乏CV和LB的实验,我无法给出每个方法的详细数字,只能大致说明它们的整体表现。以下是我在比赛中尝试的一些组合:
| 方法 | CV表现 | LB表现 | 备注 |
|---|---|---|---|
| SuperPoint + SuperGlue | 好 | 不好 | 比LightGlue慢 |
| GlueStick | 一般 | - | 慢 |
| SuperPoint + LightGlue | 非常好 | 不好 | 不知道为什么在LB上表现不好|
| ALIKED + LightGlue | 好 | 非常好 | LB上最佳 |
| DISK + LightGlue | 好 | 一般 | |
| OmniGlue | 不好 | - | 慢 |
此外,我还尝试将SIFT + NN作为轻量级集成模型添加到LightGlue中。IMC23第七名方案声称将SIFT与LightGlue集成可以提升性能。我认为在某些场景的CV中确实如此,但它对LB结果造成了很大伤害(-0.03)。
总之,我想说LightGlue是目前图像匹配问题中最好的模型之一(向作者致敬)!
今年我花了一些时间尝试更好地利用colmap,超越主办方的基线。以下是我的一些尝试:
很遗憾地说,我无法在colmap上做出任何明显的改进。
我认为这个类别决定了金牌。因为当我解决这个问题时,我立即从第300名跃升至第10名!!!
首先,我将展示如何创建这个解决方案的过程,希望会更生动 :)。
如果你打开一张图片,然后逐张移动到下一张,你会发现这就像是从一个相机拍摄的视频中截取的帧序列。
人类会如何匹配这些图片?如果是我,我会只聚焦在物体上,忽略整个背景。此外,我只需要匹配一个序列(或环)的帧:(0, 1), (1, 2),...,(35, 0),这意味着不需要匹配(1, 20)或(3, 29)!

通过在匹配cylinder之前添加这两行代码,我在CV上使用LightGlue从~0.0提升到了0.86:
image = image[950:2850, :, :]
index_pairs = [(i, i+1) for i in range(len(scene)-1)] + [(len(scene)-1, 0)]
所以现在问题可以分解为两个更小的问题:
方法1(无效):使用目标检测模型:我尝试了Yolo系列。不过,很难让模型找到精确的物体位置。
方法2(最终解决方案):使用分割模型:
我也尝试了DBSCAN。然而,由于开发时间的限制,我没有最终完成它来看看它是否可以取代SAM。

问题定义:
方法1(不好):基于两帧之间像素移动最小的原理,我使用RAFT计算所有可能对的光流,然后获得平均幅度。我进一步结合上述全局嵌入的余弦相似度构建NxN矩阵:
pair_score[i, j] = -of_mag[i, j] + cos_sim[i, j]
TSP求解器无法产生完美的环(约90%准确率)。因此,我认为它不够好。
方法2(更简单但更好):我对所有图像对进行穷举匹配。然后,构建一个NxN矩阵,其元素是每对之间的匹配数量:
pair_score[i, j] = n_matches[i, j]
随后,我简单地选择每行中最大的两个值。这种简单的方法惊人地产生了接近100%的准确率(我尝试了不同的匹配器,有时会有1-2个错误的配对)。
方法1:找出暗图像并增强它们。
暗检测非常容易,只需要找出均值小于阈值(可以是65、70)的图像。
我使用CLAHE来增强暗图像。不幸的是,它使我的LB分数降低了0.01。
方法2:使用DarkFeat匹配器。
我的想法是将LightGlue与一个对暗图像更鲁棒的匹配器集成。我发现DarkFeat可能是一个有前途的候选者。不幸的是,我没有看到使用它的任何好处。
我认为这些场景由于其自然特性可能存在大量误匹配。
方法1:首先,我尝试使用更严格的参数进行调优(例如,将匹配阈值提高到0.5等)。尽管如此,它没有显示任何改进。
方法2:接下来,我转向一个更有前途的方法:Doppelgangers: Learning to Disambiguate Images of Similar Structures。这种方法的主要思想是:
它在本地CV的Church场景上没有显示任何改进。
所以基本上,我无法在这个类别上做出任何改进。
剩余的类别包括自然场景、航拍ground、历史保护、时间序列。
实际上,很难定制这些场景,因为它们似乎太通用了。
因此,我只是应用了旋转检测方法来校正图像方向。它在本地CV的Dioscuri场景上产生了巨大提升,并在LB上增加了约+0.005。
交叉验证
| 场景 | 方法 | 结果 |
|---|---|---|
| Pond | ALIKED+LightGlue | 0.46 |
| Lizard | SP+LightGlue | 0.73 |
| Church | ALIKED+LightGlue | 0.18 |
| Dioscuri | ALIKED+LightGlue | 0.49 |
| Multi-temporal-temple-baalshamin | ALIKED+LightGlue | 0.48 |
| Transp_obj_glass_cup | DISK+LightGlue | 0.32 |
| Transp_obj_glass_cylinder | ALIKED+LightGlue | 0.81 |
排行榜
| 方法 | 公开LB | 私有LB |
|---|---|---|
| 我的IMC23: SP+SG | 0.104 | 0.111 |
| SP+LG | 0.099 | 0.115 |
| SP+LG+rot | 0.103 | 0.119 |
| ALIKED+LG+rot | 0.135 | 0.147 |
| ALIKED+LG+rot+transparent_custom | 0.18 | 0.19 |
| ALIKED+LG+rot+transparent_custom+tuning | 0.186 | 0.195 |
| ALIKED+LG+rot+transparent_custom+tuning+dark_enhance | 0.179 | 0.183 |
有趣的事实:我参加了Kaggle上的所有三届图像匹配挑战赛,并获得了三种不同颜色的奖牌 😂:
参加这样艰难的比赛让我感到精疲力竭。但最终,经过不懈努力,甜蜜的果实终于来了 😁。
感谢你的阅读。希望你能从中找到一些有趣的内容。
快乐Kaggling!