这里有多个要点。
为了确定两个图像是否(几乎)相等,您需要找到它们的同构投影,使得投影结果在投影特征位置之间产生最小误差。暴力破解是可能的,但不高效,因此一个技巧是假设相似的图像往往也具有相同的特征位置(稍微有所不同)。例如,在拼接图像时,通常仅从略微不同的角度和/或位置拍摄要拼接的图像;即使没有,距离也可能会随着方向差异的增加而增长(“成比例”)。
这意味着您可以通过找到所有图像对之间最小空间距离(k
个最近邻居)的k
个点对来选择候选图像,仅在这些点上执行同构。然后,您只需比较投影点对之间的空间距离并按该距离对图像进行排序;最低距离意味着在给定情况下可能的最佳匹配。
如果我没有弄错的话,描述符是由角度直方图中最强的角度定向的。这意味着您也可以直接采用64或128维特征描述符的欧几里得(L2)距离来获取给定两个特征的实际特征空间相似度,并对最佳k个候选进行单应性变换。(不过,您不会比较描述符发现的“尺度”,因为那样会破坏尺度不变性的目的。)
这两种选择都非常耗时,而且直接取决于图像和特征的数量;换句话说:这是一个愚蠢的想法。
近似最近邻
一个巧妙的技巧是根本不使用实际距离,而是使用近似距离。换句话说,您需要一种近似最近邻算法,
FLANN(虽然不适用于.NET)就是其中之一。
这里的一个关键点是投影搜索算法。它的工作方式如下:假设您想比较 64 维特征空间中的描述符。您生成一个随机的 64 维向量并对其进行归一化,从而得到一个任意的特征空间单位向量;我们称之为
A
。现在(在索引期间),您将每个描述符与该向量的点积形成。这将每个 64 维向量投影到
A
上,从而得到一个单个的实数
a_n
。(该值
a_n
表示描述符沿着
A
相对于
A
的原点的距离。)
我从
this 在 CrossValidated 上的答案中借用了这张图片来直观地展示它;将旋转视为不同随机选择的
A
的结果,其中红色点对应于投影(因此,标量
a_n
)。红色线显示了使用该方法所产生的误差,这就是搜索变得近似的原因。
![Projection onto a vector](https://istack.dev59.com/Q7HIP.gif)
你需要再次使用
A
进行搜索,因此你要将其存储。你还要跟踪每个投影值
a_n
及其来源描述符;此外,你按
a_n
对每个
a_n
(带有其描述符的链接)进行排序并在列表中对齐。
为了使用
here中的另一张图片进行澄清,我们感兴趣的是沿着轴
A
的投影点的位置。
![Projection search](https://istack.dev59.com/IJhhl.webp)
在图像中,4个投影点的值a_0..a_3大约为sqrt(0.5²+2²)=1.58、sqrt(0.4²+1.1²)=1.17、-0.84和-0.95,对应它们到A的原点的距离。如果您现在想找到类似的图像,则执行相同操作:将每个描述符投影到A上,得到一个标量q(查询)。现在,您可以转到列表中的q位置,并获取k个周围条目。这些是您的近似最近邻居。
现在取这些k个值的特征空间距离,并按最低距离排序——顶部的条目是您的最佳候选项。
回到上一张图片,假设最顶部的点是我们的查询点。它的投影是
1.58
,它的近似最近邻(四个投影点中的一个)是
1.17
。虽然在特征空间中它们并不是真正接近的,但考虑到我们只使用了两个值来比较两个64维向量,这也不算太糟糕。
你可以看到这里的限制,类似的投影根本不需要原始值接近,这当然会导致相当有创意的匹配。为了适应这种情况,你只需要生成更多的基向量
B
、
C
等——比如说
n
个,并为每个向量列表保留一个单独的列表。在所有向量上取出前
k
个最佳匹配,将这个由
k*n
个64维向量组成的列表按照它们到查询向量的欧几里得距离进行排序,对最佳的向量执行单应性变换,选择投影误差最小的向量。
这里的好处是,如果你有n(随机、标准化的)投影轴,并且想要在64维空间中进行搜索,你只需要用一个n x 64的矩阵将每个描述符乘起来,得到n个标量。