KCF(Kernelized Correlation Filter)基于核化的 岭回归分类器 使用循环移位得到的 循环矩阵 来采集正负样本,利用循环矩阵在 傅里叶空间 可对角化的性质,将矩阵的运算转化为元素的点乘,从而降低了运算量,使得算法满足实时性要求。同时, KCF使用 多通道HOG特征 代替单通道灰度特征,将特征扩展到多通道的非线性特征空间,达到了更高的鲁棒性和准确性。

源码及参考

数据集

论文中提及所用的数据集是 OTB2013 Y. Wu, J. Lim, and M. H. Yang, “Online object tracking: A benchmark,” in CVPR, 2013 共包含50个视频序列。官方下载:Visual Tracker Benchmark

视频列表:

videos = {'basketball', 'bolt', 'boy', 'car4', 'carDark', 'carScale', ...
	'coke', 'couple', 'crossing', 'david2', 'david3', 'david', 'deer', ...
	'dog1', 'doll', 'dudek', 'faceocc1', 'faceocc2', 'fish', 'fleetface', ...
	'football', 'football1', 'freeman1', 'freeman3', 'freeman4', 'girl', ...
	'ironman', 'jogging', 'jumping', 'lemming', 'liquor', 'matrix', ...
	'mhyang', 'motorRolling', 'mountainBike', 'shaking', 'singer1', ...
	'singer2', 'skating1', 'skiing', 'soccer', 'subway', 'suv', 'sylvester', ...
	'tiger1', 'tiger2', 'trellis', 'walking', 'walking2', 'woman'};

MATLAB 代码测试

Quickstart:

  1. Extract code somewhere.
  2. The tracker is prepared to run on any of the 50 videos of the Visual Tracking Benchmark [3]. For that, it must know where they are/will be located. You can change the default location ‘base_path’ in ‘download_videos.m’ and run_tracker.m.
  3. If you don’t have the videos already, run download_videos.m (may take some time).
  4. Execute ‘run_tracker’ without parameters to choose a video and test the KCF on it.

注意:

  • 在国内用脚本下载数据集容易失败,建议前往官网手动下载;
  • 代码不兼容部分需要按提示更改,如show_video.m中第24行的Number应改为NumberTitle等,MATLAB2018环境可直接下载调整好的代码:MATLAB 2018 KCF源码

测试环境:

测试结果:

>> run_tracker all gaussian hog  %Kernelized Correlation Filter (KCF)

从最后结果来看,KCF(0.742,293)要优于论文结果(0.732,172), DCF(0.730, 604)也优于论文结果(0.728, 292). 代码相同的前提下,可能是硬件不同以及MATLAB版本升级带来了巨大的性能提升。

MATLAB 代码分析

只对 KCF-HOG 部分的代码进行分析

性能评估接口:
run_tracker.m

这是并行测试50个视频序列,最后对结果取平均。从下面的跟踪接口代码来看,img_files中存放图片名称,在tracker函数中进行读取并跟踪。从tic() toc()包括的代码来看,只测量跟踪算法消耗的时间,imread()时间不计入。

跟踪接口代码:

run_tracker.m

跟踪参数:

padding = 1.5;    				// extra area surrounding the target
feature_type = 'hog';			// feature type
kernel.type = 'gaussian';   	// kernel
kernel.sigma = 0.5;				// gaussian kernel bandwidth
lambda = 1e-4;    				// regularization
output_sigma_factor = 0.1;  	// spatial bandwidth (proportional to target)
interp_factor = 0.02;			// linear interpolation factor for adaptation of model parameters
cell_size = 4;					// HOG cell size 
features.hog = true;			// enable HOG feature
features.hog_orientations = 9;	// the number of HOG bins

跟踪代码:

与论文中的伪代码相差不大:

这是由以下的核心公式得出的。

KCF核心公式

  • 核相关矩阵的初始向量:

  • 核化后的岭回归分类器权值:

  • 快速检测:

KCF公式推导

Step 1:KCF的基本模型是岭回归分类器


Step 2:为了 简化闭式解的计算,消除矩阵乘法与求逆运算,以及为了 增广样本,需要引入循环矩阵。


循环矩阵有着良好性质:

离散傅里叶变换简介:


Step 3:简化计算


注:最后结果的 d i a g diag diag运算可以省略。


Step 4:为了提高分类器的准确度,解决“线性不可分”问题,对岭回归分类器进行 “核化”。

核空间的岭回归:


Step 5:核化分类器的简化计算



对闭式解进行同等化简(对角化、傅里叶变换):


Step 6:核相关矩阵的加速计算


Step 7:快速检测


Step 8:选用多通道HOG特征提升准确率。对于多通道的特征描述符,只需在傅立叶域中对对每个通道的各个点积求和即可。

HOG特征与FHOG特征:

C++ 代码测试


需要修改数据集,这里只对Coke序列进行了测试。OpenCV版本 4.x,修改后的可运行代码和数据集已经上传: Streamlined KCF.zip

video info:

  • img size (640, 480)
  • roi size (48, 80)
  • win size (120, 200) = roi * 2.5
  • frame count 291


相比MATLAB的测试结果(143 fps),慢了太多。根据作者GitHub所描述的,这并不是单一尺度的跟踪,使用的特征是FHOG+CN,因此测试基本性能需要将这些参数清零:

再次测试,速度明显提升:

此时,C++ 版本的算法实现参数为:单一尺度、仅使用灰度图像的FHOG特征、使用Gaussian核,达到平均帧率 110 fps;跟踪效果方面仅可以抵抗小部分遮挡,完全遮挡则会出现目标丢失。

OpenCV 代码测试

版本 4.1.2

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/tracking.hpp>

using namespace std;

int main(int argc, char* argv[])
{
    // 读取视频序列
    string frame_files = "../datasets/OTB2013/Coke/img/%04d.jpg";
    cv::VideoCapture cap(frame_files);
    int frame_height = int(cap.get(cv::CAP_PROP_FRAME_HEIGHT));
    int frame_width = int(cap.get(cv::CAP_PROP_FRAME_WIDTH));
    int frame_count = (int)cap.get(cv::CAP_PROP_FRAME_COUNT);
    printf("video info: (%d, %d), %d frames\n", frame_width, frame_height, frame_count);
    cv::Mat frame;
    cap >> frame;
    cv::Rect2d bbox(298, 160, 48, 80);

    // 跟踪测试
    cv::Ptr<cv::Tracker> tracker;
    cv::TrackerKCF::Params tracker_params;
    tracker_params.detect_thresh = 0.3f;
    tracker = cv::TrackerKCF::create(tracker_params);
    tracker->init(frame, bbox);
    double total_time_s = 0.;
    for (int i = 0; i < frame_count - 1; ++i)
    {
        cap >> frame;
        double time_profile_counter = cv::getTickCount();
        tracker->update(frame, bbox);
        time_profile_counter = cv::getTickCount() - time_profile_counter;
        auto time = time_profile_counter / cv::getTickFrequency();
        total_time_s += time;
        std::cout << " -> speed : " << 1. / time << " fps" << std::endl;
    }

    cap.release();
    std::cout << "\nAverage speed " << (frame_count - 1) / total_time_s << " fps" << std::endl;
    std::cout << "\nProcessing time: " << total_time_s << " s." << std::endl;

    return 0;
}

同样的数据集,比着上一节的Streamlined KCF要快的多,并且高于MATLAB(143 fps) 的测试结果。此时采用的是 cv::TrackerKCF 默认参数,选择的是压缩后的ColorName特征,并不是论文中设计的FHOG特征。从跟踪效果上看,无法应对小部分遮挡,在 OTB2013/Coke 数据集中 第10帧往后即丢失目标

关于帧率统计需要说明的是:

  • 评价tracker的性能,应该只统计跟踪时间,图像读取时间是被排除的,在作者的MATLAB源码中也是这么计时的(上文中有提及)。
  • 如果在for/while循环外进行计时,则连带统计了imread的耗时,结果有所不同:总耗时 2.498 s,由此可见,KCF的跟踪性能与OpenCV的图像读取差不多,的确性能出众。