OpenCV Tracker–目标跟踪
OpenCV Tracker位于OpenCV contrib modules模块中,需要另行下载编译安装,**contrib版本一定要与opencv版本匹配 **。库名称为tracking.hpp
一、Object Tracking
物体跟踪就是在连续的视频帧中定位一个物体。 例如,以下所有不同但相关的思想通常在对象跟踪下研究:
- 稠密光流(Dense Optical flow DOF):这些算法有助于估计视频帧中每个像素的运动矢量。
- 稀疏光流(Sparse optical flow): 例如Kanade-Lucas-Tomashi (KLT)特征跟踪算法,跟踪图像中几个特征点的位置。
- 卡尔曼滤波(Kalman Filtering):一种非常流行的基于先验运动信息的信号处理算法,用于预测运动目标的位置。这种算法的早期应用之一是导弹制导!引导阿波罗11号登月舱降落月球的机载计算机有一个卡尔曼滤波器。
- Meanshift and Camshift:这是定位密度函数最大值的算法,它们还用于跟踪。
- 单目标跟踪器(Single object trackers):在这类跟踪器中,第一个帧使用矩形标记,以指示要跟踪的对象的位置。然后使用跟踪算法在后续帧中跟踪对象。在大多数实际应用程序中,这些跟踪器与对象检测器一起使用。
- 多目标跟踪查找算法(Multiple object track finding algorithms):当我们有一个快速的目标检测器时,在每一帧中检测多个对象,然后运行一个跟踪查找算法来识别一个帧中的哪个矩形与下一个帧中的矩形相对应是有意义的。
二、Tracking VS Detection
- 跟踪比检测快:跟踪可以获得前一帧的位置和它的运动方向和速度等额外信息。高效的系统应该是跟踪与检测结合。
- 当检测失败时,跟踪可以提供帮助。跟踪起到去遮挡作用。
- 跟踪保持标识:多个选择对象下,跟踪提供了一种真正连接点的方法。
三、Object Tracking Algorithms
基础概念
- 运动模型: 物体在前一帧中的位置和速度(速度+运动方向),根据运动模型预测物体的在新帧中的位置。
- 外观模型: 对对象的外观进行编码。外观模型可以在运动模型预测位置的小邻域内进行搜索,从而更准确地预测目标的位置。现代跟踪器中,外观模型是一个分类器,用在线方式训练获取。
- 分类器: 将图像的矩形区域分类为对象或背景。图像patch作为输入,返回0到1之间的score,表示图像patch包含该对象的概率。
- 在线训练: 我们使用“在线”这个词来指代在运行时动态训练的算法。离线分类器可能需要数千个示例来训练分类器,但是在线分类器通常在运行时使用很少的示例进行训练。
Opencv追踪算法
- BOOSTING Tracker: 基于在线版本的AdaBoost——基于HAAR级联的人脸检测器内部使用的算法。该分类器在运行时使用对象的正反样本进行训练。以用户提供的初始bounding box (或其他对象检测算法提供的)作为对象的正样本,bounding box外的许多图像补丁作为背景。给定一个新的帧,在前一个位置邻域的每个像素上运行分类器,记录分类器的score。对象的新位置是score最大的位置。现在对于分类器我们多了一个正样本。随着更多的帧进入,分类器将使用这些额外的数据进行更新。
优点:没有。这个算法已经有10年的历史了,工作正常,但是我找不到一个很好的理由去使用它,尤其是当其他基于类似原理的高级跟踪器(MIL, KCF)可用时。 缺点:跟踪性能一般。它不能可靠地知道跟踪何时失败。 - MIL Tracker: 这个跟踪器在思想上与上面描述的BOOSTING跟踪器相似。最大的区别是,它不会只考虑对象的当前位置作为一个正样本,而是在当前位置附近的一个小邻域中寻找,以生成几个潜在的正样本。你可能会认为这是一个坏主意,因为在大多数“正样本”的例子中,对象不是居中的。这就是多实例学习(MIL)的用得上的地方。在MIL中,你没有指定正样本和负样本,而是指定正面和负面的“包”。在正样本包中的图像集合并不都是正样本。相反只有一个图像在positive bag需要是一个正样本!在我们的例子中,一个positive bag包含以对象当前位置为中心的patches,以及它周围一个小邻域的patches。即使被跟踪对象的当前位置不准确,当来自当前位置附近的样本被放入positive bag时,这个包很可能包含至少一个对象居中的图像。MIL project page为那些希望深入了解MIL跟踪器内部工作原理的人提供了更多信息。
优点:性能相当好。它不像BOOSTING漂移那么大,而且在部分遮挡的情况下,它能做合理的工作。如果您正在使用OpenCV 3.0,这可能是您可以使用的最好的跟踪器。但是如果您使用更高的版本,请考虑KCF。 缺点:追踪失败并不可靠。无法从完全遮挡中恢复。 - KCF Tracker: KCF是kernefied Correlation Filters的缩写。此跟踪器基于前两个跟踪器中提出的思想。该跟踪器利用了MIL跟踪器中使用的多个正样本具有较大重叠区域这一事实。这些重叠的数据导致了一些很好的数学特性,这些特性被这个跟踪器利用,使跟踪速度更快,同时也更准确。
优点:准确性和速度都比MIL好,而且它比提振和MIL更有效地追踪失败,如果你使用的是OpenCV 3.1和以上,我建议用这个来做大部分的应用。 缺点:不能从完全遮挡中恢复。OpenCV 3.0中没有实现。 - TLD Tracker : TLD代表跟踪、学习和检测。顾名思义,这个追踪分解长期跟踪任务分为三部分——(短期)跟踪、学习、和检测。从作者的论文,“跟踪器跟踪对象从一帧到另一帧。检测器定位到目前为止观察到的所有外观,并在必要时纠正跟踪器。学习估计检测器的错误,并对其进行更新,以避免以后出现这些错误。“这个跟踪器的输出往往有点跳跃。例如,如果您正在跟踪一个行人,并且场景中有其他行人,那么这个跟踪器有时可以临时跟踪与您打算跟踪的行人不同的行人。在积极的一面,这个轨迹似乎在更大的范围内跟踪一个物体,运动和遮挡。如果你有一个视频序列,其中对象隐藏在另一个对象后面,这个跟踪器可能是一个不错的选择。
优点:在多帧的遮挡下效果最好。此外,跟踪规模变化最好。 缺点:大量的假阳性使它几乎无法使用。 - MEDIANFLOW Tracker: 在内部,该跟踪器在时间上同时在向前和向后两个方向跟踪对象,并测量这两个轨迹之间的差异。最小化这种向前向后的误差可以使他们可靠地检测跟踪失败,并在视频序列中选择可靠的轨迹。在我的测试中,我发现当运动是可预测的并且很小的时候,这种跟踪器工作得最好。与其他跟踪器不同的是,即使在跟踪时,跟踪器也会一直运行。
优点:出色的报告跟踪失败。当运动是可预测的并且没有遮挡时,这种方法非常有效。 缺点:在大动作下失败。 - GOTURN tracker: 在跟踪器类中的所有跟踪算法中,这是唯一一个基于卷积神经网络(CNN)的算法。从OpenCV文档中,我们知道它是“对视点变化、光照变化和变形的健壮性”。但它不能很好地处理遮挡。GOTURN是一个基于CNN的跟踪器,使用caffe模型进行跟踪。Caffe模型和原型文本文件必须出现在代码所在的目录中。这些文件也可以从opencv_extra存储库下载,在使用前连接并提取。GOTURN目标跟踪算法已经移植到OpenCV。
- MOSSE tracker: 最小平方误差输出和(MOSSE)使用自适应相关的目标跟踪,产生稳定的相关滤波器时,初始化使用一帧。MOSSE跟踪器对于光线、比例、姿态和非刚性变形的变化是鲁棒的。它还根据峰值旁瓣比检测遮挡,这使得跟踪器能够在对象重新出现时暂停并恢复到它停止的位置。MOSSE跟踪器也运行在更高的fps (450 fps甚至更多)。此外,它也非常容易实现,与其他复杂的跟踪器一样准确,而且速度快得多。但是,在性能方面,它落后于基于深度学习的跟踪器。
- CSRT tracker: 在带通道和空间可靠性的判别相关滤波器(DCF-CSR)中,我们使用空间可靠性图将滤波器支持调整到从帧中选择区域的部分进行跟踪。这确保了选定区域的放大和定位,并改进了对非矩形区域或对象的跟踪。它只使用两个标准特性(生猪和颜色名称)。它的fps也相对较低(25 fps),但对目标跟踪具有较高的精度。
四、代码示例
import cv2
import sys
(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)
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 = 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);
cv2.putText(frame, "FPS : " + str(int(fps)), (100,50), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50,170,50), 2);
cv2.imshow("Tracking", frame)
k = cv2.waitKey(1) & 0xff
if k == 27 : break
|