目标跟踪 opencv,opencv目标识别与跟踪
本文主要介绍如何以及何时使用OpenCV4.2中提供的八种不同的跟踪器——Boosting、MIL、KCF、TLD、MedianFlow、Go Turn、Mosse和CSRT,并使用它们实现单目标跟踪。有需要可以参考一下。
00-1010 1.什么是目标跟踪2。跟踪和探测。使用OpenCV4的对象跟踪3.1使用OpenCV4的对象跟踪C代码3.2使用OpenCV4的对象跟踪Python代码4。跟踪算法分析4.1 Boosting Tracker 4.2 MIL Tracker 4.3 KCF跟踪器4.4 TLD tr ack 4.5 MedianflowTracker 4.6 GotturnTracker 4.7 mosse Tracker 4.8 CSRT跟踪器在本教程中,我们将学习使用OpenCV来跟踪对象。OpenCV 3.0开始引入跟踪API。我们将学习如何以及何时使用OpenCV 4.2中提供的8种不同的跟踪器——Boosting、MIL、KCF、TLD、MedianFlow、Go Turn、Mosse和CSRT。我们还将学习现代跟踪算法背后的一般理论。
目录
简单地说,在连续的视频帧中定位一个对象叫做跟踪。
这个定义听起来很简单,但在计算机视觉和机器学习中,跟踪是一个非常宽泛的术语,包括概念相似但技术不同的想法。例如,以下所有不同但相关的想法通常在对象跟踪中进行研究。
1.密集光流:这些算法有助于估计视频帧中每个像素的运动矢量。
2.稀疏光流:这些算法,如Kanade-Lucas-Tomashi (KLT)特征跟踪器,跟踪图像中几个特征点的位置。
3.卡尔曼滤波(Kalman Filtering):一种非常流行的信号处理算法,用于根据先验运动信息预测运动目标的位置。这个算法的早期应用之一就是导弹制导!
4.Meanshift和Camshift:这是定位密度函数最大值的算法。它们也用于跟踪。
5.单一对象跟踪器:在这种跟踪器中,第一帧使用一个矩形来标记我们要跟踪的对象的位置。然后使用跟踪算法在后续帧中跟踪目标。在大多数实际应用中,这些追踪器与物体探测器结合使用。
6.多目标跟踪寻找算法:当我们有一个快速目标检测器时,在每一帧中检测多个目标是有意义的,然后运行跟踪寻找算法来识别一帧中的哪个矩形对应于下一帧中的矩形。
1.什么是目标跟踪
如果你玩过OpenCV人脸检测,你就知道它是实时工作的,你可以很容易地检测出每一帧的人脸。那么,为什么首先需要跟踪呢?让我们探讨一下您可能想要跟踪视频中的对象而不仅仅是重复检测的不同原因。
1.跟踪比侦查快。3360通常情况下,跟踪算法比检测算法快。原因很简单。当你在追踪前一帧检测到的物体时,你会对物体的外观有很多了解。你也知道了它在前一个坐标系中的位置及其运动的方向和速度。所以在下一帧中,你可以利用所有这些信息来预测物体在下一帧中的位置,并对物体的预期位置进行小搜索,以准确定位物体。一个好的跟踪算法将使用它所拥有的关于目标的所有信息,而检测算法总是从头开始。因此,在设计高效系统时,通常每n帧进行一次目标检测,在n-1帧之间使用跟踪算法。为什么不直接在第一帧检测目标,然后跟踪呢?追踪确实可以受益于它所拥有的额外信息,但如果一个物体长时间停留在障碍物后面,或者它移动得太快,以至于追踪算法跟不上,你也会失去对它的追踪。跟踪算法往往会累积误差,被跟踪对象的包围盒会慢慢偏离被跟踪对象。我们经常使用检测算法来解决跟踪算法的这些问题。检测算法基于大数据训练,所以他们更了解物体的一般类别。另一方面,跟踪算法知道更多关于它们跟踪的类的具体实例。
2.当检测失败时,跟踪可以有所帮助:如果你在视频中运行人脸检测器,而这个人的脸被一个物体挡住了,人脸检测器很可能会失败。好的跟踪算法将解决某种程度的遮挡。
3.跟踪和保护ID
:对象检测的输出是一个包含对象的矩形数组。但是,该对象没有附加身份。例如,在下面的视频中,一个检测红点的探测器将输出与它在一帧中检测到的所有点相对应的矩形。在下一帧中,它将输出另一个矩形数组。在第一帧中,一个特定的点可能由数组中位置10的矩形表示,而在第二帧中,它可能位于位置17。当在帧上使用检测时,我们不知道哪个矩形对应哪个对象。另一方面,追踪提供了一种将这些点连接起来的方法!
3.使用OpenCV 4实现对象跟踪
OpenCV 4附带了一个跟踪API,它包含了许多单对象跟踪算法的实现。在OpenCV 4.2中有8种不同的跟踪器可用- BOOSTING, MIL, KCF, TLD, MEDIANFLOW, GOTURN, MOSSE,和CSRT。
注意: OpenCV 3.2实现了这6个跟踪器- BOOSTING, MIL, TLD, MEDIANFLOW, MOSSE和GOTURN。OpenCV 3.1实现了这5个跟踪器- BOOSTING, MIL, KCF, TLD, MEDIANFLOW。OpenCV 3.0实现了以下4个跟踪器- BOOSTING, MIL, TLD, MEDIANFLOW。
在OpenCV 3.3中,跟踪API已经改变。代码检查版本,然后使用相应的API。
在简要描述这些算法之前,让我们先看看它们的设置和使用方法。在下面的注释代码中,我们首先通过选择跟踪器类型来设置跟踪器——BOOSTING、MIL、KCF、TLD、MEDIANFLOW、GOTURN、MOSSE或CSRT。然后我们打开一段视频,抓取一帧。我们定义了一个包含第一帧对象的边界框,并用第一帧和边界框初始化跟踪器。最后,我们从视频中读取帧,并在循环中更新跟踪器,以获得当前帧的新包围框。随后显示结果。
3.1使用OpenCV 4实现对象跟踪 C++代码
#include <opencv2/opencv.hpp>#include <opencv2/tracking.hpp>
#include <opencv2/core/ocl.hpp>
using namespace cv;
using namespace std;
// 转换为字符串
#define SSTR( x ) static_cast< std::ostringstream & >( ( std::ostringstream() << std::dec << x ) ).str()
int main(int argc, char **argv)
{
// OpenCV 3.4.1中的跟踪器类型列表
string trackerTypes[8] = {"BOOSTING", "MIL", "KCF", "TLD","MEDIANFLOW", "GOTURN", "MOSSE", "CSRT"};
// vector <string> trackerTypes(types, std::end(types));
// 创建一个跟踪器
string trackerType = trackerTypes[2];
Ptr<Tracker> tracker;
#if (CV_MINOR_VERSION < 3)
{
tracker = Tracker::create(trackerType);
}
#else
{
if (trackerType == "BOOSTING")
tracker = TrackerBoosting::create();
if (trackerType == "MIL")
tracker = TrackerMIL::create();
if (trackerType == "KCF")
tracker = TrackerKCF::create();
if (trackerType == "TLD")
tracker = TrackerTLD::create();
if (trackerType == "MEDIANFLOW")
tracker = TrackerMedianFlow::create();
if (trackerType == "GOTURN")
tracker = TrackerGOTURN::create();
if (trackerType == "MOSSE")
tracker = TrackerMOSSE::create();
if (trackerType == "CSRT")
tracker = TrackerCSRT::create();
}
#endif
// 读取视频
VideoCapture video("videos/chaplin.mp4");
// 如果视频没有打开,退出
if(!video.isOpened())
{
cout << "Could not read video file" << endl;
return 1;
}
// 读第一帧
Mat frame;
bool ok = video.read(frame);
// 定义初始边界框
Rect2d bbox(287, 23, 86, 320);
// 取消注释下面的行以选择一个不同的边界框
// bbox = selectROI(frame, false);
// 显示边界框
rectangle(frame, bbox, Scalar( 255, 0, 0 ), 2, 1 );
imshow("Tracking", frame);
tracker->init(frame, bbox);
while(video.read(frame))
{
// 启动定时器
double timer = (double)getTickCount();
// 更新跟踪结果
bool ok = tracker->update(frame, bbox);
// 计算每秒帧数(FPS)
float fps = getTickFrequency() / ((double)getTickCount() - timer);
if (ok)
{
// 跟踪成功:绘制被跟踪对象
rectangle(frame, bbox, Scalar( 255, 0, 0 ), 2, 1 );
}
else
{
// 跟踪失败
putText(frame, "Tracking failure detected", Point(100,80), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0,0,255),2);
}
// 在帧上显示跟踪器类型
putText(frame, trackerType + " Tracker", Point(100,20), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(50,170,50),2);
// 帧显示FPS
putText(frame, "FPS : " + SSTR(int(fps)), Point(100,50), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(50,170,50), 2);
// 显示帧
imshow("Tracking", frame);
// 按ESC键退出。
int k = waitKey(1);
if(k == 27)
{
break;
}
}
}
3.2使用OpenCV 4实现对象跟踪 Python代码
import cv2import sys
(major_ver, minor_ver, subminor_ver) = (cv2.__version__).split(.)
if __name__ == __main__ :
# 建立追踪器
# 除了MIL之外,您还可以使用
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("videos/chaplin.mp4")
# 如果视频没有打开,退出。
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)
# 取消注释下面的行以选择一个不同的边界框
# bbox = cv2.selectROI(frame, False)
# 用第一帧和包围框初始化跟踪器
ok = tracker.init(frame, bbox)
while True:
# 读取一个新的帧
ok, frame = video.read()
if not ok:
break
# 启动计时器
timer = cv2.getTickCount()
# 更新跟踪器
ok, bbox = tracker.update(frame)
# 计算帧率(FPS)
fps = cv2.getTickFrequency() / (cv2.getTickCount() - timer);
# 绘制包围框
if ok:
# 跟踪成功
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 :
# 跟踪失败
cv2.putText(frame, "Tracking failure detected", (100,80), cv2.FONT_HERSHEY_SIMPLEX, 0.75,(0,0,255),2)
# 在帧上显示跟踪器类型名字
cv2.putText(frame, tracker_type + " Tracker", (100,20), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50,170,50),2);
# 在帧上显示帧率FPS
cv2.putText(frame, "FPS : " + str(int(fps)), (100,50), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50,170,50), 2);
# 显示结果
cv2.imshow("Tracking", frame)
# 按ESC键退出
k = cv2.waitKey(1) & 0xff
if k == 27 : break
4.跟踪算法解析
在本节中,我们将深入研究不同的跟踪算法。我们的目标不是对每一个跟踪器都有一个深刻的理论理解,而是从实际的角度来理解它们。
让我首先解释一些跟踪的一般原则。在跟踪中,我们的目标是在当前帧中找到一个对象,因为我们已经成功地在所有(或几乎所有)之前的帧中跟踪了这个对象。
因为我们一直跟踪对象直到当前帧,所以我们知道它是如何移动的。换句话说,我们知道运动模型的参数。运动模型只是一种花哨的说法,表示你知道物体在前几帧中的位置和速度(速度+运动方向)。如果你对物体一无所知,你可以根据当前的运动模型预测新的位置,你会非常接近物体的新位置。
但我们有比物体运动更多的信息。我们知道物体在之前的每一帧中的样子。换句话说,我们可以构建一个对对象的外观进行编码的外观模型。该外观模型可用于在运动模型预测的小邻域内搜索位置,从而更准确地预测物体的位置。
运动模型预测了物体的大致位置。外观模型对这个估计进行微调,以提供基于外观的更准确的估计。
如果对象非常简单,并且没有太多改变它的外观,我们可以使用一个简单的模板作为外观模型,并寻找该模板。然而,现实生活并没有那么简单。物体的外观会发生巨大的变化。为了解决这个问题,在许多现代跟踪器中,这个外观模型是一个以在线方式训练的分类器。别慌!让我用更简单的术语解释一下。
分类器的工作是将图像中的矩形区域分类为物体或背景。分类器接收图像patch作为输入,并返回0到1之间的分数,表示图像patch包含该对象的概率。当完全确定图像patch是背景时,分数为0;当完全确定patch是对象时,分数为1。
在机器学习中,我们用在线这个词来指在运行时进行动态训练的算法。离线分类器可能需要数千个示例来训练一个分类器,但在线分类器通常在运行时使用很少的示例进行训练。
通过向分类器输入正(对象)和负(背景)的例子来训练分类器。如果您想要构建一个用于检测猫的分类器,您可以使用数千张包含猫的图像和数千张不包含猫的图像来训练它。这样分类器学会区分什么是猫,什么不是。在构建一个在线分类器时,我们没有机会拥有数千个正面和负面类的例子。
让我们看看不同的跟踪算法是如何处理在线训练的这个问题的。
4.1 BOOSTING Tracker
该跟踪器基于AdaBoost的在线版本——基于HAAR级联的人脸检测器内部使用的算法。这个分类器需要在运行时用对象的正面和反面例子进行训练。将用户提供的初始包围盒(或其他目标检测算法提供的初始包围盒)作为目标的正例,将包围盒外的许多图像patch作为背景。
给定一个新的帧,分类器在前一个位置附近的每个像素上运行,并记录分类器的得分。对象的新位置是分数最高的位置。现在分类器又多了一个正样本。当更多的帧进来时,分类器就会用这些额外的数据更新。
优点:没有。 这个算法已经有10年的历史了,而且运行良好,但我找不到使用它的好理由,特别是当基于类似原则的其他高级跟踪器(MIL, KCF)可用时。
缺点:跟踪性能平庸。 它不能可靠地知道何时跟踪失败了。
4.2 MIL Tracker
这个跟踪器在思想上与上述的BOOSTING跟踪器相似。最大的区别是,它不是只考虑对象的当前位置作为一个正样本,而是在当前位置周围的一个小领域中寻找几个潜在的正样本。你可能会认为这不是一个好主意,因为在大多数这些正样本的例子中,物体不是居中的。
这就是多实例学习 (MIL) 的用武之地。在 MIL 中,您不指定正面和负面示例,而是指定正面和负面袋子。正面袋子中的图像集合并不都是正例。取而代之的是,正面袋子中只有一张图像需要是正面的例子!
在我们的示例中,一个正面袋子包含以对象当前位置为中心的patch,以及它周围的一个小邻域中的patch。即使被跟踪对象的当前位置不准确,当来自当前位置附近的样本被放入正面袋子中时,这个正面袋子很有可能包含至少一个对象很好地居中的图像。
优点:性能很好。 它不像BOOSTING跟踪器那样漂移,并且在部分遮挡下做了合理的工作。如果你正在使用OpenCV 3.0,这可能是你可用的最好的跟踪器。但是,如果您使用的是更高的版本,请考虑KCF。
缺点: 无法可靠地报告跟踪失败。不能从完全遮挡中恢复。
4.3 KCF Tracker
KFC 代表Kernelized Correlation Filters(Kernelized相关性过滤器)。该跟踪器建立在前两个跟踪器中提出的想法之上。该跟踪器利用了 MIL 跟踪器中使用的多个正样本具有较大重叠区域的事实。这种重叠数据导致了一些很好的数学特性,该跟踪器利用这些特性使跟踪更快、更准确。
优点:准确性和速度都优于 MIL,它报告的跟踪失败比 BOOSTING 和 MIL 更好。 如果您使用的是 OpenCV 3.1 及更高版本,我建议将其用于大多数应用程序。
缺点: 不能从完全遮挡中恢复。
4.4 TLD Tracker
TLD 代表跟踪、学习和检测。顾名思义,这个跟踪器将长期跟踪任务分解为三个部分——(短期)跟踪、学习和检测。从作者的论文中,跟踪器逐帧跟踪对象。检测器定位到目前为止已观察到的所有外观,并在必要时纠正跟踪器。
学习估计检测器的错误并对其进行更新以避免将来出现这些错误。这个跟踪器的输出往往会有点跳跃。例如,如果您正在跟踪行人并且场景中有其他行人,则此跟踪器有时可以临时跟踪与您打算跟踪的行人不同的行人。从积极的方面来说,这条轨迹似乎可以在更大的范围、运动和遮挡范围内跟踪对象。如果您有一个对象隐藏在另一个对象后面的视频序列,则此跟踪器可能是一个不错的选择。
优点:在多个帧的遮挡下效果最佳。此外,跟踪最好的规模变化。
缺点:大量的误报使得它几乎无法使用。
4.5 MEDIANFLOW Tracker
在内部,该跟踪器在时间上向前和向后跟踪对象,并测量这两个轨迹之间的差异。最小化这种 ForwardBackward 误差使他们能够可靠地检测跟踪失败并在视频序列中选择可靠的轨迹。
在我的测试中,我发现该跟踪器在运动可预测且较小时效果最佳。与其他跟踪器即使在跟踪明显失败时仍继续运行不同,该跟踪器知道跟踪何时失败。
优点:出色的跟踪失败报告。当运动是可预测的并且没有遮挡时效果很好。
缺点:在大运动下失败。
4.6 GOTURN tracker
在跟踪器类的所有跟踪算法中,这是唯一一种基于卷积神经网络 (CNN) 的算法。从 OpenCV 文档中,我们知道它对视点变化、光照变化和变形具有鲁棒性。但它不能很好地处理遮挡。
注意:GOTURN 是基于 CNN 的跟踪器,使用 Caffe 模型进行跟踪。 Caffe 模型和 proto 文本文件必须存在于代码所在的目录中。这些文件也可以从 opencv_extra 存储库下载、连接并在使用前提取。
4.7 MOSSE tracker
最小输出平方误差和 (MOSSE) 使用自适应相关性进行对象跟踪,在使用单帧初始化时会产生稳定的相关性滤波器。 MOSSE 跟踪器对光照、比例、姿势和非刚性变形的变化具有鲁棒性。它还根据峰值旁瓣(peak-to-sidelobe)比检测遮挡,这使跟踪器能够在对象重新出现时暂停并从中断的地方恢复。 MOSSE 跟踪器还以更高的 fps(450 fps 甚至更高)运行。除此之外,它还非常容易执行,与其他复杂追踪器一样准确,而且速度更快。但是,在性能尺度上,它落后于基于深度学习的跟踪器。
4.8 CSRT tracker
在DCF-CSR (Discriminative Correlation Filter with Channel and Spatial Reliability, DCF-CSR)中,我们使用空间可靠性映射来调整滤波器的支持度,使其适应帧中被选择区域的跟踪部分。这确保了所选区域的放大和定位,并改进了对非矩形区域或对象的跟踪。它只使用2个标准特性(hog和Colornames)。它也运行在一个相对较低的fps (25 fps),但提供了较高的目标跟踪精度。
到此这篇关于基于OpenCV4.2实现单目标跟踪的文章就介绍到这了,更多相关OpenCV单目标跟踪内容请搜索盛行IT软件开发工作室以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT软件开发工作室!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。