视频分析目标跟踪
opencv (opencv_contrib) 实现目标跟踪
前提
需要安装 opencv 和 opencv_contrib。
请参考文章:linux 下 opencv_contrib 源代码编译方法
为什么需要跟踪?
通常跟踪比检测快
单目标检测速度可能为 100+ ms,而单目标跟踪的速度为 10+ ms。
目标跟踪可以基于前一帧检测的位置,运动方向,速度预测下一帧的位置。并围绕预期位置进行小范围搜索以准确定位物体。
比无依赖直接进行检测会快很多。
一个高效的系统应该通常会在 n 帧的第一帧进行使用检测算法进行目标检测,此后 n - 1 帧使用跟踪算法。
为什么不基于第一次检测结果的基础上,后续全部使用跟踪算法?
因为跟踪在遇到遮挡,运动方向和速度高速变化以致于跟踪算法跟不上时,可能会导致跟踪失败。
而且跟踪在一定程度上会有误差参数,误差一直积累下去时,会导致跟踪偏离原始目标。
所以需要检测算法对目标进行修正,一定程度上避免跟踪误差的积累。
当检测失败时,跟踪可以提供帮助
检测在目标被遮挡时,会检测失败。
而一个好的跟踪算法,还能依靠前面帧的位置,方向,速度信息,预测当前的目标。
一定程度上解决一些遮挡问题、
目标跟踪
opencv (opencv_contrib 模块) 目前支持 8 种跟踪算法。
跟踪算法 | opencv 支持的最低版本 | 说明 |
---|---|---|
Boosting | opencv 3.0.0 | 比较古老的目标跟踪算法,速度慢 |
MIL | opencv 3.0.0 | 速度快,但是失败率较高 |
KCF | opencv 3.1.0 | 比 Boosting 和 MIL 快,但是遮挡情况下效果差 |
TLD | opencv 3.0.0 | (TLD 目前有 3 种版本算法。TLD 1.0,TLD 2.0,TLD 3.0。opencv 的 TLD 跟踪效果较差,怀疑是基于 TLD 1.0 算法实现的) |
MedianFlow | opencv 3.0.0 | 跟踪效果较好,但对于快速移动/跳动的物体容易失败。 |
GOTURN | opencv 3.2.0 | 基于深度学习的目标检测器。需要额外的 GOTURN 模型,可以自行训练目标跟踪模型。 |
MOSSE | opencv 3.4.1 | 速度比其它算法快,但是准确率比 CSRT 和 KCF 低。 |
CSRT | opencv 3.4.2 | 准确率比 KCF 稍高,但速度不如 KCF。 |
建议:
- CSRT:如果可以接受较慢速度下,追求高准确度。
- KCF:速度要求稍高,准确度要求不高。
- MOSSE:只要求高速,不要求准确度。
- GOTURN:可以自行训练模型,提高识别效果。
opencv 目标跟踪
参考代码如下:
#include <opencv2/opencv.hpp>
#include <opencv2/tracking.hpp>
#define TEST_MODE_VIDEO 0
#define TEST_MODE_CAMERA 1
#define ENABLE_TEST_MODE TEST_MODE_VIDEO
#define ENABLE_SHOW_FPS 1
// #define TEST_VIDEO_FILE "videos/run.mp4"
enum EnumTrackerType {
E_TRACKER_TYPE_BOOSTING,
E_TRACKER_TYPE_MIL,
E_TRACKER_TYPE_KCF,
E_TRACKER_TYPE_TLD,
E_TRACKER_TYPE_MEDIANFLOW,
E_TRACKER_TYPE_GOTURN,
E_TRACKER_TYPE_MOSSE,
E_TRACKER_TYPE_CSRT,
E_TRACKER_TYPE_MAX
};
#define ENUM_TRACKER_TYPE(type) E_TRACKER_TYPE_##type
#define TEXT_TRACKER_TYPE(type) #type
#define VEC_TRACKER_TYPE(vec, type) do { \
vec[ENUM_TRACKER_TYPE(type)] = TEXT_TRACKER_TYPE(type); \
} while(0)
std::vector<std::string> trackerTypes(E_TRACKER_TYPE_MAX);
int initTrackerTypes(std::vector<std::string> & vec) {
// vec.reserve(E_TRACKER_TYPE_MAX);
VEC_TRACKER_TYPE(vec, BOOSTING);
VEC_TRACKER_TYPE(vec, MIL);
VEC_TRACKER_TYPE(vec, KCF);
VEC_TRACKER_TYPE(vec, TLD);
VEC_TRACKER_TYPE(vec, MEDIANFLOW);
VEC_TRACKER_TYPE(vec, GOTURN);
VEC_TRACKER_TYPE(vec, MOSSE);
VEC_TRACKER_TYPE(vec, CSRT);
return vec.size();
}
cv::Ptr<cv::Tracker> createTrackerByName(EnumTrackerType eTrackerType) {
switch( eTrackerType ) {
case ENUM_TRACKER_TYPE(BOOSTING): return cv::TrackerBoosting::create();
case ENUM_TRACKER_TYPE(MIL): return cv::TrackerMIL::create();
case ENUM_TRACKER_TYPE(KCF): return cv::TrackerKCF::create();
case ENUM_TRACKER_TYPE(TLD): return cv::TrackerTLD::create();
case ENUM_TRACKER_TYPE(MEDIANFLOW): return cv::TrackerMedianFlow::create();
case ENUM_TRACKER_TYPE(GOTURN): return cv::TrackerGOTURN::create();
case ENUM_TRACKER_TYPE(MOSSE): return cv::TrackerMOSSE::create();
case ENUM_TRACKER_TYPE(CSRT): return cv::TrackerCSRT::create();
default:
std::cout << "Incorrect tracker index : " << eTrackerType << std::endl;
for (int i = 0, len = trackerTypes.size(); i < len; ++i) {
printf(" [ %d ] %s\n", i, trackerTypes[i].c_str());
}
break;
}
cv::Ptr<cv::Tracker> tracker;
return tracker;
}
void getRandomColors(std::vector<cv::Scalar> &colors, int numColors) {
cv::RNG rng(0);
for(int i = 0; i < numColors; ++i) {
colors.push_back(cv::Scalar(rng.uniform(0,255), rng.uniform(0, 255), rng.uniform(0, 255)));
}
}
int main(int argc, char * argv[]) {
std::string videoPath = TEST_VIDEO_FILE;
int trackerTypeMax = initTrackerTypes(trackerTypes);
int trackerTypeIndex = 0;
if (argc >= 2) {
int index = argv[1][0] - '0';
if (index >= 0 && index < trackerTypeMax) {
trackerTypeIndex = index;
}
}
if (argc >= 3) {
videoPath = argv[2];
}
std::string trackerType = trackerTypes[trackerTypeIndex];
std::vector<cv::Rect> bboxes;
cv::Mat frame;
std::cout << "Default tracking algoritm is " << trackerType << std::endl;
std::cout << "Available tracking algorithms are:" << std::endl;
for (int i = 0; i < trackerTypeMax; ++i) {
printf(" [ %d ] %s\n", i, trackerTypes[i].c_str());
}
#if (ENABLE_TEST_MODE == TEST_MODE_VIDEO)
cv::VideoCapture cap(videoPath);
#elif (ENABLE_TEST_MODE == TEST_MODE_CAMERA)
cv::VideoCapture cap(0);
#endif
if(!cap.isOpened()) {
std::cout << "Error opening video file " << videoPath << std::endl;
return -1;
}
cap.read(frame);
bool showCrosshair = true, fromCenter = false;
std::cout << "\n==========================================================\n";
std::cout << "OpenCV says press c to cancel objects selection process" << std::endl;
std::cout << "It doesn't work. Press Escape to exit selection process" << std::endl;
std::cout << "\n==========================================================\n";
cv::selectROIs("MultiTracker", frame, bboxes, showCrosshair, fromCenter);
if (bboxes.size() < 1) {
return 0;
}
std::vector<cv::Scalar> colors;
getRandomColors(colors, bboxes.size());
cv::Ptr<cv::MultiTracker> multiTracker = cv::MultiTracker::create();
for(int i = 0; i < bboxes.size(); ++i) {
multiTracker->add(createTrackerByName((EnumTrackerType)trackerTypeIndex), frame, cv::Rect2d(bboxes[i]));
}
std::cout << "\n==========================================================\n";
std::cout << "Started tracking, press ESC to quit." << std::endl;
#if ENABLE_SHOW_FPS
char strText[30];
sprintf(strText, "[ %s ] FPS: ", trackerType.c_str());
const int len = strlen(strText);
#endif
while(cap.isOpened()) {
cap.read(frame);
if (frame.empty()) {
break;
}
#if ENABLE_SHOW_FPS
double timer = (double) cv::getTickCount();
#endif
multiTracker->update(frame);
#if ENABLE_SHOW_FPS
float fps = cv::getTickFrequency() / ((double) cv::getTickCount() - timer);
#endif
for(unsigned i = 0; i < multiTracker->getObjects().size(); ++i) {
cv::rectangle(frame, multiTracker->getObjects()[i], colors[i], 2, 1);
}
#if ENABLE_SHOW_FPS
sprintf(strText + len, "%0.2f", fps);
cv::putText(frame, strText, cv::Point(100,50), cv::FONT_HERSHEY_SIMPLEX, 0.75, cv::Scalar(0, 0, 250), 2);
#endif
cv::imshow("MultiTracker", frame);
if (cv::waitKey(1) == 27) {
break;
}
}
return 0;
}
使用方式:
# 编译
g++ multiTracker.cpp `pkg-config --libs --cflags opencv` -o multiTracker
# 运行
# 第一个参数:使用哪一种跟踪算法
# 0 - BOOSTING
# 1 - MIL
# 2 - KCF
# 3 - TLD
# 4 - MEDIANFLOW
# 5 - GOTURN (需要下载 goturn 模型)
# 6 - MOSSE
# 7 - CSRT
# 第二个参数:测试视频的路径
./multiTracker 0 ./video.mp4
- 运行后,需要框选目标。
- 框选目标后,按 SPACE 或 ENTER 键确定
- 如果需要框选多个目标,重复步骤 1, 2.
- 选定目标后,按 ESC 进行目标跟踪。
GOTURN 运行需要安装 goturn 模型。
下载模块可以参考:GOTURN 模型
需要把模型放于与 multiTracker 同一级目录。
跟踪算法测试结果
0. BOOSTING
1. MIL
2. KCF
3. TLD
4. MEDIANFLOW
5. GOTURN
6. MOSSE
7. CSRT
- 点赞
- 收藏
- 关注作者
评论(0)