学习笔记

OpenCV实现物体追踪

发布于 2023/01/20 · 3 分钟阅读

文章目录
  1. OpenCV实现物体追踪

OpenCV实现物体追踪

项目简介

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

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

追踪对象

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

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

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

声明追踪对象

使用creat()构造

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

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

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

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

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

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

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

程序逻辑

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

KCL流程图

代码实现

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

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() 即可

int main()
{
    // ... 省略初始化节点
    SubPuber tracker;
    ROS::spin();
}    

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

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

// 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;
    }
}