OpenCV实现物体追踪

OpenCV实现物体追踪

项目简介

通过Opencv内置函数实现物体追踪,并且部署在ROS中,实现摄像头读取。本文不涉及追踪算法的具体原理,而是针对RM中装甲板识别做出具体的实践部署。

具体项目已经部署在GitHUb:https://github.com/Phoenizard/Track-Image-InROS

追踪对象

使用opencv自带的追踪对象,需要调用一下头文件:

1
2
3
#include <opencv2/opencv.hpp>
#include <opencv2/tracking.hpp>
#include <opencv2/core/ocl.hpp>

在OpenCV中一共有7中追踪算法,分别是BOOSTING, MIL, KCF, TLD , MEDIANFLOW, MOSSE, CSRT ,在使用中选择最常见的KCF算法

声明追踪对象

使用creat()构造

1
yourtracker = TrackerKCF::create();
初始化目标

使用init(cv::Mat_flame,cv::Rect2d_object)初始化

  • Mat_flame:放入初始帧图片
  • Rect2d_object:放入目标在初始帧照片中的像素矩阵
1
2
cv::Rect2d bbox;
yourtracker->init(flame, bbox);
更新目标

使用update(cv::Mat_flame,cv::Rect2d_object) 更新当前帧

  • Mat_flame:放入当前帧
  • Rect2d_object:放入上一帧目标矩形
1
yourtracker->update(flame, bbox);
判断目标丢失

算法将自动通过滤波匹配目标,update()函数在定义中为bool类型,如果目标丢失,返回值为false

1
2
bool ok = yourtracker->update(flame, bbox);
if(!ok) cout << "Track Lost" << endl;

程序逻辑

在RM中,追踪算法运用于装甲板的识别和追踪中,代码逻辑如下:

KCL流程图

代码实现

在ROS中,由于接受和发布照片在同一对象中完成,我们依然使用订阅和发布的模版对象SubPuber(自定义的对象):

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
class SubPuber
{
private:
ros::NodeHandle nodeHandle;
ros::Subscriber imgSub;
ros::Publisher trackobj;
// Define Part
public:
SubPuber()
{
imgSub = nodeHandle.subscribe("/camera/color/image_raw", 1, &SubPuber::ObjectTracker, this);
trackobj = nodeHandle.advertise<sensor_msgs::Image>("/tracker", 1);
// Initate Part
}

void ObjectTracker(const sensor_msgs::ImageConstPtr &frontRGBImg)
{
Mat image;
try
{
image = cv_bridge::toCvShare(frontRGBImg, "bgr8")->image;
}
catch (cv_bridge::Exception& e)
{
ROS_ERROR("Could not convert to image!");
return;
}
// Program Part
sensor_msgs::ImagePtr msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", image).toImageMsg();
trackobj.publish(*msg);
}
}

所以结合ROS::spin();即可实现循环。具体来说,当程序运行到ros::spin()的时候,会找到订阅和发布的API,并且循环订阅发布两个动作 [注意:不会循环代码的其他部分,仅仅是订阅和发布]。

在主程序中,创建对象和spin() 即可

1
2
3
4
5
6
int main()
{
// ... 省略初始化节点
SubPuber tracker;
ROS::spin();
}

观察代码,Initate Part 仅仅运行一遍,很适合创建追踪器,而在Program Part 可以把追踪的代码部署与此循环执行。补充代码如下:

由于作者手边没有装甲板信息,则使用ROI交互界面,通过手动框出矩形框初始化目标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Define Part
Ptr<Tracker> tracker;
cv::Rect2d bbox;
int state = 0;

// Initate Part
tracker = TrackerKCF::create();

// Program Part
if(state == 0){
bbox = bbox = selectROI(image, false);
tracker->init(image,bbox);
state = 1;
}else {
bool ok = tracker->update(image,bbox);
if(ok) {
rectangle(image, bbox, Scalar(255,0,0), 4);
}else {
cout << endl << "TrackLost" << endl;
state = 0;
}
}