长时间目标跟踪算法(1)-TLD目标跟踪算法

TLD算法源码,欢迎大家下载:下载地址
对于长时间跟踪而言,一个关键的问题是:当目标重新出现在相机视野中时,系统应该能重新检测到它,并开始重新跟踪。但是,长时间跟踪过程中,被跟踪目标将不可避免的发生形状变化、光照条件变化、尺度变化、遮挡等情况。传统的跟踪算法,前端需要跟检测模块相互配合,当检测到被跟踪目标之后,就开始进入跟踪模块,而此后,检测模块就不会介入到跟踪过程中。但这种方法有一个致命的缺陷:即,当被跟踪目标存在形状变化或遮挡时,跟踪就很容易失败;因此,对于长时间跟踪,或者被跟踪目标存在形状变化情况下的跟踪,很多人采用检测的方法来代替跟踪。该方法虽然在某些情况下可以改进跟踪效果,但它需要一个离线的学习过程。即:在检测之前,需要挑选大量的被跟踪目标的样本来进行学习和训练。这也就意味着,训练样本要涵盖被跟踪目标可能发生的各种形变和各种尺度、姿态变化和光照变化的情况。换言之,利用检测的方法来达到长时间跟踪的目的,对于训练样本的选择至关重要,否则,跟踪的鲁棒性就难以保证。

一、TLD算法概述

TLD算法是由英国萨里大学的一个捷克籍博士生Zdenek Kalal在其攻读博士学位期间提出的一种新的单目标长时间跟踪(long term tracking)算法。该算法的核心思想是通过结合目标跟踪、目标学习和目标检测的技术,实现在复杂场景下的鲁棒目标跟踪。TLD算法将传统的跟踪算法和传统的检测算法相结合,以解决被跟踪目标在被跟踪过程中发生的形变、部分遮挡等问题。同时,通过一种改进的在线学习机制不断更新跟踪模块的“显著特征点”和检测模块的目标模型及相关参数,从而使得跟踪效果更加稳定、可靠。TLD长时间目标跟踪算法C++源码

在这里插入图片描述

二、TLD算法的原理

TLD算法由三部分组成:跟踪模块、检测模块和学习模块。这三个模块协同工作,共同实现目标跟踪任务。

在这里插入图片描述

2.1 跟踪模块

跟踪模块负责观察帧与帧之间的目标动向。在TLD算法中,跟踪模块采用了一种基于中值流跟踪(Median-Flow tracker)的方法,并增加了跟踪失败检测算法。中值流跟踪方法利用目标框来表示被跟踪目标,并在连续的相邻视频帧之间估计目标的运动。具体来说,该方法首先在目标图像框内均匀撒点,并通过中值过滤筛选出可靠的目标像素点。然后,采用前向后向误差法,即通过两次光流法有效地得出成功跟踪的像素点,从而生成成功跟踪目标的矩形框。

为了应对目标被完全遮挡或消失于视野的情况,TLD算法在跟踪模块中加入了跟踪失败检测策略。该策略通过比较特征点的位移变化来检测跟踪失败。具体来说,以di表示其中一个特征点的移动位移,dm表示位移中值,则残差可定义为|di-dm|。如果残差大于一定阈值(如10个像素),则认为跟踪失败。

2.2 检测模块

检测模块负责将每张图看成独立的,然后去定位目标。在TLD算法中,检测模块采用了基于滑动窗口的检测方法,并结合了级联分类器架构。级联分类器由方差分类器、集成分类器和最近邻分类器组成。

检测过程首先通过滑动窗口扫描整幅图像,生成一系列图像块(patch)。然后,利用方差分类器快速计算每个图像块的方差,并淘汰方差过小的图像块。接下来,通过集成分类器(如随机森林)对剩余的图像块进行分类。最后,利用最近邻分类器与目标模型进行比较,确定成功检测到的目标。

2.3 学习模块

学习模块负责根据跟踪模块的结果对检测模块的错误进行评估,并生成训练样本来更新检测模块的目标模型,以避免以后出现类似错误。学习模块的核心思想为P-N(Positive-Negative)学习。P约束寻找视频序列中时域上的结构性特征,并假设目标的运动是按照一定的轨迹进行的;N约束寻找视频序列中空域的结构性特征,并假设目标在一个视频中只能出现在一个位置上。两种约束都会生成正负样本,学习模块利用新生成的正负样本更新目标模型。

三、TLD算法的实现过程

TLD算法的实现过程可以分为初始化、目标跟踪、在线学习和离线检测四个步骤。

3.1 初始化

在视频序列的第一帧中,用户需要手动选择目标对象的位置。该位置被用作目标的初始边界框,并作为后续跟踪和检测的基准。

void TLD::init(const Mat& frame1,const Rect& box,FILE* bb_file)

3.2 目标跟踪

在后续的视频帧中,TLD算法使用模板匹配的方法来跟踪目标。具体来说,首先将目标对象的初始边界框作为模板,利用相关滤波器(如MedianFlow)来估计目标的新位置。然后,根据目标的新位置更新目标的边界框。

void TLD::processFrame(const cv::Mat& img1,const cv::Mat& img2,vector<Point2f>& points1,vector<Point2f>& points2,BoundingBox& bbnext,bool& lastboxfound, bool tl, FILE* bb_file){

3.3在线学习

在线学习阶段的目标是学习目标模型并对目标进行描述。算法首先通过选择性搜索(Selective Search)方法生成一组候选框,然后对每个候选框提取特征。候选框的特征通过一个强分类器进行分类,并将分类结果作为正负样本用于在线学习。学习的目标是得到一个判别器,用于区分目标和背景。具体来说,TLD算法使用Haar-like特征描述候选框,并使用Adaboost算法训练强分类器。在训练过程中,算法会根据分类误差更新分类器的权重,以提高分类的准确性。通过反复迭代,TLD算法能够逐渐学习到目标的特征模式,实现对目标的有效分类。

void TLD::learn(const Mat& img){
  printf("[Learning] ");
  ///Check consistency
  BoundingBox bb;
  bb.x = max(lastbox.x,0);
  bb.y = max(lastbox.y,0);
  bb.width = min(min(img.cols-lastbox.x,lastbox.width),min(lastbox.width,lastbox.br().x));
  bb.height = min(min(img.rows-lastbox.y,lastbox.height),min(lastbox.height,lastbox.br().y));
  Scalar mean, stdev;
  Mat pattern;
  getPattern(img(bb),pattern,mean,stdev);
  vector<int> isin;
  float dummy, conf;
  classifier.NNConf(pattern,isin,conf,dummy);
  if (conf<0.5) {
      printf("Fast change..not training\n");
      lastvalid =false;
      return;
  }
  if (pow(stdev.val[0],2)<var){
      printf("Low variance..not training\n");
      lastvalid=false;
      return;
  }
  if(isin[2]==1){
      printf("Patch in negative data..not traing");
      lastvalid=false;
      return;
  }
/// Data generation
  for (int i=0;i<grid.size();i++){
      grid[i].overlap = bbOverlap(lastbox,grid[i]);
  }
  vector<pair<vector<int>,int> > fern_examples;
  good_boxes.clear();
  bad_boxes.clear();
  getOverlappingBoxes(lastbox,num_closest_update);
  if (good_boxes.size()>0)
    generatePositiveData(img,num_warps_update);
  else{
    lastvalid = false;
    printf("No good boxes..Not training");
    return;
  }
  fern_examples.reserve(pX.size()+bad_boxes.size());
  fern_examples.assign(pX.begin(),pX.end());
  int idx;
  for (int i=0;i<bad_boxes.size();i++){
      idx=bad_boxes[i];
      if (tmp.conf[idx]>=1){
          fern_examples.push_back(make_pair(tmp.patt[idx],0));
      }
  }
  vector<Mat> nn_examples;
  nn_examples.reserve(dt.bb.size()+1);
  nn_examples.push_back(pEx);
  for (int i=0;i<dt.bb.size();i++){
      idx = dt.bb[i];
      if (bbOverlap(lastbox,grid[idx]) < bad_overlap)
        nn_examples.push_back(dt.patch[i]);
  }
  /// Classifiers update
  classifier.trainF(fern_examples,2);
  classifier.trainNN(nn_examples);
  classifier.show();
}

3.4 离线检测

离线检测阶段主要用于在目标丢失时重新检测目标。当跟踪模块检测到跟踪失败时,检测模块会在整幅图像中进行滑动窗口扫描,以重新定位目标。一旦检测到目标,跟踪模块将重新开始跟踪过程。

void TLD::detect(const cv::Mat& frame){
  //cleaning
  dbb.clear();
  dconf.clear();
  dt.bb.clear();
  double t = (double)getTickCount();
  Mat img(frame.rows,frame.cols,CV_8U);
  integral(frame,iisum,iisqsum);
  GaussianBlur(frame,img,Size(9,9),1.5);
  int numtrees = classifier.getNumStructs();
  float fern_th = classifier.getFernTh();
  vector <int> ferns(10);
  float conf;
  int a=0;
  Mat patch;
  for (int i=0;i<grid.size();i++){//FIXME: BottleNeck
      if (getVar(grid[i],iisum,iisqsum)>=var){
          a++;
		  patch = img(grid[i]);
          classifier.getFeatures(patch,grid[i].sidx,ferns);
          conf = classifier.measure_forest(ferns);
          tmp.conf[i]=conf;
          tmp.patt[i]=ferns;
          if (conf>numtrees*fern_th){
              dt.bb.push_back(i);
          }
      }
      else
        tmp.conf[i]=0.0;
  }
  int detections = dt.bb.size();
  printf("%d Bounding boxes passed the variance filter\n",a);
  printf("%d Initial detection from Fern Classifier\n",detections);
  if (detections>100){
      nth_element(dt.bb.begin(),dt.bb.begin()+100,dt.bb.end(),CComparator(tmp.conf));
      dt.bb.resize(100);
      detections=100;
  }
//  for (int i=0;i<detections;i++){
//        drawBox(img,grid[dt.bb[i]]);
//    }
//  imshow("detections",img);
  if (detections==0){
        detected=false;
        return;
      }
  printf("Fern detector made %d detections ",detections);
  t=(double)getTickCount()-t;
  printf("in %gms\n", t*1000/getTickFrequency());
                                                                       //  Initialize detection structure
  dt.patt = vector<vector<int> >(detections,vector<int>(10,0));        //  Corresponding codes of the Ensemble Classifier
  dt.conf1 = vector<float>(detections);                                //  Relative Similarity (for final nearest neighbour classifier)
  dt.conf2 =vector<float>(detections);                                 //  Conservative Similarity (for integration with tracker)
  dt.isin = vector<vector<int> >(detections,vector<int>(3,-1));        //  Detected (isin=1) or rejected (isin=0) by nearest neighbour classifier
  dt.patch = vector<Mat>(detections,Mat(patch_size,patch_size,CV_32F));//  Corresponding patches
  int idx;
  Scalar mean, stdev;
  float nn_th = classifier.getNNTh();
  for (int i=0;i<detections;i++){                                         //  for every remaining detection
      idx=dt.bb[i];                                                       //  Get the detected bounding box index
	  patch = frame(grid[idx]);
      getPattern(patch,dt.patch[i],mean,stdev);                //  Get pattern within bounding box
      classifier.NNConf(dt.patch[i],dt.isin[i],dt.conf1[i],dt.conf2[i]);  //  Evaluate nearest neighbour classifier
      dt.patt[i]=tmp.patt[idx];
      //printf("Testing feature %d, conf:%f isin:(%d|%d|%d)\n",i,dt.conf1[i],dt.isin[i][0],dt.isin[i][1],dt.isin[i][2]);
      if (dt.conf1[i]>nn_th){                                               //  idx = dt.conf1 > tld.model.thr_nn; % get all indexes that made it through the nearest neighbour
          dbb.push_back(grid[idx]);                                         //  BB    = dt.bb(:,idx); % bounding boxes
          dconf.push_back(dt.conf2[i]);                                     //  Conf  = dt.conf2(:,idx); % conservative confidences
      }
  }                                                                         //  end
  if (dbb.size()>0){
      printf("Found %d NN matches\n",(int)dbb.size());
      detected=true;
  }
  else{
      printf("No NN matches found.\n");
      detected=false;
  }
}

四、TLD算法的优点与缺点

4.1 优点

鲁棒性强:TLD算法结合了跟踪和检测的方法,能够在复杂环境中跟踪目标并检测目标的丢失,从而提高了跟踪的准确率和稳定性。
自适应性强:通过在线学习机制不断更新目标模型和相关参数,TLD算法能够适应目标的外观变化。
长时间跟踪:TLD算法是一种单目标长时间跟踪算法,能够在目标长时间消失或遮挡后再次检测到目标并继续跟踪。

4.2 缺点

初始化要求高:TLD算法需要用户手动选择目标并进行训练,这限制了算法的应用范围。
计算复杂度高:由于结合了跟踪、检测和学习三个模块,TLD算法的计算复杂度较高,对硬件资源要求较高。
遮挡和快速移动时易失败:在目标遮挡或快速移动时,TLD算法容易出现跟踪失败的情况。

五、TLD算法的应用与优化

TLD算法在目标跟踪领域具有广泛的应用前景,如视频监控、自动驾驶、人机交互等。然而,由于存在一些缺点和限制,研究人员不断对TLD算法进行优化和改进。

5.1 初始化自动化

为了降低用户手动初始化的要求,研究人员提出了自动化初始化的方法。例如,利用背景减除法或光流法自动检测视频序列中的运动目标,并将其作为初始跟踪目标。

5.2 提高计算效率

为了提高TLD算法的计算效率,研究人员提出了多种优化方法。例如,通过减少滑动窗口的扫描范围、改进特征提取和分类算法、利用并行计算技术等手段来降低计算复杂度。

5.3 增强鲁棒性

为了增强TLD算法的鲁棒性,研究人员提出了多种改进方法。例如,结合深度学习技术来提高目标检测和跟踪的准确性;引入多目标跟踪算法来处理复杂场景下的多目标跟踪问题;利用上下文信息来提高目标跟踪的鲁棒性等。

六、结论

TLD算法作为一种经典的目标跟踪算法,在复杂场景下的鲁棒目标跟踪中表现出色。通过结合跟踪、检测和学习三个模块,TLD算法能够适应目标的外观变化,并在目标丢失时重新检测到目标。然而,由于存在一些缺点和限制,研究人员不断对TLD算法进行优化和改进。未来,随着计算机视觉技术的不断发展,TLD算法将在更多领域得到应用和发展。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深图智能

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值