opencv c ++比较不同图像中的关键点位置

时间:2015-04-08 16:05:40

标签: c++ opencv orb keypoint

通过feature extraction比较2张图片时,如何比较keypoint距离,以便忽略明显不正确的距离?

我在将相似图像相互比较时发现,大多数情况下它可以相当准确,但有时它可以抛出完全分开的匹配。

所以我在查看两张图片中的两组keypoints之后,确定匹配的keypoints是否相对位于两者的相同位置。因为它知道keypoints 1,2和3在图像1上相距很远,所以在图像2上匹配的相应关键点应该具有相当远离彼此的距离。

我过去曾使用RANSACminimum distance支票但只是为了实现某些效果,它们似乎并不像我之后那样彻底。< / p>

(使用ORBBruteForce

修改

&#34; x,y和z&#34; 更改为&#34; 1,2和3&#34;

编辑2 - 我将尝试使用快速绘制的示例进一步解释:

说我把它作为我的形象:

enter image description here

我给它这张图片进行比较:

enter image description here

它是原版的裁剪和压扁版本,但显然相似。

现在,假设您通过feature detection运行了它,然后它返回了keypoints这两张图片的结果:

enter image description here enter image description here

两张图像上的keypoints位于大致相同的区域,并且相互之间的距离相同。将keypoint圈起来,我们称之为 &#34;图片1关键点1&#34;

enter image description here

我们可以看到它周围有5个keypoints。它们与 &#34;图像1关键点1&#34; 之间的距离是我想要获得的,以便将它们与 &#34进行比较;图像2关键点1&#34; 及其5个环绕keypoints位于同一区域(见下文),以便不仅仅将keypoint与另一个{{1}进行比较},但要根据keypoint的位置比较&#34;已知形状&#34;

enter image description here

-

这有意义吗?

3 个答案:

答案 0 :(得分:5)

关键点匹配是几个维度的问题。这些维度是:

  • 空间距离,即从不同图像中两个关键点的位置测量的(x,y)距离
  • 功能距离,即描述两个关键点看起来相似的距离

根据您的上下文,您不希望计算相同的距离,或者您希望将两者结合起来。以下是一些用例:

  • 光流,由opencv&#39; sparse Lucas-Kanade optical flow实施。在这种情况下,在每个帧中计算称为良好特征的关键点,然后在空间距离的基础上进行匹配。这是有效的,因为图像应该相对缓慢地改变(输入帧具有视频帧速率);
  • 图片拼接,您可以从opencv features2d(免费或non-free)实施。在这种情况下,由于您移动相机,图像会发生根本变化。然后,您的目标就是找到稳定的点,即两个或多个图像中存在的点,无论它们的位置如何。在这种情况下,您将使用 feature distance。当您拥有要在查询图像中查找的对象的模板图像时,这也适用。

为了计算要素距离,您需要计算其外观的编码版本。此操作由DescriptorExtractor类执行。 然后,您可以计算描述输出之间的距离:如果两个描述之间的距离很小,那么原始关键点很可能对应于同一个场景点。

计算距离时要注意使用正确的距离函数:ORB,FREAK,BRISK依赖汉明距离,而SIFt和SURF使用更常见的L2距离。

匹配过滤

当您有单独匹配时,您可能希望执行匹配过滤,以拒绝可能由场景模糊引起的良好个别匹配。想想一个源自房屋窗户角落的关键点。然后它很可能与另一个房子里的另一个窗口匹配,但这可能不是好房子或好窗口。

你有几种方法可以做到:

  • RANSAC使用当前解决方案估计执行计算匹配的一致性检查。基本上,它随机选取一些匹配项,计算问题的解决方案(通常是2个图像之间的几何变换),然后计算有多少匹配符合此估计值。具有较高内部数的估计获胜;
  • David Lowe在原始SIFT论文中进行了另一种过滤。 他保留了两个与给定查询关键点匹配的最佳候选者,即具有最低距离(或最高相似度)的点。然后,他计算了比率similarity(query, best)/similarity(query, 2nd best)。如果这个比例太低,那么第二好的也是比赛的一个很好的候选人,匹配的结果被称为含糊不清并被拒绝。

因此,在您的情况下,您应该如何做到这一点很可能取决于您的确切应用。

您的具体案例

在您的情况下,您希望开发基于相邻关键点的备用要素描述符。 天空显然是这里的限制,但这里有一些我要遵循的步骤:

  1. 通过计算关键点的PCA来使描述符旋转并缩放不变:

    // Form a matrix from KP locations in current image
    cv::Mat allKeyPointsMatrix = gatherAllKeypoints(keypoints); 
    
    // Compute PCA basis
    cv::PCA currentPCA(allKeyPointsMatrix, 2);
    
    // Reproject keypoints in new basis
    cv::Mat normalizedKeyPoints = currentPCA.project(allKeyPointsMatrix);
    
  2. (可选)对四叉树或kd树中的关键点进行排序,以便更快地进行空间索引

  3. 为每个关键点计算描述符(例如)4或5个最近关键点的标准化坐标中的偏移量
  4. 在查询图片中执行相同的操作
  5. 根据这些新描述符匹配两个法师的关键点。

答案 1 :(得分:0)

你要做的是什么?需要更多信息才能给出一个好的答案。否则,它必须非常广泛,并且很可能对您的需求无益。

并使用您的陈述&#34;确定匹配的关键点是否相对位于两者的相同位置。你的意思是两个图像之间的相同x,y位置吗?

我会试用SURF算法。它适用于你上面描述的内容(虽然我发现它有点慢,除非你使用gpu加速,5fps对34fps)。

这是关于surf的教程,我个人认为它非常有用,但可执行文件仅适用于linux用户。但是,您可以简单地删除源代码中的特定于操作系统的绑定,并仅保留与opencv相关的绑定,并在linux上编译和运行它们。

https://code.google.com/p/find-object/#Tutorials

希望这有帮助!

答案 2 :(得分:0)

您可以对两个关键点之间的像素距离进行过滤。 假设匹配是你的匹配向量,kp_1是第一张图片上的关键点向量,第二张是kp_2。您可以使用上面的代码来消除明显不正确的匹配。你只需要修一个门槛。

double threshold= YourValue;
vector<DMatch> good_matches;
for (int i = 0; i < matches.size(); i++)
{
    double dist_p = sqrt(pow(abs(kp_1[matches[i][0].queryIdx].pt.x - kp_2[matches[i][0].trainIdx].pt.x), 2) + pow(abs(kp_1[matches[i][0].queryIdx].pt.y - kp_2[matches[i][0].trainIdx].pt.y), 2));
    if (dist_p < threshold)
    {
        good_matches.push_back(matches[i][0]);
    }
}