0%

OpenCV单目标跟踪

参考

环境

  • VS 2019
  • OpenCV 3.4.14 (opencv_contrib)

参考几篇文章做了一个简单的小实验:调用OpenCV自带的函数进行跟踪,完整代码见文末。程序执行后,首先弹出一个框,手动选取目标区,按下回车后开始通过跟踪,以矩形框的形式显示出来。在3.4.14版本中有7种方法可以用(当然可能会更多),没有对每一个方法做详细测试,直观感觉是CSRT最稳定,跑宽高544x960的视频中一个50x50左右的目标,帧率可以达到35;BOOSTING也挺稳的,帧率达到45,但矩形框会有抖动,且目标消失后不能检测出来;MEDIANFLOW速度特别快,帧率300-400,但基本等于没用,矩形框围绕目标疯狂蹦迪,蹦一会儿就跟丢了。

其他方法没仔细对比,借用一下参考文章中的一个测试数据,做一个对比和总结:

追踪器选择方法:

如果追求高准确度,又能忍受慢一些的速度,那么就用CSRT;

如果对准确度的要求不苛刻,想追求速度,那么就选KCF;

纯粹想节省时间就用MOSSE。

下表总结了不同版本的OpenCV中可使用的追踪器和具体速度情况。FPS在CPU(I5)下对640X360的视频进行跟踪所获得的平均结果

Tracker FPS OpenCV Version
BOOSTING 43.9 OpenCV 3.0+
MIL 11.0 OpenCV 3.0+
KCF 48.0 OpenCV 3.2+
TLD 23.0 OpenCV 3.0+
MEDIANFLOW 277.5 OpenCV 3.0+
MOSSE 144.2 OpenCV 3.1+
CSRT 16.3 OpenCV 3.4+3

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/*
* 测试OpenCV跟踪函数
*/
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/tracking.hpp>

bool track(const cv::Ptr<cv::Tracker> &tracker, const cv::Mat& frame, cv::Rect2d &bbox, double& fps);

/// <param name="videoPath"></param>
/// <param name="trackerName">["BOOSTING", "MIL", "KCF", "TLD", "MEDIANFLOW", "MOSSE", "CSRT"]</param>
void trackVideo(std::string videoPath, std::string trackerName = "CSRT");

int main(int argc, char* argv[])
{
trackVideo("C:\\Users\\XXX\\Desktop\\video.mp4", "MIL");
return 0;
}

bool track(const cv::Ptr<cv::Tracker>& tracker, const cv::Mat& frame, cv::Rect2d &bbox, double& fps)
{
if (!frame.data) return false;
if (!tracker) return false;

cv::Scalar color(255, 0, 0);
double t = double(cv::getTickCount());

bool success = tracker->update(frame, bbox);

fps = cv::getTickFrequency() / (double(cv::getTickCount()) - t);

return success;
}

void trackVideo(std::string videoPath, std::string trackerName)
{
cv::VideoCapture cap(videoPath);

cv::Ptr<cv::Tracker> tracker;

cv::Mat frame;
int curFrame = 0,
frameNum = (int)cap.get(CV_CAP_PROP_FRAME_COUNT);
cv::Scalar color(255, 0, 0);
while (true)
{
if (cap.read(frame))
{
cv::Rect2d procArea;
if (curFrame == 0)
{
procArea = cv::selectROI(frame);

//跟踪器初始化
if (trackerName == "BOOSTING")
tracker = cv::TrackerBoosting::create();
if (trackerName == "MIL")
tracker = cv::TrackerMIL::create();
if (trackerName == "KCF")
tracker = cv::TrackerKCF::create();
if (trackerName == "TLD")
tracker = cv::TrackerTLD::create();
if (trackerName == "MEDIANFLOW")
tracker = cv::TrackerMedianFlow::create();
if (trackerName == "MOSSE")
tracker = cv::TrackerMOSSE::create();
if (trackerName == "CSRT")
tracker = cv::TrackerCSRT::create();
tracker->init(frame, procArea);
cv::rectangle(frame, procArea, color);
}
else
{
double fps;
if (!track(tracker, frame, procArea, fps))
{

cv::putText(frame, "Tracking failure detected", cv::Point(100, 80), cv::FONT_HERSHEY_SIMPLEX, 0.75, color, 2);
break;
}
else
{
cv::rectangle(frame, procArea, color);
}

// Display FPS on frame 表示FPS
cv::putText(frame, "FPS : " + std::to_string(int(fps)), cv::Point(100, 50), cv::FONT_HERSHEY_SIMPLEX, 0.75, color, 2);
}

cv::namedWindow("video", 1);
cv::imshow("video", frame);
if (cv::waitKey(30) == 27)
{
break;
}
}

curFrame++;
if (curFrame == frameNum)
{
curFrame = 0;
cap.set(CV_CAP_PROP_POS_FRAMES, 0);
}
}

}