OpenCV 3 Tracking API目标跟踪学习笔记——定义、物体跟踪常用算法、demo

今天开始接触目标跟踪

本文翻译自https://www.learnopencv.com/object-tracking-using-opencv-cpp-python/#opencv-tracking-api

参考有道翻译 

一、Object Tracking

1.物体跟踪就是在连续的视频帧中定位一个物体。这个定义听起来直截了当,但在计算机视觉和机器学习中,跟踪是一个非常广泛的术语,它包含概念上相似但技术上不同的概念。例如,以下所有不同但相关的思想通常在对象跟踪下研究:

(1)稠密光流(Dense Optical flow DOF):这些算法有助于估计视频帧中每个像素的运动矢量。

(2)稀疏光流(Sparse optical flow): 例如Kanade-Lucas-Tomashi (KLT)特征跟踪算法,跟踪图像中几个特征点的位置。

(3)卡尔曼滤波(Kalman Filtering):一种非常流行的基于先验运动信息的信号处理算法,用于预测运动目标的位置。这种算法的早期应用之一是导弹制导!引导阿波罗11号登月舱降落月球的机载计算机有一个卡尔曼滤波器。

(4)Meanshift and Camshift:这是定位密度函数最大值的算法,它们还用于跟踪。

(5)单目标跟踪器(Single object trackers):在这类跟踪器中,第一个帧使用矩形标记,以指示要跟踪的对象的位置。然后使用跟踪算法在后续帧中跟踪对象。在大多数实际应用程序中,这些跟踪器与对象检测器一起使用。

(6)多目标跟踪查找算法(Multiple object track finding algorithms):当我们有一个快速的目标检测器时,在每一帧中检测多个对象,然后运行一个跟踪查找算法来识别一个帧中的哪个矩形与下一个帧中的矩形相对应是有意义的。

二、Tracking VS Detection

如果你玩过OpenCV人脸检测,你就会知道它是实时工作的,你可以很容易地在每一帧中检测到人脸。那么,为什么一开始就需要跟踪呢?让我们来探究一下您可能希望跟踪视频中的对象而不仅仅是重复检测的不同原因。

(1)跟踪比检测快

通常跟踪算法比检测算法快。原因很简单,当你跟踪在前一帧中检测到的对象时,你对该对象的外观了解很多,你也知道前一帧的位置和它的运动方向和速度。所以在下一帧中,你可以使用所有这些信息来预测下一帧中物体的位置,并围绕物体的预期位置进行小搜索,以准确定位物体。一个好的跟踪算法会使用它所拥有的关于那个点的所有信息,而检测算法总是从头开始。因此,在设计一个高效的系统时,通常在每一个第n帧上运行一个目标检测,而在这之间的n-1帧中使用跟踪算法。为什么我们不直接检测第一帧中的对象,然后跟踪呢?的确,跟踪可以从它所拥有的额外信息中获益,但是,当一个对象在较长一段时间内越过障碍物,或者它们移动太快以至于跟踪算法无法跟上时,你也可能会失去对该对象的跟踪。跟踪算法也经常积累错误,跟踪对象的边界框会慢慢偏离它所跟踪的对象。为了用跟踪算法解决这些问题,检测算法经常运行。对目标的大量实例进行了检测算法的训练。因此,他们对对象的一般类有更多的了解。另一方面,跟踪算法更了解它们所跟踪的类的特定实例。

(2)当检测失败时,跟踪可以提供帮助

如果你在视频上运行人脸检测器,而人脸被物体遮挡,那么人脸检测器很有可能失败。另一方面,一个好的跟踪算法可以处理一定程度的遮挡。

(3)跟踪保持标识

对象检测的输出是包含该对象的矩形阵列。但是,该对象没有附加标识。例如,检测红点的检测器将输出与它在一帧中检测到的所有点相对应的矩形。在下一帧中,它将输出另一个矩形数组。在第一帧中,一个特定的点可能由数组中位置10处的矩形表示,而在第二帧中,它可能位于位置17处。在帧上使用检测时,我们不知道哪个矩形对应哪个对象。另一方面,跟踪提供了一种真正连接点的方法。

三、OpenCV 3 Tracking API

OpenCV 3提供了一个新的跟踪API,它包含许多单一对象跟踪算法的实现。

OpenCV 3.4.1中有7种不同的跟踪器——boost、MIL、KCF、TLD、MEDIANFLOW、GOTURN、MOSSE和CSRT。

OpenCV 3.2实现了这6个跟踪器——boost、MIL、TLD、MEDIANFLOW和MOSSE。

OpenCV 3.1实现了这5个跟踪器——boost、MIL、KCF、TLD、MEDIANFLOW。OpenCV 3.0实现了以下4个跟踪器:boost、MIL、TLD、MEDIANFLOW。

四、Python实现

import cv2
import sys

# 获得opencv的版本
(major_ver, minor_ver, subminor_ver) = (cv2.__version__).split('.')

if __name__ == '__main__':

    # 建立跟踪器,选择跟踪器的类型

    tracker_types = ['BOOSTING', 'MIL','KCF', 'TLD', 'MEDIANFLOW', 'GOTURN', 'MOSSE', 'CSRT']
    tracker_type = tracker_types[2]

    if int(minor_ver) < 3:
        tracker = cv2.Tracker_create(tracker_type)
    else:
        if tracker_type == 'BOOSTING':
            tracker = cv2.TrackerBoosting_create()
        if tracker_type == 'MIL':
            tracker = cv2.TrackerMIL_create()
        if tracker_type == 'KCF':
            tracker = cv2.TrackerKCF_create()
        if tracker_type == 'TLD':
            tracker = cv2.TrackerTLD_create()
        if tracker_type == 'MEDIANFLOW':
            tracker = cv2.TrackerMedianFlow_create()
        if tracker_type == 'GOTURN':
            tracker = cv2.TrackerGOTURN_create()
        if tracker_type == 'MOSSE':
            tracker = cv2.TrackerMOSSE_create()
        if tracker_type == "CSRT":
            tracker = cv2.TrackerCSRT_create()

    # 读取视频
    video = cv2.VideoCapture("TownCentreXVID.avi")

    # 打开错误时退出
    if not video.isOpened():
        print("Could not open video")
        sys.exit()

    # 读取视频的第一帧
    ok, frame = video.read()
    if not ok:
        print ('Cannot read video file')
        sys.exit()

    # 定义初始边界框
    bbox = (287, 23, 86, 320)

    # Uncomment the line below to select a different bounding box
    # 选择不同的边界框
    bbox = cv2.selectROI(frame, False)

    # Initialize tracker with first frame and bounding box
    # 使用视频的第一帧和边界框初始化跟踪器
    ok = tracker.init(frame, bbox)

    while True:
        # Read a new frame
        ok, frame = video.read()
        if not ok:
            break

        # Start timer 记录开始时间
        timer = cv2.getTickCount()

        # Update tracker 更新检测器
        ok, bbox = tracker.update(frame)

        # Calculate Frames per second (FPS) 计算FPS
        fps = cv2.getTickFrequency() / (cv2.getTickCount() - timer);

        # Draw bounding box 绘制边界框
        if ok:
            # Tracking success 跟踪成功
            p1 = (int(bbox[0]), int(bbox[1]))
            p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))
            cv2.rectangle(frame, p1, p2, (255,0,0), 2, 1)
        else :  # 跟踪失败
            # Tracking failure
            cv2.putText(frame, "Tracking failure detected", (100,80), cv2.FONT_HERSHEY_SIMPLEX, 0.75,(0,0,255),2)

        # Display tracker type on frame
        # 显示跟踪器的类别
        cv2.putText(frame, tracker_type + " Tracker", (100,20), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50,170,50),2);

        # Display FPS on frame 显示FPS
        cv2.putText(frame, "FPS : " + str(int(fps)), (100,50), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50,170,50), 2);

        # Display result 显示跟踪结果
        cv2.imshow("Tracking", frame)

        # Exit if ESC pressed 按取消键退出
        k = cv2.waitKey(1) & 0xff
        if k == 27 : break

五、Object Tracking Algorithms

在这一节中,我们将深入研究不同的跟踪算法。我们的目标不是对每一个跟踪器都有深刻的理论理解,而是从实践的角度去理解它们。让我首先解释跟踪背后的一些一般原则。在跟踪中,我们的目标是在当前帧中找到一个对象,前提是我们已经在所有(或几乎所有)之前的帧中成功地跟踪了该对象。

因为我们一直跟踪这个对象直到当前帧,所以我们知道它是如何移动的。换句话说,我们知道运动模型的参数。运动模型只是一种奇特的方式,它表示你知道物体在前一帧中的位置和速度(速度+运动方向)。如果你对物体一无所知,你可以根据当前的运动模型预测新的位置,而且你会非常接近物体的新位置。但是我们有更多关于物体运动的信息。我们知道对象在前几帧中的样子。换句话说,我们可以构建一个外观模型,对对象的外观进行编码。该外观模型可以在运动模型预测位置的小邻域内进行搜索,从而更准确地预测目标的位置。

运动模型可以预测物体的大致位置。外观模型对这种估计进行微调,以提供基于外观的更准确的估计。

       如果对象非常简单,并且外观没有太大变化,那么我们可以使用一个简单的模板作为外观模型并寻找该模板。然而,现实生活并非如此简单。一个物体的外观可以发生巨大的变化。为了解决这个问题,在许多现代跟踪器中,这个外观模型是一个分类器,它是通过在线方式训练的。别慌!让我用简单的术语解释一下。

分类器的工作是将图像的矩形区域分类为对象或背景。分类器以图像patch作为输入,返回0到1之间的score,表示图像patch包含该对象的概率。当图像patch确定为背景时score为0,当patch确定为对象时score为1。

在机器学习中,我们使用“在线”这个词来指代在运行时动态训练的算法。离线分类器可能需要数千个示例来训练分类器,但是在线分类器通常在运行时使用很少的示例进行训练。

分类器是通过输入正(对象)和负(背景)的样本来训练的。如果你想构建一个用于检测猫的分类器,可以使用包含猫的数千幅图像和不包含猫的数千幅图像对其进行训练。这样分类器就能区分什么是猫,什么不是。你可以在这里了解更多关于图像分类的信息。当我们构建一个在线分类器时,我们没有奢侈地拥有上千个正样本和负样本的类。

我们来看看不同的追踪算法是如何解决在线训练的问题的。

(1)BOOSTING Tracker:这个跟踪器是基于在线版本的AdaBoost——基于HAAR级联的人脸检测器内部使用的算法。该分类器需要在运行时使用对象的正反样本进行训练。以用户提供的初始bounding box (或其他对象检测算法提供的)作为对象的正样本,bounding box外的许多图像补丁作为背景。给定一个新的帧,在前一个位置邻域的每个像素上运行分类器,记录分类器的score。对象的新位置是score最大的位置。现在对于分类器我们多了一个正样本。随着更多的帧进入,分类器将使用这些额外的数据进行更新。

优点:没有。这个算法已经有10年的历史了,工作正常,但是我找不到一个很好的理由去使用它,尤其是当其他基于类似原理的高级跟踪器(MIL, KCF)可用时。

缺点:跟踪性能一般。它不能可靠地知道跟踪何时失败。

(2)MIL Tracker:这个跟踪器在思想上与上面描述的BOOSTING跟踪器相似。最大的区别是,它不会只考虑对象的当前位置作为一个正样本,而是在当前位置附近的一个小邻域中寻找,以生成几个潜在的正样本。你可能会认为这是一个坏主意,因为在大多数“正样本”的例子中,对象不是居中的。

这就是多实例学习(MIL)的用得上的地方。在MIL中,你没有指定正样本和负样本,而是指定正面和负面的“包”。在正样本包中的图像集合并不都是正样本。相反,只有一个图像在positive bag需要是一个正样本!在我们的例子中,一个positive bag包含以对象当前位置为中心的patches,以及它周围一个小邻域的patches。即使被跟踪对象的当前位置不准确,当来自当前位置附近的样本被放入positive bag时,这个包很可能包含至少一个对象居中的图像。MIL project page为那些希望深入了解MIL跟踪器内部工作原理的人提供了更多信息。

优点:性能相当好。它不像BOOSTING漂移那么大,而且在部分遮挡的情况下,它能做合理的工作。如果您正在使用OpenCV 3.0,这可能是您可以使用的最好的跟踪器。但是如果您使用更高的版本,请考虑KCF。

缺点:追踪失败并不可靠。无法从完全遮挡中恢复。

(3)KCF Tracker:KCF是kernefied Correlation Filters的缩写。此跟踪器基于前两个跟踪器中提出的思想。该跟踪器利用了MIL跟踪器中使用的多个正样本具有较大重叠区域这一事实。这些重叠的数据导致了一些很好的数学特性,这些特性被这个跟踪器利用,使跟踪速度更快,同时也更准确。

优点:准确性和速度都比MIL好,而且它比提振和MIL更有效地追踪失败,如果你使用的是OpenCV 3.1和以上,我建议用这个来做大部分的应用。

缺点:不能从完全遮挡中恢复。OpenCV 3.0中没有实现。

(4)TLD Tracker :TLD代表跟踪、学习和检测。顾名思义,这个追踪分解长期跟踪任务分为三部分——(短期)跟踪、学习、和检测。从作者的论文,“跟踪器跟踪对象从一帧到另一帧。检测器定位到目前为止观察到的所有外观,并在必要时纠正跟踪器。学习估计检测器的错误,并对其进行更新,以避免以后出现这些错误。“这个跟踪器的输出往往有点跳跃。例如,如果您正在跟踪一个行人,并且场景中有其他行人,那么这个跟踪器有时可以临时跟踪与您打算跟踪的行人不同的行人。在积极的一面,这个轨迹似乎在更大的范围内跟踪一个物体,运动和遮挡。如果你有一个视频序列,其中对象隐藏在另一个对象后面,这个跟踪器可能是一个不错的选择。

优点:在多帧的遮挡下效果最好。此外,跟踪规模变化最好。

缺点:大量的假阳性使它几乎无法使用。

(5)MEDIANFLOW Tracker:在内部,该跟踪器在时间上同时在向前和向后两个方向跟踪对象,并测量这两个轨迹之间的差异。最小化这种向前向后的误差可以使他们可靠地检测跟踪失败,并在视频序列中选择可靠的轨迹。在我的测试中,我发现当运动是可预测的并且很小的时候,这种跟踪器工作得最好。与其他跟踪器不同的是,即使在跟踪时,跟踪器也会一直运行。

优点:出色的报告跟踪失败。当运动是可预测的并且没有遮挡时,这种方法非常有效。

缺点:在大动作下失败。

(6)GOTURN tracker:在跟踪器类中的所有跟踪算法中,这是唯一一个基于卷积神经网络(CNN)的算法。从OpenCV文档中,我们知道它是“对视点变化、光照变化和变形的健壮性”。但它不能很好地处理遮挡。GOTURN是一个基于CNN的跟踪器,使用caffe模型进行跟踪。Caffe模型和原型文本文件必须出现在代码所在的目录中。这些文件也可以从opencv_extra存储库下载,在使用前连接并提取。GOTURN目标跟踪算法已经移植到OpenCV。

(7)MOSSE tracker:最小平方误差输出和(MOSSE)使用自适应相关的目标跟踪,产生稳定的相关滤波器时,初始化使用一帧。MOSSE跟踪器对于光线、比例、姿态和非刚性变形的变化是鲁棒的。它还根据峰值旁瓣比检测遮挡,这使得跟踪器能够在对象重新出现时暂停并恢复到它停止的位置。MOSSE跟踪器也运行在更高的fps (450 fps甚至更多)。此外,它也非常容易实现,与其他复杂的跟踪器一样准确,而且速度快得多。但是,在性能方面,它落后于基于深度学习的跟踪器。

(8)CSRT tracker:在带通道和空间可靠性的判别相关滤波器(DCF-CSR)中,我们使用空间可靠性图将滤波器支持调整到从帧中选择区域的部分进行跟踪。这确保了选定区域的放大和定位,并改进了对非矩形区域或对象的跟踪。它只使用两个标准特性(生猪和颜色名称)。它的fps也相对较低(25 fps),但对目标跟踪具有较高的精度。

错误解决:

1. tracker = cv2.TrackerKCF_create()

AttributeError: module 'cv2.cv2' has no attribute 'TrackerKCF_create'

https://blog.csdn.net/qq_35759574/article/details/82146721

2. can't open "goturn.prototxt" in function 'cv::dnn::ReadProtoFromTextFile'

https://blog.csdn.net/yb1449352/article/details/80258441

 

最后附上今天的一点点学习笔记:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LiuHui*n

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值