KCF追踪器在opencv和RM中的应用

1.理论部分

【参考文档】KCF目标跟踪方法分析与总结

概念

(1)判别式模型和生成式模型
  • 判别式模型

根据训练数据得到分类函数和分界面,比如说根据SVM模型得到一个分界面,然后直接计算条件概率 P(y|x),我们将最大的 P(y|x)。

  • 生成式模型

首先根据猫的特征学习出一个猫的模型,再根据狗的特征学习出狗的模型,之后分别计算新样本X跟三个类别的联合概率 P(y|x),然后根据贝叶斯公式,分别计算 P(y|x),选择三类中最大的 P(y|x)作为样本的分类

2.实战

2.1.在opencv中

2.1.1跟踪器结构

在这里插入图片描述
基本上所有的追踪方法都会继承cv::track,在使用的时候也是使用向上转型的技术(即创建父类类型的变量指向子类对象
同时track类包含三个基本函数
①析构函数
②初始化函数init(虚函数)
③更新函数update(虚函数)
init和update都是虚函数,在相应的追踪器中实现

2.1.2. init

使用目标周围的已知边界框初始化跟踪器
在这里插入图片描述
参数
image 初始帧
boundingBox 初始边界框

2.1.2 update()

更新跟踪器,找到目标的新的最可能的边界框(返回到boundingBox中)
请添加图片描述
参数:

  • image 当前帧
  • boundingBox 表示新目标位置的边界框(如果返回为 true,则未以其他方式修改)

返回值:
True 表示目标已定位,false 表示跟踪器无法在当前帧中找到目标。请注意,后者并不意味着跟踪器已经失败,也许目标确实从框架中丢失(例如,看不见)

2.2 使用

【参考文档】opencv自带kcf算法实现目标跟踪

  1. 创建kcf追踪器
Ptr<Tracker> tracker = TrackerKCF::create()
  1. 选择目标roi(boundingbox)
    这里是使用selectROI这个函数
    在这里插入图片描述
  • 功能:允许用户在给定图像上选择 ROI。

该功能创建一个窗口,并允许用户使用鼠标选择ROI。控件:使用或完成选择,使用键取消选择(函数将返回零 cv::Rect)

  • 参数:
    (1)windowName 窗口名
    (2)img 用于选择roi的图像
    (3)showCrosshair 果将显示选择矩形的真十字准线。
    (4)fromCenter如果真正的选择中心将与初始鼠标位置匹配。相反情况下,选择矩形的一角将对应于初始鼠标位置。
  1. 初始化追踪器 tracker->init(frame, roi)
  2. 对每一帧进行追踪tracker->update(frame, roi)

2.2.1 完整代码

#include <opencv2/core/utility.hpp>
#include <opencv2/tracking.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <cstring>

using namespace std;
using namespace cv;

int main() {
    // declares all required variables
    //! [vars]
    Rect2d roi;
    Mat frame;
    //! [vars]

    // create a tracker object
    //Ptr<Tracker> tracker = Tracker::create("KCF");
    Ptr<Tracker> tracker = TrackerKCF::create();
    //! [create]

    // set input video
    //! [setvideo]
    std::string video = "E:\\car.mp4";
    VideoCapture cap(video);
    //! [setvideo]

    // get bounding box
    //! [getframe]
    cap >> frame;
    //! [getframe]
    //! [selectroi]选择目标roi以GUI的形式
    roi = selectROI("tracker", frame);
    //! [selectroi]

    //quit if ROI was not selected
    if (roi.width == 0 || roi.height == 0)
        return 0;

    // initialize the tracker
    //! [init]
    tracker->init(frame, roi);
    //! [init]

    // perform the tracking process
    printf("Start the tracking process\n");
    for (;; ) {
        // get frame from the video
        cap >> frame;

        // stop the program if no more images
        if (frame.rows == 0 || frame.cols == 0)
            break;

        // update the tracking result
        //! [update]
        tracker->update(frame, roi);
        //! [update]

        //! [visualization]
        // draw the tracked object
        rectangle(frame, roi, Scalar(255, 0, 0), 2, 1);

        // show image with the tracked object
        imshow("tracker", frame);
        //! [visualization]
        //quit on ESC button
        if (waitKey(1) == 27)
            break;
    }

    return 0;
}

3 在RM中的使用

以桂电的开源代码为例

3.1 跟踪器初始化armorTrackerInit

整体的逻辑:
请添加图片描述

3.1.1跟踪失败

        //追踪失败
        src(_trackerRect).copyTo(img);
        if (!_tracker->update(_src, _trackerRect)) {
            _trackerSuccess = false; 
            _searchRect.x = _trackerRect.x - _trackerRect.width;
            _searchRect.y = _trackerRect.y - _trackerRect.height;
            _searchRect.height = _trackerRect.height * 3;
            _searchRect.width = _trackerRect.width * 3;
            _searchRect &= cv::Rect2d(0, 0, _imgWidth, _imgHeight);
        }

_searchRect &= cv::Rect2d(0, 0, _imgWidth, _imgHeight)限制面积不越界
请添加图片描述

其他代码都挺简单的,就不细说了,下面给出完整片段

3.1.2 调用关系

在识别过程函数process中被调用

//识别过程函数
cv::RotatedRect ArmorDistinguish::process(const cv::Mat& src, EnemyColor enemyColor, CarType carType, bool isReset, DistinguishMode distinguishMode, float yawAngle, bool topRest) {
#ifdef USE_KCF
    armorTrackerInit(src, enemyColor);
#else
    imagePreprocess(src, enemyColor);
#endif

3.1.3 完整代码

#ifdef USE_KCF
//kcf追踪器
void ArmorDistinguish::armorTrackerInit(const cv::Mat& src, EnemyColor enemyColor) {
    cv::Mat img;
    _size = src.size();
    _para.enemyColor = enemyColor;
    _params.detect_thresh = 0.03f;
    if (_isTrackerStart) {
        //追踪失败
        src(_trackerRect).copyTo(img);
        if (!_tracker->update(_src, _trackerRect)) {
            _trackerSuccess = false; 
            _searchRect.x = _trackerRect.x - _trackerRect.width;
            _searchRect.y = _trackerRect.y - _trackerRect.height;
            _searchRect.height = _trackerRect.height * 3;
            _searchRect.width = _trackerRect.width * 3;
            _searchRect &= cv::Rect2d(0, 0, _imgWidth, _imgHeight);
        }
        else {//_tracker->update(_src, _trackerRect)==True
            //越界则需要从全图搜索
            if ((_trackerRect & cv::Rect2d(0, 0, _imgWidth, _imgHeight)) != _trackerRect) {
                _searchRect = cv::Rect2d(0, 0, _imgWidth, _imgHeight);
            }
            //搜索区域需要扩大两倍
            else {
                _trackerSuccess = true;
                _searchRect.x = _trackerRect.x - _trackerRect.width / 2;
                _searchRect.y = _trackerRect.y - _trackerRect.height / 2;
                _searchRect.height = _trackerRect.height * 2;
                _searchRect.width = _trackerRect.width * 2;
                _searchRect &= cv::Rect2d(0, 0, _imgWidth, _imgHeight);
            }//else
        }//else
        src(_searchRect).copyTo(_src);
        imshow("img", img);
    }
    else {//_isTrackerStart==False
        _trackerSuccess = false;
        _searchRect = cv::Rect2d(0, 0, _imgWidth, _imgHeight);
        _src = src;
    }

    imshow("_src", _src);
    cv::waitKey(1);
}
#endif

3.2 识别过程函数process

仅包含kcf部分

3.2.1

3.2.2 包含kfc的代码

完整代码见https://github.com/freezing00/Baldr/blob/main/Src/armor/armorDistinguish.cpp

//识别过程函数
cv::RotatedRect ArmorDistinguish::process(const cv::Mat& src, EnemyColor enemyColor, CarType carType, bool isReset, DistinguishMode distinguishMode, float yawAngle, bool topRest) {

#ifdef USE_KCF
    armorTrackerInit(src, enemyColor);
#else//正常图像的预处理
    imagePreprocess(src, enemyColor);
#endif
    //从轮廓中找出类似灯条矩形
    
    //类似灯条矩形过滤器

    //选择一个最优目标

    if (_resultRect.size.width > 0) {
        //中间点的坐标再加上restoreRect的坐标
#ifdef USE_KCF
        _isReulstFind = true;
        _isTrackerStart = true;
        if (_isReulstFind) {
            float lightBarWidthL = _leftLightBar.size.width < _leftLightBar.size.height ? _leftLightBar.size.width : _leftLightBar.size.height;
            float lightBarHeightL = _leftLightBar.size.width > _leftLightBar.size.height ? _leftLightBar.size.width : _leftLightBar.size.height;
            float lightBarWidthR = _rightLightBar.size.width < _rightLightBar.size.height ? _rightLightBar.size.width : _rightLightBar.size.height;
            float lightBarHeightR = _rightLightBar.size.width > _rightLightBar.size.height ? _rightLightBar.size.width : _rightLightBar.size.height;

            cv::Point2d recttl = cv::Point2d((double)(_leftLightBar.center.x - 2.0 * lightBarWidthL), (double)(_leftLightBar.center.y - 1.5 * lightBarHeightL));
            cv::Point2d rectbr = cv::Point2d((double)(_rightLightBar.center.x + 2.0 * lightBarWidthR), (double)(_rightLightBar.center.y + 1.5 * lightBarHeightR));
            recttl += cv::Point2d(_searchRect.x, _searchRect.y);
            rectbr += cv::Point2d(_searchRect.x, _searchRect.y);
            _trackerRect = cv::Rect2d(recttl, rectbr);
            _trackerRect &= cv::Rect2d(0, 0, _imgWidth, _imgHeight);
            //---------------创建KCF追踪器-----------------------------------------------
            _tracker = cv::TrackerKCF::create();
            _tracker->init(_src, _trackerRect);
        }
        resultRect.center += cv::Point2f((float)_searchRect.x, (float)_searchRect.y);
#else
        _resultRect.center += cv::Point2f((float)_restoreRect.x, (float)_restoreRect.y);
#endif
        _resultRect.points(_vertices);
        //记录上一刻的检测区域
        _resLast = _resultRect;
        _lost_cnt = 0;
        //记录上一刻的时间
        _lastTime = (double)(cv::getTickCount());

    }
    else {
#ifdef USE_KCF
        _isTrackerStart = false;
        _isReulstFind = false;
        return cv::RotatedRect();

#endif //USE_KCF
    }

}

3.3 小结

在装甲板识别中使用KFC的整体逻辑
请添加图片描述

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值