OpenCV - 特征匹配 vs 光流

17

我对使用OpenCV制作运动跟踪应用程序很感兴趣,在网上有大量的信息可用。然而,我在特征匹配和使用稀疏光流算法如Lucas-Kanade跟踪特征之间有些困惑。考虑到这一点,我有以下问题:

  • 如果我指定了要跟踪的像素区域,那么两者(特征匹配和光流)之间的主要区别是什么?我不关心实时跟踪,如果这有助于澄清任何假设。

  • 此外,既然我不进行实时跟踪,那么使用密集光流(Farneback)来跟踪我指定的兴趣区域中的像素是否是更好的主意?

谢谢。

3个回答

27

我很感兴趣这个问题,想分享一些相关思路。如前所述,特征匹配是一种技术,基于以下步骤:

  • 特征检测阶段会返回一组所谓的特征点。这些特征点位于显著的图像结构位置,例如使用FAST时类似于边缘的结构或使用SIFT或SURF时类似于斑点结构。

  • 第二步是匹配。将从两个不同图像中提取的特征点进行关联。匹配基于局部视觉描述符,例如梯度直方图或二进制模式,这些描述符在特征位置周围被局部提取。描述符是一个特征向量,并且相关特征点对是具有最小特征向量距离的点对。

大多数特征匹配方法是尺度旋转不变的,并且对照明变化(例如由阴影或不同对比度引起的)具有强大的适应性。因此,这些方法可以应用于图像序列,但通常更常用于不同视角或使用不同设备捕获的图像配准。特征匹配方法的缺点是难以定义匹配特征发生在哪里,并且特征对(在图像序列中是运动向量)通常非常稀疏。此外,由于大多数检测器被细分到整数位置,因此匹配方法的亚像素精度非常有限。

根据我的经验,特征匹配方法的主要优势是它们可以计算出非常大的运动/ 位移

OpenCV提供了一些特征匹配方法,但在线上有许多更新、更快速和更精确的方法可用,例如:

  • DeepMatching依赖于深度学习,通常用于初始化光流方法,以帮助处理长距离运动。
  • Stereoscann 是一种极快的方法,最初用于视觉里程计。
  • 相比之下,光流 方法依赖于亮度恒定的最小化和额外的约束条件,例如平稳性等。因此,它们基于连续帧序列的空间和时间图像梯度导出运动向量。因此,它们更适合于图像序列,而不是从非常不同的视角拍摄的图像对。使用光流向量估计运动的主要挑战是大运动遮挡强烈光照变化物体外貌变化,以及主要是低运行时间。然而,光流方法可以非常准确地计算出与场景中物体共享运动边界相关的密集运动场

    但是,不同光流方法的准确性差异很大。通常来说,诸如PLK(Lucas Kanade)之类的局部方法不太精确,但允许仅计算预先选择的运动向量,并且因此非常快速。 (近年来,我们已经进行了一些研究以提高局部方法的准确性,有关更多信息,请参见此处)。

    主要的OpenCV主干提供了全局方法,例如Farnback。但这是一种相当过时的方法。请尝试使用OpenCV contrib主干,其中包含更多最新的方法。但是,要获取最新方法的良好概述,请查看公共光流基准测试。在这里,您将找到代码和实现,例如:

  • KITTI 2012 光流基准测试。两者都提供链接,例如到一些新方法的git或源代码,例如FlowFields
  • 但从我的角度来看,我不会在早期阶段拒绝与光学流匹配的特定方法。尽可能多地使用在线实现,并查看对于您的应用程序最佳的是什么。


    1
    因此,它们更适合于图像序列,而不是从非常不同的视角捕获的图像对。这很有趣,我的大多数测试都来自视频库存镜头,并且使用OpenCV的LK实现得到的结果完全符合我们的要求(至少目前是这样...)。谢谢。那真是太有帮助了! - JDBones
    因此,当相机固定不动而物体在移动时,它们更适合于图像序列...确认一下,您的意思是“当相机固定不动而物体在移动时,它们更适合”,对吗? - Milan

    9
    特征匹配使用特征描述符在特征描述符空间中相互匹配(通常)使用最近邻搜索。基本思想是你有描述符向量,并且两个图像中相同的特征应该在描述符空间中彼此靠近,因此你只需这样匹配。

    光流算法不看描述符空间,而是查看围绕特征周围的像素块,然后尝试匹配这些块。如果您熟悉稠密光流,则稀疏光流仅在功能点周围的图像小区域上进行稠密光流。因此,光流假定亮度恒定,即像素亮度在帧之间不会改变。另外,由于您在查看相邻像素,所以需要假设相邻点与您的特征移动方式相似。最后,由于它在小区域上使用稠密流算法,所以它们移动的点不能远离原始特征位置的图像太远。如果是,则建议使用金字塔分辨率方法,在执行此操作之前缩小图像,以使曾经是16像素平移的现在是2像素平移,然后可以将找到的转换作为先验进行缩放。

    因此,当使用模板时,特征匹配算法在比例不完全相同、图像和模板存在透视差异或变换较大时都更好。但是,您的匹配结果只能与您的特征检测器的精度一样好。光流算法只要在正确的位置看,变换就可以非常精确。它们都需要计算量较大;光流算法采用迭代方法使其计算量大(尽管金字塔方法可能会通过运行更多的图像来消耗更多的成本,在某些情况下实际上可以使其更快地达到所需的准确性),最近邻搜索也很昂贵。然而,当变换较小时,光流算法可以工作得非常好,但如果场景中的任何东西干扰了您的照明或者出现了一些不正确的像素(例如,即使是轻微的遮挡),都可能会导致其失效。
    这取决于项目。我曾经参与过一个卫星图像项目,使用了密集光流技术,因为我处理的沙漠地形图像没有足够精确的特征(在位置上),而且不同的特征描述符看起来相对类似,所以在该特征空间中搜索并不能提供很好的匹配效果。在这种情况下,光流法是更好的方法。然而,如果你正在处理城市卫星图像的图像对齐问题,由于建筑物可能会遮挡场景的某些部分,有许多特征将保持匹配,并给出更好的结果。 OpenCV Lucas-Kanade tutorial 并没有提供很多见解,但应该根据上述内容帮助您开始编写代码。

    哇,多么棒的帖子啊!这篇文章充满了信息。谢谢你,Alexander。基于你的帖子,如果为ROI应用形状掩码,是否会改善密集光流的结果,例如cv::calcOpticalFlowFarneback返回的结果的“形状”? - JDBones
    @JDBones,恐怕我不明白你的意思;OpenCV中的光流方法不允许包含掩码。或者你是指其他什么吗? - alkasm
    抱歉回复晚了。我的意思是用黑色遮盖ROI像素区域,从而仅保留掩码点边界内的子图像。只要imgPrevimgCur的尺寸相同,这就不会在我的密集光流调用中失败某些断言。 - JDBones
    @JDBones 抱歉,我还是不太明白。您的意思是您有一个非矩形的 ROI,因此您想要在矩形 ROI 中涂黑一些像素来弥补它吗?如果是这样,那么密集光流算法将假定这些黑色像素也会出现在下一张图像中,而稀疏算法将把它们包括在图像的特征中(例如边缘)。 - alkasm
    对于稀疏算法,您可以删除在非矩形ROI之外的特征点。对于密集算法,C++接口允许在findTransformECC()中使用掩码,请参阅文档 - alkasm

    2

    关键点匹配 = 稀疏光流

    KLT跟踪是稀疏光流的一个很好的例子,可以查看演示LKDemo.cpp(它还有一些Python包装器示例,现在无法记住)。

    对于密集示例,请参见samples/python/opt_flow.py,使用Farnebäcks方法。

    你的困惑是正确的...整个世界都对这个非常简单的主题感到困惑。很大一部分原因是人们认为Lucas-Kanade是稀疏光流(由于OpenCV中一个名字和注释非常糟糕的示例:LKdemo,应该被称为KLTDemo)。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接